diff --git a/.env.sample b/.env.sample
index a7acfa2..41716cb 100644
--- a/.env.sample
+++ b/.env.sample
@@ -15,7 +15,6 @@ NEXT_PUBLIC_DISABLE_REGISTRATION=
NEXT_PUBLIC_CREDENTIALS_ENABLED=
DISABLE_NEW_SSO_USERS=
RE_ARCHIVE_LIMIT=
-NEXT_PUBLIC_MAX_FILE_SIZE=
MAX_LINKS_PER_USER=
ARCHIVE_TAKE_COUNT=
BROWSER_TIMEOUT=
@@ -23,6 +22,12 @@ IGNORE_UNAUTHORIZED_CA=
IGNORE_HTTPS_ERRORS=
IGNORE_URL_SIZE_LIMIT=
ADMINISTRATOR=
+NEXT_PUBLIC_MAX_FILE_BUFFER=
+MONOLITH_MAX_BUFFER=
+MONOLITH_OPTIONS=
+PDF_MAX_BUFFER=
+SCREENSHOT_MAX_BUFFER=
+READABILITY_MAX_BUFFER=
# AWS S3 Settings
SPACES_KEY=
@@ -52,9 +57,9 @@ PDF_MARGIN_BOTTOM=
SINGLEFILE_ARCHIVE_COMMAND= # single-file "{{URL}}" --dump-content
SINGLEFILE_ARCHIVE_HTTP_API= # http://singlefile:3000/
-#
-# SSO Providers
-#
+#################
+# SSO Providers #
+#################
# 42 School
NEXT_PUBLIC_FORTYTWO_ENABLED=
diff --git a/Dockerfile b/Dockerfile
index 9de1541..2c573c5 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -11,6 +11,8 @@ COPY ./package.json ./yarn.lock ./playwright.config.ts ./
# Increase timeout to pass github actions arm64 build
RUN --mount=type=cache,sharing=locked,target=/usr/local/share/.cache/yarn yarn install --network-timeout 10000000
+# RUN /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" && brew install monolith
+
RUN npx playwright install-deps && \
apt-get clean && \
yarn cache clean
diff --git a/components/ModalContent/PreservedFormatsModal.tsx b/components/ModalContent/PreservedFormatsModal.tsx
index 0f2ef36..17468e7 100644
--- a/components/ModalContent/PreservedFormatsModal.tsx
+++ b/components/ModalContent/PreservedFormatsModal.tsx
@@ -159,6 +159,16 @@ export default function PreservedFormatsModal({ onClose, activeLink }: Props) {
)}
+ {singlefileAvailable(link) ? (
+
+ ) : undefined}
+
{screenshotAvailable(link) ? (
{t("file_types", {
- size: process.env.NEXT_PUBLIC_MAX_FILE_SIZE || 30,
+ size: process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10,
})}
diff --git a/components/PreserverdFormatRow.tsx b/components/PreserverdFormatRow.tsx
index a5c9061..0ec0b1b 100644
--- a/components/PreserverdFormatRow.tsx
+++ b/components/PreserverdFormatRow.tsx
@@ -73,7 +73,7 @@ export default function PreservedFormatRow({
anchorElement.href = path;
anchorElement.download =
format === ArchivedFormat.singlefile
- ? link.name ?? "index"
+ ? "Webpage"
: format === ArchivedFormat.pdf
? "PDF"
: "Screenshot";
diff --git a/docker-compose.yml b/docker-compose.yml
index b809ce4..628a5d6 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -19,6 +19,9 @@ services:
- ./data:/data/data
depends_on:
- postgres
- singlefile:
- image: rutkai/single-file-web:latest
- container_name: singlefile
+ # monolith:
+ # image: ghcr.io/linkwarden/monolith:latest
+ # container_name: monolith
+ # singlefile:
+ # image: rutkai/single-file-web:latest
+ # container_name: singlefile
diff --git a/lib/api/archiveHandler.ts b/lib/api/archiveHandler.ts
index cd95db4..99729cf 100644
--- a/lib/api/archiveHandler.ts
+++ b/lib/api/archiveHandler.ts
@@ -7,9 +7,10 @@ import validateUrlSize from "./validateUrlSize";
import createFolder from "./storage/createFolder";
import generatePreview from "./generatePreview";
import { removeFiles } from "./manageLinkFiles";
-import archiveAsSinglefile from "./preservationScheme/archiveAsSinglefile";
-import archiveAsReadability from "./preservationScheme/archiveAsReadablility";
-import shell from "shelljs";
+import handleMonolith from "./preservationScheme/handleMonolith";
+import handleReadablility from "./preservationScheme/handleReadablility";
+import handleArchivePreview from "./preservationScheme/handleArchivePreview";
+import handleScreenshotAndPdf from "./preservationScheme/handleScreenshotAndPdf";
type LinksAndCollectionAndOwner = Link & {
collection: Collection & {
@@ -51,26 +52,6 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
const page = await context.newPage();
- // await page.goto("https://github.com", {
- // waitUntil: "domcontentloaded",
- // });
-
- // console.log("Opening page:", link.url);
-
- // await page.evaluate(autoScroll, Number(process.env.AUTOSCROLL_TIMEOUT) || 30);
-
- // const dom = await page.content();
-
- // console.log("The content", dom);
-
- // shell
- // .echo(dom)
- // .exec(
- // "monolith - -I -b https://marketplace.visualstudio.com/items?itemName=42Crunch.vscode-openapi -j -F -o monolith.html"
- // );
-
- // console.log("Monolith created!");
-
createFolder({
filePath: `archives/preview/${link.collectionId}`,
});
@@ -131,15 +112,6 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
},
});
- // SingleFile
- // if (
- // !link.singlefile?.startsWith("archive") &&
- // !link.singlefile?.startsWith("unavailable") &&
- // user.archiveAsSinglefile &&
- // link.url
- // )
- // await archiveAsSinglefile(link);
-
// send to archive.org
if (user.archiveAsWaybackMachine && link.url) sendToWayback(link.url);
@@ -156,19 +128,19 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
const content = await page.content();
- // Readability
- if (
- !link.readable?.startsWith("archives") &&
- !link.readable?.startsWith("unavailable")
- )
- await archiveAsReadability(content, link);
-
// Preview
if (
!link.preview?.startsWith("archives") &&
!link.preview?.startsWith("unavailable")
)
- await getArchivePreview(link, page);
+ await handleArchivePreview(link, page);
+
+ // Readability
+ if (
+ !link.readable?.startsWith("archives") &&
+ !link.readable?.startsWith("unavailable")
+ )
+ await handleReadablility(content, link);
// Screenshot/PDF
if (
@@ -177,7 +149,16 @@ export default async function archiveHandler(link: LinksAndCollectionAndOwner) {
(!link.pdf?.startsWith("archives") &&
!link.pdf?.startsWith("unavailable"))
)
- await captureScreenshotAndPdf(link, page, user);
+ await handleScreenshotAndPdf(link, page, user);
+
+ // SingleFile
+ if (
+ !link.singlefile?.startsWith("archive") &&
+ !link.singlefile?.startsWith("unavailable") &&
+ user.archiveAsSinglefile &&
+ link.url
+ )
+ await handleMonolith(link, content);
}
})(),
timeoutPromise,
@@ -268,133 +249,3 @@ const pdfHandler = async ({ url, id }: Link) => {
});
}
};
-
-const getArchivePreview = async (
- link: LinksAndCollectionAndOwner,
- page: Page
-) => {
- const ogImageUrl = await page.evaluate(() => {
- const metaTag = document.querySelector('meta[property="og:image"]');
- return metaTag ? (metaTag as any).content : null;
- });
-
- if (ogImageUrl) {
- console.log("Found og:image URL:", ogImageUrl);
-
- // Download the image
- const imageResponse = await page.goto(ogImageUrl);
-
- // Check if imageResponse is not null
- if (imageResponse && !link.preview?.startsWith("archive")) {
- const buffer = await imageResponse.body();
- generatePreview(buffer, link.collectionId, link.id);
- }
-
- await page.goBack();
- } else if (!link.preview?.startsWith("archive")) {
- console.log("No og:image found");
- await page
- .screenshot({ type: "jpeg", quality: 20 })
- .then((screenshot) => {
- return createFile({
- data: screenshot,
- filePath: `archives/preview/${link.collectionId}/${link.id}.jpeg`,
- });
- })
- .then(() => {
- return prisma.link.update({
- where: { id: link.id },
- data: {
- preview: `archives/preview/${link.collectionId}/${link.id}.jpeg`,
- },
- });
- });
- }
-};
-
-const captureScreenshotAndPdf = async (
- link: LinksAndCollectionAndOwner,
- page: Page,
- user: User
-) => {
- await page.evaluate(autoScroll, Number(process.env.AUTOSCROLL_TIMEOUT) || 30);
-
- // Check if the user hasn't deleted the link by the time we're done scrolling
- const linkExists = await prisma.link.findUnique({
- where: { id: link.id },
- });
- if (linkExists) {
- const processingPromises = [];
-
- if (user.archiveAsScreenshot && !link.image?.startsWith("archive")) {
- processingPromises.push(
- page.screenshot({ fullPage: true, type: "png" }).then((screenshot) => {
- return createFile({
- data: screenshot,
- filePath: `archives/${linkExists.collectionId}/${link.id}.png`,
- });
- })
- );
- }
-
- const margins = {
- top: process.env.PDF_MARGIN_TOP || "15px",
- bottom: process.env.PDF_MARGIN_BOTTOM || "15px",
- };
-
- if (user.archiveAsPDF && !link.pdf?.startsWith("archive")) {
- processingPromises.push(
- page
- .pdf({
- width: "1366px",
- height: "1931px",
- printBackground: true,
- margin: margins,
- })
- .then((pdf) => {
- return createFile({
- data: pdf,
- filePath: `archives/${linkExists.collectionId}/${link.id}.pdf`,
- });
- })
- );
- }
- await Promise.allSettled(processingPromises);
- await prisma.link.update({
- where: { id: link.id },
- data: {
- image: user.archiveAsScreenshot
- ? `archives/${linkExists.collectionId}/${link.id}.png`
- : undefined,
- pdf: user.archiveAsPDF
- ? `archives/${linkExists.collectionId}/${link.id}.pdf`
- : undefined,
- },
- });
- }
-};
-
-const autoScroll = async (AUTOSCROLL_TIMEOUT: number) => {
- const timeoutPromise = new Promise((resolve) => {
- setTimeout(() => {
- resolve();
- }, AUTOSCROLL_TIMEOUT * 1000);
- });
-
- const scrollingPromise = new Promise((resolve) => {
- let totalHeight = 0;
- let distance = 100;
- let scrollDown = setInterval(() => {
- let scrollHeight = document.body.scrollHeight;
- window.scrollBy(0, distance);
- totalHeight += distance;
- if (totalHeight >= scrollHeight) {
- clearInterval(scrollDown);
- window.scroll(0, 0);
- resolve();
- }
- }, 100);
- });
-
- await Promise.race([scrollingPromise, timeoutPromise]);
-};
diff --git a/lib/api/preservationScheme/archiveAsSinglefile.ts b/lib/api/preservationScheme/archiveAsSinglefile.ts
deleted file mode 100644
index 0c739b8..0000000
--- a/lib/api/preservationScheme/archiveAsSinglefile.ts
+++ /dev/null
@@ -1,111 +0,0 @@
-import { execSync } from "child_process";
-import createFile from "../storage/createFile";
-import axios from "axios";
-import { Agent } from "http";
-import { prisma } from "../db";
-import { Link } from "@prisma/client";
-
-const archiveAsSinglefile = async (link: Link) => {
- if (!link.url) return;
-
- let command = process.env.SINGLEFILE_ARCHIVE_COMMAND;
- let httpApi = process.env.SINGLEFILE_ARCHIVE_HTTP_API;
- if (command) {
- if (command.includes("{{URL}}")) {
- try {
- let html = execSync(command.replace("{{URL}}", link.url), {
- timeout: 120000,
- maxBuffer: 1024 * 1024 * 30,
- });
-
- if (!html.length) {
- console.error(
- "Error running SINGLEFILE_ARCHIVE_COMMAND: Empty buffer"
- );
- return;
- }
-
- const collectionId = (
- await prisma.link.findUnique({
- where: { id: link.id },
- select: { collectionId: true },
- })
- )?.collectionId;
-
- if (!collectionId) {
- console.error(
- "Error running SINGLEFILE_ARCHIVE_COMMAND: Collection ID not found"
- );
- return;
- }
-
- await createFile({
- data: html,
- filePath: `archives/${collectionId}/${link.id}.html`,
- }).then(async () => {
- await prisma.link.update({
- where: { id: link.id },
- data: {
- singlefile: `archives/${collectionId}/${link.id}.html`,
- },
- });
- });
- } catch (err) {
- console.error("Error running SINGLEFILE_ARCHIVE_COMMAND:", err);
- }
- } else {
- console.error("Invalid SINGLEFILE_ARCHIVE_COMMAND. Missing {{URL}}");
- }
- } else if (httpApi) {
- try {
- let html = await axios.post(
- httpApi,
- { url: link.url },
- {
- headers: {
- "Content-Type": "application/x-www-form-urlencoded",
- },
- httpAgent: new Agent({ keepAlive: false }),
- }
- );
-
- if (!html.data.length) {
- console.error("Error running SINGLEFILE_ARCHIVE_COMMAND: Empty buffer");
- return;
- }
-
- const collectionId = (
- await prisma.link.findUnique({
- where: { id: link.id },
- select: { collectionId: true },
- })
- )?.collectionId;
-
- if (!collectionId) {
- console.error(
- "Error running SINGLEFILE_ARCHIVE_COMMAND: Collection ID not found"
- );
- return;
- }
-
- await createFile({
- data: html.data,
- filePath: `archives/${collectionId}/${link.id}.html`,
- }).then(async () => {
- await prisma.link.update({
- where: { id: link.id },
- data: {
- singlefile: `archives/${collectionId}/${link.id}.html`,
- },
- });
- });
- } catch (err) {
- console.error(
- "Error fetching Singlefile using SINGLEFILE_ARCHIVE_HTTP_API:",
- err
- );
- }
- }
-};
-
-export default archiveAsSinglefile;
diff --git a/lib/api/preservationScheme/handleArchivePreview.ts b/lib/api/preservationScheme/handleArchivePreview.ts
new file mode 100644
index 0000000..c6f7955
--- /dev/null
+++ b/lib/api/preservationScheme/handleArchivePreview.ts
@@ -0,0 +1,56 @@
+import { Collection, Link, User } from "@prisma/client";
+import { Page } from "playwright";
+import generatePreview from "../generatePreview";
+import createFile from "../storage/createFile";
+import { prisma } from "../db";
+
+type LinksAndCollectionAndOwner = Link & {
+ collection: Collection & {
+ owner: User;
+ };
+};
+
+const handleArchivePreview = async (
+ link: LinksAndCollectionAndOwner,
+ page: Page
+) => {
+ const ogImageUrl = await page.evaluate(() => {
+ const metaTag = document.querySelector('meta[property="og:image"]');
+ return metaTag ? (metaTag as any).content : null;
+ });
+
+ if (ogImageUrl) {
+ console.log("Found og:image URL:", ogImageUrl);
+
+ // Download the image
+ const imageResponse = await page.goto(ogImageUrl);
+
+ // Check if imageResponse is not null
+ if (imageResponse && !link.preview?.startsWith("archive")) {
+ const buffer = await imageResponse.body();
+ generatePreview(buffer, link.collectionId, link.id);
+ }
+
+ await page.goBack();
+ } else if (!link.preview?.startsWith("archive")) {
+ console.log("No og:image found");
+ await page
+ .screenshot({ type: "jpeg", quality: 20 })
+ .then((screenshot) => {
+ return createFile({
+ data: screenshot,
+ filePath: `archives/preview/${link.collectionId}/${link.id}.jpeg`,
+ });
+ })
+ .then(() => {
+ return prisma.link.update({
+ where: { id: link.id },
+ data: {
+ preview: `archives/preview/${link.collectionId}/${link.id}.jpeg`,
+ },
+ });
+ });
+ }
+};
+
+export default handleArchivePreview;
diff --git a/lib/api/preservationScheme/handleMonolith.ts b/lib/api/preservationScheme/handleMonolith.ts
new file mode 100644
index 0000000..de5bd2a
--- /dev/null
+++ b/lib/api/preservationScheme/handleMonolith.ts
@@ -0,0 +1,97 @@
+import { execSync } from "child_process";
+import createFile from "../storage/createFile";
+import axios from "axios";
+import { Agent } from "http";
+import { prisma } from "../db";
+import { Link } from "@prisma/client";
+import { Page } from "playwright";
+
+const handleMonolith = async (link: Link, content: string) => {
+ if (!link.url) return;
+
+ let command = process.env.SINGLEFILE_ARCHIVE_COMMAND;
+ let httpApi = process.env.SINGLEFILE_ARCHIVE_HTTP_API;
+ try {
+ let html = execSync(
+ `monolith - -I -b ${link.url} ${
+ process.env.MONOLITH_OPTIONS || "-j -F -s"
+ } -o -`,
+ {
+ timeout: 120000,
+ maxBuffer: 1024 * 1024 * Number(process.env.MONOLITH_MAX_BUFFER || 5),
+ input: content,
+ }
+ );
+
+ if (!html?.length) {
+ console.error("Error running SINGLEFILE_ARCHIVE_COMMAND: Empty buffer");
+ return;
+ }
+
+ await createFile({
+ data: html,
+ filePath: `archives/${link.collectionId}/${link.id}.html`,
+ }).then(async () => {
+ await prisma.link.update({
+ where: { id: link.id },
+ data: {
+ singlefile: `archives/${link.collectionId}/${link.id}.html`,
+ },
+ });
+ });
+ } catch (err) {
+ console.error("Error running SINGLEFILE_ARCHIVE_COMMAND:", err);
+ }
+ // if (httpApi) {
+ // try {
+ // let html = await axios.post(
+ // httpApi,
+ // { url: link.url },
+ // {
+ // headers: {
+ // "Content-Type": "application/x-www-form-urlencoded",
+ // },
+ // httpAgent: new Agent({ keepAlive: false }),
+ // }
+ // );
+
+ // if (!html.data.length) {
+ // console.error("Error running SINGLEFILE_ARCHIVE_COMMAND: Empty buffer");
+ // return;
+ // }
+
+ // const collectionId = (
+ // await prisma.link.findUnique({
+ // where: { id: link.id },
+ // select: { collectionId: true },
+ // })
+ // )?.collectionId;
+
+ // if (!collectionId) {
+ // console.error(
+ // "Error running SINGLEFILE_ARCHIVE_COMMAND: Collection ID not found"
+ // );
+ // return;
+ // }
+
+ // await createFile({
+ // data: html.data,
+ // filePath: `archives/${collectionId}/${link.id}.html`,
+ // }).then(async () => {
+ // await prisma.link.update({
+ // where: { id: link.id },
+ // data: {
+ // singlefile: `archives/${collectionId}/${link.id}.html`,
+ // },
+ // });
+ // });
+ // } catch (err) {
+ // console.error(
+ // "Error fetching Singlefile using SINGLEFILE_ARCHIVE_HTTP_API:",
+ // err
+ // );
+ // }
+ // }
+};
+
+export default handleMonolith;
diff --git a/lib/api/preservationScheme/archiveAsReadablility.ts b/lib/api/preservationScheme/handleReadablility.ts
similarity index 91%
rename from lib/api/preservationScheme/archiveAsReadablility.ts
rename to lib/api/preservationScheme/handleReadablility.ts
index de14571..9514e72 100644
--- a/lib/api/preservationScheme/archiveAsReadablility.ts
+++ b/lib/api/preservationScheme/handleReadablility.ts
@@ -5,7 +5,7 @@ import { prisma } from "../db";
import createFile from "../storage/createFile";
import { Link } from "@prisma/client";
-const archiveAsReadablility = async (content: string, link: Link) => {
+const handleReadablility = async (content: string, link: Link) => {
const window = new JSDOM("").window;
const purify = DOMPurify(window);
const cleanedUpContent = purify.sanitize(content);
@@ -38,4 +38,4 @@ const archiveAsReadablility = async (content: string, link: Link) => {
}
};
-export default archiveAsReadablility;
+export default handleReadablility;
diff --git a/lib/api/preservationScheme/handleScreenshotAndPdf.ts b/lib/api/preservationScheme/handleScreenshotAndPdf.ts
new file mode 100644
index 0000000..e6e1bac
--- /dev/null
+++ b/lib/api/preservationScheme/handleScreenshotAndPdf.ts
@@ -0,0 +1,98 @@
+import { Collection, Link, User } from "@prisma/client";
+import { Page } from "playwright";
+import createFile from "../storage/createFile";
+import { prisma } from "../db";
+
+type LinksAndCollectionAndOwner = Link & {
+ collection: Collection & {
+ owner: User;
+ };
+};
+const handleScreenshotAndPdf = async (
+ link: LinksAndCollectionAndOwner,
+ page: Page,
+ user: User
+) => {
+ await page.evaluate(autoScroll, Number(process.env.AUTOSCROLL_TIMEOUT) || 30);
+
+ // Check if the user hasn't deleted the link by the time we're done scrolling
+ const linkExists = await prisma.link.findUnique({
+ where: { id: link.id },
+ });
+ if (linkExists) {
+ const processingPromises = [];
+
+ if (user.archiveAsScreenshot && !link.image?.startsWith("archive")) {
+ processingPromises.push(
+ page.screenshot({ fullPage: true, type: "png" }).then((screenshot) => {
+ return createFile({
+ data: screenshot,
+ filePath: `archives/${linkExists.collectionId}/${link.id}.png`,
+ });
+ })
+ );
+ }
+
+ const margins = {
+ top: process.env.PDF_MARGIN_TOP || "15px",
+ bottom: process.env.PDF_MARGIN_BOTTOM || "15px",
+ };
+
+ if (user.archiveAsPDF && !link.pdf?.startsWith("archive")) {
+ processingPromises.push(
+ page
+ .pdf({
+ width: "1366px",
+ height: "1931px",
+ printBackground: true,
+ margin: margins,
+ })
+ .then((pdf) => {
+ return createFile({
+ data: pdf,
+ filePath: `archives/${linkExists.collectionId}/${link.id}.pdf`,
+ });
+ })
+ );
+ }
+ await Promise.allSettled(processingPromises);
+ await prisma.link.update({
+ where: { id: link.id },
+ data: {
+ image: user.archiveAsScreenshot
+ ? `archives/${linkExists.collectionId}/${link.id}.png`
+ : undefined,
+ pdf: user.archiveAsPDF
+ ? `archives/${linkExists.collectionId}/${link.id}.pdf`
+ : undefined,
+ },
+ });
+ }
+};
+
+const autoScroll = async (AUTOSCROLL_TIMEOUT: number) => {
+ const timeoutPromise = new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ }, AUTOSCROLL_TIMEOUT * 1000);
+ });
+
+ const scrollingPromise = new Promise((resolve) => {
+ let totalHeight = 0;
+ let distance = 100;
+ let scrollDown = setInterval(() => {
+ let scrollHeight = document.body.scrollHeight;
+ window.scrollBy(0, distance);
+ totalHeight += distance;
+ if (totalHeight >= scrollHeight) {
+ clearInterval(scrollDown);
+ window.scroll(0, 0);
+ resolve();
+ }
+ }, 100);
+ });
+
+ await Promise.race([scrollingPromise, timeoutPromise]);
+};
+
+export default handleScreenshotAndPdf;
diff --git a/lib/api/validateUrlSize.ts b/lib/api/validateUrlSize.ts
index d5826b8..8b418dc 100644
--- a/lib/api/validateUrlSize.ts
+++ b/lib/api/validateUrlSize.ts
@@ -33,7 +33,7 @@ export default async function validateUrlSize(url: string) {
const totalSizeMB =
Number(response.headers.get("content-length")) / Math.pow(1024, 2);
- if (totalSizeMB > (Number(process.env.NEXT_PUBLIC_MAX_FILE_SIZE) || 30))
+ if (totalSizeMB > Number(process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10))
return null;
else return response.headers;
} catch (err) {
diff --git a/package.json b/package.json
index 7027122..0045802 100644
--- a/package.json
+++ b/package.json
@@ -70,7 +70,6 @@
"react-masonry-css": "^1.0.16",
"react-select": "^5.7.4",
"react-spinners": "^0.13.8",
- "shelljs": "^0.8.5",
"socks-proxy-agent": "^8.0.2",
"stripe": "^12.13.0",
"tailwind-merge": "^2.3.0",
diff --git a/pages/api/v1/archives/[linkId].ts b/pages/api/v1/archives/[linkId].ts
index 1e983a1..411b643 100644
--- a/pages/api/v1/archives/[linkId].ts
+++ b/pages/api/v1/archives/[linkId].ts
@@ -94,12 +94,14 @@ export default async function Index(req: NextApiRequest, res: NextApiResponse) {
// await uploadHandler(linkId, )
- const MAX_UPLOAD_SIZE = Number(process.env.NEXT_PUBLIC_MAX_FILE_SIZE);
+ const MAX_UPLOAD_SIZE = Number(
+ process.env.NEXT_PUBLIC_MAX_FILE_BUFFER || 10
+ );
const form = formidable({
maxFields: 1,
maxFiles: 1,
- maxFileSize: MAX_UPLOAD_SIZE || 30 * 1048576,
+ maxFileSize: MAX_UPLOAD_SIZE * 1048576,
});
form.parse(req, async (err, fields, files) => {
diff --git a/public/locales/en/common.json b/public/locales/en/common.json
index 88f5c33..d3ead13 100644
--- a/public/locales/en/common.json
+++ b/public/locales/en/common.json
@@ -360,5 +360,6 @@
"show_link_details": "Show Link Details",
"hide_link_details": "Hide Link Details",
"link_pinned": "Link Pinned!",
- "link_unpinned": "Link Unpinned!"
+ "link_unpinned": "Link Unpinned!",
+ "webpage": "Webpage"
}
\ No newline at end of file
diff --git a/types/enviornment.d.ts b/types/enviornment.d.ts
deleted file mode 100644
index b228e22..0000000
--- a/types/enviornment.d.ts
+++ /dev/null
@@ -1,427 +0,0 @@
-declare global {
- namespace NodeJS {
- interface ProcessEnv {
- NEXTAUTH_SECRET: string;
- DATABASE_URL: string;
- NEXTAUTH_URL: string;
- NEXT_PUBLIC_DISABLE_REGISTRATION?: string;
- PAGINATION_TAKE_COUNT?: string;
- STORAGE_FOLDER?: string;
- AUTOSCROLL_TIMEOUT?: string;
- RE_ARCHIVE_LIMIT?: string;
- NEXT_PUBLIC_MAX_FILE_SIZE?: string;
- MAX_LINKS_PER_USER?: string;
- ARCHIVE_TAKE_COUNT?: string;
- IGNORE_UNAUTHORIZED_CA?: string;
- IGNORE_URL_SIZE_LIMIT?: string;
- ADMINISTRATOR?: string;
-
- SPACES_KEY?: string;
- SPACES_SECRET?: string;
- SPACES_ENDPOINT?: string;
- SPACES_BUCKET_NAME?: string;
- SPACES_REGION?: string;
- SPACES_FORCE_PATH_STYLE?: string;
-
- NEXT_PUBLIC_CREDENTIALS_ENABLED?: string;
- DISABLE_NEW_SSO_USERS?: string;
-
- NEXT_PUBLIC_EMAIL_PROVIDER?: string;
- EMAIL_FROM?: string;
- EMAIL_SERVER?: string;
-
- BASE_URL?: string; // Used for email and stripe
-
- NEXT_PUBLIC_STRIPE?: string;
- STRIPE_SECRET_KEY?: string;
- MONTHLY_PRICE_ID?: string;
- YEARLY_PRICE_ID?: string;
- NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL?: string;
- NEXT_PUBLIC_TRIAL_PERIOD_DAYS?: string;
-
- // Proxy settings
- PROXY?: string;
- PROXY_USERNAME?: string;
- PROXY_PASSWORD?: string;
- PROXY_BYPASS?: string;
-
- // PDF archive settings
- PDF_MARGIN_TOP?: string;
- PDF_MARGIN_BOTTOM?: string;
-
- // PDF archive settings
- SINGLEFILE_ARCHIVE_COMMAND?: string;
- SINGLEFILE_ARCHIVE_HTTP_API?: string;
-
- //
- // SSO Providers
- //
-
- // 42 School
- NEXT_PUBLIC_FORTYTWO_ENABLED?: string;
- FORTYTWO_CUSTOM_NAME?: string;
- FORTYTWO_CLIENT_ID?: string;
- FORTYTWO_CLIENT_SECRET?: string;
-
- // Apple
- NEXT_PUBLIC_APPLE_ENABLED?: string;
- APPLE_CUSTOM_NAME?: string;
- APPLE_ID?: string;
- APPLE_SECRET?: string;
-
- // Atlassian
- NEXT_PUBLIC_ATLASSIAN_ENABLED?: string;
- ATLASSIAN_CUSTOM_NAME?: string;
- ATLASSIAN_CLIENT_ID?: string;
- ATLASSIAN_CLIENT_SECRET?: string;
- ATLASSIAN_SCOPE?: string;
-
- // Auth0
- NEXT_PUBLIC_AUTH0_ENABLED?: string;
- AUTH0_CUSTOM_NAME?: string;
- AUTH0_ISSUER?: string;
- AUTH0_CLIENT_SECRET?: string;
- AUTH0_CLIENT_ID?: string;
-
- // Authelia
- NEXT_PUBLIC_AUTHELIA_ENABLED?: string;
- AUTHELIA_CUSTOM_NAME?: string;
- AUTHELIA_CLIENT_ID?: string;
- AUTHELIA_CLIENT_SECRET?: string;
- AUTHELIA_WELLKNOWN_URL?: string;
-
- // Authentik
- NEXT_PUBLIC_AUTHENTIK_ENABLED?: string;
- AUTHENTIK_CUSTOM_NAME?: string;
- AUTHENTIK_ISSUER?: string;
- AUTHENTIK_CLIENT_ID?: string;
- AUTHENTIK_CLIENT_SECRET?: string;
-
- // TODO: Azure AD B2C
- // TODO: Azure AD
-
- // Battle.net
- NEXT_PUBLIC_BATTLENET_ENABLED?: string;
- BATTLENET_CUSTOM_NAME?: string;
- BATTLENET_CLIENT_ID?: string;
- BATTLENET_CLIENT_SECRET?: string;
- BATLLENET_ISSUER?: string;
-
- // Box
- NEXT_PUBLIC_BOX_ENABLED?: string;
- BOX_CUSTOM_NAME?: string;
- BOX_CLIENT_ID?: string;
- BOX_CLIENT_SECRET?: string;
-
- // TODO: BoxyHQ SAML
-
- // Bungie
- NEXT_PUBLIC_BUNGIE_ENABLED?: string;
- BUNGIE_CUSTOM_NAME?: string;
- BUNGIE_CLIENT_ID?: string;
- BUNGIE_CLIENT_SECRET?: string;
- BUNGIE_API_KEY?: string;
-
- // Cognito
- NEXT_PUBLIC_COGNITO_ENABLED?: string;
- COGNITO_CUSTOM_NAME?: string;
- COGNITO_CLIENT_ID?: string;
- COGNITO_CLIENT_SECRET?: string;
- COGNITO_ISSUER?: string;
-
- // Coinbase
- NEXT_PUBLIC_COINBASE_ENABLED?: string;
- COINBASE_CUSTOM_NAME?: string;
- COINBASE_CLIENT_ID?: string;
- COINBASE_CLIENT_SECRET?: string;
-
- // Discord
- NEXT_PUBLIC_DISCORD_ENABLED?: string;
- DISCORD_CUSTOM_NAME?: string;
- DISCORD_CLIENT_ID?: string;
- DISCORD_CLIENT_SECRET?: string;
-
- // Dropbox
- NEXT_PUBLIC_DROPBOX_ENABLED?: string;
- DROPBOX_CUSTOM_NAME?: string;
- DROPBOX_CLIENT_ID?: string;
- DROPBOX_CLIENT_SECRET?: string;
-
- // DuendeIndentityServer6
- NEXT_PUBLIC_DUENDE_IDS6_ENABLED?: string;
- DUENDE_IDS6_CUSTOM_NAME?: string;
- DUENDE_IDS6_CLIENT_ID?: string;
- DUENDE_IDS6_CLIENT_SECRET?: string;
- DUENDE_IDS6_ISSUER?: string;
-
- // EVE Online
- NEXT_PUBLIC_EVEONLINE_ENABLED?: string;
- EVEONLINE_CUSTOM_NAME?: string;
- EVEONLINE_CLIENT_ID?: string;
- EVEONLINE_CLIENT_SECRET?: string;
-
- // Facebook
- NEXT_PUBLIC_FACEBOOK_ENABLED?: string;
- FACEBOOK_CUSTOM_NAME?: string;
- FACEBOOK_CLIENT_ID?: string;
- FACEBOOK_CLIENT_SECRET?: string;
-
- // FACEIT
- NEXT_PUBLIC_FACEIT_ENABLED?: string;
- FACEIT_CUSTOM_NAME?: string;
- FACEIT_CLIENT_ID?: string;
- FACEIT_CLIENT_SECRET?: string;
-
- // Foursquare
- NEXT_PUBLIC_FOURSQUARE_ENABLED?: string;
- FOURSQUARE_CUSTOM_NAME?: string;
- FOURSQUARE_CLIENT_ID?: string;
- FOURSQUARE_CLIENT_SECRET?: string;
- FOURSQUARE_APIVERSION?: string;
-
- // Freshbooks
- NEXT_PUBLIC_FRESHBOOKS_ENABLED?: string;
- FRESHBOOKS_CUSTOM_NAME?: string;
- FRESHBOOKS_CLIENT_ID?: string;
- FRESHBOOKS_CLIENT_SECRET?: string;
-
- // FusionAuth
- NEXT_PUBLIC_FUSIONAUTH_ENABLED?: string;
- FUSIONAUTH_CUSTOM_NAME?: string;
- FUSIONAUTH_CLIENT_ID?: string;
- FUSIONAUTH_CLIENT_SECRET?: string;
- FUSIONAUTH_ISSUER?: string;
- FUSIONAUTH_TENANT_ID?: string;
-
- // GitHub
- NEXT_PUBLIC_GITHUB_ENABLED?: string;
- GITHUB_CUSTOM_NAME?: string;
- GITHUB_CLIENT_ID?: string;
- GITHUB_CLIENT_SECRET?: string;
-
- // GitLab
- NEXT_PUBLIC_GITLAB_ENABLED?: string;
- GITLAB_CUSTOM_NAME?: string;
- GITLAB_CLIENT_ID?: string;
- GITLAB_CLIENT_SECRET?: string;
-
- // Google
- NEXT_PUBLIC_GOOGLE_ENABLED?: string;
- GOOGLE_CUSTOM_NAME?: string;
- GOOGLE_CLIENT_ID?: string;
- GOOGLE_CLIENT_SECRET?: string;
-
- // HubSpot
- NEXT_PUBLIC_HUBSPOT_ENABLED?: string;
- HUBSPOT_CUSTOM_NAME?: string;
- HUBSPOT_CLIENT_ID?: string;
- HUBSPOT_CLIENT_SECRET?: string;
-
- // IdentityServer4
- NEXT_PUBLIC_IDS4_ENABLED?: string;
- IDS4_CUSTOM_NAME?: string;
- IDS4_CLIENT_ID?: string;
- IDS4_CLIENT_SECRET?: string;
- IDS4_ISSUER?: string;
-
- // TODO: Instagram (Doesn't return email)
-
- // Kakao
- NEXT_PUBLIC_KAKAO_ENABLED?: string;
- KAKAO_CUSTOM_NAME?: string;
- KAKAO_CLIENT_ID?: string;
- KAKAO_CLIENT_SECRET?: string;
-
- // Keycloak
- NEXT_PUBLIC_KEYCLOAK_ENABLED?: string;
- KEYCLOAK_CUSTOM_NAME?: string;
- KEYCLOAK_ISSUER?: string;
- KEYCLOAK_CLIENT_ID?: string;
- KEYCLOAK_CLIENT_SECRET?: string;
-
- // LINE
- NEXT_PUBLIC_LINE_ENABLED?: string;
- LINE_CUSTOM_NAME?: string;
- LINE_CLIENT_ID?: string;
- LINE_CLIENT_SECRET?: string;
-
- // LinkedIn
- NEXT_PUBLIC_LINKEDIN_ENABLED?: string;
- LINKEDIN_CUSTOM_NAME?: string;
- LINKEDIN_CLIENT_ID?: string;
- LINKEDIN_CLIENT_SECRET?: string;
-
- // Mailchimp
- NEXT_PUBLIC_MAILCHIMP_ENABLED?: string;
- MAILCHIMP_CUSTOM_NAME?: string;
- MAILCHIMP_CLIENT_ID?: string;
- MAILCHIMP_CLIENT_SECRET?: string;
-
- // Mail.ru
- NEXT_PUBLIC_MAILRU_ENABLED?: string;
- MAILRU_CUSTOM_NAME?: string;
- MAILRU_CLIENT_ID?: string;
- MAILRU_CLIENT_SECRET?: string;
-
- // TODO: Medium (Doesn't return email)
-
- // Naver
- NEXT_PUBLIC_NAVER_ENABLED?: string;
- NAVER_CUSTOM_NAME?: string;
- NAVER_CLIENT_ID?: string;
- NAVER_CLIENT_SECRET?: string;
-
- // Netlify
- NEXT_PUBLIC_NETLIFY_ENABLED?: string;
- NETLIFY_CUSTOM_NAME?: string;
- NETLIFY_CLIENT_ID?: string;
- NETLIFY_CLIENT_SECRET?: string;
-
- // Okta
- NEXT_PUBLIC_OKTA_ENABLED?: string;
- OKTA_CUSTOM_NAME?: string;
- OKTA_CLIENT_ID?: string;
- OKTA_CLIENT_SECRET?: string;
- OKTA_ISSUER?: string;
-
- // OneLogin
- NEXT_PUBLIC_ONELOGIN_ENABLED?: string;
- ONELOGIN_CUSTOM_NAME?: string;
- ONELOGIN_CLIENT_ID?: string;
- ONELOGIN_CLIENT_SECRET?: string;
- ONELOGIN_ISSUER?: string;
-
- // Osso
- NEXT_PUBLIC_OSSO_ENABLED?: string;
- OSSO_CUSTOM_NAME?: string;
- OSSO_CLIENT_ID?: string;
- OSSO_CLIENT_SECRET?: string;
- OSSO_ISSUER?: string;
-
- // osu!
- NEXT_PUBLIC_OSU_ENABLED?: string;
- OSU_CUSTOM_NAME?: string;
- OSU_CLIENT_ID?: string;
- OSU_CLIENT_SECRET?: string;
-
- // Patreon
- NEXT_PUBLIC_PATREON_ENABLED?: string;
- PATREON_CUSTOM_NAME?: string;
- PATREON_CLIENT_ID?: string;
- PATREON_CLIENT_SECRET?: string;
-
- // Pinterest
- NEXT_PUBLIC_PINTEREST_ENABLED?: string;
- PINTEREST_CUSTOM_NAME?: string;
- PINTEREST_CLIENT_ID?: string;
- PINTEREST_CLIENT_SECRET?: string;
-
- // Pipedrive
- NEXT_PUBLIC_PIPEDRIVE_ENABLED?: string;
- PIPEDRIVE_CUSTOM_NAME?: string;
- PIPEDRIVE_CLIENT_ID?: string;
- PIPEDRIVE_CLIENT_SECRET?: string;
-
- // Reddit
- // TODO (1h tokens)
- NEXT_PUBLIC_REDDIT_ENABLED?: string;
- REDDIT_CUSTOM_NAME?: string;
- REDDIT_CLIENT_ID?: string;
- REDDIT_CLIENT_SECRET?: string;
-
- // Salesforce
- NEXT_PUBLIC_SALESFORCE_ENABLED?: string;
- SALESFORCE_CUSTOM_NAME?: string;
- SALESFORCE_CLIENT_ID?: string;
- SALESFORCE_CLIENT_SECRET?: string;
-
- // Slack
- NEXT_PUBLIC_SLACK_ENABLED?: string;
- SLACK_CUSTOM_NAME?: string;
- SLACK_CLIENT_ID?: string;
- SLACK_CLIENT_SECRET?: string;
-
- // Spotify
- NEXT_PUBLIC_SPOTIFY_ENABLED?: string;
- SPOTIFY_CUSTOM_NAME?: string;
- SPOTIFY_CLIENT_ID?: string;
- SPOTIFY_CLIENT_SECRET?: string;
-
- // Strava
- NEXT_PUBLIC_STRAVA_ENABLED?: string;
- STRAVA_CUSTOM_NAME?: string;
- STRAVA_CLIENT_ID?: string;
- STRAVA_CLIENT_SECRET?: string;
-
- // Todoist
- NEXT_PUBLIC_TODOIST_ENABLED?: string;
- TODOIST_CUSTOM_NAME?: string;
- TODOIST_CLIENT_ID?: string;
- TODOIST_CLIENT_SECRET?: string;
-
- // TODO: Trakt (Doesn't return email)
-
- // Twitch
- NEXT_PUBLIC_TWITCH_ENABLED?: string;
- TWITCH_CUSTOM_NAME?: string;
- TWITCH_CLIENT_ID?: string;
- TWITCH_CLIENT_SECRET?: string;
-
- // TODO: Twitter (OAuth 1.0)
-
- // United Effects
- NEXT_PUBLIC_UNITED_EFFECTS_ENABLED?: string;
- UNITED_EFFECTS_CUSTOM_NAME?: string;
- UNITED_EFFECTS_CLIENT_ID?: string;
- UNITED_EFFECTS_CLIENT_SECRET?: string;
- UNITED_EFFECTS_ISSUER?: string;
-
- // VK
- NEXT_PUBLIC_VK_ENABLED?: string;
- VK_CUSTOM_NAME?: string;
- VK_CLIENT_ID?: string;
- VK_CLIENT_SECRET?: string;
-
- // Wikimedia
- NEXT_PUBLIC_WIKIMEDIA_ENABLED?: string;
- WIKIMEDIA_CUSTOM_NAME?: string;
- WIKIMEDIA_CLIENT_ID?: string;
- WIKIMEDIA_CLIENT_SECRET?: string;
-
- // Wordpress.com
- NEXT_PUBLIC_WORDPRESS_ENABLED?: string;
- WORDPRESS_CUSTOM_NAME?: string;
- WORDPRESS_CLIENT_ID?: string;
- WORDPRESS_CLIENT_SECRET?: string;
-
- // TODO: WorkOS (Custom flow)
-
- // Yandex
- NEXT_PUBLIC_YANDEX_ENABLED?: string;
- YANDEX_CUSTOM_NAME?: string;
- YANDEX_CLIENT_ID?: string;
- YANDEX_CLIENT_SECRET?: string;
-
- // Zitadel
- NEXT_PUBLIC_ZITADEL_ENABLED?: string;
- ZITADEL_CUSTOM_NAME?: string;
- ZITADEL_CLIENT_ID?: string;
- ZITADEL_CLIENT_SECRET?: string;
- ZITADEL_ISSUER?: string;
-
- // Zoho
- NEXT_PUBLIC_ZOHO_ENABLED?: string;
- ZOHO_CUSTOM_NAME?: string;
- ZOHO_CLIENT_ID?: string;
- ZOHO_CLIENT_SECRET?: string;
-
- // Zoom
- NEXT_PUBLIC_ZOOM_ENABLED?: string;
- ZOOM_CUSTOM_NAME?: string;
- ZOOM_CLIENT_ID?: string;
- ZOOM_CLIENT_SECRET?: string;
- }
- }
-}
-
-export {};
diff --git a/yarn.lock b/yarn.lock
index 05b76f3..55074b6 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3514,11 +3514,6 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-function-bind@^1.1.2:
- version "1.1.2"
- resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
- integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
-
function.prototype.name@^1.1.5:
version "1.1.5"
resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.5.tgz#cce0505fe1ffb80503e6f9e46cc64e46a12a9621"
@@ -3656,7 +3651,7 @@ glob@7.1.7:
once "^1.3.0"
path-is-absolute "^1.0.0"
-glob@^7.0.0, glob@^7.1.3:
+glob@^7.1.3:
version "7.2.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
@@ -3826,13 +3821,6 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
-hasown@^2.0.0:
- version "2.0.2"
- resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
- integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
- dependencies:
- function-bind "^1.1.2"
-
hexoid@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
@@ -3984,11 +3972,6 @@ internal-slot@^1.0.3, internal-slot@^1.0.4:
has "^1.0.3"
side-channel "^1.0.4"
-interpret@^1.0.0:
- version "1.4.0"
- resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e"
- integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
-
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -4070,13 +4053,6 @@ is-core-module@^2.10.0, is-core-module@^2.11.0, is-core-module@^2.9.0:
dependencies:
has "^1.0.3"
-is-core-module@^2.13.0:
- version "2.13.1"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384"
- integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==
- dependencies:
- hasown "^2.0.0"
-
is-date-object@^1.0.1, is-date-object@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f"
@@ -5396,13 +5372,6 @@ readdirp@~3.6.0:
dependencies:
picomatch "^2.2.1"
-rechoir@^0.6.2:
- version "0.6.2"
- resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384"
- integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==
- dependencies:
- resolve "^1.1.6"
-
redux@^4.0.0, redux@^4.0.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
@@ -5470,15 +5439,6 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-resolve@^1.1.6:
- version "1.22.8"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d"
- integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==
- dependencies:
- is-core-module "^2.13.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
resolve@^1.1.7, resolve@^1.19.0, resolve@^1.22.1, resolve@^1.22.2:
version "1.22.2"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
@@ -5605,15 +5565,6 @@ shell-quote@^1.8.1:
resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680"
integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==
-shelljs@^0.8.5:
- version "0.8.5"
- resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c"
- integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==
- dependencies:
- glob "^7.0.0"
- interpret "^1.0.0"
- rechoir "^0.6.2"
-
side-channel@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"