From 3ff88695d0b5f2eda4d0714642df3a601de32c63 Mon Sep 17 00:00:00 2001 From: Paul Okoli <75359053+PaulPextra@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:00:29 -0500 Subject: [PATCH 01/45] Update deploy.yml encode the SSH key with Base64 --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f2d0a7b..3e21b93 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,7 +22,7 @@ jobs: - name: Sync build to EC2 run: | - echo "$SSH_KEY" > deploy_key + echo "$SSH_KEY" | base64 -d > deploy_key chmod 600 deploy_key rsync -avz --delete \ --exclude 'node_modules' --exclude '.git' --exclude '.env' \ From 2bf0fb89c5afaf3d76f68d578e8d555f48cd98d9 Mon Sep 17 00:00:00 2001 From: Paul Okoli <75359053+PaulPextra@users.noreply.github.com> Date: Thu, 19 Jun 2025 14:06:18 -0500 Subject: [PATCH 02/45] Update deploy.yml --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 3e21b93..f2d0a7b 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -22,7 +22,7 @@ jobs: - name: Sync build to EC2 run: | - echo "$SSH_KEY" | base64 -d > deploy_key + echo "$SSH_KEY" > deploy_key chmod 600 deploy_key rsync -avz --delete \ --exclude 'node_modules' --exclude '.git' --exclude '.env' \ From 1dba68e13f6b1362eb0ca215a1c7955c48e1e71c Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Fri, 20 Jun 2025 11:47:13 -0500 Subject: [PATCH 03/45] adding logs --- extension/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/extension/index.js b/extension/index.js index 5b791e5..ba8be10 100644 --- a/extension/index.js +++ b/extension/index.js @@ -6,6 +6,7 @@ chrome.runtime.onMessage.addListener(function (request, _, sendResponse) { if (request.action === 'scrape') { scrape(); } + console.log('Listening....') if (request.action === 'model') { model = request.model; } @@ -14,6 +15,7 @@ chrome.runtime.onMessage.addListener(function (request, _, sendResponse) { }); async function scrape() { + console.log('Scraping Start') const htmlDoc = document.documentElement.innerHTML; if (!htmlDoc || isRequesting) return; From 3148fc611d242d7ec50f82ddbea2bb663bb7e928 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Fri, 20 Jun 2025 11:57:51 -0500 Subject: [PATCH 04/45] remove logs --- extension/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/extension/index.js b/extension/index.js index ba8be10..5b791e5 100644 --- a/extension/index.js +++ b/extension/index.js @@ -6,7 +6,6 @@ chrome.runtime.onMessage.addListener(function (request, _, sendResponse) { if (request.action === 'scrape') { scrape(); } - console.log('Listening....') if (request.action === 'model') { model = request.model; } @@ -15,7 +14,6 @@ chrome.runtime.onMessage.addListener(function (request, _, sendResponse) { }); async function scrape() { - console.log('Scraping Start') const htmlDoc = document.documentElement.innerHTML; if (!htmlDoc || isRequesting) return; From 2f1f585b744357d943e62b0e1de310e3b91f9490 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Thu, 3 Jul 2025 22:39:58 -0500 Subject: [PATCH 05/45] scrape chatgpt --- app/api/conversation/[id]/route.ts | 12 +- app/api/conversation/route.ts | 3 +- lib/parsers/chatgpt.ts | 42 +- lib/parsers/scrapeChatGPTWithInlineStyles.ts | 49 + package-lock.json | 1378 +++++++++++++++++- package.json | 5 + 6 files changed, 1434 insertions(+), 55 deletions(-) create mode 100644 lib/parsers/scrapeChatGPTWithInlineStyles.ts diff --git a/app/api/conversation/[id]/route.ts b/app/api/conversation/[id]/route.ts index 054fa74..c68a4f0 100644 --- a/app/api/conversation/[id]/route.ts +++ b/app/api/conversation/[id]/route.ts @@ -45,19 +45,13 @@ export async function GET( { params }: { params: Promise<{ id: string }> } ): Promise { try { + // console.log(params); await ensureInitialized(); const id = (await params).id; - - // Get conversation record from database const record = await getConversationRecord(id); + const signedUrl = await s3Client.getSignedReadUrl(record.contentKey); - // Get conversation content from S3 - const content = await s3Client.getConversationContent(record.contentKey); - - return NextResponse.json({ - conversation: record, - content: content, - }); + return NextResponse.json({ url: signedUrl }); } catch (error) { console.error('Error retrieving conversation:', error); diff --git a/app/api/conversation/route.ts b/app/api/conversation/route.ts index 990e9bd..093fc6f 100644 --- a/app/api/conversation/route.ts +++ b/app/api/conversation/route.ts @@ -81,6 +81,7 @@ export async function POST(req: NextRequest) { // Store only the conversation content in S3 const contentKey = await s3Client.storeConversation(conversationId, conversation.content); + // console.log(conversationId, conversation.content); // Create the database record with metadata const dbInput: CreateConversationInput = { @@ -94,7 +95,7 @@ export async function POST(req: NextRequest) { const record = await createConversationRecord(dbInput); // Generate the permalink using the database-generated ID - const permalink = `${process.env.NEXT_PUBLIC_BASE_URL}/conversation/${record.id}`; + const permalink = `${process.env.NEXT_PUBLIC_BASE_URL}/c/${record.id}`; return NextResponse.json( { url: permalink }, diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 2a8f0e1..8f328b8 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,13 +1,45 @@ +// lib/parsers/chatgpt.ts +import { scrapeChatGPTWithInlineStyles } from '@/lib/parsers/scrapeChatGPTWithInlineStyles'; import type { Conversation } from '@/types/conversation'; +import { JSDOM } from 'jsdom'; + +/** swap every for an inline + * • you get one big HTML string you can save or parse further + */ +export async function scrapeChatGPTWithInlineStyles( + url: string +): Promise { + const browser = await puppeteer.launch({ headless: 'new' }); + const page = await browser.newPage(); + + await page.goto(url, { waitUntil: 'networkidle0' }); + + // ── 1) Scroll so lazy elements render ───────────────────────── + await page.evaluate(async () => { + window.scrollTo({ top: document.body.scrollHeight }); + await new Promise(r => setTimeout(r, 500)); // wait a tick + }); + + // ── 2) Inline external style-sheets ─────────────────────────── + await page.evaluate(async () => { + const links = Array.from( + document.querySelectorAll('link[rel="stylesheet"]') + ); + + for (const link of links) { + const href = link.href; + if (!href) continue; + + try { + const css = await (await fetch(href)).text(); + const style = document.createElement('style'); + style.textContent = css; + style.setAttribute('data-inlined-from', href.split('?')[0]); + link.replaceWith(style); + } catch { /* ignore if a sheet fails */ } + } + }); + + // ── 3) Grab the fully-styled markup ─────────────────────────── + const html = await page.content(); + await browser.close(); + return html; +} diff --git a/package-lock.json b/package-lock.json index 5058ea1..a7be78a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,9 +15,13 @@ "@types/pg": "^8.15.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "jsdom": "^26.1.0", "lucide-react": "^0.509.0", + "mime-types": "^3.0.1", "next": "15.3.2", + "node-fetch": "^3.3.2", "pg": "^8.16.0", + "puppeteer": "^24.10.2", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwind-merge": "^3.3.0" @@ -26,6 +30,7 @@ "@eslint/eslintrc": "^3", "@shadcn/ui": "^0.0.4", "@tailwindcss/postcss": "^4", + "@types/jsdom": "^21.1.7", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", @@ -63,6 +68,19 @@ "node": ">=6.0.0" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.2.0.tgz", + "integrity": "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==", + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.3", + "@csstools/css-color-parser": "^3.0.9", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, "node_modules/@aws-crypto/crc32": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-5.2.0.tgz", @@ -948,6 +966,139 @@ "node": ">=18.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/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", + "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.10.tgz", + "integrity": "sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.4" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.5", + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", + "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.4" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", + "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@emnapi/core": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", @@ -1855,6 +2006,27 @@ "node": ">=12.4.0" } }, + "node_modules/@puppeteer/browsers": { + "version": "2.10.5", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.10.5.tgz", + "integrity": "sha512-eifa0o+i8dERnngJwKrfp3dEq7ia5XFyoqB17S4gK8GhsQE4/P8nxOfQSE0zQHxzzLo/cmF+7+ywEQ7wK7Fb+w==", + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.4.1", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.5.0", + "semver": "^7.7.2", + "tar-fs": "^3.0.8", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@radix-ui/react-avatar": { "version": "1.1.9", "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.9.tgz", @@ -3058,6 +3230,12 @@ "tailwindcss": "4.1.6" } }, + "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/@tybys/wasm-util": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", @@ -3076,6 +3254,18 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/jsdom": { + "version": "21.1.7", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.7.tgz", + "integrity": "sha512-yOriVnggzrnQ3a9OKOCxaVuSug3w3/SbOj5i7VwXWZEyUNl3bLF9V3MfxGbZKuwqJOQyRfqXyROBB1CoZLFWzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3130,6 +3320,23 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.32.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", @@ -3644,6 +3851,15 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -3678,7 +3894,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" @@ -3694,7 +3909,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/aria-query": { @@ -3865,6 +4079,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -3918,6 +4144,12 @@ "node": ">= 0.4" } }, + "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", @@ -3925,6 +4157,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.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.1.5.tgz", + "integrity": "sha512-1zccWBMypln0jEE05LzZt+V/8y8AQsQQqxtklqaIyg5nu6OAYFhZxPXinJTSG+kU5qyNmeLgcn9AW7eHiCHVLA==", + "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", @@ -3946,6 +4250,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": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -4034,6 +4347,15 @@ "ieee754": "^1.2.1" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -4109,7 +4431,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -4162,6 +4483,19 @@ "node": ">=18" } }, + "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/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -4209,6 +4543,41 @@ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", "license": "MIT" }, + "node_modules/cliui": { + "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==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/clone": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", @@ -4246,7 +4615,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==", - "devOptional": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -4259,7 +4627,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "devOptional": true, "license": "MIT" }, "node_modules/color-string": { @@ -4347,6 +4714,32 @@ "node": ">= 0.10" } }, + "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/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -4362,6 +4755,19 @@ "node": ">= 8" } }, + "node_modules/cssstyle": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.4.0.tgz", + "integrity": "sha512-W0Y2HOXlPkb2yaKrCVRjinYKciu/qSLEmK0K9mcfDei3zwlnHFEHAs/Du3cIRwPqY+J4JsiBzUjoHyc8RsJ03A==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.2.0", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -4380,12 +4786,24 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 12" } }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/data-view-buffer": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", @@ -4441,10 +4859,9 @@ } }, "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4458,6 +4875,12 @@ } } }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "license": "MIT" + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -4514,10 +4937,24 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "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/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { @@ -4534,6 +4971,12 @@ "node": ">=8" } }, + "node_modules/devtools-protocol": { + "version": "0.0.1452169", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1452169.tgz", + "integrity": "sha512-FOFDVMGrAUNp0dDKsAU1TorWJUx2JOU1k9xdgBKKJF3IBh/Uhl2yswG5r3TEAOrCiGY2QRp1e6LVDQrCsTKO4g==", + "license": "BSD-3-Clause" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -4586,6 +5029,15 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.18.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", @@ -4600,6 +5052,42 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "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/error-ex/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/es-abstract": { "version": "1.23.9", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", @@ -4774,6 +5262,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", @@ -4794,6 +5291,27 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "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/eslint": { "version": "9.26.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.26.0.tgz", @@ -5176,6 +5694,19 @@ "url": "https://opencollective.com/eslint" } }, + "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/esquery": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", @@ -5206,7 +5737,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -5216,7 +5746,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" @@ -5338,6 +5867,41 @@ "express": "^4.11 || 5 || ^5.0.0-beta.1" } }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -5345,6 +5909,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-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -5421,11 +5991,19 @@ "reusify": "^1.0.4" } }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, "funding": [ { "type": "github", @@ -5547,7 +6125,6 @@ "version": "4.0.10", "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, "license": "MIT", "dependencies": { "fetch-blob": "^3.1.2" @@ -5632,6 +6209,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", @@ -5715,6 +6301,29 @@ "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, + "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/get-uri/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/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -5879,6 +6488,18 @@ "node": ">= 0.4" } }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/http-errors": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", @@ -5896,6 +6517,32 @@ "node": ">= 0.8" } }, + "node_modules/http-proxy-agent": { + "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==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/human-signals": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-4.3.1.tgz", @@ -5910,7 +6557,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -5954,7 +6600,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -5999,6 +6644,19 @@ "node": ">= 0.4" } }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "license": "MIT", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/ipaddr.js": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", @@ -6187,6 +6845,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-fullwidth-code-point": { + "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==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-generator-function": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", @@ -6272,6 +6939,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "license": "MIT" + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -6496,14 +7169,12 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "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" @@ -6512,6 +7183,51 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "license": "MIT" + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -6519,6 +7235,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", @@ -6868,6 +7590,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/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -6934,6 +7662,12 @@ "loose-envify": "cli.js" } }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, "node_modules/lucide-react": { "version": "0.509.0", "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.509.0.tgz", @@ -7021,7 +7755,6 @@ "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.6" @@ -7031,7 +7764,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", - "dev": true, "license": "MIT", "dependencies": { "mime-db": "^1.54.0" @@ -7099,6 +7831,12 @@ "node": ">= 18" } }, + "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": "3.0.1", "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", @@ -7119,7 +7857,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -7173,6 +7910,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/next": { "version": "15.3.2", "resolved": "https://registry.npmjs.org/next/-/next-15.3.2.tgz", @@ -7260,7 +8006,6 @@ "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", "deprecated": "Use your platform's native DOMException instead", - "dev": true, "funding": [ { "type": "github", @@ -7280,7 +8025,6 @@ "version": "3.3.2", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dev": true, "license": "MIT", "dependencies": { "data-uri-to-buffer": "^4.0.0", @@ -7324,6 +8068,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nwsapi": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", + "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "license": "MIT" + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -7464,7 +8214,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -7591,11 +8340,42 @@ "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-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/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==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -7604,6 +8384,36 @@ "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/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -7651,6 +8461,12 @@ "node": ">=16" } }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "license": "MIT" + }, "node_modules/pg": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/pg/-/pg-8.16.0.tgz", @@ -7857,6 +8673,15 @@ "node": ">= 0.8.0" } }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -7897,16 +8722,97 @@ "node": ">= 0.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-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.3", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz", + "integrity": "sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==", + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/puppeteer": { + "version": "24.10.2", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.10.2.tgz", + "integrity": "sha512-+k26rCz6akFZntx0hqUoFjCojgOLIxZs6p2k53LmEicwsT8F/FMBKfRfiBw1sitjiCvlR/15K7lBqfjXa251FA==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.10.5", + "chromium-bidi": "5.1.0", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1452169", + "puppeteer-core": "24.10.2", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "24.10.2", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.10.2.tgz", + "integrity": "sha512-CnzhOgrZj8DvkDqI+Yx+9or33i3Y9uUYbKyYpP4C13jWwXx/keQ38RMTMmxuLCWQlxjZrOH0Foq7P2fGP7adDQ==", + "license": "Apache-2.0", + "dependencies": { + "@puppeteer/browsers": "2.10.5", + "chromium-bidi": "5.1.0", + "debug": "^4.4.1", + "devtools-protocol": "0.0.1452169", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.2" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/qs": { "version": "6.14.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", @@ -8057,6 +8963,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/require-directory": { + "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==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -8082,7 +8997,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -8169,6 +9083,12 @@ "node": ">= 18" } }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "license": "MIT" + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -8273,9 +9193,20 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, "license": "MIT" }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, "node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -8283,10 +9214,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "devOptional": true, + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8554,6 +9484,54 @@ "dev": true, "license": "MIT" }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.5.tgz", + "integrity": "sha512-iF+tNDQla22geJdTyJB1wM/qrX9DMRwWrciEPwWLPRWAUEM8sQiyxgckLxWT1f7+9VabJS0jTGGr4QgBuvi6Ww==", + "license": "MIT", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "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/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -8572,6 +9550,12 @@ "node": ">= 10.x" } }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "license": "BSD-3-Clause" + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -8613,6 +9597,19 @@ "node": ">=10.0.0" } }, + "node_modules/streamx": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.22.1.tgz", + "integrity": "sha512-znKXEBxfatz2GBNK02kRnCXjV+AA4kjZIUxeWSr3UGirZMJfTE9uiwKHobnbgxWyL/JWro8tTq+vOqAK1/qbSA==", + "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", @@ -8623,6 +9620,47 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/string.prototype.includes": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz", @@ -8849,6 +9887,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "license": "MIT" + }, "node_modules/tailwind-merge": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.0.tgz", @@ -8894,6 +9938,40 @@ "node": ">=18" } }, + "node_modules/tar-fs": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.10.tgz", + "integrity": "sha512-C1SwlQGNLe/jPNqapK8epDsXME7CAJR5RL3GcE6KWx1d9OUByzoHVcbu1VPI8tevg9H8Alae0AApHHFGzrD5zA==", + "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/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/tinyglobby": { "version": "0.2.13", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", @@ -8939,6 +10017,24 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -8962,6 +10058,30 @@ "node": ">=0.6" } }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", + "integrity": "sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==", + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/ts-api-utils": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", @@ -9110,11 +10230,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "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, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -9251,6 +10377,18 @@ "node": ">= 0.8" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/wcwidth": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", @@ -9265,12 +10403,54 @@ "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -9386,13 +10566,86 @@ "node": ">=0.10.0" } }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "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/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "license": "MIT" + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -9402,6 +10655,15 @@ "node": ">=0.4" } }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/yallist": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", @@ -9412,6 +10674,43 @@ "node": ">=18" } }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -9429,7 +10728,6 @@ "version": "3.24.4", "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.4.tgz", "integrity": "sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index bd99d85..c0e85a0 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,13 @@ "@types/pg": "^8.15.4", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "jsdom": "^26.1.0", "lucide-react": "^0.509.0", + "mime-types": "^3.0.1", "next": "15.3.2", + "node-fetch": "^3.3.2", "pg": "^8.16.0", + "puppeteer": "^24.10.2", "react": "^19.0.0", "react-dom": "^19.0.0", "tailwind-merge": "^3.3.0" @@ -27,6 +31,7 @@ "@eslint/eslintrc": "^3", "@shadcn/ui": "^0.0.4", "@tailwindcss/postcss": "^4", + "@types/jsdom": "^21.1.7", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", From 55d8c42d7c7ad4cc5c11ff2ee8d10995023bf5ab Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Thu, 3 Jul 2025 23:35:47 -0500 Subject: [PATCH 06/45] scrape chatgpt --- lib/parsers/chatgpt.ts | 43 ++++++++------ lib/parsers/scrapeChatGPTWithInlineStyles.ts | 59 ++++++++++++++------ 2 files changed, 69 insertions(+), 33 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 8f328b8..bf30611 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,45 +1,54 @@ -// lib/parsers/chatgpt.ts import { scrapeChatGPTWithInlineStyles } from '@/lib/parsers/scrapeChatGPTWithInlineStyles'; import type { Conversation } from '@/types/conversation'; import { JSDOM } from 'jsdom'; -/** swap every for an inline - * • you get one big HTML string you can save or parse further + * Selector that matches every chat bubble on a ChatGPT share page. + * Tweak if OpenAI changes their markup. + */ +const ARTICLE_SEL = 'article[data-testid^="conversation-turn"]'; + +/** + * Drive a ChatGPT **share URL** and return self-contained HTML that contains + * **only** the
nodes (conversation turns) with all external + * stylesheets inlined. */ export async function scrapeChatGPTWithInlineStyles( - url: string + url: string, + opts: { debugSaveFull?: string; debugSaveCropped?: string } = {} ): Promise { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle0' }); - // ── 1) Scroll so lazy elements render ───────────────────────── + /* Scroll to the bottom so lazy-loaded code blocks render */ await page.evaluate(async () => { window.scrollTo({ top: document.body.scrollHeight }); - await new Promise(r => setTimeout(r, 500)); // wait a tick + await new Promise(r => setTimeout(r, 500)); }); - // ── 2) Inline external style-sheets ─────────────────────────── + /* Inline every external */ await page.evaluate(async () => { const links = Array.from( document.querySelectorAll('link[rel="stylesheet"]') @@ -33,17 +39,38 @@ export async function scrapeChatGPTWithInlineStyles( if (!href) continue; try { - const css = await (await fetch(href)).text(); + const css = await (await fetch(href)).text(); const style = document.createElement('style'); style.textContent = css; style.setAttribute('data-inlined-from', href.split('?')[0]); link.replaceWith(style); - } catch { /* ignore if a sheet fails */ } + } catch { /* ignore failures */ } } }); - // ── 3) Grab the fully-styled markup ─────────────────────────── - const html = await page.content(); + /* Grab the fully styled markup */ + const fullHtml = await page.content(); + if (opts.debugSaveFull) await fs.writeFile(opts.debugSaveFull, fullHtml); + await browser.close(); - return html; + + /* Crop the DOM to *only* the
nodes */ + const dom = new JSDOM(fullHtml); + const { document } = dom.window; + + const main = document.createElement('main'); + document.querySelectorAll(ARTICLE_SEL).forEach(node => + main.appendChild(node.cloneNode(true)) + ); + + const cropped = + '\n' + + document.head.outerHTML + + '' + + main.outerHTML + + ''; + + if (opts.debugSaveCropped) await fs.writeFile(opts.debugSaveCropped, cropped); + + return cropped; } From 13e0b45b12a5e4edb66b5c9dd6253a47826056a2 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Fri, 4 Jul 2025 00:05:43 -0500 Subject: [PATCH 07/45] scrape chatgpt update --- lib/parsers/chatgpt.ts | 51 ++++++++++---------- lib/parsers/scrapeChatGPTWithInlineStyles.ts | 44 ++++++++--------- 2 files changed, 46 insertions(+), 49 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index bf30611..690d9a3 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,53 +1,52 @@ import { scrapeChatGPTWithInlineStyles } from '@/lib/parsers/scrapeChatGPTWithInlineStyles'; -import type { Conversation } from '@/types/conversation'; -import { JSDOM } from 'jsdom'; +import type { Conversation } from '@/types/conversation'; +import { JSDOM } from 'jsdom'; async function prepRawHtml(html: string): Promise { - const dom = new JSDOM(html); + const dom = new JSDOM(html); const { document } = dom.window; - - // 1-A Inline any external sheets that might still exist const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]')); await Promise.all( links.map(async link => { const href = link.href; if (!href) return; - + try { - const css = await (await fetch(href)).text(); - const tag = document.createElement('style'); - tag.textContent = css; - tag.setAttribute('data-inlined-from', href.split('?')[0]); - link.replaceWith(tag); - } catch { /* ignore */ } + const css = await (await fetch(href)).text(); + const style = document.createElement('style'); + style.textContent = css; + style.setAttribute('data-inlined-from', href.split('?')[0]); + link.replaceWith(style); + } catch { /* ignore failures */ } }) ); - // 1-B Crop to only
bubbles to mirror scraper output + /* Keep **only** the
bubbles, but preserve / */ const ARTICLE_SEL = 'article[data-testid^="conversation-turn"]'; - const main = document.createElement('main'); + const wrapper = document.createElement('div'); + wrapper.style.maxWidth = '46rem'; + wrapper.style.margin = '0 auto'; + document.querySelectorAll(ARTICLE_SEL).forEach(el => - main.appendChild(el.cloneNode(true)) + wrapper.appendChild(el.cloneNode(true)) ); - return ( - '\n' + - document.head.outerHTML + - '' + - main.outerHTML + - '' - ); + document.body.innerHTML = ''; + document.body.appendChild(wrapper); + + /* Return fully-serialised HTML (doctype, , attrs all intact) */ + return dom.serialize(); } export async function parseChatGPT(source: string): Promise { - const isUrl = /^https?:\/\//i.test(source); - const html = isUrl + const isUrl = /^https?:\/\//i.test(source); + + const html = isUrl ? await scrapeChatGPTWithInlineStyles(source) : await prepRawHtml(source); - return { model: 'ChatGPT', - content: html, + content: html, scrapedAt: new Date().toISOString(), sourceHtmlBytes: Buffer.byteLength(html), } as Conversation; diff --git a/lib/parsers/scrapeChatGPTWithInlineStyles.ts b/lib/parsers/scrapeChatGPTWithInlineStyles.ts index 3853d5f..da54801 100644 --- a/lib/parsers/scrapeChatGPTWithInlineStyles.ts +++ b/lib/parsers/scrapeChatGPTWithInlineStyles.ts @@ -2,33 +2,30 @@ import puppeteer from 'puppeteer'; import { JSDOM } from 'jsdom'; import fs from 'node:fs/promises'; -/** - * Selector that matches every chat bubble on a ChatGPT share page. - * Tweak if OpenAI changes their markup. - */ +/** Chat bubble selector on a ChatGPT share page */ const ARTICLE_SEL = 'article[data-testid^="conversation-turn"]'; /** - * Drive a ChatGPT **share URL** and return self-contained HTML that contains - * **only** the
nodes (conversation turns) with all external - * stylesheets inlined. + * Scrape a ChatGPT share URL, inline *external* stylesheets, and return + * self-contained HTML that shows **only the user/assistant conversation**. */ export async function scrapeChatGPTWithInlineStyles( url: string, opts: { debugSaveFull?: string; debugSaveCropped?: string } = {} ): Promise { + /* Load the page & inline external */ const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); await page.goto(url, { waitUntil: 'networkidle0' }); - /* Scroll to the bottom so lazy-loaded code blocks render */ + /* Scroll once so lazy-loaded code blocks render */ await page.evaluate(async () => { window.scrollTo({ top: document.body.scrollHeight }); await new Promise(r => setTimeout(r, 500)); }); - /* Inline every external */ + /* Inline every external stylesheet */ await page.evaluate(async () => { const links = Array.from( document.querySelectorAll('link[rel="stylesheet"]') @@ -44,32 +41,33 @@ export async function scrapeChatGPTWithInlineStyles( style.textContent = css; style.setAttribute('data-inlined-from', href.split('?')[0]); link.replaceWith(style); - } catch { /* ignore failures */ } + } catch {/* ignore CORS / 404s */} } }); - /* Grab the fully styled markup */ - const fullHtml = await page.content(); + const fullHtml = await page.content(); // <— styled page if (opts.debugSaveFull) await fs.writeFile(opts.debugSaveFull, fullHtml); - await browser.close(); - /* Crop the DOM to *only* the
nodes */ - const dom = new JSDOM(fullHtml); + /* Crop BODY to keep **only**
bubbles */ + const dom = new JSDOM(fullHtml); const { document } = dom.window; + const body = document.body; + + // Build a neat wrapper (optional – keeps max-width like the site) + const wrapper = document.createElement('div'); + wrapper.style.maxWidth = '46rem'; + wrapper.style.margin = '0 auto'; - const main = document.createElement('main'); document.querySelectorAll(ARTICLE_SEL).forEach(node => - main.appendChild(node.cloneNode(true)) + wrapper.appendChild(node.cloneNode(true)) ); - const cropped = - '\n' + - document.head.outerHTML + - '' + - main.outerHTML + - ''; + body.innerHTML = ''; // strip nav bars, footers, etc. but KEEP attrs + body.appendChild(wrapper); // inject only the conversation + /* Serialise & return */ + const cropped = dom.serialize(); // & still intact if (opts.debugSaveCropped) await fs.writeFile(opts.debugSaveCropped, cropped); return cropped; From 49ac953215da5dd710f4458a6700a097a455cbb7 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Fri, 4 Jul 2025 00:18:44 -0500 Subject: [PATCH 08/45] scrape chatgpt --- lib/parsers/chatgpt.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 690d9a3..951d062 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -17,24 +17,20 @@ async function prepRawHtml(html: string): Promise { style.textContent = css; style.setAttribute('data-inlined-from', href.split('?')[0]); link.replaceWith(style); - } catch { /* ignore failures */ } + } catch {/* ignore */ } }) ); - /* Keep **only** the
bubbles, but preserve / */ - const ARTICLE_SEL = 'article[data-testid^="conversation-turn"]'; - const wrapper = document.createElement('div'); + const mainTag = document.getElementsByTagName('main')[0] ?? document.body; + const articles = Array.from(mainTag.getElementsByTagName('article')); + const wrapper = document.createElement('div'); wrapper.style.maxWidth = '46rem'; wrapper.style.margin = '0 auto'; - - document.querySelectorAll(ARTICLE_SEL).forEach(el => - wrapper.appendChild(el.cloneNode(true)) - ); + articles.forEach(a => wrapper.appendChild(a.cloneNode(true))); document.body.innerHTML = ''; document.body.appendChild(wrapper); - /* Return fully-serialised HTML (doctype, , attrs all intact) */ return dom.serialize(); } @@ -42,11 +38,12 @@ export async function parseChatGPT(source: string): Promise { const isUrl = /^https?:\/\//i.test(source); const html = isUrl - ? await scrapeChatGPTWithInlineStyles(source) + ? await scrapeChatGPTWithInlineStyles(source) // already uses same strategy : await prepRawHtml(source); + return { model: 'ChatGPT', - content: html, + content: html, scrapedAt: new Date().toISOString(), sourceHtmlBytes: Buffer.byteLength(html), } as Conversation; From a120e1de4650ffdcb9b90250cc2ddc9114da524a Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Fri, 4 Jul 2025 00:57:28 -0500 Subject: [PATCH 09/45] update: scrape conversation --- lib/parsers/chatgpt.ts | 54 +++++---- lib/parsers/scrapeChatGPTWithInlineStyles.ts | 114 ++++++++++++------- 2 files changed, 110 insertions(+), 58 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 951d062..7ca0c3a 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -2,27 +2,35 @@ import { scrapeChatGPTWithInlineStyles } from '@/lib/parsers/scrapeChatGPTWithIn import type { Conversation } from '@/types/conversation'; import { JSDOM } from 'jsdom'; -async function prepRawHtml(html: string): Promise { - const dom = new JSDOM(html); - const { document } = dom.window; +/** + * ░▒▓█ Crop the HTML so **only the conversation bubbles remain** █▓▒░ + * – keeps / intact so in-lined CSS variables still work – + */ +async function keepOnlyArticles(html: string): Promise { + const dom = new JSDOM(html); + const { document } = dom.window; + + /* 1️⃣ Inline any leftover (raw HTML path) */ const links = Array.from(document.querySelectorAll('link[rel="stylesheet"]')); await Promise.all( links.map(async link => { - const href = link.href; - if (!href) return; - try { - const css = await (await fetch(href)).text(); + const css = await (await fetch(link.href)).text(); const style = document.createElement('style'); style.textContent = css; - style.setAttribute('data-inlined-from', href.split('?')[0]); + style.setAttribute('data-inlined-from', link.href.split('?')[0]); link.replaceWith(style); - } catch {/* ignore */ } + } catch {/* ignore network errors */ } }) ); - const mainTag = document.getElementsByTagName('main')[0] ?? document.body; - const articles = Array.from(mainTag.getElementsByTagName('article')); + /* 2️⃣ Collect the
bubbles we care about */ + const main = document.querySelector('main') ?? document.body; + const articles = Array.from( + main.querySelectorAll('article[data-testid^="conversation-turn"]') + ); + + /* 3️⃣ Replace content with just those bubbles */ const wrapper = document.createElement('div'); wrapper.style.maxWidth = '46rem'; wrapper.style.margin = '0 auto'; @@ -31,20 +39,26 @@ async function prepRawHtml(html: string): Promise { document.body.innerHTML = ''; document.body.appendChild(wrapper); - return dom.serialize(); + return dom.serialize(); // … fully styled } +/* ─────────────────────────────────────────────────────────────────────────── */ + export async function parseChatGPT(source: string): Promise { - const isUrl = /^https?:\/\//i.test(source); + const isUrl = /^https?:\/\//i.test(source); + + // 1. Get a *self-contained* page (all external CSS already in-lined) + const rawHtml = isUrl + ? await scrapeChatGPTWithInlineStyles(source) + : source; - const html = isUrl - ? await scrapeChatGPTWithInlineStyles(source) // already uses same strategy - : await prepRawHtml(source); + // 2. Strip everything except the conversation turns + const html = await keepOnlyArticles(rawHtml); return { - model: 'ChatGPT', - content: html, - scrapedAt: new Date().toISOString(), + model: 'ChatGPT', + content: html, // only
bubbles + scrapedAt: new Date().toISOString(), sourceHtmlBytes: Buffer.byteLength(html), - } as Conversation; + }; } diff --git a/lib/parsers/scrapeChatGPTWithInlineStyles.ts b/lib/parsers/scrapeChatGPTWithInlineStyles.ts index da54801..548c4d0 100644 --- a/lib/parsers/scrapeChatGPTWithInlineStyles.ts +++ b/lib/parsers/scrapeChatGPTWithInlineStyles.ts @@ -1,73 +1,111 @@ -import puppeteer from 'puppeteer'; -import { JSDOM } from 'jsdom'; -import fs from 'node:fs/promises'; +// lib/scrapeChatGPTWithInlineStyles.ts +import puppeteer from 'puppeteer'; +import { JSDOM } from 'jsdom'; +import fs from 'node:fs/promises'; -/** Chat bubble selector on a ChatGPT share page */ const ARTICLE_SEL = 'article[data-testid^="conversation-turn"]'; +const FONT_EXT = /\.(woff2?|ttf|otf)(\?[^)]+)?$/i; -/** - * Scrape a ChatGPT share URL, inline *external* stylesheets, and return - * self-contained HTML that shows **only the user/assistant conversation**. - */ -export async function scrapeChatGPTWithInlineStyles( - url: string, - opts: { debugSaveFull?: string; debugSaveCropped?: string } = {} -): Promise { - /* Load the page & inline external */ +/* ───────────────────────── STEP 1: Render & inline external ───────────────────────── */ +async function renderWithStylesheetsInlined(url: string): Promise { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); - await page.goto(url, { waitUntil: 'networkidle0' }); - /* Scroll once so lazy-loaded code blocks render */ + // force-paint lazy code blocks await page.evaluate(async () => { window.scrollTo({ top: document.body.scrollHeight }); await new Promise(r => setTimeout(r, 500)); }); - /* Inline every external stylesheet */ + // swap every for an inline `); + + // Convert the conversation HTML to a string + let conversationHtmlString = $.html(conversationHtml); + + // Inline the styles using css-inline + try { + conversationHtmlString = await inline(conversationHtmlString, { + remove_style_tags: true, // Remove original `); + // Add styles to the conversation HTML if present + if (styles) { + conversationHtml.prepend(``); + } // Convert the conversation HTML to a string let conversationHtmlString = $.html(conversationHtml); @@ -42,7 +52,11 @@ export async function parseChatGPT(html: string): Promise { try { conversationHtmlString = await inline(conversationHtmlString, { remove_style_tags: true, // Remove original `); - } - - // Convert the conversation HTML to a string - let conversationHtmlString = $.html(conversationHtml); - - // Inline the styles using css-inline - try { - conversationHtmlString = await inline(conversationHtmlString, { - remove_style_tags: true, // Remove original + + + ${bubbles} + + `.trim(); } -/* ------------------------------------------------------------------------ */ -/* 3) PUBLIC API – accepts either a URL or raw HTML and returns a snapshot */ -/* ------------------------------------------------------------------------ */ +/* ──────────────────────────────────────────────────────────────────────── */ +/* 3) Public API */ +/* ──────────────────────────────────────────────────────────────────────── */ export async function parseChatGPT(source: string): Promise { - const isUrl = /^https?:\/\//i.test(source); - const rawHtml = isUrl ? await scrapeChatGPTWithInlineStyles(source) : source; - const content = await extractConversation(rawHtml); + const isUrl = /^https?:\/\//i.test(source); + const rawHtml = isUrl ? await scrapeChatGPTWithInlineStyles(source) : source; + const content = await extractConversation(rawHtml); return { model: 'ChatGPT', - content, // → portable, self-contained HTML snippet + content, // HTML that looks like your sample scrapedAt: new Date().toISOString(), sourceHtmlBytes: Buffer.byteLength(rawHtml), }; From 921325c18c62ef74d8dc3006beab247314eee33d Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Mon, 7 Jul 2025 14:23:36 -0500 Subject: [PATCH 19/45] update --- lib/parsers/chatgpt.ts | 105 ++++------------------------------------- 1 file changed, 10 insertions(+), 95 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index cc85bdb..4ad53da 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,106 +1,21 @@ import type { Conversation } from '@/types/conversation'; -import puppeteer from 'puppeteer'; -import { JSDOM } from 'jsdom'; +import cheerio from 'cheerio'; -/* ──────────────────────────────────────────────────────────────────────── */ -/* 1) Scrape when the input is a URL */ -/* ──────────────────────────────────────────────────────────────────────── */ -async function scrapeChatGPTWithInlineStyles(url: string): Promise { - const browser = await puppeteer.launch({ headless: 'new' }); - const page = await browser.newPage(); - await page.goto(url, { waitUntil: 'networkidle0' }); - const html = await page.evaluate(() => { - /* remove navbars / footers / buttons … */ - ['nav','header','footer','aside','button'].forEach(sel => - document.querySelectorAll(sel).forEach(e => e.remove()) - ); +export async function parseChatGPT(rawHtml: string): Promise { + const $ = cheerio.load(rawHtml); + const conversationContent = $('.markdown.prose.dark\\:prose-invert.w-full.break-words'); - /* inline every external */ - document.querySelectorAll('link[rel="stylesheet"]').forEach(link => { - const cssText = (link.sheet && Array.from(link.sheet.cssRules).map(r => r.cssText).join('\n')) || ''; - const style = document.createElement('style'); - style.textContent = cssText; - link.replaceWith(style); - }); + if (conversationContent.length === 0) { + throw new Error('No conversation content found'); + } - /* keep basic visual DNA of each bubble */ - document.querySelectorAll('[data-message-author-role]').forEach(b => { - const cs = window.getComputedStyle(b); - b.setAttribute( - 'style', - [ - `font:${cs.font}`, - `padding:${cs.padding}`, - `border-radius:${cs.borderRadius}`, - /* colours are overridden later */ - ].join(';') - ); - }); - - return document.documentElement.outerHTML; - }); - - await browser.close(); - return html; -} - -/* ──────────────────────────────────────────────────────────────────────── */ -/* 2) Extract bubbles + apply the “sample” styling */ -/* ──────────────────────────────────────────────────────────────────────── */ -async function extractConversation(html: string): Promise { - const dom = new JSDOM(html); - const document = dom.window.document; - - const bubbles = Array - .from(document.querySelectorAll('[data-message-author-role]')) - .map(bubble => { - const role = bubble.getAttribute('data-message-author-role'); - const baseStyle = bubble.getAttribute('style') ?? ''; - const shared = 'max-width:70%;border-radius:1rem;'; - const userStyles = 'background:#343541;color:#ececf1;margin-left:auto;'; - const asstStyles = 'background:#dfe1e4;color:#202123;margin-right:auto;'; - - bubble.setAttribute( - 'style', - [ - shared, - baseStyle, - role === 'user' ? userStyles : asstStyles - ].join('') - ); - return bubble.outerHTML; - }) - .join('\n'); - - return ` - - - - - - - - ${bubbles} - - - `.trim(); -} - -/* ──────────────────────────────────────────────────────────────────────── */ -/* 3) Public API */ -/* ──────────────────────────────────────────────────────────────────────── */ -export async function parseChatGPT(source: string): Promise { - const isUrl = /^https?:\/\//i.test(source); - const rawHtml = isUrl ? await scrapeChatGPTWithInlineStyles(source) : source; - const content = await extractConversation(rawHtml); + const content = conversationContent.html().trim(); return { model: 'ChatGPT', - content, // HTML that looks like your sample + content, scrapedAt: new Date().toISOString(), sourceHtmlBytes: Buffer.byteLength(rawHtml), }; -} +} \ No newline at end of file From 9314ec56da5b5bedade2c51d98c4e1c58b543574 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Mon, 7 Jul 2025 14:54:22 -0500 Subject: [PATCH 20/45] update --- lib/parsers/chatgpt.ts | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 4ad53da..d3786d7 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,21 +1,37 @@ import type { Conversation } from '@/types/conversation'; import cheerio from 'cheerio'; - +/** + * Extracts *only* the
elements + * from a ChatGPT share-page HTML string. + * + * @param rawHtml HTML of the whole share page (already fetched) + * @returns Conversation object whose `content` is the joined, + * styled HTML of every message body. + */ export async function parseChatGPT(rawHtml: string): Promise { const $ = cheerio.load(rawHtml); - const conversationContent = $('.markdown.prose.dark\\:prose-invert.w-full.break-words'); - if (conversationContent.length === 0) { - throw new Error('No conversation content found'); - } + /* 1️⃣ Remove action buttons & other chrome (optional) */ + $('[data-testid$="-turn-action-button"], button, svg').remove(); - const content = conversationContent.html().trim(); + /* 2️⃣ Grab every markdown body, keep original order * + * – The long Tailwind class list sometimes changes. * + * – `.markdown.prose` is the stable core we can rely on. */ + const content = $('div.markdown.prose') + .map((_, el) => $.html(el)) // outerHTML of each body + .get() + .join('\n'); // concat with line-breaks + + if (!content.trim()) { + throw new Error('No
blocks found'); + } + /* 3️⃣ Build the return object */ return { model: 'ChatGPT', content, scrapedAt: new Date().toISOString(), - sourceHtmlBytes: Buffer.byteLength(rawHtml), + sourceHtmlBytes: Buffer.byteLength(rawHtml) }; } \ No newline at end of file From 645f8bd1374d8516c101e6cbab3da432d80fda08 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Mon, 7 Jul 2025 21:03:00 -0500 Subject: [PATCH 21/45] update: parsechatgpt --- lib/parsers/chatgpt.ts | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index d3786d7..4ad53da 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,37 +1,21 @@ import type { Conversation } from '@/types/conversation'; import cheerio from 'cheerio'; -/** - * Extracts *only* the
elements - * from a ChatGPT share-page HTML string. - * - * @param rawHtml HTML of the whole share page (already fetched) - * @returns Conversation object whose `content` is the joined, - * styled HTML of every message body. - */ + export async function parseChatGPT(rawHtml: string): Promise { const $ = cheerio.load(rawHtml); + const conversationContent = $('.markdown.prose.dark\\:prose-invert.w-full.break-words'); - /* 1️⃣ Remove action buttons & other chrome (optional) */ - $('[data-testid$="-turn-action-button"], button, svg').remove(); - - /* 2️⃣ Grab every markdown body, keep original order * - * – The long Tailwind class list sometimes changes. * - * – `.markdown.prose` is the stable core we can rely on. */ - const content = $('div.markdown.prose') - .map((_, el) => $.html(el)) // outerHTML of each body - .get() - .join('\n'); // concat with line-breaks - - if (!content.trim()) { - throw new Error('No
blocks found'); + if (conversationContent.length === 0) { + throw new Error('No conversation content found'); } - /* 3️⃣ Build the return object */ + const content = conversationContent.html().trim(); + return { model: 'ChatGPT', content, scrapedAt: new Date().toISOString(), - sourceHtmlBytes: Buffer.byteLength(rawHtml) + sourceHtmlBytes: Buffer.byteLength(rawHtml), }; } \ No newline at end of file From 88702299d3042728f0d1ca76453f853934b7ea55 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Mon, 7 Jul 2025 21:05:16 -0500 Subject: [PATCH 22/45] Scrape model conversation --- lib/parsers/chatgpt.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 4ad53da..f687420 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -2,8 +2,8 @@ import type { Conversation } from '@/types/conversation'; import cheerio from 'cheerio'; -export async function parseChatGPT(rawHtml: string): Promise { - const $ = cheerio.load(rawHtml); +export async function parseChatGPT(html: string): Promise { + const $ = cheerio.load(html); const conversationContent = $('.markdown.prose.dark\\:prose-invert.w-full.break-words'); if (conversationContent.length === 0) { From d5326d92bdb409c86febfe8549143f806791817e Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Tue, 8 Jul 2025 19:26:58 -0500 Subject: [PATCH 23/45] quick-fix: model-conversation --- lib/parsers/chatgpt.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index f687420..e85c82c 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -4,18 +4,16 @@ import cheerio from 'cheerio'; export async function parseChatGPT(html: string): Promise { const $ = cheerio.load(html); - const conversationContent = $('.markdown.prose.dark\\:prose-invert.w-full.break-words'); + const content = $('.\\@thread-xl\\/thread\\:pt-header-height.flex.flex-col.text-sm.pb-25'); - if (conversationContent.length === 0) { + if (content.length === 0) { throw new Error('No conversation content found'); } - const content = conversationContent.html().trim(); - return { model: 'ChatGPT', content, scrapedAt: new Date().toISOString(), - sourceHtmlBytes: Buffer.byteLength(rawHtml), + sourceHtmlBytes: Buffer.byteLength(html), }; } \ No newline at end of file From c6c5b85d7b422f5f3f011b80cfa9ed3f478c01bb Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Tue, 8 Jul 2025 20:05:19 -0500 Subject: [PATCH 24/45] fix:chatgpt-model --- lib/parsers/chatgpt.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index e85c82c..556b651 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,19 +1,26 @@ import type { Conversation } from '@/types/conversation'; -import cheerio from 'cheerio'; - +import { JSDOM } from 'jsdom'; export async function parseChatGPT(html: string): Promise { - const $ = cheerio.load(html); - const content = $('.\\@thread-xl\\/thread\\:pt-header-height.flex.flex-col.text-sm.pb-25'); + const dom = new JSDOM(html); + const document = dom.window.document; + const nodes = document.querySelectorAll( + '.\\@thread-xl\\/thread\\:pt-header-height.flex.flex-col.text-sm.pb-25' + ); - if (content.length === 0) { + if (nodes.length === 0) { throw new Error('No conversation content found'); } + /* Build a single HTML string from those nodes */ + const content = Array.from(nodes) + .map(el => el.outerHTML) + .join('\n'); + return { model: 'ChatGPT', content, scrapedAt: new Date().toISOString(), - sourceHtmlBytes: Buffer.byteLength(html), + sourceHtmlBytes: Buffer.byteLength(html) }; } \ No newline at end of file From e983fced9fead4604b8dbbcce0fd2fd5c3dff962 Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Tue, 8 Jul 2025 20:12:27 -0500 Subject: [PATCH 25/45] fix: chatgpt-model-conversation --- lib/parsers/chatgpt.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index 556b651..e85c82c 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,26 +1,19 @@ import type { Conversation } from '@/types/conversation'; -import { JSDOM } from 'jsdom'; +import cheerio from 'cheerio'; + export async function parseChatGPT(html: string): Promise { - const dom = new JSDOM(html); - const document = dom.window.document; - const nodes = document.querySelectorAll( - '.\\@thread-xl\\/thread\\:pt-header-height.flex.flex-col.text-sm.pb-25' - ); + const $ = cheerio.load(html); + const content = $('.\\@thread-xl\\/thread\\:pt-header-height.flex.flex-col.text-sm.pb-25'); - if (nodes.length === 0) { + if (content.length === 0) { throw new Error('No conversation content found'); } - /* Build a single HTML string from those nodes */ - const content = Array.from(nodes) - .map(el => el.outerHTML) - .join('\n'); - return { model: 'ChatGPT', content, scrapedAt: new Date().toISOString(), - sourceHtmlBytes: Buffer.byteLength(html) + sourceHtmlBytes: Buffer.byteLength(html), }; } \ No newline at end of file From 13a931fd7a76c89c15ea8f34a40078a30d50d46a Mon Sep 17 00:00:00 2001 From: Paul Okoli Date: Tue, 8 Jul 2025 21:51:34 -0500 Subject: [PATCH 26/45] update: chatgpt conversation --- lib/parsers/chatgpt.ts | 72 +++++++++++++++++++++++++++++++++++------- 1 file changed, 60 insertions(+), 12 deletions(-) diff --git a/lib/parsers/chatgpt.ts b/lib/parsers/chatgpt.ts index e85c82c..d0fe889 100644 --- a/lib/parsers/chatgpt.ts +++ b/lib/parsers/chatgpt.ts @@ -1,19 +1,67 @@ import type { Conversation } from '@/types/conversation'; -import cheerio from 'cheerio'; +import puppeteer from 'puppeteer'; +import { JSDOM } from 'jsdom'; +/** helper – replace every external stylesheet with an inline