From d02ee3afb15af5f215c581d74ebff7a245192cf2 Mon Sep 17 00:00:00 2001 From: shiva raj badu Date: Mon, 12 May 2025 02:02:50 +0545 Subject: [PATCH] userconfig ipc & build error fixed --- app/ipc/index.ts | 3 +- app/ipc/read_file.ts | 9 + app/ipc/slide_metadata.ts | 268 +++++++ app/preload.ts | 2 + package-lock.json | 673 ++++++++++++++++-- package.json | 3 +- .../components/DocumentPreviewPage.tsx | 32 +- .../utils/download.ts | 42 -- servers/nextjs/app/api/read-config/route.ts | 30 - servers/nextjs/app/api/read-file/route.ts | 37 - .../nextjs/app/api/save-user-config/route.ts | 51 -- servers/nextjs/app/page.tsx | 372 +--------- servers/nextjs/app/setting/SettingPage.tsx | 150 ++++ servers/nextjs/app/setting/page.tsx | 185 +---- servers/nextjs/components/Home.tsx | 335 +++++++++ servers/nextjs/package.json | 5 +- 16 files changed, 1427 insertions(+), 770 deletions(-) create mode 100644 app/ipc/read_file.ts create mode 100644 app/ipc/slide_metadata.ts delete mode 100644 servers/nextjs/app/(presentation-generator)/utils/download.ts delete mode 100644 servers/nextjs/app/api/read-config/route.ts delete mode 100644 servers/nextjs/app/api/read-file/route.ts delete mode 100644 servers/nextjs/app/api/save-user-config/route.ts create mode 100644 servers/nextjs/app/setting/SettingPage.tsx create mode 100644 servers/nextjs/components/Home.tsx diff --git a/app/ipc/index.ts b/app/ipc/index.ts index e48f6d31..bd5ad874 100644 --- a/app/ipc/index.ts +++ b/app/ipc/index.ts @@ -1,7 +1,8 @@ import { setupExportHandlers } from "./export_handlers"; import { setupUserConfigHandlers } from "./user_config_handlers"; - +import { setupReadFile } from "./read_file"; export function setupIpcHandlers() { setupExportHandlers(); setupUserConfigHandlers(); + setupReadFile(); } \ No newline at end of file diff --git a/app/ipc/read_file.ts b/app/ipc/read_file.ts new file mode 100644 index 00000000..4a4bac68 --- /dev/null +++ b/app/ipc/read_file.ts @@ -0,0 +1,9 @@ +import { ipcMain } from "electron"; +import fs from "fs"; +import path from "path"; +export function setupReadFile() { + ipcMain.handle("read-file", async (_, filePath: string) => { + const normalizedPath = path.normalize(filePath); + return fs.readFileSync(normalizedPath, 'utf-8'); + }); +} \ No newline at end of file diff --git a/app/ipc/slide_metadata.ts b/app/ipc/slide_metadata.ts new file mode 100644 index 00000000..f9fda489 --- /dev/null +++ b/app/ipc/slide_metadata.ts @@ -0,0 +1,268 @@ +import { ipcMain } from "electron"; +import puppeteer from "puppeteer"; +import fs from 'fs'; +import path from 'path'; +import { tempDir } from "../constants"; +interface Position { + left: number; + top: number; + width: number; + height: number; +} + +interface FontStyles { + name: string; + size: number; + bold: boolean; + weight: number; + color: string; +} + +interface TextElement { + position: Position; + paragraphs: { + alignment: number; + text: string; + font: FontStyles; + }[]; +} + +interface PictureElement { + position: Position; + picture: { + is_network: boolean; + path: string; + }; + shape: string | null; + object_fit: { + fit: string | null; + focus: number[]; + }; + overlay: string | null; + border_radius: number[]; +} + +interface BoxElement { + position: Position; + type: number; + fill: { + color: string; + }; + border_radius: number; + stroke: { + color: string; + thickness: number; + }; + shadow: { + radius: number; + color: string; + offset: number; + opacity: number; + angle: number; + }; +} + +interface LineElement { + position: Position; + lineType: number; + thickness: string; + color: string; +} + +interface GraphElement { + position: Position; + picture: { + is_network: boolean; + path: string; + }; + border_radius: number[]; +} + +type SlideElement = TextElement | PictureElement | BoxElement | LineElement | GraphElement; + +interface SlideMetadata { + slideIndex: number; + backgroundColor: string; + elements: SlideElement[]; +} + +interface ThemeParams { + theme: string; + customColors?: { + slideBg: string; + slideTitle: string; + slideHeading: string; + slideDescription: string; + slideBox: string; + }; +} + +export function setupSlideMetadataHandlers() { + ipcMain.handle("get-slide-metadata", async (_, url: string, theme: string, customColors?: ThemeParams["customColors"]) => { + let browser; + try { + browser = await puppeteer.launch({ + headless: true, + args: ['--no-sandbox', '--disable-setuid-sandbox'] + }); + + const page = await browser.newPage(); + await page.setViewport({ width: 1440, height: 900, deviceScaleFactor: 1 }); + + await page.goto(url, { waitUntil: "networkidle0", timeout: 60000 }); + await page.waitForSelector('[data-element-type="slide-container"]', { timeout: 80000 }); + + // Apply theme + await page.evaluate((params: ThemeParams) => { + const { theme, customColors } = params; + document.querySelectorAll(".slide-theme").forEach((container) => { + container.setAttribute("data-theme", theme); + }); + + if (theme === "custom" && customColors) { + const root = document.documentElement; + root.style.setProperty("--custom-slide-bg", customColors.slideBg); + root.style.setProperty("--custom-slide-title", customColors.slideTitle); + root.style.setProperty("--custom-slide-heading", customColors.slideHeading); + root.style.setProperty("--custom-slide-description", customColors.slideDescription); + root.style.setProperty("--custom-slide-box", customColors.slideBox); + } + }, { theme, customColors }); + + // Get slide metadata + const metadata = await page.evaluate(() => { + const rgbToHex = (color: string): string => { + if (!color || color === "transparent" || color === "none") return "000000"; + if (color.startsWith("#")) return color.replace("#", ""); + const matches = color.match(/\d+/g); + if (!matches) return "000000"; + const [r, g, b] = matches.map(x => parseInt(x)); + return [r, g, b].map(x => x.toString(16).padStart(2, "0")).join(""); + }; + + const slidesMetadata: SlideMetadata[] = []; + const slideContainers = document.querySelectorAll('[data-element-type="slide-container"]'); + + slideContainers.forEach((container) => { + const containerEl = container as HTMLElement; + containerEl.style.width = "1280px"; + containerEl.style.height = "720px"; + containerEl.style.transform = "none"; + + const containerRect = containerEl.getBoundingClientRect(); + const slideIndex = parseInt(containerEl.getAttribute("data-slide-index") || "0"); + const backgroundColor = rgbToHex(window.getComputedStyle(containerEl).backgroundColor); + + const elements: SlideElement[] = []; + const slideElements = containerEl.querySelectorAll('[data-slide-element]:not([data-element-type="slide-container"])'); + + slideElements.forEach((element) => { + const el = element as HTMLElement; + const elementRect = el.getBoundingClientRect(); + const computedStyle = window.getComputedStyle(el); + + const position: Position = { + left: Math.round(elementRect.left - containerRect.left), + top: Math.round(elementRect.top - containerRect.top), + width: Math.round(elementRect.width), + height: Math.round(elementRect.height), + }; + + const elementType = el.getAttribute("data-element-type"); + if (!elementType) return; + + switch (elementType) { + case "text": + elements.push({ + position, + paragraphs: [{ + alignment: el.getAttribute("data-is-align") === 'true' ? 2 : 1, + text: el.getAttribute("data-text-content") || el.textContent || "", + font: { + name: computedStyle.fontFamily.split('_')[2] || 'Inter', + size: parseInt(computedStyle.fontSize), + bold: parseInt(computedStyle.fontWeight) >= 500, + weight: parseInt(computedStyle.fontWeight), + color: rgbToHex(computedStyle.color), + }, + }], + } as TextElement); + break; + + case "picture": + const imgEl = el.tagName.toLowerCase() === "img" ? el as HTMLImageElement : el.querySelector("img") as HTMLImageElement; + if (imgEl) { + elements.push({ + position, + picture: { + is_network: imgEl.src.startsWith("http"), + path: imgEl.src || imgEl.getAttribute("data-image-path") || "", + }, + shape: imgEl.getAttribute('data-image-type'), + object_fit: { + fit: imgEl.getAttribute('data-object-fit'), + focus: [ + parseFloat(imgEl.getAttribute('data-focial-point-x') || '0'), + parseFloat(imgEl.getAttribute('data-focial-point-y') || '0'), + ], + }, + overlay: el.getAttribute("data-is-icon") ? "ffffff" : null, + border_radius: Array(4).fill(parseInt(computedStyle.borderRadius) || 0), + } as PictureElement); + } + break; + + case "graph": + elements.push({ + position, + picture: { + is_network: true, + path: `__GRAPH_PLACEHOLDER__${el.getAttribute("data-element-id")}`, + }, + border_radius: [0, 0, 0, 0], + } as GraphElement); + break; + } + }); + + slidesMetadata.push({ slideIndex, backgroundColor, elements }); + }); + + return slidesMetadata; + }); + + // Handle graph elements + const graphElements = await page.$$('[data-element-type="graph"]'); + for (const graphElement of graphElements) { + const graphId = await graphElement.evaluate(el => el.getAttribute("data-element-id")); + const screenshot = await graphElement.screenshot({ + type: "jpeg", + encoding: "base64", + quality: 100, + omitBackground: true, + }); + + + const filename = `chart-${graphId}-${Date.now()}.jpg`; + const filePath = path.join(tempDir, filename); + + fs.writeFileSync(filePath, Buffer.from(screenshot, 'base64')); + + metadata.forEach(slide => { + slide.elements.forEach(element => { + if ('picture' in element && element.picture.path === `__GRAPH_PLACEHOLDER__${graphId}`) { + element.picture.path = filePath; + } + }); + }); + } + + return metadata; + } catch (error) { + console.error("Error during page preparation:", error); + throw error; + } finally { + if (browser) await browser.close(); + } + }); +} diff --git a/app/preload.ts b/app/preload.ts index edcd7387..3094c0ee 100644 --- a/app/preload.ts +++ b/app/preload.ts @@ -12,4 +12,6 @@ contextBridge.exposeInMainWorld('electron', { fileDownloaded: (filePath: string) => ipcRenderer.invoke("file-downloaded", filePath), getUserConfig: () => ipcRenderer.invoke("get-user-config"), setUserConfig: (userConfig: UserConfig) => ipcRenderer.invoke("set-user-config", userConfig), + readFile: (filePath: string) => ipcRenderer.invoke("read-file", filePath), + getSlideMetadata: (url: string, theme: string, customColors?: any) => ipcRenderer.invoke("get-slide-metadata", url, theme, customColors), }); diff --git a/package-lock.json b/package-lock.json index 38e1e4a5..28110fba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@tailwindcss/cli": "^4.1.5", "dotenv": "^16.5.0", "electron-squirrel-startup": "^1.0.1", + "puppeteer": "^24.8.2", "tailwindcss": "^4.1.5", "tree-kill": "^1.2.2" }, @@ -23,6 +24,29 @@ "typescript": "^5.0.0" } }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -854,6 +878,27 @@ "node": ">=14" } }, + "node_modules/@puppeteer/browsers": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.4.tgz", + "integrity": "sha512-9DxbZx+XGMNdjBynIs4BRSz+M3iRDeB7qRcAr6UORFLphCIM2x3DXgOucvADiifcqCE4XePFUKcnaAMyGbrDlQ==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.0", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.1", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@sindresorhus/is": { "version": "4.6.0", "dev": true, @@ -1129,6 +1174,12 @@ "node": ">= 10" } }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "license": "MIT" + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "dev": true, @@ -1182,7 +1233,7 @@ }, "node_modules/@types/node": { "version": "22.15.3", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "undici-types": "~6.21.0" @@ -1218,7 +1269,6 @@ }, "node_modules/@types/yauzl": { "version": "2.10.3", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -1253,7 +1303,6 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -1317,7 +1366,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1327,7 +1375,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -1399,7 +1446,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, "license": "Python-2.0" }, "node_modules/assert-plus": { @@ -1413,6 +1459,18 @@ "node": ">=0.8" } }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -1458,6 +1516,12 @@ "node": ">= 4.0.0" } }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "license": "Apache-2.0" + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1465,6 +1529,78 @@ "dev": true, "license": "MIT" }, + "node_modules/bare-events": { + "version": "2.5.4", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.4.tgz", + "integrity": "sha512-+gFfDkR8pj4/TrWCGUGWmJIkBwuxPS5F+a5yWjOHQt2hHvNZd5YLzadjmDUtFmMM4y429bnKLa8bYBMHcYdnQA==", + "license": "Apache-2.0", + "optional": true + }, + "node_modules/bare-fs": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.4.tgz", + "integrity": "sha512-r8+26Voz8dGX3AYpJdFb1ZPaUSM8XOLCZvy+YGpRTmwPHIxA7Z3Jov/oMPtV7hfRQbOnH8qGlLTzQAbgtdNN0Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-events": "^2.5.4", + "bare-path": "^3.0.0", + "bare-stream": "^2.6.4" + }, + "engines": { + "bare": ">=1.16.0" + }, + "peerDependencies": { + "bare-buffer": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + } + } + }, + "node_modules/bare-os": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-3.6.1.tgz", + "integrity": "sha512-uaIjxokhFidJP+bmmvKSgiMzj2sV5GPHaZVAIktcxcpCyBFFWO+YlikVAdhmUo2vYFvFhOXIAlldqV29L8126g==", + "license": "Apache-2.0", + "optional": true, + "engines": { + "bare": ">=1.14.0" + } + }, + "node_modules/bare-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.0.0.tgz", + "integrity": "sha512-tyfW2cQcB5NN8Saijrhqn0Zh7AnFNsnczRcuWODH0eYAXBsJ5gVxAUuNr7tsHSC6IZ77cA0SitzT+s47kot8Mw==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "bare-os": "^3.0.1" + } + }, + "node_modules/bare-stream": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.6.5.tgz", + "integrity": "sha512-jSmxKJNJmHySi6hC42zlZnq00rga4jjxcgNZjY9N5WlOe/iOoGRtdwGsHzQv2RlH2KOYMwGUXhf2zXd32BA9RA==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "streamx": "^2.21.0" + }, + "peerDependencies": { + "bare-buffer": "*", + "bare-events": "*" + }, + "peerDependenciesMeta": { + "bare-buffer": { + "optional": true + }, + "bare-events": { + "optional": true + } + } + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -1486,6 +1622,15 @@ ], "license": "MIT" }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/bl": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", @@ -1551,7 +1696,6 @@ }, "node_modules/buffer-crc32": { "version": "0.2.13", - "dev": true, "license": "MIT", "engines": { "node": "*" @@ -1717,6 +1861,15 @@ "node": ">= 0.4" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1744,6 +1897,19 @@ "node": ">=10" } }, + "node_modules/chromium-bidi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-5.1.0.tgz", + "integrity": "sha512-9MSRhWRVoRPDG0TgzkHrshFSJJNZzfY5UFqUMuksg7zL1yoZIZ3jLB0YAgHclbiAxPI86pBnwDX1tbzoiV8aFw==", + "license": "Apache-2.0", + "dependencies": { + "mitt": "^3.0.1", + "zod": "^3.24.1" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, "node_modules/chromium-pickle-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", @@ -1825,7 +1991,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -1869,7 +2034,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1882,7 +2046,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { @@ -1991,6 +2154,32 @@ "license": "MIT", "optional": true }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/crc": { "version": "3.8.0", "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", @@ -2026,9 +2215,17 @@ "node": ">= 8" } }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/debug": { "version": "4.4.0", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2111,6 +2308,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "license": "MIT", + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -2134,6 +2345,12 @@ "license": "MIT", "optional": true }, + "node_modules/devtools-protocol": { + "version": "0.0.1439962", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1439962.tgz", + "integrity": "sha512-jJF48UdryzKiWhJ1bLKr7BFWUQCEIT5uCNbDLqkQJBtkFxYzILJH44WN0PDKMIlGDN7Utb8vyUY85C3w4R/t2g==", + "license": "BSD-3-Clause" + }, "node_modules/dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -2500,7 +2717,6 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/encoding": { @@ -2516,7 +2732,6 @@ }, "node_modules/end-of-stream": { "version": "1.4.4", - "dev": true, "license": "MIT", "dependencies": { "once": "^1.4.0" @@ -2536,7 +2751,6 @@ }, "node_modules/env-paths": { "version": "2.2.1", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2549,6 +2763,15 @@ "dev": true, "license": "MIT" }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "dev": true, @@ -2604,12 +2827,63 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "license": "BSD-2-Clause", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.2.tgz", @@ -2619,7 +2893,6 @@ }, "node_modules/extract-zip": { "version": "2.0.1", - "dev": true, "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", @@ -2654,6 +2927,12 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "license": "MIT" + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2663,7 +2942,6 @@ }, "node_modules/fd-slicer": { "version": "1.1.0", - "dev": true, "license": "MIT", "dependencies": { "pend": "~1.2.0" @@ -2797,7 +3075,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" @@ -2844,7 +3121,6 @@ }, "node_modules/get-stream": { "version": "5.2.0", - "dev": true, "license": "MIT", "dependencies": { "pump": "^3.0.0" @@ -2856,6 +3132,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-uri": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.4.tgz", + "integrity": "sha512-E1b1lFFLvLgak2whF2xDBcOy6NLVGZBqqjJjsIhvopKfWWEi64pLVTWWehV8KlLerZkfNTA95sTe2OdJKm1OzQ==", + "license": "MIT", + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -3060,7 +3350,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -3086,7 +3375,6 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -3166,6 +3454,22 @@ ], "license": "BSD-3-Clause" }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3216,7 +3520,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "dev": true, "license": "MIT", "dependencies": { "jsbn": "1.1.0", @@ -3226,6 +3529,12 @@ "node": ">= 12" } }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "license": "MIT" + }, "node_modules/is-ci": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", @@ -3250,7 +3559,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3390,11 +3698,16 @@ "jiti": "lib/jiti-cli.mjs" } }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "license": "MIT", "dependencies": { "argparse": "^2.0.1" @@ -3407,7 +3720,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true, "license": "MIT" }, "node_modules/json-buffer": { @@ -3415,6 +3727,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -3686,6 +4004,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -4036,6 +4360,12 @@ "node": ">= 8" } }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "license": "MIT" + }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", @@ -4059,7 +4389,6 @@ }, "node_modules/ms": { "version": "2.1.3", - "dev": true, "license": "MIT" }, "node_modules/negotiator": { @@ -4072,6 +4401,15 @@ "node": ">= 0.6" } }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/node-abi": { "version": "3.75.0", "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.75.0.tgz", @@ -4138,7 +4476,6 @@ }, "node_modules/once": { "version": "1.4.0", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -4224,6 +4561,52 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/pac-proxy-agent": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz", + "integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==", + "license": "MIT", + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.6", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "license": "MIT", + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/package-json-from-dist": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", @@ -4231,6 +4614,36 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -4302,7 +4715,6 @@ }, "node_modules/pend": { "version": "1.2.0", - "dev": true, "license": "MIT" }, "node_modules/picocolors": { @@ -4377,7 +4789,6 @@ }, "node_modules/progress": { "version": "2.0.3", - "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" @@ -4404,9 +4815,56 @@ "node": ">=10" } }, + "node_modules/proxy-agent": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz", + "integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.6", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.1.0", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-agent/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, "node_modules/pump": { "version": "3.0.2", - "dev": true, "license": "MIT", "dependencies": { "end-of-stream": "^1.1.0", @@ -4423,6 +4881,44 @@ "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "24.8.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.8.2.tgz", + "integrity": "sha512-Sn6SBPwJ6ASFvQ7knQkR+yG7pcmr4LfXzmoVp3NR0xXyBbPhJa8a8ybtb6fnw1g/DD/2t34//yirubVczko37w==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.10.4", + "chromium-bidi": "5.1.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1439962", + "puppeteer-core": "24.8.2", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "24.8.2", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.8.2.tgz", + "integrity": "sha512-wNw5cRZOHiFibWc0vdYCYO92QuKTbJ8frXiUfOq/UGJWMqhPoBThTKkV+dJ99YyWfzJ2CfQQ4T1nhhR0h8FlVw==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.10.4", + "chromium-bidi": "5.1.0", + "debug": "^4.4.0", + "devtools-protocol": "0.0.1439962", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/quick-lru": { "version": "5.1.1", "dev": true, @@ -4466,7 +4962,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -4495,6 +4990,15 @@ "dev": true, "license": "MIT" }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/responselike": { "version": "2.0.1", "dev": true, @@ -4613,7 +5117,6 @@ "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -4706,7 +5209,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6.0.0", @@ -4717,7 +5219,6 @@ "version": "2.8.4", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz", "integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==", - "dev": true, "license": "MIT", "dependencies": { "ip-address": "^9.0.5", @@ -4760,7 +5261,7 @@ "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, + "devOptional": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -4779,7 +5280,6 @@ }, "node_modules/sprintf-js": { "version": "1.1.3", - "dev": true, "license": "BSD-3-Clause" }, "node_modules/ssri": { @@ -4805,6 +5305,19 @@ "node": ">= 6" } }, + "node_modules/streamx": { + "version": "2.22.0", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.0.tgz", + "integrity": "sha512-sLh1evHOzBy/iWRiR6d1zRcLao4gGZr3C1kzNz4fopCOKJb6xD9ub8Mpi9Mr1R6id5o43S+d93fI48UC5uM9aw==", + "license": "MIT", + "dependencies": { + "fast-fifo": "^1.3.2", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -4819,7 +5332,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -4850,7 +5362,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -4928,6 +5439,31 @@ "node": ">=10" } }, + "node_modules/tar-fs": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.8.tgz", + "integrity": "sha512-ZoROL70jptorGAlgAYiLoBLItEKw/fUxg9BSYK/dF/GAGYFJOJJJMvjPAKDJraCXFwadD456FCuvLWgfhMsPwg==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^4.0.1", + "bare-path": "^3.0.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "license": "MIT", + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -4993,6 +5529,15 @@ "rimraf": "bin.js" } }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "license": "Apache-2.0", + "dependencies": { + "b4a": "^1.6.4" + } + }, "node_modules/tiny-async-pool": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", @@ -5061,6 +5606,12 @@ "utf8-byte-length": "^1.0.1" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-fest": { "version": "0.13.1", "dev": true, @@ -5073,11 +5624,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "license": "MIT" + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -5088,7 +5645,7 @@ }, "node_modules/undici-types": { "version": "6.21.0", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/unique-filename": { @@ -5197,7 +5754,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -5232,9 +5788,29 @@ }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz", + "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xmlbuilder": { "version": "15.1.1", "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", @@ -5249,7 +5825,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "license": "ISC", "engines": { "node": ">=10" @@ -5266,7 +5841,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "license": "MIT", "dependencies": { "cliui": "^8.0.1", @@ -5285,7 +5859,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "license": "ISC", "engines": { "node": ">=12" @@ -5293,7 +5866,6 @@ }, "node_modules/yauzl": { "version": "2.10.0", - "dev": true, "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", @@ -5312,6 +5884,15 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.24.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", + "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/package.json b/package.json index 5a973c56..63e3f740 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "@tailwindcss/cli": "^4.1.5", "dotenv": "^16.5.0", "electron-squirrel-startup": "^1.0.1", + "puppeteer": "^24.8.2", "tailwindcss": "^4.1.5", "tree-kill": "^1.2.2" } -} \ No newline at end of file +} diff --git a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx index 6e23bafb..17764d57 100644 --- a/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx +++ b/servers/nextjs/app/(presentation-generator)/documents-preview/components/DocumentPreviewPage.tsx @@ -27,7 +27,6 @@ import { Button } from "@/components/ui/button"; import { toast } from "@/hooks/use-toast"; import Header from "@/app/dashboard/components/Header"; import MarkdownRenderer from "./MarkdownRenderer"; -import { fetchTextFromURL } from "../../utils/download"; import { getIconFromFile, removeUUID } from "../../utils/others"; import { ChevronRight, PanelRightOpen, X } from "lucide-react"; import ToolTip from "@/components/ToolTip"; @@ -83,8 +82,8 @@ const DocumentsPreviewPage: React.FC = () => { } }; - const maintainDocumentTexts = async () => { + const maintainDocumentTexts = async () => { const newDocuments: string[] = []; const promises: Promise[] = []; @@ -92,7 +91,8 @@ const DocumentsPreviewPage: React.FC = () => { documentKeys.forEach(key => { if (!(key in textContents)) { newDocuments.push(key); - promises.push(fetchTextFromURL(documents[key])); + // @ts-ignore + promises.push(window.electron.readFile(documents[key])); } }); @@ -100,20 +100,30 @@ const DocumentsPreviewPage: React.FC = () => { reportKeys.forEach(key => { if (!(key in textContents)) { newDocuments.push(key); - promises.push(fetchTextFromURL(reports[key])); + // @ts-ignore + promises.push(window.electron.readFile(reports[key])); } }); if (promises.length > 0) { setDownloadingDocuments(newDocuments); - const results = await Promise.all(promises); - setTextContents(prev => { - const newContents = { ...prev }; - newDocuments.forEach((key, index) => { - newContents[key] = results[index]; + try { + const results = await Promise.all(promises); + setTextContents(prev => { + const newContents = { ...prev }; + newDocuments.forEach((key, index) => { + newContents[key] = results[index]; + }); + return newContents; }); - return newContents; - }); + } catch (error) { + console.error('Error reading files:', error); + toast({ + title: "Error", + description: "Failed to read document content", + variant: "destructive", + }); + } setDownloadingDocuments([]); } }; diff --git a/servers/nextjs/app/(presentation-generator)/utils/download.ts b/servers/nextjs/app/(presentation-generator)/utils/download.ts deleted file mode 100644 index 17ddb95c..00000000 --- a/servers/nextjs/app/(presentation-generator)/utils/download.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Fetches text content from a URL or local file path - * @param url - The URL or file path to fetch content from - * @returns Promise - The text content - */ -export async function fetchTextFromURL(url: string): Promise { - if (!url) return ""; - - try { - // Remove file:// prefix if present - const cleanUrl = url.replace('file://', ''); - - // If it's a local file path, use the API endpoint - if (cleanUrl.startsWith('/tmp/') || cleanUrl.startsWith('/')) { - const response = await fetch('/api/read-file', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ filePath: cleanUrl }), - }); - - if (!response.ok) { - throw new Error(`Failed to fetch file: ${response.status} ${response.statusText}`); - } - - const data = await response.json(); - return data.content; - } - - // For remote URLs, use regular fetch - const response = await fetch(url); - if (!response.ok) { - throw new Error(`Failed to fetch: ${response.status} ${response.statusText}`); - } - - return await response.text(); - } catch (error) { - console.error("Error fetching text:", error); - return ""; - } -} \ No newline at end of file diff --git a/servers/nextjs/app/api/read-config/route.ts b/servers/nextjs/app/api/read-config/route.ts deleted file mode 100644 index 68a12481..00000000 --- a/servers/nextjs/app/api/read-config/route.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import fs from "fs"; - -export async function GET(request: NextRequest) { - try { - const { searchParams } = new URL(request.url); - const path = searchParams.get('path'); - - if (!path) { - return NextResponse.json( - { error: "Path parameter is required" }, - { status: 400 } - ); - } - - let config = {}; - if (fs.existsSync(path)) { - const configData = fs.readFileSync(path, 'utf-8'); - config = JSON.parse(configData); - } - - return NextResponse.json({ config }); - } catch (error) { - console.error("Error reading config:", error); - return NextResponse.json( - { error: "Failed to read configuration" }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/servers/nextjs/app/api/read-file/route.ts b/servers/nextjs/app/api/read-file/route.ts deleted file mode 100644 index 1278776e..00000000 --- a/servers/nextjs/app/api/read-file/route.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { NextResponse } from 'next/server'; -import fs from 'fs/promises'; -import path from 'path'; - -export async function POST(request: Request) { - try { - const { filePath } = await request.json(); - - // Validate file path - if (!filePath || typeof filePath !== 'string') { - return NextResponse.json( - { error: 'Invalid file path' }, - { status: 400 } - ); - } - - // Security check: ensure the path is within /tmp directory - const normalizedPath = path.normalize(filePath); - if (!normalizedPath.startsWith('/tmp/')) { - return NextResponse.json( - { error: 'Access denied: File must be in /tmp directory' }, - { status: 403 } - ); - } - - // Read file content - const content = await fs.readFile(normalizedPath, 'utf-8'); - - return NextResponse.json({ content }); - } catch (error) { - console.error('Error reading file:', error); - return NextResponse.json( - { error: 'Failed to read file' }, - { status: 500 } - ); - } -} \ No newline at end of file diff --git a/servers/nextjs/app/api/save-user-config/route.ts b/servers/nextjs/app/api/save-user-config/route.ts deleted file mode 100644 index 5824fab2..00000000 --- a/servers/nextjs/app/api/save-user-config/route.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import fs from "fs"; - -export async function POST(request: NextRequest) { - try { - const body = await request.json(); - const { provider, apiKey, userConfigPath } = body; - - if (!userConfigPath) { - return NextResponse.json( - { error: "User config path not found" }, - { status: 500 } - ); - } - - // Create config object based on provider - const config = { - LLM: provider === "google" ? "gemini-pro" : "gpt-4", - OPENAI_API_KEY: provider === "openai" ? apiKey : undefined, - GOOGLE_API_KEY: provider === "google" ? apiKey : undefined, - }; - - // Read existing config if it exists - let existingConfig = {}; - if (fs.existsSync(userConfigPath)) { - try { - const existingData = fs.readFileSync(userConfigPath, 'utf-8'); - existingConfig = JSON.parse(existingData); - } catch (error) { - console.error("Error reading existing config:", error); - } - } - - // Merge with existing config - const mergedConfig = { - ...existingConfig, - ...config, - }; - - // Write to file - fs.writeFileSync(userConfigPath, JSON.stringify(mergedConfig, null, 2)); - - return NextResponse.json({ success: true, config: mergedConfig }); - } catch (error) { - console.error("Error saving user config:", error); - return NextResponse.json( - { error: "Failed to save configuration" }, - { status: 500 } - ); - } -} diff --git a/servers/nextjs/app/page.tsx b/servers/nextjs/app/page.tsx index 25390701..6f38ab3d 100644 --- a/servers/nextjs/app/page.tsx +++ b/servers/nextjs/app/page.tsx @@ -1,369 +1,9 @@ -"use client"; -import { useState, useEffect } from "react"; -import { useRouter } from "next/navigation"; -import { toast } from "@/hooks/use-toast"; -import { Info, ExternalLink, PlayCircle, Loader2 } from "lucide-react"; -import Link from "next/link"; -import { getEnv } from "@/utils/constant"; -import { - Accordion, - AccordionContent, - AccordionItem, - AccordionTrigger, -} from "@/components/ui/accordion"; - -interface ModelOption { - value: string; - label: string; - description?: string; -} - -interface ProviderConfig { - textModels: ModelOption[]; - imageModels: ModelOption[]; - apiGuide: { - title: string; - steps: string[]; - videoUrl?: string; - docsUrl: string; - }; -} - -const PROVIDER_CONFIGS: Record = { - openai: { - textModels: [ - { - value: "gpt-4", - label: "GPT-4", - description: "Most capable model, best for complex tasks", - }, - ], - imageModels: [ - { - value: "dall-e-3", - label: "DALL-E 3", - description: "Latest version with highest quality", - }, - ], - apiGuide: { - title: "How to get your OpenAI API Key", - steps: [ - "Go to platform.openai.com and sign in or create an account", - 'Click on your profile icon and select "View API keys"', - 'Click "Create new secret key" and give it a name', - "Copy your API key immediately (you won't be able to see it again)", - "Make sure you have sufficient credits in your account", - ], - videoUrl: "https://www.youtube.com/watch?v=OB99E7Y1cMA", - docsUrl: "https://platform.openai.com/docs/api-reference/authentication", - }, - }, - google: { - textModels: [ - { - value: "gemini-pro", - label: "Gemini Pro", - description: "Balanced model for most tasks", - }, - ], - imageModels: [ - { - value: "imagen", - label: "Imagen", - description: "Google's primary image generation model", - }, - ], - apiGuide: { - title: "How to get your Google AI Studio API Key", - steps: [ - "Visit aistudio.google.com", - 'Click on "Get API key" in the top navigation', - 'Click "Create API key" on the next page', - 'Choose either "Create API Key in new Project" or select an existing project', - "Copy your API key - you're ready to go!", - ], - videoUrl: "https://www.youtube.com/watch?v=o8iyrtQyrZM&t=66s", - docsUrl: "https://aistudio.google.com/app/apikey", - }, - }, -}; - -interface ConfigState { - provider: string; - apiKey: string; - textModel: string; - imageModel: string; -} - -export default function Home() { - const router = useRouter(); - const [isLoading, setIsLoading] = useState(true); - const [config, setConfig] = useState({ - provider: "openai", - apiKey: "", - textModel: PROVIDER_CONFIGS.openai.textModels[0].value, - imageModel: PROVIDER_CONFIGS.openai.imageModels[0].value, - }); - - useEffect(() => { - const checkExistingConfig = async () => { - try { - const urls = getEnv(); - const userConfigPath = urls.USER_CONFIG_PATH; - - if (!userConfigPath) { - console.error("User config path not found"); - setIsLoading(false); - return; - } - - const response = await fetch(`/api/read-config?path=${encodeURIComponent(userConfigPath)}`); - if (!response.ok) { - throw new Error('Failed to load configuration'); - } - - const { config: savedConfig } = await response.json(); - - // If either API key exists, redirect to upload - if (savedConfig?.OPENAI_API_KEY || savedConfig?.GOOGLE_API_KEY) { - router.push('/upload'); - } else { - setIsLoading(false); - } - } catch (error) { - console.error("Error checking config:", error); - setIsLoading(false); - } - }; - - checkExistingConfig(); - }, [router]); - - if (isLoading) { - return ( -
-
- -

Loading configuration...

-
-
- ); - } - - const handleProviderChange = (provider: string) => { - setConfig((prev) => ({ - ...prev, - provider, - textModel: PROVIDER_CONFIGS[provider].textModels[0].value, - imageModel: PROVIDER_CONFIGS[provider].imageModels[0].value, - })); - }; - - const handleConfigChange = ( - field: keyof ConfigState, - value: string | number - ) => { - setConfig((prev) => ({ - ...prev, - [field]: value, - })); - }; - - const currentProvider = PROVIDER_CONFIGS[config.provider]; - const handleSaveConfig = async () => { - if (!config.apiKey) { - toast({ - title: "Error", - description: "Please enter an API key", - }); - return; - } - - try { - const userConfigPath = getEnv().USER_CONFIG_PATH; - - if (!userConfigPath) { - toast({ - title: "Error", - description: "Configuration path not found", - }); - return; - } - - const response = await fetch('/api/save-user-config', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - provider: config.provider, - apiKey: config.apiKey, - userConfigPath, - }), - }); - - if (!response.ok) { - throw new Error('Failed to save configuration'); - } - - toast({ - title: "Configuration saved", - description: "You can now upload your presentation", - }); - - router.push("/upload"); - } catch (error) { - console.error('Error saving configuration:', error); - toast({ - title: "Error", - description: "Failed to save configuration", - }); - } - }; +import Home from '../components/Home' +const page = () => { return ( -
-
- {/* Branding Header */} -
-
- Presenton Logo -
-

- Open-source AI presentation generator -

-
- - {/* Main Configuration Card */} -
- {/* Provider Selection */} -
- -
- {Object.keys(PROVIDER_CONFIGS).map((provider) => ( - - ))} -
-
- - {/* API Key Input */} -
- -
- handleConfigChange("apiKey", e.target.value)} - className="w-full px-4 py-2.5 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" - placeholder="Enter your API key" - /> -
-

- - Your API key will be stored locally and never shared -

-
- - {/* Model Information */} -
-
- -
-

- Selected Models -

-

- Using {currentProvider.textModels[0].label} for text - generation and {currentProvider.imageModels[0].label} for - images -

-

- We've pre-selected the best models for optimal presentation - generation -

-
-
-
- {/* API Guide Section */} - - - -
- -

- {currentProvider.apiGuide.title} -

-
-
- -
-
    - {currentProvider.apiGuide.steps.map((step, index) => ( -
  1. - {step} -
  2. - ))} -
- -
- {currentProvider.apiGuide.videoUrl && ( - - - Watch Video Tutorial - - - )} - - Official Documentation - - -
-
-
-
-
- - {/* Save Button */} - -
-
-
- ); + + ) } + +export default page diff --git a/servers/nextjs/app/setting/SettingPage.tsx b/servers/nextjs/app/setting/SettingPage.tsx new file mode 100644 index 00000000..e1e872de --- /dev/null +++ b/servers/nextjs/app/setting/SettingPage.tsx @@ -0,0 +1,150 @@ +'use client'; + +import React, { useState, useEffect } from "react"; +import Header from "../dashboard/components/Header"; +import Wrapper from "@/components/Wrapper"; +import { Settings, Key } from 'lucide-react'; +import { toast } from '@/hooks/use-toast'; +import { getEnv } from "@/utils/constant"; + +interface UserConfig { + LLM?: string; + OPENAI_API_KEY?: string; + GOOGLE_API_KEY?: string; +} + +const SettingsPage = () => { + const [config, setConfig] = useState({}); + const [isLoading, setIsLoading] = useState(true); + + useEffect(() => { + const loadConfig = async () => { + try { + // @ts-ignore + const config = await window.electron.getUserConfig(); + setConfig(config); + } catch (error) { + console.error("Error loading config:", error); + toast({ + title: 'Error', + description: 'Failed to load configuration', + }); + } finally { + setIsLoading(false); + } + }; + + loadConfig(); + }, []); + + const handleSaveConfig = async (provider: string, apiKey: string) => { + try { + const newConfig = { + ...config, + LLM: provider, + [provider === 'openai' ? 'OPENAI_API_KEY' : 'GOOGLE_API_KEY']: apiKey + }; + + // @ts-ignore + await window.electron.setUserConfig(newConfig); + setConfig(newConfig); + + toast({ + title: 'Success', + description: 'Configuration saved successfully', + }); + } catch (error) { + console.error('Error:', error); + toast({ + title: 'Error', + description: 'Failed to save configuration', + }); + } + }; + + if (isLoading) { + return ( +
+
+ +
+
Loading configuration...
+
+
+
+ ); + } + + return ( +
+
+ +
+ {/* Settings Header */} +
+ +

Settings

+
+ + {/* API Configuration Section */} +
+
+ +

API Configuration

+
+ +
+ {/* OpenAI Configuration */} +
+ +
+ setConfig(prev => ({ ...prev, OPENAI_API_KEY: e.target.value }))} + className="flex-1 px-4 py-2.5 border border-gray-300 outline-none rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" + placeholder="Enter your OpenAI API key" + /> + +
+

Required for using OpenAI services

+
+ + {/* Google Configuration */} +
+ +
+ setConfig(prev => ({ ...prev, GOOGLE_API_KEY: e.target.value }))} + className="flex-1 px-4 py-2.5 border border-gray-300 outline-none rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" + placeholder="Enter your Google API key" + /> + +
+

Required for using Google services

+
+
+
+
+
+
+ ); +}; + +export default SettingsPage; diff --git a/servers/nextjs/app/setting/page.tsx b/servers/nextjs/app/setting/page.tsx index d0d54cd2..7eafc72d 100644 --- a/servers/nextjs/app/setting/page.tsx +++ b/servers/nextjs/app/setting/page.tsx @@ -1,183 +1,2 @@ -'use client'; - -import React, { useState, useEffect } from "react"; -import Header from "../dashboard/components/Header"; -import Wrapper from "@/components/Wrapper"; -import { Settings, Key } from 'lucide-react'; -import { toast } from '@/hooks/use-toast'; -import { getEnv } from "@/utils/constant"; - -interface UserConfig { - LLM?: string; - OPENAI_API_KEY?: string; - GOOGLE_API_KEY?: string; -} - -const SettingsPage = () => { - const [config, setConfig] = useState({}); - const [isLoading, setIsLoading] = useState(true); - - useEffect(() => { - const loadConfig = async () => { - try { - const urls = getEnv(); - const userConfigPath = urls.USER_CONFIG_PATH; - - if (!userConfigPath) { - console.error("User config path not found"); - return; - } - - // Use the Node.js fs API through an API route - const response = await fetch(`/api/read-config?path=${encodeURIComponent(userConfigPath)}`); - if (!response.ok) { - throw new Error('Failed to load configuration'); - } - - const { config } = await response.json(); - setConfig(config); - } catch (error) { - console.error("Error loading config:", error); - toast({ - title: 'Error', - description: 'Failed to load configuration', - }); - } finally { - setIsLoading(false); - } - }; - - loadConfig(); - }, []); - - const handleSaveConfig = async (provider: string, apiKey: string) => { - try { - const urls = getEnv(); - const userConfigPath = urls.USER_CONFIG_PATH; - - if (!userConfigPath) { - toast({ - title: 'Error', - description: 'Configuration path not found', - }); - return; - } - - const response = await fetch('/api/save-user-config', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - provider, - apiKey, - userConfigPath, - }), - }); - - if (!response.ok) { - throw new Error('Failed to save configuration'); - } - - const { config: newConfig } = await response.json(); - setConfig(newConfig); - - toast({ - title: 'Success', - description: 'Configuration saved successfully', - }); - } catch (error) { - console.error('Error:', error); - toast({ - title: 'Error', - description: 'Failed to save configuration', - }); - } - }; - - if (isLoading) { - return ( -
-
- -
-
Loading configuration...
-
-
-
- ); - } - - return ( -
-
- -
- {/* Settings Header */} -
- -

Settings

-
- - {/* API Configuration Section */} -
-
- -

API Configuration

-
- -
- {/* OpenAI Configuration */} -
- -
- setConfig(prev => ({ ...prev, OPENAI_API_KEY: e.target.value }))} - className="flex-1 px-4 py-2.5 border border-gray-300 outline-none rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" - placeholder="Enter your OpenAI API key" - /> - -
-

Required for using OpenAI services

-
- - {/* Google Configuration */} -
- -
- setConfig(prev => ({ ...prev, GOOGLE_API_KEY: e.target.value }))} - className="flex-1 px-4 py-2.5 border border-gray-300 outline-none rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" - placeholder="Enter your Google API key" - /> - -
-

Required for using Google services

-
-
-
-
-
-
- ); -}; - -export default SettingsPage; +import SettingPage from './SettingPage' +export default SettingPage diff --git a/servers/nextjs/components/Home.tsx b/servers/nextjs/components/Home.tsx new file mode 100644 index 00000000..2c957c6e --- /dev/null +++ b/servers/nextjs/components/Home.tsx @@ -0,0 +1,335 @@ +"use client"; +import { useState, useEffect } from "react"; +import { useRouter } from "next/navigation"; +import { toast } from "@/hooks/use-toast"; +import { Info, ExternalLink, PlayCircle, Loader2 } from "lucide-react"; +import Link from "next/link"; +import { + Accordion, + AccordionContent, + AccordionItem, + AccordionTrigger, +} from "@/components/ui/accordion"; + +interface ModelOption { + value: string; + label: string; + description?: string; +} + +interface ProviderConfig { + textModels: ModelOption[]; + imageModels: ModelOption[]; + apiGuide: { + title: string; + steps: string[]; + videoUrl?: string; + docsUrl: string; + }; +} + +const PROVIDER_CONFIGS: Record = { + openai: { + textModels: [ + { + value: "gpt-4", + label: "GPT-4", + description: "Most capable model, best for complex tasks", + }, + ], + imageModels: [ + { + value: "dall-e-3", + label: "DALL-E 3", + description: "Latest version with highest quality", + }, + ], + apiGuide: { + title: "How to get your OpenAI API Key", + steps: [ + "Go to platform.openai.com and sign in or create an account", + 'Click on your profile icon and select "View API keys"', + 'Click "Create new secret key" and give it a name', + "Copy your API key immediately (you won't be able to see it again)", + "Make sure you have sufficient credits in your account", + ], + videoUrl: "https://www.youtube.com/watch?v=OB99E7Y1cMA", + docsUrl: "https://platform.openai.com/docs/api-reference/authentication", + }, + }, + google: { + textModels: [ + { + value: "gemini-pro", + label: "Gemini Pro", + description: "Balanced model for most tasks", + }, + ], + imageModels: [ + { + value: "imagen", + label: "Imagen", + description: "Google's primary image generation model", + }, + ], + apiGuide: { + title: "How to get your Google AI Studio API Key", + steps: [ + "Visit aistudio.google.com", + 'Click on "Get API key" in the top navigation', + 'Click "Create API key" on the next page', + 'Choose either "Create API Key in new Project" or select an existing project', + "Copy your API key - you're ready to go!", + ], + videoUrl: "https://www.youtube.com/watch?v=o8iyrtQyrZM&t=66s", + docsUrl: "https://aistudio.google.com/app/apikey", + }, + }, +}; + +interface ConfigState { + provider: string; + apiKey: string; + textModel: string; + imageModel: string; +} + +export default function Home() { + const router = useRouter(); + const [isLoading, setIsLoading] = useState(true); + const [config, setConfig] = useState({ + provider: "openai", + apiKey: "", + textModel: PROVIDER_CONFIGS.openai.textModels[0].value, + imageModel: PROVIDER_CONFIGS.openai.imageModels[0].value, + }); + + useEffect(() => { + const checkExistingConfig = async () => { + try { + // @ts-ignore + const savedConfig = await window.electron.getUserConfig(); + + // If either API key exists, redirect to upload + if (savedConfig?.OPENAI_API_KEY || savedConfig?.GOOGLE_API_KEY) { + router.push('/upload'); + } else { + setIsLoading(false); + } + } catch (error) { + console.error("Error checking config:", error); + setIsLoading(false); + } + }; + + checkExistingConfig(); + }, [router]); + + if (isLoading) { + return ( +
+
+ +

Loading configuration...

+
+
+ ); + } + + const handleProviderChange = (provider: string) => { + setConfig((prev) => ({ + ...prev, + provider, + textModel: PROVIDER_CONFIGS[provider].textModels[0].value, + imageModel: PROVIDER_CONFIGS[provider].imageModels[0].value, + })); + }; + + const handleConfigChange = ( + field: keyof ConfigState, + value: string | number + ) => { + setConfig((prev) => ({ + ...prev, + [field]: value, + })); + }; + + const currentProvider = PROVIDER_CONFIGS[config.provider]; + const handleSaveConfig = async () => { + if (!config.apiKey) { + toast({ + title: "Error", + description: "Please enter an API key", + }); + return; + } + + try { + // @ts-ignore + await window.electron.setUserConfig({ + LLM: config.provider, + [config.provider === 'openai' ? 'OPENAI_API_KEY' : 'GOOGLE_API_KEY']: config.apiKey + }); + + toast({ + title: "Configuration saved", + description: "You can now upload your presentation", + }); + + router.push("/upload"); + } catch (error) { + console.error('Error saving configuration:', error); + toast({ + title: "Error", + description: "Failed to save configuration", + }); + } + }; + + return ( +
+
+ {/* Branding Header */} +
+
+ Presenton Logo +
+

+ Open-source AI presentation generator +

+
+ + {/* Main Configuration Card */} +
+ {/* Provider Selection */} +
+ +
+ {Object.keys(PROVIDER_CONFIGS).map((provider) => ( + + ))} +
+
+ + {/* API Key Input */} +
+ +
+ handleConfigChange("apiKey", e.target.value)} + className="w-full px-4 py-2.5 outline-none border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500/20 focus:border-blue-500 transition-colors" + placeholder="Enter your API key" + /> +
+

+ + Your API key will be stored locally and never shared +

+
+ + {/* Model Information */} +
+
+ +
+

+ Selected Models +

+

+ Using {currentProvider.textModels[0].label} for text + generation and {currentProvider.imageModels[0].label} for + images +

+

+ We've pre-selected the best models for optimal presentation + generation +

+
+
+
+ {/* API Guide Section */} + + + +
+ +

+ {currentProvider.apiGuide.title} +

+
+
+ +
+
    + {currentProvider.apiGuide.steps.map((step, index) => ( +
  1. + {step} +
  2. + ))} +
+ +
+ {currentProvider.apiGuide.videoUrl && ( + + + Watch Video Tutorial + + + )} + + Official Documentation + + +
+
+
+
+
+ + {/* Save Button */} + +
+
+
+ ); +} diff --git a/servers/nextjs/package.json b/servers/nextjs/package.json index 776d1f6a..5d0c64f0 100644 --- a/servers/nextjs/package.json +++ b/servers/nextjs/package.json @@ -56,10 +56,11 @@ "tailwind-merge": "^2.5.3", "tailwind-scrollbar-hide": "^2.0.0", "tailwindcss-animate": "^1.0.7", - "tiptap-markdown": "^0.8.10" + "tiptap-markdown": "^0.8.10", + "@tailwindcss/typography": "^0.5.16" + }, "devDependencies": { - "@tailwindcss/typography": "^0.5.16", "@types/animejs": "^3.1.12", "@types/node": "^20", "@types/puppeteer": "^5.4.7",