From 70f0c3e162c6b6d87f2eaddbad1d46ecc8622a9c Mon Sep 17 00:00:00 2001 From: h7ml Date: Sat, 26 Oct 2024 18:26:56 +0800 Subject: [PATCH] =?UTF-8?q?docs(README):=20=E6=9B=B4=E6=96=B0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=96=87=E6=A1=A3=E5=B9=B6=E6=B7=BB=E5=8A=A0=E6=96=B0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/lint.yml | 20 + .github/workflows/release.yml | 39 + .github/workflows/test.yml | 20 + LICENSE | 22 + README.md | 128 ++- e2e/basic.spec.ts | 23 + e2e/context.ts | 8 + manifest.ts | 48 - package.json | 28 +- playwright.config.ts | 9 + pnpm-lock.yaml | 902 +++++++++++++++++- public/logo.png | Bin 0 -> 61554 bytes rsbuild.config.ts | 47 +- src/api/juejin.ts | 1 + src/assets/text-logo.svg | 1 + src/background/index.ts | 2 +- src/content-scripts/api/bookApi.ts | 27 + src/content-scripts/api/index.ts | 4 + src/content-scripts/api/juejin.ts | 34 + src/content-scripts/api/sectionApi.ts | 27 + src/content-scripts/api/types.ts | 38 + .../components/DownloadModal.tsx | 17 +- src/content-scripts/index.tsx | 35 + src/content-scripts/juejin.tsx | 136 +++ src/content-scripts/utils/asyncUtils.ts | 10 + .../utils/cache.ts | 32 +- src/content-scripts/utils/download.ts | 43 + src/content-scripts/utils/file.ts | 26 + src/content-scripts/utils/fileUtils.ts | 25 + src/content-scripts/utils/index.ts | 8 + src/content-scripts/utils/markdownUtils.ts | 50 + src/content/api.ts | 65 -- src/content/index.css | 4 - src/content/index.tsx | 66 -- src/content/utils.ts | 109 --- src/devtools/devtools.tsx | 12 - src/devtools/index.html | 12 - src/devtools/index.tsx | 6 - src/env.d.ts | 1 - src/global.less | 5 + src/manifest.ts | 30 + src/pages/options/app.tsx | 8 + src/pages/options/index.tsx | 6 + src/pages/options/style.less | 5 + src/pages/popup/app.tsx | 8 + src/pages/popup/index.tsx | 5 + src/popup/index.html | 12 - src/popup/index.tsx | 6 - src/popup/popup.tsx | 12 - src/webx-env.d.ts | 4 + tailwind.config.ts | 23 +- tsconfig.json | 22 +- 52 files changed, 1778 insertions(+), 453 deletions(-) create mode 100644 .github/workflows/lint.yml create mode 100644 .github/workflows/release.yml create mode 100644 .github/workflows/test.yml create mode 100644 LICENSE create mode 100644 e2e/basic.spec.ts create mode 100644 e2e/context.ts delete mode 100644 manifest.ts create mode 100644 playwright.config.ts create mode 100644 public/logo.png create mode 100644 src/api/juejin.ts create mode 100644 src/assets/text-logo.svg create mode 100644 src/content-scripts/api/bookApi.ts create mode 100644 src/content-scripts/api/index.ts create mode 100644 src/content-scripts/api/juejin.ts create mode 100644 src/content-scripts/api/sectionApi.ts create mode 100644 src/content-scripts/api/types.ts rename src/{content => content-scripts}/components/DownloadModal.tsx (96%) create mode 100644 src/content-scripts/index.tsx create mode 100644 src/content-scripts/juejin.tsx create mode 100644 src/content-scripts/utils/asyncUtils.ts rename src/{content => content-scripts}/utils/cache.ts (66%) create mode 100644 src/content-scripts/utils/download.ts create mode 100644 src/content-scripts/utils/file.ts create mode 100644 src/content-scripts/utils/fileUtils.ts create mode 100644 src/content-scripts/utils/index.ts create mode 100644 src/content-scripts/utils/markdownUtils.ts delete mode 100644 src/content/api.ts delete mode 100644 src/content/index.css delete mode 100644 src/content/index.tsx delete mode 100644 src/content/utils.ts delete mode 100644 src/devtools/devtools.tsx delete mode 100644 src/devtools/index.html delete mode 100644 src/devtools/index.tsx delete mode 100644 src/env.d.ts create mode 100644 src/global.less create mode 100644 src/manifest.ts create mode 100644 src/pages/options/app.tsx create mode 100644 src/pages/options/index.tsx create mode 100644 src/pages/options/style.less create mode 100644 src/pages/popup/app.tsx create mode 100644 src/pages/popup/index.tsx delete mode 100644 src/popup/index.html delete mode 100644 src/popup/index.tsx delete mode 100644 src/popup/popup.tsx create mode 100644 src/webx-env.d.ts diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..a8392a8 --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,20 @@ +name: Lint + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + - run: npm ci + - run: npm run lint:type \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9d7fccb --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,39 @@ +name: Release + +on: + push: + tags: + - 'v*' + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + - run: npm ci + - run: npm run build + - name: Zip Extension + run: zip -r juejin-book-downloader.zip dist + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + draft: false + prerelease: false + - name: Upload Release Asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./juejin-book-downloader.zip + asset_name: juejin-book-downloader.zip + asset_content_type: application/zip \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..985ab22 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Test + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Use Node.js + uses: actions/setup-node@v3 + with: + node-version: '16' + - run: npm ci + - run: npm test \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..169f955 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2023 h7ml + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md index 11753bd..f060c47 100644 --- a/README.md +++ b/README.md @@ -1,82 +1,128 @@ -# 掘金小册下载器 (Juejin Book Downloader) +# 掘金小册下载器 -![License](https://img.shields.io/github/license/h7ml/juejin-book-downloader) -![GitHub stars](https://img.shields.io/github/stars/h7ml/juejin-book-downloader?style=social) +## 项目简介 -一个用于下载掘金小册的Chrome扩展工具。 - -A Chrome extension tool for downloading books from Juejin. +掘金小册下载器是一个便捷的浏览器扩展,专为掘金平台用户设计。它允许用户轻松下载已购买的掘金小册内容,支持下载整本小册或单个章节,并将内容保存为多种格式,方便离线阅读和学习。 ## 功能特点 -- 支持下载已购买的掘金小册 -- 多种保存格式选择: - - PDF - - Markdown - - HTML - - JSON -- 简单易用的用户界面 -- 支持批量下载 +- 在小册页面智能添加下载按钮 +- 支持下载整本小册 +- 支持下载单个章节 +- 支持多种下载格式:HTML、Markdown、PDF 和 JSON +- 友好的用户界面和交互体验 +- 支持离线阅读,方便随时学习 + +## 安装说明 + +### 方法 1:从 GitHub Release 安装(推荐) + +1. 访问项目的 [Releases 页面](https://github.com/h7ml/juejin-book-downloader/releases)。 +2. 下载最新版本的 `juejin-book-downloader.zip` 文件。 +3. 解压下载的 zip 文件。 +4. 在 Chrome 浏览器中,进入 `chrome://extensions/`。 +5. 开启右上角的"开发者模式"。 +6. 点击左上角的"加载已解压的扩展程序"。 +7. 选择刚才解压的文件夹。 +8. 扩展程序现在应该已经安装完成并在浏览器中激活。 -## 安装 +### 方法 2:从源代码构建 -1. 克隆此仓库到本地: +如果您想自己构建扩展程序,请按照以下步骤操作: + +1. 克隆仓库到本地: ``` git clone https://github.com/h7ml/juejin-book-downloader.git ``` -2. 进入项目目录: +2. 进入项目目录: ``` cd juejin-book-downloader ``` -3. 安装依赖: +3. 安装依赖: ``` npm install ``` -4. 构建项目: +4. 构建项目: ``` npm run build ``` -5. 在Chrome浏览器中加载扩展: - - 打开Chrome浏览器,进入`chrome://extensions/` +5. 在浏览器中加载扩展: + - 打开 Chrome 浏览器,进入 `chrome://extensions/` - 开启"开发者模式" - 点击"加载已解压的扩展程序" - - 选择项目的`dist`目录 + - 选择项目的 `dist` 目录 + +## 更新扩展程序 + +要更新到最新版本: + +1. 下载最新的 Release 版本。 +2. 解压新版本的 zip 文件。 +3. 在 Chrome 的扩展管理页面 (`chrome://extensions/`) 中找到"掘金小册下载器"。 +4. 点击"删除"以卸载旧版本。 +5. 按照上述安装步骤重新安装新版本。 + +注意:更新过程中您的设置和数据可能会丢失。 ## 使用方法 -1. 登录掘金网站 (https://juejin.cn/) -2. 打开您已购买的小册页面 -3. 点击扩展图标,打开下载界面 -4. 选择您想要的保存格式(PDF、Markdown、HTML或JSON) -5. 点击"开始下载"按钮 -6. 下载完成后,您可以在指定位置找到保存的文件 +1. 安装扩展后,访问掘金小册页面。 +2. 在小册首页或章节页面,您会看到一个新的下载按钮。 +3. 点击下载按钮,选择所需的下载格式(HTML、Markdown、PDF 或 JSON)。 +4. 确认下载,内容将被保存为所选格式的文件。 + +## 技术栈 + +- React:用于构建用户界面 +- TypeScript:提供类型安全和更好的开发体验 +- Ant Design:UI 组件库,提供美观的界面元素 +- Chrome Extension API:与浏览器交互,实现扩展功能 +- file-saver:用于保存下载的文件 +- html-to-pdf:用于生成 PDF 文件 +- markdown-it:用于处理 Markdown 格式 -## 开发 +## 项目结构 -- 运行开发服务器: `npm run dev` -- 构建项目: `npm run build` -- 预览构建结果: `npm run preview` +src/ +├── content-scripts/ +│ ├── juejin.tsx # 注入到掘金页面的主要脚本 +│ └── utils/ +│ ├── sectionDownloader.ts # 处理章节下载的工具函数 +│ ├── htmlConverter.ts # HTML 转换工具 +│ ├── pdfGenerator.ts # PDF 生成工具 +│ └── jsonFormatter.ts # JSON 格式化工具 +├── background/ +│ └── index.ts # 背景脚本,处理扩展的后台逻辑 +└── popup/ + └── index.tsx # 扩展的弹出窗口界面 -## 贡献 +## 贡献指南 -欢迎提交问题和合并请求。对于重大更改,请先打开一个问题讨论您想要更改的内容。 +我们欢迎并感谢任何形式的贡献!如果您想为项目做出贡献,请遵循以下步骤: + +1. Fork 本仓库 +2. 创建您的特性分支 (`git checkout -b feature/AmazingFeature`) +3. 提交您的更改 (`git commit -m 'Add some AmazingFeature'`) +4. 推送到分支 (`git push origin feature/AmazingFeature`) +5. 开启一个 Pull Request + +在提交 Pull Request 之前,请确保您的代码符合我们的编码规范,并且所有测试都已通过。 ## 许可证 本项目采用 MIT 许可证。详情请见 [LICENSE](LICENSE) 文件。 -## 作者 - -- **h7ml** - [GitHub](https://github.com/h7ml) +## 联系方式 -## 致谢 +如有任何问题、建议或反馈,请通过以下方式联系我们: -感谢所有为这个项目做出贡献的开发者。 +- 项目 Issues: [https://github.com/h7ml/juejin-book-downloader/issues](https://github.com/h7ml/juejin-book-downloader/issues) +- 邮箱: h7ml@qq.com ---- +## 免责声明 -如果您觉得这个项目有用,请给它一个星标 ⭐️ +本扩展程序仅供学习和研究使用。请尊重作者的知识产权,不要将下载的内容用于商业用途或非法传播。使用本扩展程序时,请遵守掘金平台的用户协议和相关法律法规。 \ No newline at end of file diff --git a/e2e/basic.spec.ts b/e2e/basic.spec.ts new file mode 100644 index 0000000..09bcabe --- /dev/null +++ b/e2e/basic.spec.ts @@ -0,0 +1,23 @@ +import { setupStaticServer } from '@webx-kit/test-utils/playwright'; +import { expect, test } from './context'; + +const getWebpageURL = setupStaticServer(test); + +test('Options Page', async ({ getURL, page }) => { + await page.goto(await getURL('options.html')); + await expect(page.locator('#root')).toHaveText('Options Page'); +}); + +test('Popup Page', async ({ getURL, page }) => { + await page.goto(await getURL('popup.html')); + await expect(page.locator('#root')).toHaveText('Popup Page'); +}); + +test('Content Scripts', async ({ page }) => { + await page.goto(getWebpageURL()); + await expect(page.locator('webx-root')).toBeInViewport(); + // await page.locator('body').screenshot({ path: './webx-root.png' }); + await expect(page.locator('webx-root')).toContainText('Count: 0'); + await page.locator('webx-root').locator('button').click(); + await expect(page.locator('webx-root')).toContainText('Count: 1'); +}); \ No newline at end of file diff --git a/e2e/context.ts b/e2e/context.ts new file mode 100644 index 0000000..56aec0c --- /dev/null +++ b/e2e/context.ts @@ -0,0 +1,8 @@ +import path from 'node:path'; +import { createWebxTest } from '@webx-kit/test-utils/playwright'; + +export const test = createWebxTest({ + extensionPath: path.resolve(__dirname, '../dist'), +}); + +export const { expect } = test; \ No newline at end of file diff --git a/manifest.ts b/manifest.ts deleted file mode 100644 index 4b4679c..0000000 --- a/manifest.ts +++ /dev/null @@ -1,48 +0,0 @@ -import fs from "fs"; - -const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf8")); - -// 创建 Manifest 配置 -const manifest: chrome.runtime.ManifestV3 = { - manifest_version: 3, - name: '掘金小册下载助手dext7r', - version: packageJson.version, - icons: { - "16": "images/icon@16.png", - "32": "images/icon@32.png", - "48": "images/icon@48.png", - "128": "images/icon@128.png", - }, - author: { - email: 'h7ml@qq.com' - }, - homepage_url: "https://github.com/h7ml", - permissions: ["storage", "scripting"], - host_permissions: ["https://juejin.cn/*"], - content_scripts: [ - { - matches: ["https://juejin.cn/*"], - js: ["./src/content/index.tsx"], - css: ["./src/content/index.css"], - }, - ], - offline_enabled: true, - action: { - default_popup: "./src/popup/index.html", - default_icon: { - "16": "images/icon@16.png", - "32": "images/icon@32.png", - "48": "images/icon@48.png", - "128": "images/icon@128.png", - }, - }, - description: packageJson.description || "", - background: { - service_worker: "./src/background/index.ts", - type: "module", - }, - devtools_page: "./src/devtools/index.html", -}; - -// 导出 manifest 配置 -export default manifest; diff --git a/package.json b/package.json index b277adf..1b7a361 100644 --- a/package.json +++ b/package.json @@ -26,43 +26,49 @@ "book-downloader" ], "scripts": { - "dev": "rsbuild dev --open", - "build:watch": "rsbuild build --watch", + "dev": "rsbuild dev", "build": "rsbuild build", - "preview": "rsbuild preview" + "test": "playwright test", + "lint:type": "tsc --noEmit" }, "type": "module", "dependencies": { "@ant-design/icons": "^5.5.1", "@rspack/cli": "^1.0.14", "@rspack/plugin-react-refresh": "^1.0.0", - "ahooks": "^3.8.0", - "antd": "^5.19.3", + "@webx-kit/runtime": "^0.1.0", + "ahooks": "^3.8.1", + "antd": "^5.21.5", "file-saver": "^2.0.5", - "html2pdf.js": "^0.10.1", - "jspdf": "^2.5.1", + "html2pdf.js": "^0.10.2", + "jspdf": "^2.5.2", "jszip": "^3.10.1", - "marked": "^4.0.12", + "marked": "^14.1.3", "react": "^18.3.1", "react-dom": "^18.3.1" }, "devDependencies": { + "@playwright/test": "^1.47.1", "@rsbuild/core": "^1.0.17", + "@rsbuild/plugin-less": "^1.0.2", + "@rsbuild/plugin-node-polyfill": "^1.2.0", "@rsbuild/plugin-react": "^1.0.5", "@types/chrome": "^0.0.279", "@types/file-saver": "^2.0.7", "@types/node": "^22.8.1", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@webx-kit/rsbuild-plugin": "^0.1.0", + "@webx-kit/test-utils": "^0.1.0", "autoprefixer": "^10.4.20", "cross-env": "^7.0.3", "css-loader": "^7.1.2", - "postcss": "^8.4.41", + "postcss": "^8.4.47", "postcss-loader": "^8.1.1", - "react-refresh": "^0.14.0", + "react-refresh": "^0.14.2", "rsbuild-plugin-web-extension": "^0.0.10", "style-loader": "^4.0.0", - "tailwindcss": "^3.4.10", + "tailwindcss": "^3.4.14", "ts-node": "^10.9.2", "typescript": "^5.6.3" }, diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..f46b45e --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,9 @@ +/** + * @see {@link https://playwright.dev/docs/chrome-extensions Chrome extensions | Playwright} + */ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + testDir: './e2e', + retries: 2, +}); \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c6326ec..8d87d49 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -17,27 +17,30 @@ importers: '@rspack/plugin-react-refresh': specifier: ^1.0.0 version: 1.0.0(react-refresh@0.14.2) + '@webx-kit/runtime': + specifier: ^0.1.0 + version: 0.1.0 ahooks: - specifier: ^3.8.0 + specifier: ^3.8.1 version: 3.8.1(react@18.3.1) antd: - specifier: ^5.19.3 + specifier: ^5.21.5 version: 5.21.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) file-saver: specifier: ^2.0.5 version: 2.0.5 html2pdf.js: - specifier: ^0.10.1 + specifier: ^0.10.2 version: 0.10.2 jspdf: - specifier: ^2.5.1 + specifier: ^2.5.2 version: 2.5.2 jszip: specifier: ^3.10.1 version: 3.10.1 marked: - specifier: ^4.0.12 - version: 4.3.0 + specifier: ^14.1.3 + version: 14.1.3 react: specifier: ^18.3.1 version: 18.3.1 @@ -45,9 +48,18 @@ importers: specifier: ^18.3.1 version: 18.3.1(react@18.3.1) devDependencies: + '@playwright/test': + specifier: ^1.47.1 + version: 1.48.2 '@rsbuild/core': specifier: ^1.0.17 version: 1.0.17 + '@rsbuild/plugin-less': + specifier: ^1.0.2 + version: 1.0.2(@rsbuild/core@1.0.17) + '@rsbuild/plugin-node-polyfill': + specifier: ^1.2.0 + version: 1.2.0(@rsbuild/core@1.0.17) '@rsbuild/plugin-react': specifier: ^1.0.5 version: 1.0.5(@rsbuild/core@1.0.17) @@ -66,6 +78,12 @@ importers: '@types/react-dom': specifier: ^18.3.1 version: 18.3.1 + '@webx-kit/rsbuild-plugin': + specifier: ^0.1.0 + version: 0.1.0(@rsbuild/core@1.0.17)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))) + '@webx-kit/test-utils': + specifier: ^0.1.0 + version: 0.1.0(@playwright/test@1.48.2) autoprefixer: specifier: ^10.4.20 version: 10.4.20(postcss@8.4.47) @@ -76,13 +94,13 @@ importers: specifier: ^7.1.2 version: 7.1.2(@rspack/core@1.0.14(@swc/helpers@0.5.13))(webpack@5.95.0) postcss: - specifier: ^8.4.41 + specifier: ^8.4.47 version: 8.4.47 postcss-loader: specifier: ^8.1.1 version: 8.1.1(@rspack/core@1.0.14(@swc/helpers@0.5.13))(postcss@8.4.47)(typescript@5.6.3)(webpack@5.95.0) react-refresh: - specifier: ^0.14.0 + specifier: ^0.14.2 version: 0.14.2 rsbuild-plugin-web-extension: specifier: ^0.0.10 @@ -91,7 +109,7 @@ importers: specifier: ^4.0.0 version: 4.0.0(webpack@5.95.0) tailwindcss: - specifier: ^3.4.10 + specifier: ^3.4.14 version: 3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)) ts-node: specifier: ^10.9.2 @@ -170,6 +188,15 @@ packages: '@emotion/unitless@0.7.5': resolution: {integrity: sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==} + '@floating-ui/core@1.6.8': + resolution: {integrity: sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==} + + '@floating-ui/dom@1.6.11': + resolution: {integrity: sha512-qkMCxSR24v2vGkhYDo/UzxfJN3D4syqSjyuTFz6C7XcpU1pASPRieNI0Kj5VP3/503mOfYiGY891ugBX1GlABQ==} + + '@floating-ui/utils@0.2.8': + resolution: {integrity: sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==} + '@isaacs/cliui@8.0.2': resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -219,6 +246,9 @@ packages: '@leichtgewicht/ip-codec@2.0.5': resolution: {integrity: sha512-Vo+PSpZG2/fmgmiNzYK9qWRh8h/CHrwD0mo1h1DzL4yzHNSfWYujGTYsWGreD000gcgmZ7K4Ys6Tx9TxtsKdDw==} + '@modern-js/utils@2.60.5': + resolution: {integrity: sha512-ZnQNCs8Vdxji5K6OwSq9QUQ0MYU9QdOpWm7lWwi+YPq2RIQcHfAtnEkFu1B2RvifPyGfjVo2kafu+rldUlZMyw==} + '@module-federation/runtime-tools@0.5.1': resolution: {integrity: sha512-nfBedkoZ3/SWyO0hnmaxuz0R0iGPSikHZOAZ0N/dVSQaIzlffUo35B5nlC2wgWIc0JdMZfkwkjZRrnuuDIJbzg==} @@ -247,6 +277,11 @@ packages: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} + '@playwright/test@1.48.2': + resolution: {integrity: sha512-54w1xCWfXuax7dz4W2M9uw0gDyh+ti/0K/MxcCUxChFh37kkdxPdfZDw5QBbuPUJHr1CiHJ1hXgSs+GgeQc5Zw==} + engines: {node: '>=18'} + hasBin: true + '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} @@ -310,6 +345,19 @@ packages: engines: {node: '>=16.7.0'} hasBin: true + '@rsbuild/plugin-less@1.0.2': + resolution: {integrity: sha512-FtnJbonHfBrPP5tCiAHaOYyfqUYpvCUZVHfDv6wsky5copjDG0xnW7NL4JCNdT2QxTbssudL46UhYq67pLW5eA==} + peerDependencies: + '@rsbuild/core': 1.x || ^1.0.1-rc.0 + + '@rsbuild/plugin-node-polyfill@1.2.0': + resolution: {integrity: sha512-mYctpK5Jn2yxTOxQ4rOJ0iFBJNW7sADFtKsLp9dL7MjToMhKiyIs4Mc65piI7B+YOBshdyMqCk3LPjJ+CtSRXQ==} + peerDependencies: + '@rsbuild/core': 1.x || ^1.0.1-beta.0 + peerDependenciesMeta: + '@rsbuild/core': + optional: true + '@rsbuild/plugin-react@1.0.5': resolution: {integrity: sha512-9n3oaWH36y07C5vmQOHhPscKkM14cJZEapozopvSzNXyEHLRN4PFhPhJB6tFA5C/yXnxo8BQCKYw2ejNL0gdvA==} peerDependencies: @@ -416,6 +464,9 @@ packages: '@types/bonjour@3.5.13': resolution: {integrity: sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==} + '@types/chrome@0.0.270': + resolution: {integrity: sha512-ADvkowV7YnJfycZZxL2brluZ6STGW+9oKG37B422UePf2PCXuFA/XdERI0T18wtuWPx0tmFeZqq6MOXVk1IC+Q==} + '@types/chrome@0.0.279': resolution: {integrity: sha512-wl0IxQ2OQiMazPZM5LimHQ7Jwd72/O8UvvzyptplXT2S4eUqXH5C0n8S+v8PtKhyX89p0igCPpNy3Bwksyk57g==} @@ -551,12 +602,39 @@ packages: '@webassemblyjs/wast-printer@1.12.1': resolution: {integrity: sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA==} + '@webx-kit/chrome-types@0.1.0': + resolution: {integrity: sha512-EbyyN5vmgHPDNXwqIv5Gml+uRW76X3n9wz3s8K2bpZ5MuBpkWb+z1bOonOEfRKNNjLQdTBkLMRpLvpc+oRnDig==} + + '@webx-kit/core-plugin@0.1.0': + resolution: {integrity: sha512-uUI7wm/Xgly228VY3YSQZXp1ftWR1wzZf6fqvq9IORLB8URaXAvT9UURamPFo6UnDjLPxPffhDqOT3mfXjsVQg==} + peerDependencies: + '@rsbuild/core': ^1.0.0 + tailwindcss: ^3.0.0 + + '@webx-kit/rsbuild-plugin@0.1.0': + resolution: {integrity: sha512-RFvzxHq4bcTbLolxK1jn+eGIWcwzEvdbdgBPDZzqeTuxt0tY09mKc3479Mt6TKIOYWM7uOYeQrQV0FGh1R8Caw==} + peerDependencies: + '@rsbuild/core': ^0.7.0 + + '@webx-kit/runtime@0.1.0': + resolution: {integrity: sha512-mueseEjfVJ7RN6W7vmxQzYMoaE47JNQl6EhhyqcNkc719FKC4GtIMpprJsQDQLVh1rSwIGRsd33cS2CbpweIJQ==} + + '@webx-kit/test-utils@0.1.0': + resolution: {integrity: sha512-l26ImTYpQZuVR5NQV997rnUPztpuEispUHav3bb7k8dre7n4duJx4S7pQ3RDAwxcBB0Jbuy21nkVfT2MUUcLYw==} + hasBin: true + peerDependencies: + '@playwright/test': ^1.30.0 + '@xtuc/ieee754@1.2.0': resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} '@xtuc/long@4.2.2': resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -654,6 +732,12 @@ packages: array-tree-filter@2.1.0: resolution: {integrity: sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==} + asn1.js@4.10.1: + resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + + assert@2.1.0: + resolution: {integrity: sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==} + atob@2.1.2: resolution: {integrity: sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==} engines: {node: '>= 4.5.0'} @@ -666,6 +750,10 @@ packages: peerDependencies: postcss: ^8.1.0 + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -673,6 +761,9 @@ packages: resolution: {integrity: sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==} engines: {node: '>= 0.6.0'} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + batch@0.6.1: resolution: {integrity: sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==} @@ -680,6 +771,12 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bn.js@4.12.0: + resolution: {integrity: sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -694,6 +791,29 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + + browserify-aes@1.2.0: + resolution: {integrity: sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==} + + browserify-cipher@1.0.1: + resolution: {integrity: sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==} + + browserify-des@1.0.2: + resolution: {integrity: sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==} + + browserify-rsa@4.1.1: + resolution: {integrity: sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==} + engines: {node: '>= 0.10'} + + browserify-sign@4.2.3: + resolution: {integrity: sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==} + engines: {node: '>= 0.12'} + + browserify-zlib@0.2.0: + resolution: {integrity: sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==} + browserslist@4.24.2: resolution: {integrity: sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -707,6 +827,18 @@ packages: buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer-xor@1.0.3: + resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} + + buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + + builtin-status-codes@3.0.0: + resolution: {integrity: sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==} + bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} engines: {node: '>=18'} @@ -746,10 +878,18 @@ packages: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} engines: {node: '>= 8.10.0'} + chrome-launcher@1.1.2: + resolution: {integrity: sha512-YclTJey34KUm5jB1aEJCq807bSievi7Nb/TU4Gu504fUYi3jw3KCIaH6L7nFWQhdEgH3V+wCh+kKD1P5cXnfxw==} + engines: {node: '>=12.13.0'} + hasBin: true + chrome-trace-event@1.0.4: resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} engines: {node: '>=6.0'} + cipher-base@1.0.4: + resolution: {integrity: sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -793,6 +933,12 @@ packages: resolution: {integrity: sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==} engines: {node: '>=0.8'} + console-browserify@1.2.0: + resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==} + + constants-browserify@1.0.0: + resolution: {integrity: sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==} + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -826,6 +972,15 @@ packages: typescript: optional: true + create-ecdh@4.0.4: + resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} + + create-hash@1.2.0: + resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + + create-hmac@1.1.7: + resolution: {integrity: sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==} + create-require@1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -838,6 +993,10 @@ packages: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} + crypto-browserify@3.12.1: + resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} + engines: {node: '>= 0.10'} + css-line-break@2.1.0: resolution: {integrity: sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==} @@ -881,6 +1040,10 @@ packages: supports-color: optional: true + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + default-browser-id@5.0.0: resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} engines: {node: '>=18'} @@ -901,6 +1064,10 @@ packages: resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} engines: {node: '>=12'} + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} + depd@1.1.2: resolution: {integrity: sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==} engines: {node: '>= 0.6'} @@ -909,6 +1076,9 @@ packages: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} engines: {node: '>= 0.8'} + des.js@1.1.0: + resolution: {integrity: sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==} + destroy@1.2.0: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} @@ -923,6 +1093,9 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} + diffie-hellman@5.0.3: + resolution: {integrity: sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==} + dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -930,6 +1103,10 @@ packages: resolution: {integrity: sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==} engines: {node: '>=6'} + domain-browser@5.7.0: + resolution: {integrity: sha512-edTFu0M/7wO1pXY6GDxVNVW086uqwWYIHP98txhcPyV995X21JIH2DtYp33sQJOupYoXKe9RwTw2Ya2vWaquTQ==} + engines: {node: '>=4'} + dompurify@2.5.7: resolution: {integrity: sha512-2q4bEI+coQM8f5ez7kt2xclg1XsecaV9ASJk/54vwlfRRNQfDqJz2pzQ8t0Ix/ToBpXlVjrRIx7pFC/o8itG2Q==} @@ -945,6 +1122,9 @@ packages: electron-to-chromium@1.5.47: resolution: {integrity: sha512-zS5Yer0MOYw4rtK2iq43cJagHZ8sXN0jDHDKzB+86gSBSAI4v07S97mcq+Gs2vclAxSh1j7vOAHxSVgduiiuVQ==} + elliptic@6.6.0: + resolution: {integrity: sha512-dpwoQcLc/2WLQvJvLRHKZ+f9FgOdjnq11rurqwekGQygGPsYSK29OMMD2WalatiqQ+XGFDglTNixpPfI+lpaAA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -994,6 +1174,10 @@ packages: escape-html@1.0.3: resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + eslint-scope@5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -1014,6 +1198,10 @@ packages: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -1021,6 +1209,9 @@ packages: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} + evp_bytestokey@1.0.3: + resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} + execa@5.1.1: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} @@ -1076,6 +1267,9 @@ packages: debug: optional: true + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -1091,6 +1285,11 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1154,10 +1353,24 @@ packages: resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} engines: {node: '>= 0.4'} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hash-base@3.0.4: + resolution: {integrity: sha512-EeeoJKjTyt868liAlVmcv2ZsUfGHlE3Q+BICOXcZiwN3osr5Q/zFGYmTJpoIzuaSTAwndFy+GqhEwlU4L3j4Ow==} + engines: {node: '>=4'} + + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} @@ -1198,6 +1411,9 @@ packages: resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==} engines: {node: '>=8.0.0'} + https-browserify@1.0.0: + resolution: {integrity: sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==} + human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -1216,6 +1432,9 @@ packages: peerDependencies: postcss: ^8.1.0 + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + immediate@3.0.6: resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} @@ -1244,6 +1463,10 @@ packages: resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==} engines: {node: '>= 10'} + is-arguments@1.1.1: + resolution: {integrity: sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==} + engines: {node: '>= 0.4'} + is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} @@ -1251,10 +1474,19 @@ packages: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + is-core-module@2.15.1: resolution: {integrity: sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1268,6 +1500,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-generator-function@1.0.10: + resolution: {integrity: sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==} + engines: {node: '>= 0.4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1277,6 +1513,10 @@ packages: engines: {node: '>=14.16'} hasBin: true + is-nan@1.3.2: + resolution: {integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==} + engines: {node: '>= 0.4'} + is-network-error@1.1.0: resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} engines: {node: '>=16'} @@ -1293,6 +1533,14 @@ packages: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} + is-typed-array@1.1.13: + resolution: {integrity: sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==} + engines: {node: '>= 0.4'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + is-wsl@3.1.0: resolution: {integrity: sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==} engines: {node: '>=16'} @@ -1349,6 +1597,9 @@ packages: lie@3.3.0: resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + lighthouse-logger@2.0.1: + resolution: {integrity: sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -1377,11 +1628,17 @@ packages: make-error@1.3.6: resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - marked@4.3.0: - resolution: {integrity: sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==} - engines: {node: '>= 12'} + marked@14.1.3: + resolution: {integrity: sha512-ZibJqTULGlt9g5k4VMARAktMAjXoVnnr+Y3aCqW1oDftcV4BA3UmrBifzXoZyenHRk75csiPu9iwsTj4VNBT0g==} + engines: {node: '>= 18'} hasBin: true + marky@1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + + md5.js@1.3.5: + resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -1408,6 +1665,10 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} + miller-rabin@4.0.1: + resolution: {integrity: sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==} + hasBin: true + mime-db@1.52.0: resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} engines: {node: '>= 0.6'} @@ -1428,6 +1689,9 @@ packages: minimalistic-assert@1.0.1: resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=} + minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -1496,6 +1760,18 @@ packages: resolution: {integrity: sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==} engines: {node: '>= 0.4'} + object-is@1.1.6: + resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} + engines: {node: '>= 0.4'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.5: + resolution: {integrity: sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==} + engines: {node: '>= 0.4'} + obuf@1.1.2: resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} @@ -1519,6 +1795,9 @@ packages: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true + os-browserify@0.3.0: + resolution: {integrity: sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==} + p-retry@4.6.2: resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} engines: {node: '>=8'} @@ -1537,6 +1816,10 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-asn1@5.1.7: + resolution: {integrity: sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==} + engines: {node: '>= 0.10'} + parse-json@5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} engines: {node: '>=8'} @@ -1545,6 +1828,9 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -1559,6 +1845,10 @@ packages: path-to-regexp@0.1.10: resolution: {integrity: sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==} + pbkdf2@3.1.2: + resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} + engines: {node: '>=0.12'} + performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} @@ -1577,6 +1867,20 @@ packages: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} + playwright-core@1.48.2: + resolution: {integrity: sha512-sjjw+qrLFlriJo64du+EK0kJgZzoQPsabGF4lBvsid+3CNIZIYLgnMj9V6JY5VhM2Peh20DJWIVpVljLLnlawA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.48.2: + resolution: {integrity: sha512-NjYvYgp4BPmiwfe31j4gHLa3J7bD2WiBz8Lk2RoSsmX38SVIARZ18VYjxLjAcDsAhA+F4iSEXTSGgjua0rrlgQ==} + engines: {node: '>=18'} + hasBin: true + + possible-typed-array-names@1.0.0: + resolution: {integrity: sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==} + engines: {node: '>= 0.4'} + postcss-import@15.1.0: resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} engines: {node: '>=14.0.0'} @@ -1658,10 +1962,20 @@ packages: process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + public-encrypt@4.0.3: + resolution: {integrity: sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==} + + punycode@1.4.1: + resolution: {integrity: sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1670,6 +1984,10 @@ packages: resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} engines: {node: '>=0.6'} + querystring-es3@0.2.1: + resolution: {integrity: sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==} + engines: {node: '>=0.4.x'} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -1679,6 +1997,9 @@ packages: randombytes@2.1.0: resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + randomfill@1.0.4: + resolution: {integrity: sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==} + range-parser@1.2.1: resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} engines: {node: '>= 0.6'} @@ -1944,6 +2265,10 @@ packages: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} + readable-stream@4.5.2: + resolution: {integrity: sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -1952,6 +2277,9 @@ packages: resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} engines: {node: '>= 10.13.0'} + reduce-configs@1.0.0: + resolution: {integrity: sha512-/JCYSgL/QeXXsq0Lv/7kOZfqvof7vyzHWfyNQPt3c6vc73mU4WRyT8RJ6ZH5Ci08vUOqXwk7jkZy6BycHTDD9w==} + regenerator-runtime@0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} @@ -1996,11 +2324,18 @@ packages: resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} hasBin: true + ripemd160@2.0.2: + resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + rsbuild-plugin-web-extension@0.0.10: resolution: {integrity: sha512-YVwcFEjV4q5iKxChvYfjh3A+13oaw/KF17JH19KVBswYFCpbD9HH6C5PljaJZvDGA9d4OeR83EN1D/9E8IyRJQ==} peerDependencies: '@rsbuild/core': 1.x + rslog@1.2.3: + resolution: {integrity: sha512-antALPJaKBRPBU1X2q9t085K4htWDOOv/K1qhTUk7h0l1ePU/KbDqKJn19eKP0dk7PqMioeA0+fu3gyPXCsXxQ==} + engines: {node: '>=14.17.6'} + run-applescript@7.0.0: resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} engines: {node: '>=18'} @@ -2075,6 +2410,10 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + sha.js@2.4.11: + resolution: {integrity: sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==} + hasBin: true + shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2137,6 +2476,12 @@ packages: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + stream-browserify@3.0.0: + resolution: {integrity: sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==} + + stream-http@3.2.0: + resolution: {integrity: sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==} + string-convert@0.2.1: resolution: {integrity: sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A==} @@ -2151,6 +2496,9 @@ packages: string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -2246,6 +2594,10 @@ packages: thunky@1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} + timers-browserify@2.0.12: + resolution: {integrity: sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==} + engines: {node: '>=0.6.0'} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2287,6 +2639,13 @@ packages: tslib@2.8.0: resolution: {integrity: sha512-jWVzBLplnCmoaTr13V9dYbiQ99wvZRd0vNWaDRg+aVYRcjDF3nDksxFDE/+fkXnKhpnUUkmx5pK/v8mCtLVqZA==} + tty-browserify@0.0.1: + resolution: {integrity: sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==} + + type-fest@4.26.1: + resolution: {integrity: sha512-yOGpmOAL7CkKe/91I5O3gPICmJNLJ1G4zFYVAsRHg7M64biSnPtRj0WNQt++bRkjYOqjWXrhnUw1utzmVErAdg==} + engines: {node: '>=16'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -2312,9 +2671,16 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + url@0.11.4: + resolution: {integrity: sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==} + engines: {node: '>= 0.4'} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + utils-merge@1.0.1: resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} engines: {node: '>= 0.4.0'} @@ -2333,6 +2699,9 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + vm-browserify@1.1.2: + resolution: {integrity: sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==} + watchpack@2.4.2: resolution: {integrity: sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw==} engines: {node: '>=10.13.0'} @@ -2389,6 +2758,10 @@ packages: resolution: {integrity: sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==} engines: {node: '>=0.8.0'} + which-typed-array@1.1.15: + resolution: {integrity: sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==} + engines: {node: '>= 0.4'} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2426,6 +2799,10 @@ packages: utf-8-validate: optional: true + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -2524,6 +2901,17 @@ snapshots: '@emotion/unitless@0.7.5': {} + '@floating-ui/core@1.6.8': + dependencies: + '@floating-ui/utils': 0.2.8 + + '@floating-ui/dom@1.6.11': + dependencies: + '@floating-ui/core': 1.6.8 + '@floating-ui/utils': 0.2.8 + + '@floating-ui/utils@0.2.8': {} + '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -2578,6 +2966,13 @@ snapshots: '@leichtgewicht/ip-codec@2.0.5': {} + '@modern-js/utils@2.60.5': + dependencies: + '@swc/helpers': 0.5.13 + caniuse-lite: 1.0.30001671 + lodash: 4.17.21 + rslog: 1.2.3 + '@module-federation/runtime-tools@0.5.1': dependencies: '@module-federation/runtime': 0.5.1 @@ -2609,6 +3004,10 @@ snapshots: '@pkgjs/parseargs@0.11.0': optional: true + '@playwright/test@1.48.2': + dependencies: + playwright: 1.48.2 + '@polka/url@1.0.0-next.28': {} '@rc-component/async-validator@5.0.4': @@ -2689,6 +3088,40 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + '@rsbuild/plugin-less@1.0.2(@rsbuild/core@1.0.17)': + dependencies: + '@rsbuild/core': 1.0.17 + deepmerge: 4.3.1 + reduce-configs: 1.0.0 + + '@rsbuild/plugin-node-polyfill@1.2.0(@rsbuild/core@1.0.17)': + dependencies: + assert: 2.1.0 + browserify-zlib: 0.2.0 + buffer: 5.7.1 + console-browserify: 1.2.0 + constants-browserify: 1.0.0 + crypto-browserify: 3.12.1 + domain-browser: 5.7.0 + events: 3.3.0 + https-browserify: 1.0.0 + os-browserify: 0.3.0 + path-browserify: 1.0.1 + process: 0.11.10 + punycode: 2.3.1 + querystring-es3: 0.2.1 + readable-stream: 4.5.2 + stream-browserify: 3.0.0 + stream-http: 3.2.0 + string_decoder: 1.3.0 + timers-browserify: 2.0.12 + tty-browserify: 0.0.1 + url: 0.11.4 + util: 0.12.5 + vm-browserify: 1.1.2 + optionalDependencies: + '@rsbuild/core': 1.0.17 + '@rsbuild/plugin-react@1.0.5(@rsbuild/core@1.0.17)': dependencies: '@rsbuild/core': 1.0.17 @@ -2815,6 +3248,11 @@ snapshots: dependencies: '@types/node': 22.8.1 + '@types/chrome@0.0.270': + dependencies: + '@types/filesystem': 0.0.36 + '@types/har-format': 1.2.16 + '@types/chrome@0.0.279': dependencies: '@types/filesystem': 0.0.36 @@ -3001,10 +3439,49 @@ snapshots: '@webassemblyjs/ast': 1.12.1 '@xtuc/long': 4.2.2 + '@webx-kit/chrome-types@0.1.0': + dependencies: + '@types/chrome': 0.0.270 + + '@webx-kit/core-plugin@0.1.0(@rsbuild/core@1.0.17)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)))': + dependencies: + '@rsbuild/core': 1.0.17 + '@types/chrome': 0.0.270 + chokidar: 3.6.0 + jiti: 1.21.6 + tailwindcss: 3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)) + type-fest: 4.26.1 + + '@webx-kit/rsbuild-plugin@0.1.0(@rsbuild/core@1.0.17)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3)))': + dependencies: + '@rsbuild/core': 1.0.17 + '@types/chrome': 0.0.270 + '@webx-kit/core-plugin': 0.1.0(@rsbuild/core@1.0.17)(tailwindcss@3.4.14(ts-node@10.9.2(@types/node@22.8.1)(typescript@5.6.3))) + transitivePeerDependencies: + - tailwindcss + + '@webx-kit/runtime@0.1.0': + dependencies: + '@floating-ui/dom': 1.6.11 + '@types/chrome': 0.0.270 + + '@webx-kit/test-utils@0.1.0(@playwright/test@1.48.2)': + dependencies: + '@modern-js/utils': 2.60.5 + '@playwright/test': 1.48.2 + '@webx-kit/chrome-types': 0.1.0 + chrome-launcher: 1.1.2 + transitivePeerDependencies: + - supports-color + '@xtuc/ieee754@1.2.0': {} '@xtuc/long@4.2.2': {} + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + accepts@1.3.8: dependencies: mime-types: 2.1.35 @@ -3147,6 +3624,20 @@ snapshots: array-tree-filter@2.1.0: {} + asn1.js@4.10.1: + dependencies: + bn.js: 4.12.0 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + + assert@2.1.0: + dependencies: + call-bind: 1.0.7 + is-nan: 1.3.2 + object-is: 1.1.6 + object.assign: 4.1.5 + util: 0.12.5 + atob@2.1.2: {} autoprefixer@10.4.20(postcss@8.4.47): @@ -3159,14 +3650,24 @@ snapshots: postcss: 8.4.47 postcss-value-parser: 4.2.0 + available-typed-arrays@1.0.7: + dependencies: + possible-typed-array-names: 1.0.0 + balanced-match@1.0.2: {} base64-arraybuffer@1.0.2: {} + base64-js@1.5.1: {} + batch@0.6.1: {} binary-extensions@2.3.0: {} + bn.js@4.12.0: {} + + bn.js@5.2.1: {} + body-parser@1.20.3: dependencies: bytes: 3.1.2 @@ -3197,6 +3698,53 @@ snapshots: dependencies: fill-range: 7.1.1 + brorand@1.1.0: {} + + browserify-aes@1.2.0: + dependencies: + buffer-xor: 1.0.3 + cipher-base: 1.0.4 + create-hash: 1.2.0 + evp_bytestokey: 1.0.3 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-cipher@1.0.1: + dependencies: + browserify-aes: 1.2.0 + browserify-des: 1.0.2 + evp_bytestokey: 1.0.3 + + browserify-des@1.0.2: + dependencies: + cipher-base: 1.0.4 + des.js: 1.1.0 + inherits: 2.0.4 + safe-buffer: 5.2.1 + + browserify-rsa@4.1.1: + dependencies: + bn.js: 5.2.1 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + browserify-sign@4.2.3: + dependencies: + bn.js: 5.2.1 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + create-hmac: 1.1.7 + elliptic: 6.6.0 + hash-base: 3.0.4 + inherits: 2.0.4 + parse-asn1: 5.1.7 + readable-stream: 2.3.8 + safe-buffer: 5.2.1 + + browserify-zlib@0.2.0: + dependencies: + pako: 1.0.11 + browserslist@4.24.2: dependencies: caniuse-lite: 1.0.30001671 @@ -3208,6 +3756,20 @@ snapshots: buffer-from@1.1.2: {} + buffer-xor@1.0.3: {} + + buffer@5.7.1: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + buffer@6.0.3: + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + + builtin-status-codes@3.0.0: {} + bundle-name@4.1.0: dependencies: run-applescript: 7.0.0 @@ -3259,8 +3821,22 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + chrome-launcher@1.1.2: + dependencies: + '@types/node': 22.8.1 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.1 + transitivePeerDependencies: + - supports-color + chrome-trace-event@1.0.4: {} + cipher-base@1.0.4: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + classnames@2.5.1: {} cliui@8.0.1: @@ -3303,6 +3879,10 @@ snapshots: connect-history-api-fallback@2.0.0: {} + console-browserify@1.2.0: {} + + constants-browserify@1.0.0: {} + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -3330,6 +3910,28 @@ snapshots: optionalDependencies: typescript: 5.6.3 + create-ecdh@4.0.4: + dependencies: + bn.js: 4.12.0 + elliptic: 6.6.0 + + create-hash@1.2.0: + dependencies: + cipher-base: 1.0.4 + inherits: 2.0.4 + md5.js: 1.3.5 + ripemd160: 2.0.2 + sha.js: 2.4.11 + + create-hmac@1.1.7: + dependencies: + cipher-base: 1.0.4 + create-hash: 1.2.0 + inherits: 2.0.4 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + create-require@1.1.1: {} cross-env@7.0.3: @@ -3342,6 +3944,21 @@ snapshots: shebang-command: 2.0.0 which: 2.0.2 + crypto-browserify@3.12.1: + dependencies: + browserify-cipher: 1.0.1 + browserify-sign: 4.2.3 + create-ecdh: 4.0.4 + create-hash: 1.2.0 + create-hmac: 1.1.7 + diffie-hellman: 5.0.3 + hash-base: 3.0.4 + inherits: 2.0.4 + pbkdf2: 3.1.2 + public-encrypt: 4.0.3 + randombytes: 2.1.0 + randomfill: 1.0.4 + css-line-break@2.1.0: dependencies: utrie: 1.0.2 @@ -3374,6 +3991,8 @@ snapshots: dependencies: ms: 2.1.3 + deepmerge@4.3.1: {} + default-browser-id@5.0.0: {} default-browser@5.2.1: @@ -3393,10 +4012,21 @@ snapshots: define-lazy-prop@3.0.0: {} + define-properties@1.2.1: + dependencies: + define-data-property: 1.1.4 + has-property-descriptors: 1.0.2 + object-keys: 1.1.1 + depd@1.1.2: {} depd@2.0.0: {} + des.js@1.1.0: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + destroy@1.2.0: {} detect-node@2.1.0: {} @@ -3405,12 +4035,20 @@ snapshots: diff@4.0.2: {} + diffie-hellman@5.0.3: + dependencies: + bn.js: 4.12.0 + miller-rabin: 4.0.1 + randombytes: 2.1.0 + dlv@1.1.3: {} dns-packet@5.6.1: dependencies: '@leichtgewicht/ip-codec': 2.0.5 + domain-browser@5.7.0: {} + dompurify@2.5.7: optional: true @@ -3422,6 +4060,16 @@ snapshots: electron-to-chromium@1.5.47: {} + elliptic@6.6.0: + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -3459,6 +4107,8 @@ snapshots: escape-html@1.0.3: {} + escape-string-regexp@4.0.0: {} + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 @@ -3474,10 +4124,17 @@ snapshots: etag@1.8.1: {} + event-target-shim@5.0.1: {} + eventemitter3@4.0.7: {} events@3.3.0: {} + evp_bytestokey@1.0.3: + dependencies: + md5.js: 1.3.5 + safe-buffer: 5.2.1 + execa@5.1.1: dependencies: cross-spawn: 7.0.3 @@ -3572,6 +4229,10 @@ snapshots: follow-redirects@1.15.9: {} + for-each@0.3.3: + dependencies: + is-callable: 1.2.7 + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 @@ -3583,6 +4244,9 @@ snapshots: fresh@0.5.2: {} + fsevents@2.3.2: + optional: true + fsevents@2.3.3: optional: true @@ -3641,10 +4305,30 @@ snapshots: has-symbols@1.0.3: {} + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.0.3 + + hash-base@3.0.4: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + hpack.js@2.1.6: dependencies: inherits: 2.0.4 @@ -3704,6 +4388,8 @@ snapshots: transitivePeerDependencies: - debug + https-browserify@1.0.0: {} + human-signals@2.1.0: {} hyperdyperid@1.2.0: {} @@ -3716,6 +4402,8 @@ snapshots: dependencies: postcss: 8.4.47 + ieee754@1.2.1: {} + immediate@3.0.6: {} import-fresh@3.3.0: @@ -3735,22 +4423,35 @@ snapshots: ipaddr.js@2.2.0: {} + is-arguments@1.1.1: + dependencies: + call-bind: 1.0.7 + has-tostringtag: 1.0.2 + is-arrayish@0.2.1: {} is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 + is-callable@1.2.7: {} + is-core-module@2.15.1: dependencies: hasown: 2.0.2 + is-docker@2.2.1: {} + is-docker@3.0.0: {} is-extglob@2.1.1: {} is-fullwidth-code-point@3.0.0: {} + is-generator-function@1.0.10: + dependencies: + has-tostringtag: 1.0.2 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -3759,6 +4460,11 @@ snapshots: dependencies: is-docker: 3.0.0 + is-nan@1.3.2: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + is-network-error@1.1.0: {} is-number@7.0.0: {} @@ -3767,6 +4473,14 @@ snapshots: is-stream@2.0.1: {} + is-typed-array@1.1.13: + dependencies: + which-typed-array: 1.1.15 + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + is-wsl@3.1.0: dependencies: is-inside-container: 1.0.0 @@ -3835,6 +4549,13 @@ snapshots: dependencies: immediate: 3.0.6 + lighthouse-logger@2.0.1: + dependencies: + debug: 2.6.9 + marky: 1.2.5 + transitivePeerDependencies: + - supports-color + lilconfig@2.1.0: {} lilconfig@3.1.2: {} @@ -3853,7 +4574,15 @@ snapshots: make-error@1.3.6: {} - marked@4.3.0: {} + marked@14.1.3: {} + + marky@1.2.5: {} + + md5.js@1.3.5: + dependencies: + hash-base: 3.0.4 + inherits: 2.0.4 + safe-buffer: 5.2.1 media-typer@0.3.0: {} @@ -3877,6 +4606,11 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + miller-rabin@4.0.1: + dependencies: + bn.js: 4.12.0 + brorand: 1.1.0 + mime-db@1.52.0: {} mime-types@2.1.35: @@ -3889,6 +4623,8 @@ snapshots: minimalistic-assert@1.0.1: {} + minimalistic-crypto-utils@1.0.1: {} + minimatch@9.0.5: dependencies: brace-expansion: 2.0.1 @@ -3936,6 +4672,20 @@ snapshots: object-inspect@1.13.2: {} + object-is@1.1.6: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + + object-keys@1.1.1: {} + + object.assign@4.1.5: + dependencies: + call-bind: 1.0.7 + define-properties: 1.2.1 + has-symbols: 1.0.3 + object-keys: 1.1.1 + obuf@1.1.2: {} on-finished@2.4.1: @@ -3957,6 +4707,8 @@ snapshots: opener@1.5.2: {} + os-browserify@0.3.0: {} + p-retry@4.6.2: dependencies: '@types/retry': 0.12.0 @@ -3976,6 +4728,15 @@ snapshots: dependencies: callsites: 3.1.0 + parse-asn1@5.1.7: + dependencies: + asn1.js: 4.10.1 + browserify-aes: 1.2.0 + evp_bytestokey: 1.0.3 + hash-base: 3.0.4 + pbkdf2: 3.1.2 + safe-buffer: 5.2.1 + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.26.0 @@ -3985,6 +4746,8 @@ snapshots: parseurl@1.3.3: {} + path-browserify@1.0.1: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -3996,6 +4759,14 @@ snapshots: path-to-regexp@0.1.10: {} + pbkdf2@3.1.2: + dependencies: + create-hash: 1.2.0 + create-hmac: 1.1.7 + ripemd160: 2.0.2 + safe-buffer: 5.2.1 + sha.js: 2.4.11 + performance-now@2.1.0: optional: true @@ -4007,6 +4778,16 @@ snapshots: pirates@4.0.6: {} + playwright-core@1.48.2: {} + + playwright@1.48.2: + dependencies: + playwright-core: 1.48.2 + optionalDependencies: + fsevents: 2.3.2 + + possible-typed-array-names@1.0.0: {} + postcss-import@15.1.0(postcss@8.4.47): dependencies: postcss: 8.4.47 @@ -4080,17 +4861,32 @@ snapshots: process-nextick-args@2.0.1: {} + process@0.11.10: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 + public-encrypt@4.0.3: + dependencies: + bn.js: 4.12.0 + browserify-rsa: 4.1.1 + create-hash: 1.2.0 + parse-asn1: 5.1.7 + randombytes: 2.1.0 + safe-buffer: 5.2.1 + + punycode@1.4.1: {} + punycode@2.3.1: {} qs@6.13.0: dependencies: side-channel: 1.0.6 + querystring-es3@0.2.1: {} + queue-microtask@1.2.3: {} raf@3.4.1: @@ -4102,6 +4898,11 @@ snapshots: dependencies: safe-buffer: 5.2.1 + randomfill@1.0.4: + dependencies: + randombytes: 2.1.0 + safe-buffer: 5.2.1 + range-parser@1.2.1: {} raw-body@2.5.2: @@ -4463,9 +5264,17 @@ snapshots: readable-stream@3.6.2: dependencies: inherits: 2.0.4 - string_decoder: 1.1.1 + string_decoder: 1.3.0 util-deprecate: 1.0.2 + readable-stream@4.5.2: + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + string_decoder: 1.3.0 + readdirp@3.6.0: dependencies: picomatch: 2.3.1 @@ -4474,6 +5283,10 @@ snapshots: dependencies: resolve: 1.22.8 + reduce-configs@1.0.0: + dependencies: + browserslist: 4.24.2 + regenerator-runtime@0.13.11: optional: true @@ -4506,10 +5319,17 @@ snapshots: dependencies: glob: 10.4.5 + ripemd160@2.0.2: + dependencies: + hash-base: 3.0.4 + inherits: 2.0.4 + rsbuild-plugin-web-extension@0.0.10(@rsbuild/core@1.0.17): dependencies: '@rsbuild/core': 1.0.17 + rslog@1.2.3: {} + run-applescript@7.0.0: {} run-parallel@1.2.0: @@ -4612,6 +5432,11 @@ snapshots: setprototypeof@1.2.0: {} + sha.js@2.4.11: + dependencies: + inherits: 2.0.4 + safe-buffer: 5.2.1 + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -4682,6 +5507,18 @@ snapshots: statuses@2.0.1: {} + stream-browserify@3.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 3.6.2 + + stream-http@3.2.0: + dependencies: + builtin-status-codes: 3.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + xtend: 4.0.2 + string-convert@0.2.1: {} string-width@4.2.3: @@ -4700,6 +5537,10 @@ snapshots: dependencies: safe-buffer: 5.1.2 + string_decoder@1.3.0: + dependencies: + safe-buffer: 5.2.1 + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -4804,6 +5645,10 @@ snapshots: thunky@1.1.0: {} + timers-browserify@2.0.12: + dependencies: + setimmediate: 1.0.5 + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 @@ -4840,6 +5685,10 @@ snapshots: tslib@2.8.0: {} + tty-browserify@0.0.1: {} + + type-fest@4.26.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -4861,8 +5710,21 @@ snapshots: dependencies: punycode: 2.3.1 + url@0.11.4: + dependencies: + punycode: 1.4.1 + qs: 6.13.0 + util-deprecate@1.0.2: {} + util@0.12.5: + dependencies: + inherits: 2.0.4 + is-arguments: 1.1.1 + is-generator-function: 1.0.10 + is-typed-array: 1.1.13 + which-typed-array: 1.1.15 + utils-merge@1.0.1: {} utrie@1.0.2: @@ -4875,6 +5737,8 @@ snapshots: vary@1.1.2: {} + vm-browserify@1.1.2: {} + watchpack@2.4.2: dependencies: glob-to-regexp: 0.4.1 @@ -4990,6 +5854,14 @@ snapshots: websocket-extensions@0.1.4: {} + which-typed-array@1.1.15: + dependencies: + available-typed-arrays: 1.0.7 + call-bind: 1.0.7 + for-each: 0.3.3 + gopd: 1.0.1 + has-tostringtag: 1.0.2 + which@2.0.2: dependencies: isexe: 2.0.0 @@ -5010,6 +5882,8 @@ snapshots: ws@8.18.0: {} + xtend@4.0.2: {} + y18n@5.0.8: {} yaml@2.6.0: {} diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..8eac0df15cac41ad179023e99324aa22113bdd98 GIT binary patch literal 61554 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�df)5gtmT?YH4tN|9V54#W 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 literal 0 HcmV?d00001 diff --git a/rsbuild.config.ts b/rsbuild.config.ts index d0ec6a6..a7c1868 100644 --- a/rsbuild.config.ts +++ b/rsbuild.config.ts @@ -1,12 +1,39 @@ -import { defineConfig } from "@rsbuild/core"; -import { pluginReact } from "@rsbuild/plugin-react"; -import { pluginWebExtension } from "rsbuild-plugin-web-extension"; -import manifest from "./manifest"; +import { defineConfig } from '@rsbuild/core'; +import { pluginLess } from '@rsbuild/plugin-less'; +import { pluginReact } from '@rsbuild/plugin-react'; +import { webxPlugin } from '@webx-kit/rsbuild-plugin'; + export default defineConfig({ - plugins: [ - pluginReact(), - pluginWebExtension({ - manifest, - }) + plugins: [ + pluginLess(), + pluginReact(), + webxPlugin({ + background: './src/background/index.ts', + contentScripts: { + import: './src/content-scripts/index.tsx', + matches: ['https://juejin.cn/book/*'], + }, + }), + ], + source: { + entry: { + options: './src/pages/options/index.tsx', + popup: './src/pages/popup/index.tsx', + }, + }, + output: { + copy: [ + { + from: './public', + to: './public', + }, ], -}); \ No newline at end of file + }, + tools: { + // postcss: { + // postcssOptions: { + // plugins: [require('tailwindcss')], + // }, + // }, + }, +}); diff --git a/src/api/juejin.ts b/src/api/juejin.ts new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/src/api/juejin.ts @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/text-logo.svg b/src/assets/text-logo.svg new file mode 100644 index 0000000..a54a875 --- /dev/null +++ b/src/assets/text-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/background/index.ts b/src/background/index.ts index 0f3434e..e921523 100644 --- a/src/background/index.ts +++ b/src/background/index.ts @@ -1 +1 @@ -console.log("background script"); \ No newline at end of file +console.log('hello'); diff --git a/src/content-scripts/api/bookApi.ts b/src/content-scripts/api/bookApi.ts new file mode 100644 index 0000000..e3eba72 --- /dev/null +++ b/src/content-scripts/api/bookApi.ts @@ -0,0 +1,27 @@ +import { BookInfoType } from './types'; + +/** + * 获取小册信息 + * @param bookId 小册ID + * @returns 返回小册信息 + */ +export async function getBookInfo(bookId: string): Promise { + // 发送POST请求获取小册信息 + const response = await fetch( + 'https://api.juejin.cn/booklet_api/v1/booklet/get', + { + method: 'POST', + body: JSON.stringify({ + booklet_id: bookId, + }), + credentials: 'include', // 包含凭证信息 + headers: { + 'Content-Type': 'application/json', + }, + } + ); + + // 解析响应数据 + const data: BookInfoType = await response.json(); + return data; +} diff --git a/src/content-scripts/api/index.ts b/src/content-scripts/api/index.ts new file mode 100644 index 0000000..522642b --- /dev/null +++ b/src/content-scripts/api/index.ts @@ -0,0 +1,4 @@ +export * from './types'; +export * from './bookApi'; +export * from './sectionApi'; +export * from './juejin'; diff --git a/src/content-scripts/api/juejin.ts b/src/content-scripts/api/juejin.ts new file mode 100644 index 0000000..3d0a310 --- /dev/null +++ b/src/content-scripts/api/juejin.ts @@ -0,0 +1,34 @@ +/** + * 获取小册章节列表 + * @param bookID 小册ID + * @returns 章节列表 + */ +export const getSectionList = async (bookID: string) => { + const response = await fetch('https://api.juejin.cn/booklet_api/v1/booklet/get', { + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify({ booklet_id: bookID }), + method: 'POST', + }); + const { data } = await response.json(); + return data.sections; +}; + +/** + * 获取章节Markdown内容 + * @param sectionID 章节ID + * @returns 章节内容,包括标题和Markdown文本 + */ +export const getMarkdownContent = async (sectionID: string) => { + const response = await fetch('https://api.juejin.cn/booklet_api/v1/section/get', { + headers: { + 'content-type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify({ section_id: sectionID }), + method: 'POST', + }); + const { data } = await response.json(); + return data.section; +}; diff --git a/src/content-scripts/api/sectionApi.ts b/src/content-scripts/api/sectionApi.ts new file mode 100644 index 0000000..d919e69 --- /dev/null +++ b/src/content-scripts/api/sectionApi.ts @@ -0,0 +1,27 @@ +import { SectionInfoType } from './types'; + +/** + * 获取小册章节信息 + * @param sectionId 章节ID + * @returns 返回章节信息 + */ +export async function getSectionInfo(sectionId: string): Promise { + // 发送POST请求获取章节信息 + const response = await fetch( + 'https://api.juejin.cn/booklet_api/v1/section/get', + { + method: 'POST', + body: JSON.stringify({ + section_id: sectionId, + }), + credentials: 'include', // 包含凭证信息 + headers: { + 'Content-Type': 'application/json', + }, + } + ); + + // 解析响应数据 + const data: SectionInfoType = await response.json(); + return data; +} diff --git a/src/content-scripts/api/types.ts b/src/content-scripts/api/types.ts new file mode 100644 index 0000000..6ed11a9 --- /dev/null +++ b/src/content-scripts/api/types.ts @@ -0,0 +1,38 @@ +/** + * 章节类型接口 + */ +export interface SectionType { + section_id: string; // 章节ID + title: string; // 章节标题 + booklet_id: string; // 所属小册ID + status: number; // 章节状态 + markdown_show: string; // 章节内容(Markdown格式) +} + +/** + * 小册信息类型接口 + */ +export interface BookInfoType { + data: { + booklet: { + base_info: { + title: string; // 小册标题 + }; + }; + introduction: { + markdown_show: string; // 小册简介(Markdown格式) + }; + sections: SectionType[]; // 小册章节列表 + }; + err_no: number; // 错误码 +} + +/** + * 章节信息类型接口 + */ +export interface SectionInfoType { + data: { + section: SectionType; // 章节详细信息 + }; + err_no: number; // 错误码 +} diff --git a/src/content/components/DownloadModal.tsx b/src/content-scripts/components/DownloadModal.tsx similarity index 96% rename from src/content/components/DownloadModal.tsx rename to src/content-scripts/components/DownloadModal.tsx index a383747..87852ca 100644 --- a/src/content/components/DownloadModal.tsx +++ b/src/content-scripts/components/DownloadModal.tsx @@ -4,14 +4,17 @@ import { useMount } from 'ahooks'; import JSZip from 'jszip'; import { saveAs } from 'file-saver'; -import type { SectionType } from '../api.ts'; -import { getBookInfo, getSectionInfo } from '../api.ts'; -import { replaceFileName, sleep, convertToHtml, convertToPdf } from '../utils.ts'; -import { saveToCache, getFromCache, clearCache, isCacheExpired, CachedSection } from '../utils/cache.ts'; +import { getBookInfo, getSectionInfo } from '../api/index'; +import { replaceFileName, sleep, convertToHtml, convertToPdf } from '../utils/'; +import { saveToCache, getFromCache, clearCache, isCacheExpired, CachedSection } from '../utils/cache'; const { Title, Text } = Typography; -const DownloadModal = () => { +interface DownloadModalProps { + onConfirm: () => Promise; +} + +const DownloadModal: React.FC = ({ onConfirm }) => { const [open, setOpen] = useState(true); const [status, setStatus] = useState('准备就绪,可以开始下载'); const [bookName, setBookName] = useState(''); @@ -95,7 +98,7 @@ const DownloadModal = () => { await sleep(); const sectionInfo = await getSectionInfo(section.section_id); if (sectionInfo.err_no !== 0) { - setStatus(`第 ${index + 1} 章下载失败,下载终止`); + setStatus(`第 ${index + 1} 章获取失败,下载终止`); setIsFetching(false); return; } @@ -106,7 +109,7 @@ const DownloadModal = () => { title: `${index + 1}. ${sectionTitle}`, cachedAt: Date.now() }); - setStatus(`第 ${index + 1} 章下载完成:${sectionTitle}`); + setStatus(`第 ${index + 1} 章获取完成:${sectionTitle}`); } setSections(updatedSections); saveToCache(bookId, updatedSections); diff --git a/src/content-scripts/index.tsx b/src/content-scripts/index.tsx new file mode 100644 index 0000000..16b0044 --- /dev/null +++ b/src/content-scripts/index.tsx @@ -0,0 +1,35 @@ +// 导入必要的模块和样式 +import { createShadowRootUI } from '@webx-kit/runtime/content-scripts'; +import { createRoot } from 'react-dom/client'; +import { App } from './juejin'; +import '../global.less'; +import packageJson from '../../package.json'; + +// 创建影子DOM UI +createShadowRootUI({ + render({ root }) { + // 定义控制台输出的样式 + const styles = { + title: 'font-size: 14px; font-weight: bold; color: #3498db;', + label: 'color: #2ecc71; font-weight: bold;', + value: 'color: #e74c3c;', + link: 'color: #3498db; text-decoration: underline; cursor: pointer;', + tip: 'font-style: italic; color: #7f8c8d;' + }; + + // 在控制台输出扩展信息 + console.log(`%c掘金小册下载助手 v${packageJson.version} 已加载`, styles.title); + console.group('%c扩展信息', styles.title); + console.log(`%c版本:%c${packageJson.version}`, styles.label, styles.value); + console.log(`%c作者:%c${typeof packageJson.author === 'object' ? packageJson.author.name : packageJson.author}`, styles.label, styles.value); + console.log(`%c邮箱:%c${typeof packageJson.author === 'object' ? packageJson.author.email : '未提供'}`, styles.label, styles.link); + console.log(`%cGitHub:%c${typeof packageJson.author === 'object' && packageJson.author.url ? packageJson.author.url.replace('https://github.com/', '') : '未提供'}`, styles.label, styles.link); + console.log(`%c名称:%c${packageJson.name}`, styles.label, styles.value); + console.log(`%c反馈:%chttps://github.com/h7ml/juejinBooksDownloader/issues`, styles.label, styles.link); + console.log(`%c下载:%chttps://github.com/h7ml/juejinBooksDownloader/releases`, styles.label, styles.link); + console.groupEnd(); + + // 渲染React应用 + createRoot(root).render(); + }, +}); \ No newline at end of file diff --git a/src/content-scripts/juejin.tsx b/src/content-scripts/juejin.tsx new file mode 100644 index 0000000..ca80258 --- /dev/null +++ b/src/content-scripts/juejin.tsx @@ -0,0 +1,136 @@ +import React, { useEffect, useState } from 'react'; +import ReactDOM from 'react-dom/client'; +import { Popconfirm, Button } from 'antd'; +import { DownloadOutlined } from '@ant-design/icons'; +import DownloadModal from './components/DownloadModal'; +import { handleDownload } from './utils/'; + +/** + * 主应用组件 + */ +export const App: React.FC = () => { + // 是否已注入下载按钮的状态 + const [isInjected, setIsInjected] = useState(false); + // 当前页面URL + const [currentUrl, setCurrentUrl] = useState(''); + + /** + * 显示确认对话框 + */ + const showConfirm = () => { + const downloadEle = document.createElement('div'); + document.body.appendChild(downloadEle); + ReactDOM.createRoot(downloadEle).render( + + + + ); + }; + + /** + * 注入下载按钮 + */ + const injectDownloadBtn = () => { + const buyEle = document.querySelector('.is-buy'); + const injectBtn = document.querySelector('.other'); + const sectionEle = document.querySelector('.book-content__header> .title'); + + // 如果已经存在下载按钮,则直接返回 + if (document.querySelector('#download')) return; + + // 判断是否为单章节页面并提取 ID + const urlMatch = window.location.href.match(/\/book\/(\d+)\/section\/(\d+)/); + const isSectionPage = !!urlMatch; + const bookId = urlMatch ? urlMatch[1] : null; + const sectionId = urlMatch ? urlMatch[2] : null; + + // 创建下载按钮元素 + const downloadEle = document.createElement('div'); + downloadEle.id = 'download'; + downloadEle.style.paddingLeft = '10px'; + if (isSectionPage) { + downloadEle.style.display = 'contents'; + } + + // 渲染下载按钮内容 + ReactDOM.createRoot(downloadEle).render( + + + + + + ); + + // 情况1:在小册首页插入下载按钮 + if (buyEle && injectBtn) { + injectBtn.appendChild(downloadEle); + setIsInjected(true); + return; + } + + // 情况2:在单章节页面插入下载按钮 + if (isSectionPage) { + sectionEle && sectionEle.appendChild(downloadEle); + setIsInjected(true); + return; + } + }; + + /** + * 观察DOM变化并注入按钮 + * @returns {MutationObserver} DOM观察器 + */ + const observeAndInject = () => { + if (isInjected) return; + + const observer = new MutationObserver(() => { + if (!document.querySelector('#download')) { + injectDownloadBtn(); + } + }); + observer.observe(document, { childList: true, subtree: true }); + return observer; + }; + + /** + * 检查URL变化 + */ + const checkUrlChange = () => { + if (window.location.href !== currentUrl) { + setCurrentUrl(window.location.href); + setIsInjected(false); + injectDownloadBtn(); + } + }; + + // 初始化函数 + useEffect(() => { + const observer = observeAndInject(); + setCurrentUrl(window.location.href); + + // 添加URL变化检测 + window.addEventListener('popstate', checkUrlChange); + const intervalId = setInterval(checkUrlChange, 1000); + + // 清理函数 + return () => { + if (observer) observer.disconnect(); + window.removeEventListener('popstate', checkUrlChange); + clearInterval(intervalId); + }; + }, [isInjected, currentUrl]); + + return null; +}; diff --git a/src/content-scripts/utils/asyncUtils.ts b/src/content-scripts/utils/asyncUtils.ts new file mode 100644 index 0000000..5826a1c --- /dev/null +++ b/src/content-scripts/utils/asyncUtils.ts @@ -0,0 +1,10 @@ +/** + * 异步睡眠函数 + * @param timeout 睡眠时间,默认为1000毫秒 + * @returns 返回一个Promise,在指定的超时时间后解决 + */ +export const sleep = async (timeout = 1000) => { + return new Promise(resolve => { + setTimeout(resolve, timeout); + }); +}; diff --git a/src/content/utils/cache.ts b/src/content-scripts/utils/cache.ts similarity index 66% rename from src/content/utils/cache.ts rename to src/content-scripts/utils/cache.ts index 584219d..59ca7f3 100644 --- a/src/content/utils/cache.ts +++ b/src/content-scripts/utils/cache.ts @@ -1,14 +1,29 @@ import type { SectionType } from '../api'; -// 使用 Map 作为内存缓存 +/** + * 使用 Map 作为内存缓存,用于存储缓存的章节数据 + */ const memoryCache = new Map(); +/** + * 扩展 SectionType 接口,添加缓存时间戳 + */ export interface CachedSection extends SectionType { cachedAt: number; } +/** + * 生成缓存键 + * @param bookId 书籍ID + * @returns 格式化的缓存键 + */ export const cacheKey = (bookId: string): string => `cached_book_${bookId}`; +/** + * 将章节数据保存到缓存中 + * @param bookId 书籍ID + * @param sections 要缓存的章节数据 + */ export const saveToCache = (bookId: string, sections: CachedSection[]): void => { const key = cacheKey(bookId); // 使用 localStorage 进行本地存储 @@ -17,6 +32,11 @@ export const saveToCache = (bookId: string, sections: CachedSection[]): void => memoryCache.set(key, sections); }; +/** + * 从缓存中获取章节数据 + * @param bookId 书籍ID + * @returns 缓存的章节数据,如果不存在则返回 null + */ export const getFromCache = (bookId: string): CachedSection[] | null => { const key = cacheKey(bookId); if (memoryCache.has(key)) { @@ -32,6 +52,10 @@ export const getFromCache = (bookId: string): CachedSection[] | null => { return null; }; +/** + * 清除指定书籍的缓存 + * @param bookId 书籍ID + */ export const clearCache = (bookId: string): void => { const key = cacheKey(bookId); // 从 localStorage 中删除缓存 @@ -40,7 +64,11 @@ export const clearCache = (bookId: string): void => { memoryCache.delete(key); }; -// 检查缓存是否过期(例如,24小时后过期) +/** + * 检查缓存是否过期 + * @param cachedAt 缓存时间戳 + * @returns 如果缓存已过期则返回 true,否则返回 false + */ export const isCacheExpired = (cachedAt: number): boolean => { const expirationTime = 24 * 60 * 60 * 1000; // 24小时 return Date.now() - cachedAt > expirationTime; diff --git a/src/content-scripts/utils/download.ts b/src/content-scripts/utils/download.ts new file mode 100644 index 0000000..9238e0e --- /dev/null +++ b/src/content-scripts/utils/download.ts @@ -0,0 +1,43 @@ +import { message } from 'antd'; +import { getSectionList, getMarkdownContent } from '../api/juejin'; +import { saveFile } from './file'; +/** + * 处理下载操作 + * 根据当前URL判断是下载单个章节还是整个小册 + */ +export const handleDownload = async () => { + // 匹配URL中的章节ID + const match = window.location.href.match(/\/book\/(\d+)\/section\/(\d+)/); + if (match) { + // 下载单个章节 + const [, , sectionID] = match; + try { + // 获取章节内容 + const { title, markdown_show } = await getMarkdownContent(sectionID); + // 保存章节文件 + await saveFile(1, title, markdown_show); + message.success('章节下载成功'); + } catch (error) { + console.error('下载失败:', error); + message.error('章节下载失败'); + } + } else { + // 下载整个小册 + const bookID = window.location.href.split('/').pop(); + if (bookID) { + try { + // 获取小册所有章节 + const sections = await getSectionList(bookID); + // 遍历下载每个章节 + for (let i = 0; i < sections.length; i++) { + const { title, markdown_show } = await getMarkdownContent(sections[i].section_id); + await saveFile(i + 1, title, markdown_show); + } + message.success('小册下载完成'); + } catch (error) { + console.error('下载失败:', error); + message.error('小册下载失败'); + } + } + } +}; \ No newline at end of file diff --git a/src/content-scripts/utils/file.ts b/src/content-scripts/utils/file.ts new file mode 100644 index 0000000..eec4dce --- /dev/null +++ b/src/content-scripts/utils/file.ts @@ -0,0 +1,26 @@ +import { replaceFileName } from '.'; + +/** + * 保存文件到本地 + * @param index 文件索引 + * @param name 文件名 + * @param content 文件内容 + */ +export const saveFile = async (index: number, name: string, content: string) => { + // 创建Blob对象 + const blob = new Blob([content], { type: 'text/plain' }); + + // 创建临时下载链接 + const a = document.createElement('a'); + a.href = window.URL.createObjectURL(blob); + + // 设置文件名 + a.download = replaceFileName(`${index}、${name}.md`); + + // 添加链接到DOM并触发点击 + document.body.appendChild(a); + a.click(); + + // 清理临时DOM元素 + document.body.removeChild(a); +}; diff --git a/src/content-scripts/utils/fileUtils.ts b/src/content-scripts/utils/fileUtils.ts new file mode 100644 index 0000000..4e203ab --- /dev/null +++ b/src/content-scripts/utils/fileUtils.ts @@ -0,0 +1,25 @@ +/** + * 使用 Unicode 字符替换文件名中的特殊字符 + * @param fileName 需要处理的文件名 + * @returns 替换特殊字符后的文件名 + */ +export const replaceFileName = (fileName: string): string => { + // 定义特殊字符到 Unicode 字符的映射 + const replaceMap = new Map([ + ['<', '\uFE64'], // 小于号替换为全角小于号 + ['>', '\uFE65'], // 大于号替换为全角大于号 + [':', '\uA789'], // 冒号替换为冒号分隔符 + ['/', '\u2215'], // 正斜杠替换为除号 + ['\\', '\uFE68'], // 反斜杠替换为小型反斜杠 + ['|', '\u2758'], // 竖线替换为垂直线 + ['?', '\uFE16'], // 问号替换为全角问号 + ['*', '\uFE61'], // 星号替换为小型星号 + ]); + + // 构建正则表达式模式,用于匹配所有需要替换的特殊字符 + const pattern = [...replaceMap.keys()].map(key => '\\' + key).join('|'); + const regex = new RegExp(pattern, 'g'); + + // 使用正则表达式替换所有匹配的特殊字符 + return fileName.replace(regex, match => replaceMap.get(match)!); +}; diff --git a/src/content-scripts/utils/index.ts b/src/content-scripts/utils/index.ts new file mode 100644 index 0000000..00e31a9 --- /dev/null +++ b/src/content-scripts/utils/index.ts @@ -0,0 +1,8 @@ +export * from './file'; +export * from './download'; +export * from './fileUtils'; +export * from './asyncUtils'; +export * from './markdownUtils'; +export * from './cache'; +export * from './download'; +export * from './file'; diff --git a/src/content-scripts/utils/markdownUtils.ts b/src/content-scripts/utils/markdownUtils.ts new file mode 100644 index 0000000..8404f4a --- /dev/null +++ b/src/content-scripts/utils/markdownUtils.ts @@ -0,0 +1,50 @@ +import { marked } from 'marked'; +import html2pdf from 'html2pdf.js'; + +/** + * 将Markdown文本转换为HTML + * @param markdown Markdown格式的文本 + * @returns 转换后的HTML字符串 + */ +export const convertToHtml = async (markdown: string): Promise => { + return marked(markdown); +}; + +/** + * 将Markdown文本转换为PDF + * @param markdown Markdown格式的文本 + * @returns 包含PDF内容的Blob对象 + */ +export const convertToPdf = async (markdown: string): Promise => { + // 首先将Markdown转换为HTML + const html = await convertToHtml(markdown); + + // 创建一个临时的div元素来容纳HTML内容 + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = ` + + ${html} + `; + document.body.appendChild(tempDiv); + + // 配置PDF生成选项 + const opt = { + margin: 10, + filename: 'document.pdf', + image: { type: 'jpeg', quality: 0.98 }, + html2canvas: { scale: 2, useCORS: true }, + jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }, + pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } + }; + + try { + // 使用html2pdf库生成PDF + const pdfBlob = await html2pdf().from(tempDiv).set(opt).outputPdf('blob'); + return pdfBlob; + } finally { + // 清理:移除临时创建的div元素 + document.body.removeChild(tempDiv); + } +}; diff --git a/src/content/api.ts b/src/content/api.ts deleted file mode 100644 index 8542011..0000000 --- a/src/content/api.ts +++ /dev/null @@ -1,65 +0,0 @@ -export interface SectionType { - section_id: string; - title: string; - booklet_id: string; - status: number; - markdown_show: string; -} - -export interface BookInfoType { - data: { - booklet: { - base_info: { - title: string; - }; - }; - introduction: { - markdown_show: string; - }; - sections: SectionType[]; - }; - err_no: number; -} - -export interface SectionInfoType { - data: { - section: SectionType; - }; - err_no: number; -} - -export async function getBookInfo(bookId: string) { - const response = await fetch( - 'https://api.juejin.cn/booklet_api/v1/booklet/get', - { - method: 'POST', - body: JSON.stringify({ - booklet_id: bookId, - }), - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - }, - } - ); - const data: BookInfoType = await response.json(); - return data; -} - -export async function getSectionInfo(sectionId: string) { - const response = await fetch( - 'https://api.juejin.cn/booklet_api/v1/section/get', - { - method: 'POST', - body: JSON.stringify({ - section_id: sectionId, - }), - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - }, - } - ); - const data: SectionInfoType = await response.json(); - return data; -} diff --git a/src/content/index.css b/src/content/index.css deleted file mode 100644 index 3dccd58..0000000 --- a/src/content/index.css +++ /dev/null @@ -1,4 +0,0 @@ -/* remove preflight https://tailwindcss.com/docs/preflight */ -/* @tailwind base; */ -/* @tailwind components; -@tailwind utilities; */ diff --git a/src/content/index.tsx b/src/content/index.tsx deleted file mode 100644 index df1a000..0000000 --- a/src/content/index.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import { Popconfirm, Button } from 'antd'; -import { DownloadOutlined } from '@ant-design/icons'; -import DownloadModal from './components/DownloadModal'; - -import './index.css'; - -const showConfirm = () => { - const downloadEle = document.createElement('div'); - document.body.appendChild(downloadEle); - ReactDOM.createRoot(downloadEle).render( - - - - ); -}; - -const injectDownloadBtn = () => { - const buyEle = document.querySelector('.is-buy')!; - - const downloadEle = document.createElement('div'); - downloadEle.id = 'download'; - - ReactDOM.createRoot(downloadEle).render( - - - - - - ); - buyEle.appendChild(downloadEle); -}; - -const callback: MutationCallback = (mutationsList, observer) => { - const buyEle = document.querySelector('.is-buy'); - - if (document.querySelector('#download')) { - return; - } - - if (buyEle) { - injectDownloadBtn(); - } -}; - -const observer = new MutationObserver(callback); -observer.observe(document, { childList: true, subtree: true }); diff --git a/src/content/utils.ts b/src/content/utils.ts deleted file mode 100644 index 3181f29..0000000 --- a/src/content/utils.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** 使用 Unicode 字符替换文件名中的特殊字符 */ -export const replaceFileName = (fileName: string) => { - // https://docs.microsoft.com/zh-cn/windows/desktop/FileIO/naming-a-file#naming_conventions - const replaceMap = new Map([ - ['<', '\uFE64'], - ['>', '\uFE65'], - [':', '\uA789'], - ['/', '\u2215'], - ['\\', '\uFE68'], - ['|', '\u2758'], - ['?', '\uFE16'], - ['*', '\uFE61'], - ]); - - const pattern = [...replaceMap.keys()].map(key => '\\' + key).join('|'); - - const regex = new RegExp(pattern, 'g'); - - return fileName.replace(regex, match => replaceMap.get(match)!); -}; - -export const sleep = async (timeout = 1000) => { - return new Promise(resolve => { - setTimeout(() => { - resolve(); - }, timeout); - }); -}; - -import { marked } from 'marked'; -import html2pdf from 'html2pdf.js'; - -export const convertToHtml = async (markdown: string): Promise => { - return marked(markdown); -}; - -export const convertToPdf = async (markdown: string): Promise => { - const html = await convertToHtml(markdown); - - // 创建一个临时的 div 元素来容纳 HTML 内容 - const tempDiv = document.createElement('div'); - tempDiv.innerHTML = ` - - ${html} - `; - document.body.appendChild(tempDiv); - - // 配置 html2pdf 选项 - const opt = { - margin: 10, - filename: 'document.pdf', - image: { type: 'jpeg', quality: 0.98 }, - html2canvas: { scale: 2, useCORS: true }, - jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }, - pagebreak: { mode: ['avoid-all', 'css', 'legacy'] } - }; - - try { - // 使用 html2pdf 生成 PDF - const pdfBlob = await html2pdf().from(tempDiv).set(opt).outputPdf('blob'); - return pdfBlob; - } finally { - // 清理临时 div - document.body.removeChild(tempDiv); - } -}; diff --git a/src/devtools/devtools.tsx b/src/devtools/devtools.tsx deleted file mode 100644 index f1b59a5..0000000 --- a/src/devtools/devtools.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useState } from "react"; - -export const DevTools = () => { - const [count, setCount] = useState(0); - - return ( -
-

