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"