Count: {count}

- -
- ); -}; \ No newline at end of file diff --git a/src/devtools/index.html b/src/devtools/index.html deleted file mode 100644 index ab05d42..0000000 --- a/src/devtools/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - DevTools - - - -
- - - \ No newline at end of file diff --git a/src/devtools/index.tsx b/src/devtools/index.tsx deleted file mode 100644 index d390620..0000000 --- a/src/devtools/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { createRoot } from "react-dom/client"; -import { DevTools } from "./devtools"; - -const root = createRoot(document.querySelector("#root")!); - -root.render(); \ No newline at end of file diff --git a/src/env.d.ts b/src/env.d.ts deleted file mode 100644 index 09c0137..0000000 --- a/src/env.d.ts +++ /dev/null @@ -1 +0,0 @@ -/// \ No newline at end of file diff --git a/src/global.less b/src/global.less new file mode 100644 index 0000000..25981b8 --- /dev/null +++ b/src/global.less @@ -0,0 +1,5 @@ +@tailwind components; +@tailwind utilities; + + +@import 'antd/dist/reset.css'; diff --git a/src/manifest.ts b/src/manifest.ts new file mode 100644 index 0000000..5ec34b4 --- /dev/null +++ b/src/manifest.ts @@ -0,0 +1,30 @@ +import { defineManifest } from '@webx-kit/rsbuild-plugin/manifest'; +import * as fs from 'fs'; + +const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf8")); + +export default defineManifest(() => ({ + manifest_version: 3, + name: '掘金小册下载助手-h7ml', + version: packageJson.version, + author: { + email: 'h7ml@qq.com' + }, + icons: { + 512: 'public/logo.png', + }, + action: { + default_popup: 'popup.html', + }, + options_ui: { + page: 'options.html', + open_in_tab: true, + }, + host_permissions: ["https://juejin.cn/*"], + web_accessible_resources: [ + { + matches: [''], + resources: ['static/svg/*'], + }, + ], +})); diff --git a/src/pages/options/app.tsx b/src/pages/options/app.tsx new file mode 100644 index 0000000..df19bf7 --- /dev/null +++ b/src/pages/options/app.tsx @@ -0,0 +1,8 @@ +import logo from '@/assets/text-logo.svg'; + +export const App = () => ( +
+ Logo +
Options Page
+
+); diff --git a/src/pages/options/index.tsx b/src/pages/options/index.tsx new file mode 100644 index 0000000..94bc651 --- /dev/null +++ b/src/pages/options/index.tsx @@ -0,0 +1,6 @@ +import { createRoot } from 'react-dom/client'; +import { App } from './app'; +import '../../global.less'; +import './style.less'; + +createRoot(document.getElementById('root')!).render(); diff --git a/src/pages/options/style.less b/src/pages/options/style.less new file mode 100644 index 0000000..06f062d --- /dev/null +++ b/src/pages/options/style.less @@ -0,0 +1,5 @@ +html, +body, +#root { + height: 100%; +} diff --git a/src/pages/popup/app.tsx b/src/pages/popup/app.tsx new file mode 100644 index 0000000..8e7fa22 --- /dev/null +++ b/src/pages/popup/app.tsx @@ -0,0 +1,8 @@ +import logo from '@/assets/text-logo.svg'; + +export const App = () => ( +
+ Logo +
Popup Page
+
+); diff --git a/src/pages/popup/index.tsx b/src/pages/popup/index.tsx new file mode 100644 index 0000000..28115e5 --- /dev/null +++ b/src/pages/popup/index.tsx @@ -0,0 +1,5 @@ +import { createRoot } from 'react-dom/client'; +import { App } from './app'; +import '../../global.less'; + +createRoot(document.getElementById('root')!).render(); diff --git a/src/popup/index.html b/src/popup/index.html deleted file mode 100644 index d628eef..0000000 --- a/src/popup/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - Popup - - - -
- - - \ No newline at end of file diff --git a/src/popup/index.tsx b/src/popup/index.tsx deleted file mode 100644 index c500351..0000000 --- a/src/popup/index.tsx +++ /dev/null @@ -1,6 +0,0 @@ -import { createRoot } from "react-dom/client"; -import { Popup } from "./popup"; - -const root = createRoot(document.querySelector("#root")!); - -root.render(); \ No newline at end of file diff --git a/src/popup/popup.tsx b/src/popup/popup.tsx deleted file mode 100644 index 21dc5cb..0000000 --- a/src/popup/popup.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { useState } from "react"; - -export const Popup = () => { - const [count, setCount] = useState(0); - - return ( -
-

Count: {count}

- -
- ); -}; \ No newline at end of file diff --git a/src/webx-env.d.ts b/src/webx-env.d.ts new file mode 100644 index 0000000..5c7d2fd --- /dev/null +++ b/src/webx-env.d.ts @@ -0,0 +1,4 @@ +/// + +declare module '*.svg'; +declare module 'html2pdf.js'; diff --git a/tailwind.config.ts b/tailwind.config.ts index 0aed6b5..6374143 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -1,8 +1,17 @@ -/** @type {import('tailwindcss').Config} */ -module.exports = { - content: ['./src/**/*.{html,js,ts,jsx,tsx}'], - theme: { - extend: {}, - }, - plugins: [], +// import { getPixelUnitDefaultTheme } from '@webx-kit/rsbuild-plugin/tailwind'; +import type { Config } from 'tailwindcss'; +// import plugin from 'tailwindcss/plugin'; + +const config: Config = { + // theme: getPixelUnitDefaultTheme(), + content: ['./src/**/*.{html,js,ts,jsx,tsx}'], + // plugins: [ + // plugin(({ addUtilities }) => { + // addUtilities({ + // '.flex-center': { display: 'flex', 'align-items': 'center', 'justify-content': 'center' }, + // }); + // }), + // ], }; + +export default config; \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index dd3abab..2e298a7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,23 @@ { "compilerOptions": { - "target": "ES2020", - "lib": ["DOM", "ES2020"], + "target": "ESNext", + "lib": ["DOM", "ESNext"], + "allowJs": true, "module": "ESNext", - "jsx": "react-jsx", "strict": true, + "esModuleInterop": true, "skipLibCheck": true, - "isolatedModules": true, + "forceConsistentCasingInFileNames": true, + "declaration": false, + "jsx": "preserve", + "experimentalDecorators": true, "resolveJsonModule": true, - "moduleResolution": "bundler", - "useDefineForClassFields": true + "isolatedModules": true, + "moduleResolution": "Bundler", + "baseUrl": "./", + "paths": { + "@/*": ["./src/*"] + } }, - "include": ["src"] + "exclude": ["dist"] } \ No newline at end of file