diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index ec6b88a6..edcb1184 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -20,15 +20,42 @@ npm run lint # Check lint errors npm run check # Run all checks (CI) ``` -Pre-commit hooks via Husky will run Biome automatically on staged files. +Git hooks via Husky run automatically: +- **Pre-commit**: Biome (format/lint) + TypeScript type check +- **Pre-push**: Unit tests For a better experience, install the [Biome VS Code extension](https://marketplace.visualstudio.com/items?itemName=biomejs.biome) for real-time linting and format-on-save. +## Testing + +Run tests before submitting PRs: + +```bash +npm run test # Unit tests (Vitest) +npm run test:e2e # E2E tests (Playwright) +``` + +E2E tests use mocked API responses - no AI provider needed. Tests are in `tests/e2e/`. + +To run a specific test file: +```bash +npx playwright test tests/e2e/diagram-generation.spec.ts +``` + +To run tests with UI mode: +```bash +npx playwright test --ui +``` + ## Pull Requests 1. Create a feature branch -2. Make changes and ensure `npm run check` passes -3. Submit PR against `main` with a clear description +2. Make changes (pre-commit runs lint + type check automatically) +3. Run E2E tests with `npm run test:e2e` +4. Push (pre-push runs unit tests automatically) +5. Submit PR against `main` with a clear description + +CI will run the full test suite on your PR. ## Issues diff --git a/.github/renovate.json b/.github/renovate.json index 8f2861ed..437ea5d6 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,7 +1,7 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": ["config:recommended"], - "schedule": ["after 10am on saturday"], + "schedule": ["after 10am on the first day of the month"], "timezone": "Asia/Tokyo", "packageRules": [ { @@ -13,6 +13,7 @@ { "matchUpdateTypes": ["major"], "matchPackagePatterns": ["*"], + "groupName": "major dependencies", "automerge": false }, { diff --git a/.github/workflows/electron-release.yml b/.github/workflows/electron-release.yml index e6e57f0a..9cb15ac6 100644 --- a/.github/workflows/electron-release.yml +++ b/.github/workflows/electron-release.yml @@ -11,7 +11,8 @@ on: required: false jobs: - build: + # Mac and Linux: Build and publish directly (no signing needed) + build-mac-linux: permissions: contents: write strategy: @@ -20,13 +21,9 @@ jobs: include: - os: macos-latest platform: mac - - os: windows-latest - platform: win - os: ubuntu-latest platform: linux - runs-on: ${{ matrix.os }} - steps: - name: Checkout code uses: actions/checkout@v6 @@ -40,7 +37,58 @@ jobs: - name: Install dependencies run: npm install - - name: Build and publish Electron app + - name: Build and publish run: npm run dist:${{ matrix.platform }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + # Windows: Build, sign with SignPath, then publish + build-windows: + permissions: + contents: write + runs-on: windows-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: "npm" + + - name: Install dependencies + run: npm install + + # Build WITHOUT publishing + - name: Build Windows app + run: npm run dist:win:build + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Upload unsigned artifacts for signing + uses: actions/upload-artifact@v6 + id: upload-unsigned + with: + name: windows-unsigned + path: release/*.exe + retention-days: 1 + + - name: Sign with SignPath + uses: signpath/github-action-submit-signing-request@v2 + with: + api-token: ${{ secrets.SIGNPATH_API_TOKEN }} + organization-id: '880a211d-2cd3-4e7b-8d04-3d1f8eb39df5' + project-slug: 'next-ai-draw-io' + signing-policy-slug: 'test-signing' + artifact-configuration-slug: 'windows-exe' + github-artifact-id: ${{ steps.upload-unsigned.outputs.artifact-id }} + wait-for-completion: true + output-artifact-directory: release-signed + + - name: Upload signed artifacts to release + uses: softprops/action-gh-release@v2 + with: + files: release-signed/*.exe + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..52428f18 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,75 @@ +name: Test + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + lint-and-unit: + name: Lint & Unit Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: "20" + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Run lint + run: npm run check + + - name: Run unit tests + run: npm run test -- --run + + e2e: + name: E2E Tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: "20" + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Cache Playwright browsers + uses: actions/cache@v5 + id: playwright-cache + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }} + + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: npx playwright install chromium --with-deps + + - name: Install Playwright deps (cached) + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: npx playwright install-deps chromium + + - name: Build app + run: npm run build + + - name: Run E2E tests + run: npm run test:e2e + env: + CI: true + + - name: Upload test results + uses: actions/upload-artifact@v6 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 7 diff --git a/.gitignore b/.gitignore index e0596a24..ef02da91 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,8 @@ packages/*/dist # testing /coverage +/playwright-report/ +/test-results/ # next.js /.next/ @@ -65,4 +67,5 @@ CLAUDE.md .spec-workflow # edgeone -.edgeone \ No newline at end of file +.edgeone +opencode.json \ No newline at end of file diff --git a/.husky/pre-commit b/.husky/pre-commit index 2312dc58..ef9088d0 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1 +1,2 @@ npx lint-staged +npx tsc --noEmit diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100644 index 00000000..2674c5f2 --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1,4 @@ +# Skip if node_modules not installed (e.g., on EC2 push server) +if [ -d "node_modules" ]; then + npm run test -- --run +fi diff --git a/Dockerfile b/Dockerfile index fb674006..a4af9806 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,6 +30,10 @@ ENV NEXT_PUBLIC_DRAWIO_BASE_URL=${NEXT_PUBLIC_DRAWIO_BASE_URL} ARG NEXT_PUBLIC_SHOW_ABOUT_AND_NOTICE=false ENV NEXT_PUBLIC_SHOW_ABOUT_AND_NOTICE=${NEXT_PUBLIC_SHOW_ABOUT_AND_NOTICE} +# Build-time argument for subdirectory deployment (e.g., /nextaidrawio) +ARG NEXT_PUBLIC_BASE_PATH="" +ENV NEXT_PUBLIC_BASE_PATH=${NEXT_PUBLIC_BASE_PATH} + # Build Next.js application (standalone mode) RUN npm run build diff --git a/README.md b/README.md index 6d7b405b..7db249aa 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,12 @@ https://github.com/user-attachments/assets/9d60a3e8-4a1c-4b5e-acbb-26af2d3eabd1 - [Installation](#installation) - [Deployment](#deployment) - [Deploy to EdgeOne Pages](#deploy-to-edgeone-pages) - - [Deploy on Vercel (Recommended)](#deploy-on-vercel-recommended) + - [Deploy on Vercel](#deploy-on-vercel) - [Deploy on Cloudflare Workers](#deploy-on-cloudflare-workers) - [Multi-Provider Support](#multi-provider-support) - [How It Works](#how-it-works) - [Support \& Contact](#support--contact) + - [FAQ](#faq) - [Star History](#star-history) ## Examples @@ -185,7 +186,7 @@ Check out the [Tencent EdgeOne Pages documentation](https://pages.edgeone.ai/doc Additionally, deploying through Tencent EdgeOne Pages will also grant you a [daily free quota for DeepSeek models](https://pages.edgeone.ai/document/edge-ai). -### Deploy on Vercel (Recommended) +### Deploy on Vercel [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FDayuanJiang%2Fnext-ai-draw-io) @@ -211,6 +212,7 @@ See the [Next.js deployment documentation](https://nextjs.org/docs/app/building- - OpenRouter - DeepSeek - SiliconFlow +- ModelScope - SGLang - Vercel AI Gateway @@ -245,6 +247,10 @@ For support or inquiries, please open an issue on the GitHub repository or conta - Email: me[at]jiang.jp +## FAQ + +See [FAQ](./docs/en/FAQ.md) for common issues and solutions. + ## Star History [![Star History Chart](https://api.star-history.com/svg?repos=DayuanJiang/next-ai-draw-io&type=date&legend=top-left)](https://www.star-history.com/#DayuanJiang/next-ai-draw-io&type=date&legend=top-left) diff --git a/app/[lang]/about/cn/page.tsx b/app/[lang]/about/cn/page.tsx index 591df695..e88a8add 100644 --- a/app/[lang]/about/cn/page.tsx +++ b/app/[lang]/about/cn/page.tsx @@ -10,18 +10,7 @@ export const metadata: Metadata = { keywords: ["AI图表", "draw.io", "AWS架构", "GCP图表", "Azure图表", "LLM"], } -function formatNumber(num: number): string { - if (num >= 1000) { - return `${num / 1000}k` - } - return num.toString() -} - export default function AboutCN() { - const dailyRequestLimit = Number(process.env.DAILY_REQUEST_LIMIT) || 20 - const dailyTokenLimit = Number(process.env.DAILY_TOKEN_LIMIT) || 500000 - const tpmLimit = Number(process.env.TPM_LIMIT) || 50000 - return (
{/* Navigation */} @@ -108,42 +97,6 @@ export default function AboutCN() {

- {/* Usage Limits */} -

- 当前使用限制: -

-
-
-

- {formatNumber(dailyRequestLimit)} -

-

- 请求/天 -

-
-
-

- {formatNumber(dailyTokenLimit)} -

-

- Token/天 -

-
-
-

- {formatNumber(tpmLimit)} -

-

- Token/分钟 -

-
-
- - {/* Divider */} -
-
-
- {/* Bring Your Own Key */}

@@ -344,6 +297,7 @@ export default function AboutCN() {
  • OpenRouter
  • DeepSeek
  • SiliconFlow
  • +
  • ModelScope
  • 注意:claude-sonnet-4-5{" "} diff --git a/app/[lang]/about/ja/page.tsx b/app/[lang]/about/ja/page.tsx index 4dd22d64..dbbabaf2 100644 --- a/app/[lang]/about/ja/page.tsx +++ b/app/[lang]/about/ja/page.tsx @@ -17,18 +17,7 @@ export const metadata: Metadata = { ], } -function formatNumber(num: number): string { - if (num >= 1000) { - return `${num / 1000}k` - } - return num.toString() -} - export default function AboutJA() { - const dailyRequestLimit = Number(process.env.DAILY_REQUEST_LIMIT) || 20 - const dailyTokenLimit = Number(process.env.DAILY_TOKEN_LIMIT) || 500000 - const tpmLimit = Number(process.env.TPM_LIMIT) || 50000 - return (

    {/* Navigation */} @@ -116,42 +105,6 @@ export default function AboutJA() {

    - {/* Usage Limits */} -

    - 現在の使用制限: -

    -
    -
    -

    - {formatNumber(dailyRequestLimit)} -

    -

    - リクエスト/日 -

    -
    -
    -

    - {formatNumber(dailyTokenLimit)} -

    -

    - トークン/日 -

    -
    -
    -

    - {formatNumber(tpmLimit)} -

    -

    - トークン/分 -

    -
    -
    - - {/* Divider */} -
    -
    -
    - {/* Bring Your Own Key */}

    @@ -359,6 +312,7 @@ export default function AboutJA() {
  • OpenRouter
  • DeepSeek
  • SiliconFlow
  • +
  • ModelScope
  • 注:claude-sonnet-4-5 diff --git a/app/[lang]/about/page.tsx b/app/[lang]/about/page.tsx index d5240fdc..2750b515 100644 --- a/app/[lang]/about/page.tsx +++ b/app/[lang]/about/page.tsx @@ -17,18 +17,7 @@ export const metadata: Metadata = { ], } -function formatNumber(num: number): string { - if (num >= 1000) { - return `${num / 1000}k` - } - return num.toString() -} - export default function About() { - const dailyRequestLimit = Number(process.env.DAILY_REQUEST_LIMIT) || 20 - const dailyTokenLimit = Number(process.env.DAILY_TOKEN_LIMIT) || 500000 - const tpmLimit = Number(process.env.TPM_LIMIT) || 50000 - return (

    {/* Navigation */} @@ -118,42 +107,6 @@ export default function About() {

    - {/* Usage Limits */} -

    - Please note the current usage limits: -

    -
    -
    -

    - {formatNumber(dailyRequestLimit)} -

    -

    - requests/day -

    -
    -
    -

    - {formatNumber(dailyTokenLimit)} -

    -

    - tokens/day -

    -
    -
    -

    - {formatNumber(tpmLimit)} -

    -

    - tokens/min -

    -
    -
    - - {/* Divider */} -
    -
    -
    - {/* Bring Your Own Key */}

    @@ -378,6 +331,7 @@ export default function About() {
  • OpenRouter
  • DeepSeek
  • SiliconFlow
  • +
  • ModelScope
  • Note that claude-sonnet-4-5 has trained on diff --git a/app/[lang]/page.tsx b/app/[lang]/page.tsx index ac06a5f8..30fa1346 100644 --- a/app/[lang]/page.tsx +++ b/app/[lang]/page.tsx @@ -4,7 +4,6 @@ import { Suspense, useCallback, useEffect, useRef, useState } from "react" import { DrawIoEmbed } from "react-drawio" import type { ImperativePanelHandle } from "react-resizable-panels" import ChatPanel from "@/components/chat-panel" -import { STORAGE_CLOSE_PROTECTION_KEY } from "@/components/settings-dialog" import { ResizableHandle, ResizablePanel, @@ -34,7 +33,6 @@ export default function Home() { const [darkMode, setDarkMode] = useState(false) const [isLoaded, setIsLoaded] = useState(false) const [isDrawioReady, setIsDrawioReady] = useState(false) - const [closeProtection, setCloseProtection] = useState(false) const chatPanelRef = useRef(null) const isMobileRef = useRef(false) @@ -73,13 +71,6 @@ export default function Home() { document.documentElement.classList.toggle("dark", prefersDark) } - const savedCloseProtection = localStorage.getItem( - STORAGE_CLOSE_PROTECTION_KEY, - ) - if (savedCloseProtection === "true") { - setCloseProtection(true) - } - setIsLoaded(true) }, [pathname, router]) @@ -152,20 +143,6 @@ export default function Home() { return () => window.removeEventListener("keydown", handleKeyDown) }, []) - // Show confirmation dialog when user tries to leave the page - useEffect(() => { - if (!closeProtection) return - - const handleBeforeUnload = (event: BeforeUnloadEvent) => { - event.preventDefault() - return "" - } - - window.addEventListener("beforeunload", handleBeforeUnload) - return () => - window.removeEventListener("beforeunload", handleBeforeUnload) - }, [closeProtection]) - return (

    diff --git a/app/api/chat/route.ts b/app/api/chat/route.ts index 55dbbdea..872b8702 100644 --- a/app/api/chat/route.ts +++ b/app/api/chat/route.ts @@ -18,6 +18,11 @@ import { supportsPromptCaching, } from "@/lib/ai-providers" import { findCachedResponse } from "@/lib/cached-responses" +import { + isMinimalDiagram, + replaceHistoricalToolInputs, + validateFileParts, +} from "@/lib/chat-helpers" import { checkAndIncrementRequest, isQuotaEnabled, @@ -34,93 +39,6 @@ import { getUserIdFromRequest } from "@/lib/user-id" export const maxDuration = 120 -// File upload limits (must match client-side) -const MAX_FILE_SIZE = 2 * 1024 * 1024 // 2MB -const MAX_FILES = 5 - -// Helper function to validate file parts in messages -function validateFileParts(messages: any[]): { - valid: boolean - error?: string -} { - const lastMessage = messages[messages.length - 1] - const fileParts = - lastMessage?.parts?.filter((p: any) => p.type === "file") || [] - - if (fileParts.length > MAX_FILES) { - return { - valid: false, - error: `Too many files. Maximum ${MAX_FILES} allowed.`, - } - } - - for (const filePart of fileParts) { - // Data URLs format: data:image/png;base64, - // Base64 increases size by ~33%, so we check the decoded size - if (filePart.url?.startsWith("data:")) { - const base64Data = filePart.url.split(",")[1] - if (base64Data) { - const sizeInBytes = Math.ceil((base64Data.length * 3) / 4) - if (sizeInBytes > MAX_FILE_SIZE) { - return { - valid: false, - error: `File exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`, - } - } - } - } - } - - return { valid: true } -} - -// Helper function to check if diagram is minimal/empty -function isMinimalDiagram(xml: string): boolean { - const stripped = xml.replace(/\s/g, "") - return !stripped.includes('id="2"') -} - -// Helper function to replace historical tool call XML with placeholders -// This reduces token usage and forces LLM to rely on the current diagram XML (source of truth) -// Also fixes invalid/undefined inputs from interrupted streaming -function replaceHistoricalToolInputs(messages: any[]): any[] { - return messages.map((msg) => { - if (msg.role !== "assistant" || !Array.isArray(msg.content)) { - return msg - } - const replacedContent = msg.content - .map((part: any) => { - if (part.type === "tool-call") { - const toolName = part.toolName - // Fix invalid/undefined inputs from interrupted streaming - if ( - !part.input || - typeof part.input !== "object" || - Object.keys(part.input).length === 0 - ) { - // Skip tool calls with invalid inputs entirely - return null - } - if ( - toolName === "display_diagram" || - toolName === "edit_diagram" - ) { - return { - ...part, - input: { - placeholder: - "[XML content replaced - see current diagram XML in system context]", - }, - } - } - } - return part - }) - .filter(Boolean) // Remove null entries (invalid tool calls) - return { ...msg, content: replacedContent } - }) -} - // Helper function to create cached stream response function createCachedStreamResponse(xml: string): Response { const toolCallId = `cached-${Date.now()}` diff --git a/app/api/parse-url/route.ts b/app/api/parse-url/route.ts new file mode 100644 index 00000000..f5278e65 --- /dev/null +++ b/app/api/parse-url/route.ts @@ -0,0 +1,154 @@ +import { extract } from "@extractus/article-extractor" +import { NextResponse } from "next/server" +import TurndownService from "turndown" + +const MAX_CONTENT_LENGTH = 150000 // Match PDF limit +const EXTRACT_TIMEOUT_MS = 15000 + +// SSRF protection - block private/internal addresses +function isPrivateUrl(urlString: string): boolean { + try { + const url = new URL(urlString) + const hostname = url.hostname.toLowerCase() + + // Block localhost + if ( + hostname === "localhost" || + hostname === "127.0.0.1" || + hostname === "::1" + ) { + return true + } + + // Block AWS/cloud metadata endpoints + if ( + hostname === "169.254.169.254" || + hostname === "metadata.google.internal" + ) { + return true + } + + // Check for private IPv4 ranges + const ipv4Match = hostname.match( + /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/, + ) + if (ipv4Match) { + const [, a, b] = ipv4Match.map(Number) + if (a === 10) return true // 10.0.0.0/8 + if (a === 172 && b >= 16 && b <= 31) return true // 172.16.0.0/12 + if (a === 192 && b === 168) return true // 192.168.0.0/16 + if (a === 169 && b === 254) return true // 169.254.0.0/16 (link-local) + if (a === 127) return true // 127.0.0.0/8 (loopback) + } + + // Block common internal hostnames + if ( + hostname.endsWith(".local") || + hostname.endsWith(".internal") || + hostname.endsWith(".localhost") + ) { + return true + } + + return false + } catch { + return true // Invalid URL - block it + } +} + +export async function POST(req: Request) { + try { + const { url } = await req.json() + + if (!url || typeof url !== "string") { + return NextResponse.json( + { error: "URL is required" }, + { status: 400 }, + ) + } + + // Validate URL format + try { + new URL(url) + } catch { + return NextResponse.json( + { error: "Invalid URL format" }, + { status: 400 }, + ) + } + + // SSRF protection + if (isPrivateUrl(url)) { + return NextResponse.json( + { error: "Cannot access private/internal URLs" }, + { status: 400 }, + ) + } + + // Extract article content with timeout to avoid tying up server resources + const controller = new AbortController() + const timeoutId = setTimeout(() => { + controller.abort() + }, EXTRACT_TIMEOUT_MS) + + let article + try { + article = await extract(url, undefined, { + headers: { + "User-Agent": "Mozilla/5.0 (compatible; NextAIDrawio/1.0)", + }, + signal: controller.signal, + }) + } catch (err: any) { + if (err?.name === "AbortError") { + return NextResponse.json( + { error: "Timed out while fetching URL content" }, + { status: 504 }, + ) + } + throw err + } finally { + clearTimeout(timeoutId) + } + + if (!article || !article.content) { + return NextResponse.json( + { error: "Could not extract content from URL" }, + { status: 400 }, + ) + } + + // Convert HTML to Markdown + const turndownService = new TurndownService({ + headingStyle: "atx", + codeBlockStyle: "fenced", + }) + + // Remove unwanted elements before conversion + turndownService.remove(["script", "style", "iframe", "noscript"]) + + const markdown = turndownService.turndown(article.content) + + // Check content length + if (markdown.length > MAX_CONTENT_LENGTH) { + return NextResponse.json( + { + error: `Content exceeds ${MAX_CONTENT_LENGTH / 1000}k character limit (${(markdown.length / 1000).toFixed(1)}k chars)`, + }, + { status: 400 }, + ) + } + + return NextResponse.json({ + title: article.title || "Untitled", + content: markdown, + charCount: markdown.length, + }) + } catch (error) { + console.error("URL extraction error:", error) + return NextResponse.json( + { error: "Failed to fetch or parse URL content" }, + { status: 500 }, + ) + } +} diff --git a/app/api/validate-model/route.ts b/app/api/validate-model/route.ts index 2185ae86..b8b258e6 100644 --- a/app/api/validate-model/route.ts +++ b/app/api/validate-model/route.ts @@ -202,7 +202,7 @@ export async function POST(req: Request) { case "siliconflow": { const sf = createOpenAI({ apiKey, - baseURL: baseUrl || "https://api.siliconflow.com/v1", + baseURL: baseUrl || "https://api.siliconflow.cn/v1", }) model = sf.chat(modelId) break @@ -251,16 +251,98 @@ export async function POST(req: Request) { } case "doubao": { - // ByteDance Doubao uses DeepSeek-compatible API - const doubao = createDeepSeek({ - apiKey, - baseURL: - baseUrl || "https://ark.cn-beijing.volces.com/api/v3", - }) - model = doubao(modelId) + // ByteDance Doubao: use DeepSeek for DeepSeek/Kimi models, OpenAI for others + const doubaoBaseUrl = + baseUrl || "https://ark.cn-beijing.volces.com/api/v3" + const lowerModelId = modelId.toLowerCase() + if ( + lowerModelId.includes("deepseek") || + lowerModelId.includes("kimi") + ) { + const doubao = createDeepSeek({ + apiKey, + baseURL: doubaoBaseUrl, + }) + model = doubao(modelId) + } else { + const doubao = createOpenAI({ + apiKey, + baseURL: doubaoBaseUrl, + }) + model = doubao.chat(modelId) + } break } + case "modelscope": { + const baseURL = + baseUrl || "https://api-inference.modelscope.cn/v1" + const startTime = Date.now() + + try { + // Initiate a streaming request (required for QwQ-32B and certain Qwen3 models) + const response = await fetch( + `${baseURL}/chat/completions`, + { + method: "POST", + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${apiKey}`, + }, + body: JSON.stringify({ + model: modelId, + messages: [ + { role: "user", content: "Say 'OK'" }, + ], + max_tokens: 20, + stream: true, + enable_thinking: false, + }), + }, + ) + + if (!response.ok) { + const errorText = await response.text() + throw new Error( + `ModelScope API error (${response.status}): ${errorText}`, + ) + } + + const contentType = + response.headers.get("content-type") || "" + const isValidStreamingResponse = + response.status === 200 && + (contentType.includes("text/event-stream") || + contentType.includes("application/json")) + + if (!isValidStreamingResponse) { + throw new Error( + `Unexpected response format: ${contentType}`, + ) + } + + const responseTime = Date.now() - startTime + + if (response.body) { + response.body.cancel().catch(() => { + /* Ignore cancellation errors */ + }) + } + + return NextResponse.json({ + valid: true, + responseTime, + note: "ModelScope model validated (using streaming API)", + }) + } catch (error) { + console.error( + "[validate-model] ModelScope validation failed:", + error, + ) + throw error + } + } + default: return NextResponse.json( { valid: false, error: `Unknown provider: ${provider}` }, diff --git a/app/globals.css b/app/globals.css index d91c503d..f4754392 100644 --- a/app/globals.css +++ b/app/globals.css @@ -244,6 +244,19 @@ .scrollbar-thin::-webkit-scrollbar-thumb:hover { background-color: oklch(0.75 0.01 260); } + + /* Dark mode scrollbar */ + .dark .scrollbar-thin { + scrollbar-color: oklch(0.35 0.015 260) transparent; + } + + .dark .scrollbar-thin::-webkit-scrollbar-thumb { + background-color: oklch(0.35 0.015 260); + } + + .dark .scrollbar-thin::-webkit-scrollbar-thumb:hover { + background-color: oklch(0.45 0.015 260); + } } /* Smooth page transitions */ diff --git a/components/ai-elements/model-selector.tsx b/components/ai-elements/model-selector.tsx index 92f82fc5..1b71cb70 100644 --- a/components/ai-elements/model-selector.tsx +++ b/components/ai-elements/model-selector.tsx @@ -134,6 +134,7 @@ export const ModelSelectorLogo = ({ } return ( + // biome-ignore lint/performance/noImgElement: External URL from models.dev {`${provider} + urlData?: Map + onUrlChange?: (data: Map) => void sessionId?: string error?: Error | null @@ -163,6 +169,8 @@ export function ChatInput({ files = [], onFileChange = () => {}, pdfData = new Map(), + urlData, + onUrlChange, sessionId, error = null, models = [], @@ -183,6 +191,9 @@ export function ChatInput({ const fileInputRef = useRef(null) const [isDragging, setIsDragging] = useState(false) const [showHistory, setShowHistory] = useState(false) + const [showUrlDialog, setShowUrlDialog] = useState(false) + const [isExtractingUrl, setIsExtractingUrl] = useState(false) + const [sendShortcut, setSendShortcut] = useState("ctrl-enter") // Allow retry when there's an error (even if status is still "streaming" or "submitted") const isDisabled = (status === "streaming" || status === "submitted") && !error @@ -199,13 +210,36 @@ export function ChatInput({ adjustTextareaHeight() }, [input, adjustTextareaHeight]) + // Load send shortcut preference from localStorage and listen for changes + useEffect(() => { + const stored = localStorage.getItem(STORAGE_KEYS.sendShortcut) + if (stored) setSendShortcut(stored) + + const handleChange = (e: CustomEvent) => + setSendShortcut(e.detail) + window.addEventListener( + "sendShortcutChange", + handleChange as EventListener, + ) + return () => + window.removeEventListener( + "sendShortcutChange", + handleChange as EventListener, + ) + }, []) + const handleChange = (e: React.ChangeEvent) => { onChange(e) adjustTextareaHeight() } const handleKeyDown = (e: React.KeyboardEvent) => { - if ((e.metaKey || e.ctrlKey) && e.key === "Enter") { + const shouldSend = + sendShortcut === "enter" + ? e.key === "Enter" && !e.shiftKey && !e.ctrlKey && !e.metaKey + : (e.metaKey || e.ctrlKey) && e.key === "Enter" + + if (shouldSend) { e.preventDefault() const form = e.currentTarget.closest("form") if (form && input.trim() && !isDisabled) { @@ -312,6 +346,50 @@ export function ChatInput({ } } + const handleUrlExtract = async (url: string) => { + if (!onUrlChange) return + + setIsExtractingUrl(true) + + try { + const existing = urlData + ? new Map(urlData) + : new Map() + existing.set(url, { + url, + title: url, + content: "", + charCount: 0, + isExtracting: true, + }) + onUrlChange(existing) + + const data = await extractUrlContent(url) + + const newUrlData = new Map(existing) + newUrlData.set(url, data) + onUrlChange(newUrlData) + + setShowUrlDialog(false) + } catch (error) { + // Remove the URL from the data map on error + const newUrlData = urlData + ? new Map(urlData) + : new Map() + newUrlData.delete(url) + onUrlChange(newUrlData) + showErrorToast( + + {error instanceof Error + ? error.message + : "Failed to extract URL content"} + , + ) + } finally { + setIsExtractingUrl(false) + } + } + return (
    - {/* File previews */} - {files.length > 0 && ( + {/* File & URL previews */} + {(files.length > 0 || (urlData && urlData.size > 0)) && (
    { + const next = new Map(urlData) + next.delete(url) + onUrlChange(next) + } + : undefined + } />
    )} @@ -344,7 +432,7 @@ export function ChatInput({ placeholder={dict.chat.placeholder} disabled={isDisabled} aria-label="Chat input" - className="min-h-[60px] max-h-[200px] resize-none border-0 bg-transparent px-4 py-3 text-sm focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-muted-foreground/60" + className="min-h-[60px] max-h-[200px] resize-none border-0 bg-transparent px-4 py-3 text-sm focus-visible:ring-0 focus-visible:ring-offset-0 placeholder:text-muted-foreground/60 scrollbar-thin" />
    @@ -385,6 +473,20 @@ export function ChatInput({ + {onUrlChange && ( + setShowUrlDialog(true)} + disabled={isDisabled} + tooltipContent={dict.chat.ExtractURL} + className="h-8 w-8 p-0 text-muted-foreground hover:text-foreground" + > + + + )} + + {onUrlChange && ( + + )} ) } diff --git a/components/chat-message-display.tsx b/components/chat-message-display.tsx index 27bfbf98..83666096 100644 --- a/components/chat-message-display.tsx +++ b/components/chat-message-display.tsx @@ -38,7 +38,6 @@ import { replaceNodes, validateAndFixXml, } from "@/lib/utils" -import ExamplePanel from "./chat-example-panel" // Helper to extract complete operations from streaming input function getCompleteOperations( @@ -1115,7 +1114,7 @@ export function ChatMessageDisplay({ )} {isExpanded && ( -
    +
                                                                                                                     {
                                                                                                                         section.content
    diff --git a/components/chat-panel.tsx b/components/chat-panel.tsx
    index 7e699d32..8d486249 100644
    --- a/components/chat-panel.tsx
    +++ b/components/chat-panel.tsx
    @@ -34,6 +34,7 @@ import { findCachedResponse } from "@/lib/cached-responses"
     import { formatMessage } from "@/lib/i18n/utils"
     import { isPdfFile, isTextFile } from "@/lib/pdf-utils"
     import { sanitizeMessages } from "@/lib/session-storage"
    +import type { UrlData } from "@/lib/url-utils"
     import { type FileData, useFileProcessor } from "@/lib/use-file-processor"
     import { useQuotaManager } from "@/lib/use-quota-manager"
     import { cn, formatXML, isRealDiagram } from "@/lib/utils"
    @@ -69,7 +70,6 @@ interface ChatPanelProps {
         darkMode: boolean
         onToggleDarkMode: () => void
         isMobile?: boolean
    -    onCloseProtectionChange?: (enabled: boolean) => void
     }
     
     // Constants for tool states
    @@ -110,7 +110,6 @@ export default function ChatPanel({
         darkMode,
         onToggleDarkMode,
         isMobile = false,
    -    onCloseProtectionChange,
     }: ChatPanelProps) {
         const {
             loadDiagram: onDisplayChart,
    @@ -158,6 +157,7 @@ export default function ChatPanel({
     
         // File processing using extracted hook
         const { files, pdfData, handleFileChange, setFiles } = useFileProcessor()
    +    const [urlData, setUrlData] = useState>(new Map())
     
         const [showSettingsDialog, setShowSettingsDialog] = useState(false)
         const [showModelConfigDialog, setShowModelConfigDialog] = useState(false)
    @@ -710,6 +710,8 @@ export default function ChatPanel({
                             input,
                             files,
                             pdfData,
    +                        undefined,
    +                        urlData,
                         )
     
                         setMessages([
    @@ -735,6 +737,7 @@ export default function ChatPanel({
                         setInput("")
                         sessionStorage.removeItem(SESSION_STORAGE_INPUT_KEY)
                         setFiles([])
    +                    setUrlData(new Map())
                         return
                     }
                 }
    @@ -755,6 +758,7 @@ export default function ChatPanel({
                         files,
                         pdfData,
                         parts,
    +                    urlData,
                     )
     
                     // Add the combined text as the first part
    @@ -779,6 +783,7 @@ export default function ChatPanel({
                     setInput("")
                     sessionStorage.removeItem(SESSION_STORAGE_INPUT_KEY)
                     setFiles([])
    +                setUrlData(new Map())
                 } catch (error) {
                     console.error("Error fetching chart data:", error)
                 }
    @@ -854,6 +859,7 @@ export default function ChatPanel({
             clearDiagram()
             setDiagramHistory([])
             handleFileChange([]) // Use handleFileChange to also clear pdfData
    +        setUrlData(new Map())
             const newSessionId = `session-${Date.now()}-${Math.random()
                 .toString(36)
                 .slice(2, 9)}`
    @@ -972,6 +978,7 @@ export default function ChatPanel({
             files: File[],
             pdfData: Map,
             imageParts?: any[],
    +        urlDataParam?: Map,
         ): Promise => {
             let userText = baseText
     
    @@ -1002,6 +1009,14 @@ export default function ChatPanel({
                 }
             }
     
    +        if (urlDataParam) {
    +            for (const [url, data] of urlDataParam) {
    +                if (data.content) {
    +                    userText += `\n\n[URL: ${url}]\nTitle: ${data.title}\n\n${data.content}`
    +                }
    +            }
    +        }
    +
             return userText
         }
     
    @@ -1185,6 +1200,7 @@ export default function ChatPanel({
                                     status === "streaming" || status === "submitted"
                                 }
                                 className="hover:bg-accent disabled:opacity-50 disabled:cursor-not-allowed"
    +                            data-testid="new-chat-button"
                             >
                                  setShowSettingsDialog(true)}
                                 className="hover:bg-accent"
    +                            data-testid="settings-button"
                             >
                                 
    +    urlData?: Map<
    +        string,
    +        { url: string; title: string; charCount: number; isExtracting: boolean }
    +    >
    +    onRemoveUrl?: (url: string) => void
     }
     
     export function FilePreviewList({
         files,
         onRemoveFile,
         pdfData = new Map(),
    +    urlData,
    +    onRemoveUrl,
     }: FilePreviewListProps) {
         const dict = useDictionary()
         const [selectedImage, setSelectedImage] = useState(null)
    @@ -77,7 +84,7 @@ export function FilePreviewList({
             }
         }, [imageUrls, selectedImage])
     
    -    if (files.length === 0) return null
    +    if (files.length === 0 && (!urlData || urlData.size === 0)) return null
     
         return (
             <>
    @@ -152,6 +159,59 @@ export function FilePreviewList({
                             
    ) })} + {/* URL previews */} + {urlData && urlData.size > 0 && ( +
    + {Array.from(urlData.entries()).map( + ([url, data], index) => ( +
    +
    +
    + {data.isExtracting ? ( + <> + + + {dict.file.reading} + + + ) : ( + <> + + + {data.title.length > 10 + ? `${data.title.slice(0, 7)}...` + : data.title} + + {data.charCount && ( + + {formatCharCount( + data.charCount, + )}{" "} + {dict.file.chars} + + )} + + )} +
    +
    + {onRemoveUrl && ( + + )} +
    + ), + )} +
    + )}
    {/* Image Modal/Lightbox */} {selectedImage && ( diff --git a/components/history-dialog.tsx b/components/history-dialog.tsx index 3ba6068f..21675e06 100644 --- a/components/history-dialog.tsx +++ b/components/history-dialog.tsx @@ -43,7 +43,7 @@ export function HistoryDialog({ return ( - + {dict.history.title} diff --git a/components/model-config-dialog.tsx b/components/model-config-dialog.tsx index 500d8f46..0c3aae37 100644 --- a/components/model-config-dialog.tsx +++ b/components/model-config-dialog.tsx @@ -79,6 +79,7 @@ const PROVIDER_LOGO_MAP: Record = { gateway: "vercel", edgeone: "tencent-cloud", doubao: "bytedance", + modelscope: "modelscope", } // Provider logo component @@ -102,6 +103,7 @@ function ProviderLogo({ const logoName = PROVIDER_LOGO_MAP[provider] || provider return ( + // biome-ignore lint/performance/noImgElement: External URL from models.dev {`${provider} { - if (!selectedProvider) return + if (!selectedProvider || !selectedProviderId) return // Check credentials based on provider type const isBedrock = selectedProvider.provider === "bedrock" @@ -331,14 +333,14 @@ export function ModelConfigDialog({ const data = await response.json() if (data.valid) { - updateModel(selectedProviderId!, model.id, { + updateModel(selectedProviderId, model.id, { validated: true, validationError: undefined, }) } else { allValid = false errorCount++ - updateModel(selectedProviderId!, model.id, { + updateModel(selectedProviderId, model.id, { validated: false, validationError: data.error || "Validation failed", }) @@ -346,7 +348,7 @@ export function ModelConfigDialog({ } catch { allValid = false errorCount++ - updateModel(selectedProviderId!, model.id, { + updateModel(selectedProviderId, model.id, { validated: false, validationError: "Network error", }) @@ -357,7 +359,7 @@ export function ModelConfigDialog({ if (allValid) { setValidationStatus("success") - updateProvider(selectedProviderId!, { validated: true }) + updateProvider(selectedProviderId, { validated: true }) // Reset to idle after showing success briefly (with cleanup) if (validationResetTimeoutRef.current) { clearTimeout(validationResetTimeoutRef.current) @@ -1298,20 +1300,24 @@ export function ModelConfigDialog({ null, ) } - updateModel( - selectedProviderId!, - model.id, - { - modelId: - e - .target - .value, - validated: - undefined, - validationError: - undefined, - }, - ) + if ( + selectedProviderId + ) { + updateModel( + selectedProviderId, + model.id, + { + modelId: + e + .target + .value, + validated: + undefined, + validationError: + undefined, + }, + ) + } }} onKeyDown={( e, diff --git a/components/model-selector.tsx b/components/model-selector.tsx index 027c6995..49e8b957 100644 --- a/components/model-selector.tsx +++ b/components/model-selector.tsx @@ -50,6 +50,7 @@ const PROVIDER_LOGO_MAP: Record = { gateway: "vercel", edgeone: "tencent-cloud", doubao: "bytedance", + modelscope: "modelscope", } // Group models by providerLabel (handles duplicate providers) diff --git a/components/settings-dialog.tsx b/components/settings-dialog.tsx index ccc1b6f9..67a07978 100644 --- a/components/settings-dialog.tsx +++ b/components/settings-dialog.tsx @@ -3,6 +3,7 @@ import { Github, Info, Moon, Sun, Tag } from "lucide-react" import { usePathname, useRouter, useSearchParams } from "next/navigation" import { Suspense, useEffect, useState } from "react" +import { toast } from "sonner" import { Button } from "@/components/ui/button" import { Dialog, @@ -25,6 +26,7 @@ import { useDictionary } from "@/hooks/use-dictionary" import { getApiEndpoint } from "@/lib/base-path" import { DRAWIO_THEMES, type DrawioTheme } from "@/lib/drawio-themes" import { i18n, type Locale } from "@/lib/i18n/config" +import { STORAGE_KEYS } from "@/lib/storage" // Reusable setting item component for consistent layout function SettingItem({ @@ -82,7 +84,6 @@ interface SettingsDialogProps { } export const STORAGE_ACCESS_CODE_KEY = "next-ai-draw-io-access-code" -export const STORAGE_CLOSE_PROTECTION_KEY = "next-ai-draw-io-close-protection" const STORAGE_ACCESS_CODE_REQUIRED_KEY = "next-ai-draw-io-access-code-required" function getStoredAccessCodeRequired(): boolean | null { @@ -95,7 +96,6 @@ function getStoredAccessCodeRequired(): boolean | null { function SettingsContent({ open, onOpenChange, - onCloseProtectionChange, drawioUi, onDrawioUiChange, darkMode, @@ -108,13 +108,18 @@ function SettingsContent({ const pathname = usePathname() || "/" const search = useSearchParams() const [accessCode, setAccessCode] = useState("") - const [closeProtection, setCloseProtection] = useState(true) const [isVerifying, setIsVerifying] = useState(false) const [error, setError] = useState("") const [accessCodeRequired, setAccessCodeRequired] = useState( () => getStoredAccessCodeRequired() ?? false, ) const [currentLang, setCurrentLang] = useState("en") + const [sendShortcut, setSendShortcut] = useState("ctrl-enter") + + // Proxy settings state (Electron only) + const [httpProxy, setHttpProxy] = useState("") + const [httpsProxy, setHttpsProxy] = useState("") + const [isApplyingProxy, setIsApplyingProxy] = useState(false) useEffect(() => { // Only fetch if not cached in localStorage @@ -156,13 +161,20 @@ function SettingsContent({ localStorage.getItem(STORAGE_ACCESS_CODE_KEY) || "" setAccessCode(storedCode) - const storedCloseProtection = localStorage.getItem( - STORAGE_CLOSE_PROTECTION_KEY, + const storedSendShortcut = localStorage.getItem( + STORAGE_KEYS.sendShortcut, ) - // Default to true if not set - setCloseProtection(storedCloseProtection !== "false") + setSendShortcut(storedSendShortcut || "ctrl-enter") setError("") + + // Load proxy settings (Electron only) + if (window.electronAPI?.getProxy) { + window.electronAPI.getProxy().then((config) => { + setHttpProxy(config.httpProxy || "") + setHttpsProxy(config.httpsProxy || "") + }) + } } }, [open]) @@ -221,6 +233,46 @@ function SettingsContent({ } } + const handleApplyProxy = async () => { + if (!window.electronAPI?.setProxy) return + + // Validate proxy URLs (must start with http:// or https://) + const validateProxyUrl = (url: string): boolean => { + if (!url) return true // Empty is OK + return url.startsWith("http://") || url.startsWith("https://") + } + + const trimmedHttp = httpProxy.trim() + const trimmedHttps = httpsProxy.trim() + + if (trimmedHttp && !validateProxyUrl(trimmedHttp)) { + toast.error("HTTP Proxy must start with http:// or https://") + return + } + if (trimmedHttps && !validateProxyUrl(trimmedHttps)) { + toast.error("HTTPS Proxy must start with http:// or https://") + return + } + + setIsApplyingProxy(true) + try { + const result = await window.electronAPI.setProxy({ + httpProxy: trimmedHttp || undefined, + httpsProxy: trimmedHttps || undefined, + }) + + if (result.success) { + toast.success(dict.settings.proxyApplied) + } else { + toast.error(result.error || "Failed to apply proxy settings") + } + } catch { + toast.error("Failed to apply proxy settings") + } finally { + setIsApplyingProxy(false) + } + } + return ( {/* Header */} @@ -357,25 +409,6 @@ function SettingsContent({ - {/* Close Protection */} - - { - setCloseProtection(checked) - localStorage.setItem( - STORAGE_CLOSE_PROTECTION_KEY, - checked.toString(), - ) - onCloseProtectionChange?.(checked) - }} - /> - - {/* Diagram Style */}
    + + {/* Send Shortcut */} + + + + + {/* Proxy Settings - Electron only */} + {typeof window !== "undefined" && + window.electronAPI?.isElectron && ( +
    +
    + +

    + {dict.settings.proxyDescription} +

    +
    + +
    + + setHttpProxy(e.target.value) + } + placeholder={`${dict.settings.httpProxy}: http://proxy:8080`} + className="h-9" + /> + + setHttpsProxy(e.target.value) + } + placeholder={`${dict.settings.httpsProxy}: http://proxy:8080`} + className="h-9" + /> +
    + + +
    + )}

    diff --git a/components/ui/card.tsx b/components/ui/card.tsx deleted file mode 100644 index 99541f3d..00000000 --- a/components/ui/card.tsx +++ /dev/null @@ -1,92 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -function Card({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardHeader({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardTitle({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardDescription({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardAction({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardContent({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -function CardFooter({ className, ...props }: React.ComponentProps<"div">) { - return ( -
    - ) -} - -export { - Card, - CardHeader, - CardFooter, - CardTitle, - CardAction, - CardDescription, - CardContent, -} diff --git a/components/url-input-dialog.tsx b/components/url-input-dialog.tsx new file mode 100644 index 00000000..8d9e3399 --- /dev/null +++ b/components/url-input-dialog.tsx @@ -0,0 +1,116 @@ +"use client" + +import { Link, Loader2 } from "lucide-react" +import { useState } from "react" +import { Button } from "@/components/ui/button" +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" +import { Input } from "@/components/ui/input" +import { useDictionary } from "@/hooks/use-dictionary" + +interface UrlInputDialogProps { + open: boolean + onOpenChange: (open: boolean) => void + onSubmit: (url: string) => void + isExtracting: boolean +} + +export function UrlInputDialog({ + open, + onOpenChange, + onSubmit, + isExtracting, +}: UrlInputDialogProps) { + const dict = useDictionary() + const [url, setUrl] = useState("") + const [error, setError] = useState("") + + const handleSubmit = () => { + setError("") + + if (!url.trim()) { + setError(dict.url.enterUrl) + return + } + + try { + new URL(url) + } catch { + setError(dict.url.invalidFormat) + return + } + + onSubmit(url.trim()) + } + + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter" && !isExtracting) { + e.preventDefault() + handleSubmit() + } + } + + return ( + + + + {dict.url.title} + + {dict.url.description} + + + +
    +
    + { + setUrl(e.target.value) + setError("") + }} + onKeyDown={handleKeyDown} + placeholder="https://example.com/article" + disabled={isExtracting} + autoFocus + /> + {error && ( +

    {error}

    + )} +
    +
    + + + + + +
    +
    + ) +} diff --git a/docs/cn/FAQ.md b/docs/cn/FAQ.md new file mode 100644 index 00000000..7242bf33 --- /dev/null +++ b/docs/cn/FAQ.md @@ -0,0 +1,78 @@ +# 常见问题解答 (FAQ) + +--- + +## 1. 无法导出 PDF + +**问题**: Web 版点击导出 PDF 后跳转到 `convert.diagrams.net/node/export` 然后无响应 + +**原因**: 嵌入式 Draw.io 不支持直接 PDF 导出,依赖外部转换服务,在 iframe 中无法正常工作 + +**解决方案**: 先导出为图片(PNG),再打印转成 PDF + +**相关 Issue**: #539, #125 + +--- + +## 2. 无法访问 embed.diagrams.net(离线/内网部署) + +**问题**: 内网环境提示"找不到 embed.diagrams.net 的服务器 IP 地址" + +**关键点**: `NEXT_PUBLIC_*` 环境变量是**构建时**变量,会被打包到 JS 代码中,**运行时设置无效**! + +**解决方案**: 必须在构建时通过 `args` 传入: + +```yaml +# docker-compose.yml +services: + drawio: + image: jgraph/drawio:latest + ports: ["8080:8080"] + next-ai-draw-io: + build: + context: . + args: + - NEXT_PUBLIC_DRAWIO_BASE_URL=http://你的服务器IP:8080/ + ports: ["3000:3000"] + env_file: .env +``` + +**内网用户**: 在外网修改 Dockerfile 并构建镜像,再传到内网使用 + +**相关 Issue**: #295, #317 + +--- + +## 3. 自建模型只思考不画图 + +**问题**: 本地部署的模型(如 Qwen、LiteLLM)只输出思考过程,不生成图表 + +**可能原因**: +1. **模型太小** - 小模型难以正确遵循 tool calling 指令,建议使用 32B+ 参数的模型 +2. **未开启 tool calling** - 模型服务需要配置 tool use 功能 + +**解决方案**: 开启 tool calling,例如 vLLM: +```bash +python -m vllm.entrypoints.openai.api_server \ + --model Qwen/Qwen3-32B \ + --enable-auto-tool-choice \ + --tool-call-parser hermes +``` + +**相关 Issue**: #269, #75 + +--- + +## 4. 上传图片后提示"未提供图片" + +**问题**: 上传图片后,系统显示"未提供图片"错误 + +**可能原因**: +1. 模型不支持视觉功能(如 Kimi K2、DeepSeek、Qwen 文本模型) + +**解决方案**: +- 使用支持视觉的模型:GPT-5.2、Claude 4.5 Sonnet、Gemini 3 Pro +- 模型名带 `vision` 或 `vl` 的支持图片 +- 更新到最新版本(v0.4.9+) + +**相关 Issue**: #324, #421, #469 diff --git a/docs/cn/README_CN.md b/docs/cn/README_CN.md index 64e3587c..a2c94ec8 100644 --- a/docs/cn/README_CN.md +++ b/docs/cn/README_CN.md @@ -37,11 +37,12 @@ https://github.com/user-attachments/assets/b2eef5f3-b335-4e71-a755-dc2e80931979 - [安装](#安装) - [部署](#部署) - [部署到腾讯云EdgeOne Pages](#部署到腾讯云edgeone-pages) - - [部署到Vercel(推荐)](#部署到vercel推荐) + - [部署到Vercel](#部署到vercel) - [部署到Cloudflare Workers](#部署到cloudflare-workers) - [多提供商支持](#多提供商支持) - [工作原理](#工作原理) - [支持与联系](#支持与联系) + - [常见问题](#常见问题) - [Star历史](#star历史) ## 示例 @@ -179,7 +180,7 @@ npm run dev 同时,通过腾讯云EdgeOne Pages部署,也会获得[每日免费的DeepSeek模型额度](https://edgeone.cloud.tencent.com/pages/document/169925463311781888)。 -### 部署到Vercel(推荐) +### 部署到Vercel [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FDayuanJiang%2Fnext-ai-draw-io) @@ -204,6 +205,7 @@ npm run dev - OpenRouter - DeepSeek - SiliconFlow +- ModelScope - SGLang - Vercel AI Gateway @@ -237,6 +239,10 @@ npm run dev - 邮箱:me[at]jiang.jp +## 常见问题 + +请参阅 [FAQ](./FAQ.md) 了解常见问题和解决方案。 + ## Star历史 [![Star History Chart](https://api.star-history.com/svg?repos=DayuanJiang/next-ai-draw-io&type=date&legend=top-left)](https://www.star-history.com/#DayuanJiang/next-ai-draw-io&type=date&legend=top-left) diff --git a/docs/cn/ai-providers.md b/docs/cn/ai-providers.md index 25e5e31a..fe2de2af 100644 --- a/docs/cn/ai-providers.md +++ b/docs/cn/ai-providers.md @@ -152,6 +152,19 @@ AI_PROVIDER=ollama AI_MODEL=llama3.2 ``` +### ModelScope + +```bash +MODELSCOPE_API_KEY=your_api_key +AI_MODEL=Qwen/Qwen3-235B-A22B-Instruct-2507 +``` + +可选的自定义端点: + +```bash +MODELSCOPE_BASE_URL=https://your-custom-endpoint +``` + 可选的自定义 URL: ```bash diff --git a/docs/en/FAQ.md b/docs/en/FAQ.md new file mode 100644 index 00000000..69e48363 --- /dev/null +++ b/docs/en/FAQ.md @@ -0,0 +1,78 @@ +# Frequently Asked Questions (FAQ) + +--- + +## 1. Cannot Export PDF + +**Problem**: Web version redirects to `convert.diagrams.net/node/export` when exporting PDF, then nothing happens + +**Cause**: Embedded Draw.io doesn't support direct PDF export, it relies on external conversion service which doesn't work in iframe + +**Solution**: Export as image (PNG) first, then print to PDF + +**Related Issues**: #539, #125 + +--- + +## 2. Cannot Access embed.diagrams.net (Offline/Intranet Deployment) + +**Problem**: Intranet environment shows "Cannot find server IP address for embed.diagrams.net" + +**Key Point**: `NEXT_PUBLIC_*` environment variables are **build-time** variables, they get bundled into JS code. **Runtime settings don't work!** + +**Solution**: Must pass via `args` at build time: + +```yaml +# docker-compose.yml +services: + drawio: + image: jgraph/drawio:latest + ports: ["8080:8080"] + next-ai-draw-io: + build: + context: . + args: + - NEXT_PUBLIC_DRAWIO_BASE_URL=http://your-server-ip:8080/ + ports: ["3000:3000"] + env_file: .env +``` + +**Intranet Users**: Modify Dockerfile and build image on external network, then transfer to intranet + +**Related Issues**: #295, #317 + +--- + +## 3. Self-hosted Model Only Thinks But Doesn't Draw + +**Problem**: Locally deployed models (e.g., Qwen, LiteLLM) only output thinking process, don't generate diagrams + +**Possible Causes**: +1. **Model too small** - Small models struggle to follow tool calling instructions correctly, recommend 32B+ parameter models +2. **Tool calling not enabled** - Model service needs tool use configuration + +**Solution**: Enable tool calling, e.g., vLLM: +```bash +python -m vllm.entrypoints.openai.api_server \ + --model Qwen/Qwen3-32B \ + --enable-auto-tool-choice \ + --tool-call-parser hermes +``` + +**Related Issues**: #269, #75 + +--- + +## 4. "No Image Provided" After Uploading Image + +**Problem**: After uploading an image, the system shows "No image provided" error + +**Possible Causes**: +1. Model doesn't support vision (e.g., Kimi K2, DeepSeek, Qwen text models) + +**Solution**: +- Use vision-capable models: GPT-5.2, Claude 4.5 Sonnet, Gemini 3 Pro +- Models with `vision` or `vl` in name support images +- Update to latest version (v0.4.9+) + +**Related Issues**: #324, #421, #469 diff --git a/docs/en/ai-providers.md b/docs/en/ai-providers.md index 0f0b0d1e..0df82bf9 100644 --- a/docs/en/ai-providers.md +++ b/docs/en/ai-providers.md @@ -158,6 +158,19 @@ Optional custom URL: OLLAMA_BASE_URL=http://localhost:11434 ``` +### ModelScope + +```bash +MODELSCOPE_API_KEY=your_api_key +AI_MODEL=Qwen/Qwen3-235B-A22B-Instruct-2507 +``` + +Optional custom endpoint: + +```bash +MODELSCOPE_BASE_URL=https://your-custom-endpoint +``` + ### Vercel AI Gateway Vercel AI Gateway provides unified access to multiple AI providers through a single API key. This simplifies authentication and allows you to switch between providers without managing multiple API keys. @@ -201,7 +214,7 @@ If you only configure **one** provider's API key, the system will automatically If you configure **multiple** API keys, you must explicitly set `AI_PROVIDER`: ```bash -AI_PROVIDER=google # or: openai, anthropic, deepseek, siliconflow, doubao, azure, bedrock, openrouter, ollama, gateway, sglang +AI_PROVIDER=google # or: openai, anthropic, deepseek, siliconflow, doubao, azure, bedrock, openrouter, ollama, gateway, sglang, modelscope ``` ## Model Capability Requirements diff --git a/docs/ja/FAQ.md b/docs/ja/FAQ.md new file mode 100644 index 00000000..e9559d00 --- /dev/null +++ b/docs/ja/FAQ.md @@ -0,0 +1,78 @@ +# よくある質問 (FAQ) + +--- + +## 1. PDFをエクスポートできない + +**問題**: Web版でPDFエクスポートをクリックすると `convert.diagrams.net/node/export` にリダイレクトされ、その後何も起こらない + +**原因**: 埋め込みDraw.ioは直接PDFエクスポートをサポートしておらず、外部変換サービスに依存しているが、iframe内では正常に動作しない + +**解決策**: まず画像(PNG)としてエクスポートし、その後PDFに印刷する + +**関連Issue**: #539, #125 + +--- + +## 2. embed.diagrams.netにアクセスできない(オフライン/イントラネットデプロイ) + +**問題**: イントラネット環境で「embed.diagrams.netのサーバーIPアドレスが見つかりません」と表示される + +**重要**: `NEXT_PUBLIC_*` 環境変数は**ビルド時**変数であり、JSコードにバンドルされます。**実行時の設定は無効です!** + +**解決策**: ビルド時に `args` で渡す必要があります: + +```yaml +# docker-compose.yml +services: + drawio: + image: jgraph/drawio:latest + ports: ["8080:8080"] + next-ai-draw-io: + build: + context: . + args: + - NEXT_PUBLIC_DRAWIO_BASE_URL=http://あなたのサーバーIP:8080/ + ports: ["3000:3000"] + env_file: .env +``` + +**イントラネットユーザー**: 外部ネットワークでDockerfileを修正してイメージをビルドし、イントラネットに転送する + +**関連Issue**: #295, #317 + +--- + +## 3. 自前モデルが思考するだけで描画しない + +**問題**: ローカルデプロイのモデル(Qwen、LiteLLMなど)が思考過程のみを出力し、図表を生成しない + +**考えられる原因**: +1. **モデルが小さすぎる** - 小さいモデルはtool calling指示に正しく従うことが難しい、32B+パラメータのモデルを推奨 +2. **tool callingが有効になっていない** - モデルサービスでtool use機能を設定する必要がある + +**解決策**: tool callingを有効にする、例えばvLLM: +```bash +python -m vllm.entrypoints.openai.api_server \ + --model Qwen/Qwen3-32B \ + --enable-auto-tool-choice \ + --tool-call-parser hermes +``` + +**関連Issue**: #269, #75 + +--- + +## 4. 画像アップロード後「画像が提供されていません」と表示される + +**問題**: 画像をアップロードした後、「画像が提供されていません」というエラーが表示される + +**考えられる原因**: +1. モデルがビジョン機能をサポートしていない(Kimi K2、DeepSeek、Qwenテキストモデルなど) + +**解決策**: +- ビジョン対応モデルを使用:GPT-5.2、Claude 4.5 Sonnet、Gemini 3 Pro +- モデル名に `vision` または `vl` が含まれているものは画像をサポート +- 最新バージョン(v0.4.9+)にアップデート + +**関連Issue**: #324, #421, #469 diff --git a/docs/ja/README_JA.md b/docs/ja/README_JA.md index c5ae2a29..3018440c 100644 --- a/docs/ja/README_JA.md +++ b/docs/ja/README_JA.md @@ -37,11 +37,12 @@ https://github.com/user-attachments/assets/b2eef5f3-b335-4e71-a755-dc2e80931979 - [インストール](#インストール) - [デプロイ](#デプロイ) - [EdgeOne Pagesへのデプロイ](#edgeone-pagesへのデプロイ) - - [Vercelへのデプロイ(推奨)](#vercelへのデプロイ推奨) + - [Vercelへのデプロイ](#vercelへのデプロイ) - [Cloudflare Workersへのデプロイ](#cloudflare-workersへのデプロイ) - [マルチプロバイダーサポート](#マルチプロバイダーサポート) - [仕組み](#仕組み) - [サポート&お問い合わせ](#サポートお問い合わせ) + - [よくある質問](#よくある質問) - [スター履歴](#スター履歴) ## 例 @@ -180,7 +181,7 @@ npm run dev また、Tencent EdgeOne Pagesでデプロイすると、[DeepSeekモデルの毎日の無料クォータ](https://pages.edgeone.ai/document/edge-ai)が付与されます。 -### Vercelへのデプロイ(推奨) +### Vercelへのデプロイ [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2FDayuanJiang%2Fnext-ai-draw-io) @@ -205,6 +206,7 @@ Next.jsアプリをデプロイする最も簡単な方法は、Next.jsの作成 - OpenRouter - DeepSeek - SiliconFlow +- ModelScope - SGLang - Vercel AI Gateway @@ -238,6 +240,10 @@ AWS BedrockとOpenRouter以外のすべてのプロバイダーはカスタム - メール:me[at]jiang.jp +## よくある質問 + +一般的な問題と解決策については [FAQ](./FAQ.md) をご覧ください。 + ## スター履歴 [![Star History Chart](https://api.star-history.com/svg?repos=DayuanJiang/next-ai-draw-io&type=date&legend=top-left)](https://www.star-history.com/#DayuanJiang/next-ai-draw-io&type=date&legend=top-left) diff --git a/docs/ja/ai-providers.md b/docs/ja/ai-providers.md index 63d23d67..a7ad9311 100644 --- a/docs/ja/ai-providers.md +++ b/docs/ja/ai-providers.md @@ -158,6 +158,19 @@ AI_MODEL=llama3.2 OLLAMA_BASE_URL=http://localhost:11434 ``` +### ModelScope + +```bash +MODELSCOPE_API_KEY=your_api_key +AI_MODEL=Qwen/Qwen3-235B-A22B-Instruct-2507 +``` + +任意のカスタムエンドポイント: + +```bash +MODELSCOPE_BASE_URL=https://your-custom-endpoint +``` + ### Vercel AI Gateway Vercel AI Gateway は、単一の API キーで複数の AI プロバイダーへの統合アクセスを提供します。これにより認証が簡素化され、複数の API キーを管理することなくプロバイダーを切り替えることができます。 diff --git a/edge-functions/api/edgeai/chat/completions.ts b/edge-functions/api/edgeai/chat/completions.ts index fd62f80b..eafd4de1 100644 --- a/edge-functions/api/edgeai/chat/completions.ts +++ b/edge-functions/api/edgeai/chat/completions.ts @@ -99,7 +99,7 @@ function handleOptionsRequest(): Response { }) } -export async function onRequest({ request, env }: any) { +export async function onRequest({ request, env: _env }: any) { if (request.method === "OPTIONS") { return handleOptionsRequest() } diff --git a/electron/electron.d.ts b/electron/electron.d.ts index a629e9b0..7a219e88 100644 --- a/electron/electron.d.ts +++ b/electron/electron.d.ts @@ -25,6 +25,19 @@ interface ApplyPresetResult { env?: Record } +/** Proxy configuration interface */ +interface ProxyConfig { + httpProxy?: string + httpsProxy?: string +} + +/** Result of setting proxy */ +interface SetProxyResult { + success: boolean + error?: string + devMode?: boolean +} + declare global { interface Window { /** Main window Electron API */ @@ -45,6 +58,10 @@ declare global { openFile: () => Promise /** Save data to file via save dialog */ saveFile: (data: string) => Promise + /** Get proxy configuration */ + getProxy: () => Promise + /** Set proxy configuration (saves and restarts server) */ + setProxy: (config: ProxyConfig) => Promise } /** Settings window Electron API */ @@ -71,4 +88,4 @@ declare global { } } -export { ConfigPreset, ApplyPresetResult } +export { ConfigPreset, ApplyPresetResult, ProxyConfig, SetProxyResult } diff --git a/electron/main/config-manager.ts b/electron/main/config-manager.ts index 2a66d358..b1489e08 100644 --- a/electron/main/config-manager.ts +++ b/electron/main/config-manager.ts @@ -351,6 +351,10 @@ const PROVIDER_ENV_MAP: Record = { apiKey: "SILICONFLOW_API_KEY", baseUrl: "SILICONFLOW_BASE_URL", }, + modelscope: { + apiKey: "MODELSCOPE_API_KEY", + baseUrl: "MODELSCOPE_BASE_URL", + }, gateway: { apiKey: "AI_GATEWAY_API_KEY", baseUrl: "AI_GATEWAY_BASE_URL" }, // bedrock and ollama don't use API keys in the same way bedrock: { apiKey: "", baseUrl: "" }, diff --git a/electron/main/index.ts b/electron/main/index.ts index 60254def..7c29146c 100644 --- a/electron/main/index.ts +++ b/electron/main/index.ts @@ -4,6 +4,7 @@ import { getCurrentPresetEnv } from "./config-manager" import { loadEnvFile } from "./env-loader" import { registerIpcHandlers } from "./ipc-handlers" import { startNextServer, stopNextServer } from "./next-server" +import { applyProxyToEnv } from "./proxy-manager" import { registerSettingsWindowHandlers } from "./settings-window" import { createWindow, getMainWindow } from "./window-manager" @@ -24,6 +25,9 @@ if (!gotTheLock) { // Load environment variables from .env files loadEnvFile() + // Apply proxy settings from saved config + applyProxyToEnv() + // Apply saved preset environment variables (overrides .env) const presetEnv = getCurrentPresetEnv() for (const [key, value] of Object.entries(presetEnv)) { diff --git a/electron/main/ipc-handlers.ts b/electron/main/ipc-handlers.ts index 7e801d1c..dc4bc966 100644 --- a/electron/main/ipc-handlers.ts +++ b/electron/main/ipc-handlers.ts @@ -11,6 +11,12 @@ import { updatePreset, } from "./config-manager" import { restartNextServer } from "./next-server" +import { + applyProxyToEnv, + getProxyConfig, + type ProxyConfig, + saveProxyConfig, +} from "./proxy-manager" /** * Allowed configuration keys for presets @@ -209,4 +215,40 @@ export function registerIpcHandlers(): void { return setCurrentPreset(id) }, ) + + // ==================== Proxy Settings ==================== + + ipcMain.handle("get-proxy", () => { + return getProxyConfig() + }) + + ipcMain.handle("set-proxy", async (_event, config: ProxyConfig) => { + try { + // Save config to file + saveProxyConfig(config) + + // Apply to current process environment + applyProxyToEnv() + + const isDev = process.env.NODE_ENV === "development" + + if (isDev) { + // In development, env vars are already applied + // Next.js dev server may need manual restart + return { success: true, devMode: true } + } + + // Production: restart Next.js server to pick up new env vars + await restartNextServer() + return { success: true } + } catch (error) { + return { + success: false, + error: + error instanceof Error + ? error.message + : "Failed to apply proxy settings", + } + } + }) } diff --git a/electron/main/next-server.ts b/electron/main/next-server.ts index fce07ec2..c6dd7df4 100644 --- a/electron/main/next-server.ts +++ b/electron/main/next-server.ts @@ -69,6 +69,8 @@ export async function startNextServer(): Promise { NODE_ENV: "production", PORT: String(port), HOSTNAME: "localhost", + // Enable Node.js built-in proxy support for fetch (Node.js 24+) + NODE_USE_ENV_PROXY: "1", } // Set cache directory to a writable location (user's app data folder) @@ -85,6 +87,13 @@ export async function startNextServer(): Promise { } } + // Debug: log proxy-related env vars + console.log("Proxy env vars being passed to server:", { + HTTP_PROXY: env.HTTP_PROXY || env.http_proxy || "not set", + HTTPS_PROXY: env.HTTPS_PROXY || env.https_proxy || "not set", + NODE_USE_ENV_PROXY: env.NODE_USE_ENV_PROXY || "not set", + }) + // Use Electron's utilityProcess API for running Node.js in background // This is the recommended way to run Node.js code in Electron serverProcess = utilityProcess.fork(serverPath, [], { @@ -114,13 +123,41 @@ export async function startNextServer(): Promise { } /** - * Stop the Next.js server process + * Stop the Next.js server process and wait for it to exit */ -export function stopNextServer(): void { +export async function stopNextServer(): Promise { if (serverProcess) { console.log("Stopping Next.js server...") + + // Create a promise that resolves when the process exits + const exitPromise = new Promise((resolve) => { + const proc = serverProcess + if (!proc) { + resolve() + return + } + + const onExit = () => { + resolve() + } + + proc.once("exit", onExit) + + // Timeout after 5 seconds + setTimeout(() => { + proc.removeListener("exit", onExit) + resolve() + }, 5000) + }) + serverProcess.kill() serverProcess = null + + // Wait for process to exit + await exitPromise + + // Additional wait for OS to release port + await new Promise((resolve) => setTimeout(resolve, 500)) } } @@ -150,8 +187,8 @@ async function waitForServerStop(timeout = 5000): Promise { export async function restartNextServer(): Promise { console.log("Restarting Next.js server...") - // Stop the current server - stopNextServer() + // Stop the current server and wait for it to exit + await stopNextServer() // Wait for the port to be released await waitForServerStop() diff --git a/electron/main/proxy-manager.ts b/electron/main/proxy-manager.ts new file mode 100644 index 00000000..cb41de56 --- /dev/null +++ b/electron/main/proxy-manager.ts @@ -0,0 +1,75 @@ +import { app } from "electron" +import * as fs from "fs" +import * as path from "path" +import type { ProxyConfig } from "../electron.d" + +export type { ProxyConfig } + +const CONFIG_FILE = "proxy-config.json" + +function getConfigPath(): string { + return path.join(app.getPath("userData"), CONFIG_FILE) +} + +/** + * Load proxy configuration from JSON file + */ +export function loadProxyConfig(): ProxyConfig { + try { + const configPath = getConfigPath() + if (fs.existsSync(configPath)) { + const data = fs.readFileSync(configPath, "utf-8") + return JSON.parse(data) as ProxyConfig + } + } catch (error) { + console.error("Failed to load proxy config:", error) + } + return {} +} + +/** + * Save proxy configuration to JSON file + */ +export function saveProxyConfig(config: ProxyConfig): void { + try { + const configPath = getConfigPath() + fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8") + } catch (error) { + console.error("Failed to save proxy config:", error) + throw error + } +} + +/** + * Apply proxy configuration to process.env + * Must be called BEFORE starting the Next.js server + */ +export function applyProxyToEnv(): void { + const config = loadProxyConfig() + + if (config.httpProxy) { + process.env.HTTP_PROXY = config.httpProxy + process.env.http_proxy = config.httpProxy + } else { + delete process.env.HTTP_PROXY + delete process.env.http_proxy + } + + if (config.httpsProxy) { + process.env.HTTPS_PROXY = config.httpsProxy + process.env.https_proxy = config.httpsProxy + } else { + delete process.env.HTTPS_PROXY + delete process.env.https_proxy + } +} + +/** + * Get current proxy configuration (from process.env) + */ +export function getProxyConfig(): ProxyConfig { + return { + httpProxy: process.env.HTTP_PROXY || process.env.http_proxy || "", + httpsProxy: process.env.HTTPS_PROXY || process.env.https_proxy || "", + } +} diff --git a/electron/preload/index.ts b/electron/preload/index.ts index 2b460c75..7cbef9c6 100644 --- a/electron/preload/index.ts +++ b/electron/preload/index.ts @@ -21,4 +21,9 @@ contextBridge.exposeInMainWorld("electronAPI", { // File operations openFile: () => ipcRenderer.invoke("dialog-open-file"), saveFile: (data: string) => ipcRenderer.invoke("dialog-save-file", data), + + // Proxy settings + getProxy: () => ipcRenderer.invoke("get-proxy"), + setProxy: (config: { httpProxy?: string; httpsProxy?: string }) => + ipcRenderer.invoke("set-proxy", config), }) diff --git a/electron/settings/index.html b/electron/settings/index.html index 81ad8ffd..9f5fed1a 100644 --- a/electron/settings/index.html +++ b/electron/settings/index.html @@ -55,6 +55,7 @@ +
    diff --git a/electron/settings/settings.js b/electron/settings/settings.js index 3e550c91..235b2fe5 100644 --- a/electron/settings/settings.js +++ b/electron/settings/settings.js @@ -288,6 +288,7 @@ function getProviderLabel(provider) { openrouter: "OpenRouter", deepseek: "DeepSeek", siliconflow: "SiliconFlow", + modelscope: "ModelScope", ollama: "Ollama", } return labels[provider] || provider diff --git a/env.example b/env.example index a1b5269a..fcd63f08 100644 --- a/env.example +++ b/env.example @@ -72,6 +72,10 @@ AI_MODEL=global.anthropic.claude-sonnet-4-5-20250929-v1:0 # SGLANG_API_KEY=your-sglang-api-key # SGLANG_BASE_URL=http://127.0.0.1:8000/v1 # Your SGLang endpoint +# ModelScope Configuration +# MODELSCOPE_API_KEY=ms-... +# MODELSCOPE_BASE_URL=https://api-inference.modelscope.cn/v1 # Optional: Custom endpoint + # ByteDance Doubao Configuration (via Volcengine) # DOUBAO_API_KEY=your-doubao-api-key # DOUBAO_BASE_URL=https://ark.cn-beijing.volces.com/api/v3 # ByteDance Volcengine endpoint diff --git a/hooks/use-diagram-tool-handlers.ts b/hooks/use-diagram-tool-handlers.ts index 0e4c7bbc..0636f005 100644 --- a/hooks/use-diagram-tool-handlers.ts +++ b/hooks/use-diagram-tool-handlers.ts @@ -1,4 +1,5 @@ import type { MutableRefObject } from "react" +import type { DiagramOperation } from "@/components/chat/types" import { isMxCellXmlComplete, wrapWithMxFile } from "@/lib/utils" const DEBUG = process.env.NODE_ENV === "development" @@ -29,12 +30,6 @@ type AddToolOutputParams = AddToolOutputSuccess | AddToolOutputError type AddToolOutputFn = (params: AddToolOutputParams) => void -interface DiagramOperation { - operation: "update" | "add" | "delete" - cell_id: string - new_xml?: string -} - interface UseDiagramToolHandlersParams { partialXmlRef: MutableRefObject editDiagramOriginalXmlRef: MutableRefObject> diff --git a/lib/ai-config.ts b/lib/ai-config.ts deleted file mode 100644 index 128d830f..00000000 --- a/lib/ai-config.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { STORAGE_KEYS } from "./storage" - -/** - * Get AI configuration from localStorage. - * Returns API keys and settings for custom AI providers. - * Used to override server defaults when user provides their own API key. - */ -export function getAIConfig() { - if (typeof window === "undefined") { - return { - accessCode: "", - aiProvider: "", - aiBaseUrl: "", - aiApiKey: "", - aiModel: "", - } - } - - return { - accessCode: localStorage.getItem(STORAGE_KEYS.accessCode) || "", - aiProvider: localStorage.getItem(STORAGE_KEYS.aiProvider) || "", - aiBaseUrl: localStorage.getItem(STORAGE_KEYS.aiBaseUrl) || "", - aiApiKey: localStorage.getItem(STORAGE_KEYS.aiApiKey) || "", - aiModel: localStorage.getItem(STORAGE_KEYS.aiModel) || "", - } -} diff --git a/lib/ai-providers.ts b/lib/ai-providers.ts index 8e27be60..918dafe5 100644 --- a/lib/ai-providers.ts +++ b/lib/ai-providers.ts @@ -8,21 +8,9 @@ import { createOpenAI, openai } from "@ai-sdk/openai" import { fromNodeProviderChain } from "@aws-sdk/credential-providers" import { createOpenRouter } from "@openrouter/ai-sdk-provider" import { createOllama, ollama } from "ollama-ai-provider-v2" +import type { ProviderName } from "@/lib/types/model-config" -export type ProviderName = - | "bedrock" - | "openai" - | "anthropic" - | "google" - | "azure" - | "ollama" - | "openrouter" - | "deepseek" - | "siliconflow" - | "sglang" - | "gateway" - | "edgeone" - | "doubao" +export type { ProviderName } interface ModelConfig { model: any @@ -59,6 +47,7 @@ const ALLOWED_CLIENT_PROVIDERS: ProviderName[] = [ "gateway", "edgeone", "doubao", + "modelscope", ] // Bedrock provider options for Anthropic beta features @@ -353,6 +342,7 @@ function buildProviderOptions( case "siliconflow": case "sglang": case "gateway": + case "modelscope": case "doubao": { // These providers don't have reasoning configs in AI SDK yet // Gateway passes through to underlying providers which handle their own configs @@ -381,6 +371,7 @@ const PROVIDER_ENV_VARS: Record = { gateway: "AI_GATEWAY_API_KEY", edgeone: null, // No credentials needed - uses EdgeOne Edge AI doubao: "DOUBAO_API_KEY", + modelscope: "MODELSCOPE_API_KEY", } /** @@ -445,7 +436,7 @@ function validateProviderCredentials(provider: ProviderName): void { * Get the AI model based on environment variables * * Environment variables: - * - AI_PROVIDER: The provider to use (bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway) + * - AI_PROVIDER: The provider to use (bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway, modelscope) * - AI_MODEL: The model ID/name for the selected provider * * Provider-specific env vars: @@ -460,9 +451,11 @@ function validateProviderCredentials(provider: ProviderName): void { * - DEEPSEEK_API_KEY: DeepSeek API key * - DEEPSEEK_BASE_URL: DeepSeek endpoint (optional) * - SILICONFLOW_API_KEY: SiliconFlow API key - * - SILICONFLOW_BASE_URL: SiliconFlow endpoint (optional, defaults to https://api.siliconflow.com/v1) + * - SILICONFLOW_BASE_URL: SiliconFlow endpoint (optional, defaults to https://api.siliconflow.cn/v1) * - SGLANG_API_KEY: SGLang API key * - SGLANG_BASE_URL: SGLang endpoint (optional) + * - MODELSCOPE_API_KEY: ModelScope API key + * - MODELSCOPE_BASE_URL: ModelScope endpoint (optional) */ export function getAIModel(overrides?: ClientOverrides): ModelConfig { // SECURITY: Prevent SSRF attacks (GHSA-9qf7-mprq-9qgm) @@ -537,6 +530,7 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { `- AZURE_API_KEY for Azure\n` + `- SILICONFLOW_API_KEY for SiliconFlow\n` + `- SGLANG_API_KEY for SGLang\n` + + `- MODELSCOPE_API_KEY for ModelScope\n` + `Or set AI_PROVIDER=ollama for local Ollama.`, ) } else { @@ -573,8 +567,8 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { const bedrockProvider = hasClientCredentials ? createAmazonBedrock({ region: bedrockRegion, - accessKeyId: overrides.awsAccessKeyId!, - secretAccessKey: overrides.awsSecretAccessKey!, + accessKeyId: overrides.awsAccessKeyId as string, + secretAccessKey: overrides.awsSecretAccessKey as string, ...(overrides?.awsSessionToken && { sessionToken: overrides.awsSessionToken, }), @@ -714,7 +708,7 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { const baseURL = overrides?.baseUrl || process.env.SILICONFLOW_BASE_URL || - "https://api.siliconflow.com/v1" + "https://api.siliconflow.cn/v1" const siliconflowProvider = createOpenAI({ apiKey, baseURL, @@ -871,17 +865,44 @@ export function getAIModel(overrides?: ClientOverrides): ModelConfig { overrides?.baseUrl || process.env.DOUBAO_BASE_URL || "https://ark.cn-beijing.volces.com/api/v3" - const doubaoProvider = createDeepSeek({ + const lowerModelId = modelId.toLowerCase() + // Use DeepSeek provider for DeepSeek/Kimi models, OpenAI for others (multimodal support) + if ( + lowerModelId.includes("deepseek") || + lowerModelId.includes("kimi") + ) { + const doubaoProvider = createDeepSeek({ + apiKey, + baseURL, + }) + model = doubaoProvider(modelId) + } else { + const doubaoProvider = createOpenAI({ + apiKey, + baseURL, + }) + model = doubaoProvider.chat(modelId) + } + break + } + + case "modelscope": { + const apiKey = overrides?.apiKey || process.env.MODELSCOPE_API_KEY + const baseURL = + overrides?.baseUrl || + process.env.MODELSCOPE_BASE_URL || + "https://api-inference.modelscope.cn/v1" + const modelscopeProvider = createOpenAI({ apiKey, baseURL, }) - model = doubaoProvider(modelId) + model = modelscopeProvider.chat(modelId) break } default: throw new Error( - `Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway, edgeone, doubao`, + `Unknown AI provider: ${provider}. Supported providers: bedrock, openai, anthropic, google, azure, ollama, openrouter, deepseek, siliconflow, sglang, gateway, edgeone, doubao, modelscope`, ) } diff --git a/lib/chat-helpers.ts b/lib/chat-helpers.ts new file mode 100644 index 00000000..e9c054f1 --- /dev/null +++ b/lib/chat-helpers.ts @@ -0,0 +1,89 @@ +// Shared helper functions for chat route +// Exported for testing + +// File upload limits (must match client-side) +export const MAX_FILE_SIZE = 2 * 1024 * 1024 // 2MB +export const MAX_FILES = 5 + +// Helper function to validate file parts in messages +export function validateFileParts(messages: any[]): { + valid: boolean + error?: string +} { + const lastMessage = messages[messages.length - 1] + const fileParts = + lastMessage?.parts?.filter((p: any) => p.type === "file") || [] + + if (fileParts.length > MAX_FILES) { + return { + valid: false, + error: `Too many files. Maximum ${MAX_FILES} allowed.`, + } + } + + for (const filePart of fileParts) { + // Data URLs format: data:image/png;base64, + // Base64 increases size by ~33%, so we check the decoded size + if (filePart.url?.startsWith("data:")) { + const base64Data = filePart.url.split(",")[1] + if (base64Data) { + const sizeInBytes = Math.ceil((base64Data.length * 3) / 4) + if (sizeInBytes > MAX_FILE_SIZE) { + return { + valid: false, + error: `File exceeds ${MAX_FILE_SIZE / 1024 / 1024}MB limit.`, + } + } + } + } + } + + return { valid: true } +} + +// Helper function to check if diagram is minimal/empty +export function isMinimalDiagram(xml: string): boolean { + const stripped = xml.replace(/\s/g, "") + return !stripped.includes('id="2"') +} + +// Helper function to replace historical tool call XML with placeholders +// This reduces token usage and forces LLM to rely on the current diagram XML (source of truth) +// Also fixes invalid/undefined inputs from interrupted streaming +export function replaceHistoricalToolInputs(messages: any[]): any[] { + return messages.map((msg) => { + if (msg.role !== "assistant" || !Array.isArray(msg.content)) { + return msg + } + const replacedContent = msg.content + .map((part: any) => { + if (part.type === "tool-call") { + const toolName = part.toolName + // Fix invalid/undefined inputs from interrupted streaming + if ( + !part.input || + typeof part.input !== "object" || + Object.keys(part.input).length === 0 + ) { + // Skip tool calls with invalid inputs entirely + return null + } + if ( + toolName === "display_diagram" || + toolName === "edit_diagram" + ) { + return { + ...part, + input: { + placeholder: + "[XML content replaced - see current diagram XML in system context]", + }, + } + } + } + return part + }) + .filter(Boolean) // Remove null entries (invalid tool calls) + return { ...msg, content: replacedContent } + }) +} diff --git a/lib/i18n/dictionaries/en.json b/lib/i18n/dictionaries/en.json index bce3ef25..923e4ce1 100644 --- a/lib/i18n/dictionaries/en.json +++ b/lib/i18n/dictionaries/en.json @@ -28,7 +28,8 @@ "azure": "Azure OpenAI", "openrouter": "OpenRouter", "deepseek": "DeepSeek", - "siliconflow": "SiliconFlow" + "siliconflow": "SiliconFlow", + "modelscope": "ModelScope" }, "chat": { "placeholder": "Describe your diagram or upload a file...", @@ -51,7 +52,8 @@ "badResponse": "Bad response", "clickToEdit": "Click to edit", "editMessage": "Edit message", - "saveAndSubmit": "Save & Submit" + "saveAndSubmit": "Save & Submit", + "ExtractURL": "Extract from URL" }, "examples": { "title": "Create diagrams with AI", @@ -106,10 +108,20 @@ "closeProtectionDescription": "Show confirmation when leaving the page.", "diagramStyle": "Diagram Style", "diagramStyleDescription": "Toggle between minimal and styled diagram output.", + "sendShortcut": "Send Shortcut", + "sendShortcutDescription": "Choose how to send messages.", + "enterToSend": "Enter to send", + "ctrlEnterToSend": "Cmd/Ctrl+Enter to send", "diagramActions": "Diagram Actions", "diagramActionsDescription": "Manage diagram history and exports", "history": "History", - "download": "Download" + "download": "Download", + "proxy": "Proxy Settings", + "proxyDescription": "Configure HTTP/HTTPS proxy for API requests (Desktop only)", + "httpProxy": "HTTP Proxy", + "httpsProxy": "HTTPS Proxy", + "applyProxy": "Apply", + "proxyApplied": "Proxy settings applied" }, "save": { "title": "Save Diagram", @@ -190,6 +202,15 @@ "chars": "chars", "removeFile": "Remove file" }, + "url": { + "title": "Extract Content from URL", + "description": "Paste a URL to extract and analyze its content", + "Extracting": "Extracting...", + "extract": "Extract", + "Cancel": "Cancel", + "enterUrl": "Please enter a URL", + "invalidFormat": "Invalid URL format" + }, "reasoning": { "thinking": "Thinking...", "thoughtFor": "Thought for {duration} seconds", diff --git a/lib/i18n/dictionaries/ja.json b/lib/i18n/dictionaries/ja.json index 59750d6a..78b47b1a 100644 --- a/lib/i18n/dictionaries/ja.json +++ b/lib/i18n/dictionaries/ja.json @@ -28,7 +28,8 @@ "azure": "Azure OpenAI", "openrouter": "OpenRouter", "deepseek": "DeepSeek", - "siliconflow": "SiliconFlow" + "siliconflow": "SiliconFlow", + "modelscope": "ModelScope" }, "chat": { "placeholder": "ダイアグラムを説明するか、ファイルをアップロード...", @@ -51,7 +52,8 @@ "badResponse": "悪い応答", "clickToEdit": "クリックして編集", "editMessage": "メッセージを編集", - "saveAndSubmit": "保存して送信" + "saveAndSubmit": "保存して送信", + "ExtractURL": "URLから抽出" }, "examples": { "title": "AI でダイアグラムを作成", @@ -106,10 +108,20 @@ "closeProtectionDescription": "ページを離れる際に確認を表示します。", "diagramStyle": "ダイアグラムスタイル", "diagramStyleDescription": "ミニマルとスタイル付きの出力を切り替えます。", + "sendShortcut": "送信ショートカット", + "sendShortcutDescription": "メッセージの送信方法を選択します。", + "enterToSend": "Enterで送信", + "ctrlEnterToSend": "Cmd/Ctrl+Enterで送信", "diagramActions": "ダイアグラム操作", "diagramActionsDescription": "ダイアグラムの履歴とエクスポートを管理", "history": "履歴", - "download": "ダウンロード" + "download": "ダウンロード", + "proxy": "プロキシ設定", + "proxyDescription": "API リクエスト用の HTTP/HTTPS プロキシを設定(デスクトップ版のみ)", + "httpProxy": "HTTP プロキシ", + "httpsProxy": "HTTPS プロキシ", + "applyProxy": "適用", + "proxyApplied": "プロキシ設定が適用されました" }, "save": { "title": "ダイアグラムを保存", @@ -190,6 +202,15 @@ "chars": "文字", "removeFile": "ファイルを削除" }, + "url": { + "title": "URLからコンテンツを抽出", + "description": "URLを貼り付けてそのコンテンツを抽出および分析します", + "Extracting": "抽出中...", + "extract": "抽出", + "Cancel": "キャンセル", + "enterUrl": "URLを入力してください", + "invalidFormat": "無効なURL形式です" + }, "reasoning": { "thinking": "考え中...", "thoughtFor": "{duration} 秒考えました", diff --git a/lib/i18n/dictionaries/zh.json b/lib/i18n/dictionaries/zh.json index 98a111a2..0749e5be 100644 --- a/lib/i18n/dictionaries/zh.json +++ b/lib/i18n/dictionaries/zh.json @@ -28,7 +28,8 @@ "azure": "Azure OpenAI", "openrouter": "OpenRouter", "deepseek": "DeepSeek", - "siliconflow": "SiliconFlow" + "siliconflow": "SiliconFlow", + "modelscope": "ModelScope" }, "chat": { "placeholder": "描述您的图表或上传文件...", @@ -51,7 +52,8 @@ "badResponse": "无帮助", "clickToEdit": "点击编辑", "editMessage": "编辑消息", - "saveAndSubmit": "保存并提交" + "saveAndSubmit": "保存并提交", + "ExtractURL": "从 URL 提取" }, "examples": { "title": "用 AI 创建图表", @@ -106,10 +108,20 @@ "closeProtectionDescription": "离开页面时显示确认。", "diagramStyle": "图表样式", "diagramStyleDescription": "切换简约与精致图表输出模式。", + "sendShortcut": "发送快捷键", + "sendShortcutDescription": "选择发送消息的方式。", + "enterToSend": "回车发送", + "ctrlEnterToSend": "Cmd/Ctrl+回车发送", "diagramActions": "图表操作", "diagramActionsDescription": "管理图表历史记录和导出", "history": "历史记录", - "download": "下载" + "download": "下载", + "proxy": "代理设置", + "proxyDescription": "配置 API 请求的 HTTP/HTTPS 代理(仅桌面版)", + "httpProxy": "HTTP 代理", + "httpsProxy": "HTTPS 代理", + "applyProxy": "应用", + "proxyApplied": "代理设置已应用" }, "save": { "title": "保存图表", @@ -190,6 +202,15 @@ "chars": "字符", "removeFile": "移除文件" }, + "url": { + "title": "从 URL 提取内容", + "description": "粘贴 URL 以提取和分析其内容", + "Extracting": "提取中...", + "extract": "提取", + "Cancel": "取消", + "enterUrl": "请输入 URL", + "invalidFormat": "URL 格式无效" + }, "reasoning": { "thinking": "思考中...", "thoughtFor": "思考了 {duration} 秒", diff --git a/lib/storage.ts b/lib/storage.ts index f64d1ddf..57974e9e 100644 --- a/lib/storage.ts +++ b/lib/storage.ts @@ -12,7 +12,6 @@ export const STORAGE_KEYS = { // Settings accessCode: "next-ai-draw-io-access-code", - closeProtection: "next-ai-draw-io-close-protection", accessCodeRequired: "next-ai-draw-io-access-code-required", aiProvider: "next-ai-draw-io-ai-provider", aiBaseUrl: "next-ai-draw-io-ai-base-url", @@ -22,4 +21,7 @@ export const STORAGE_KEYS = { // Multi-model configuration modelConfigs: "next-ai-draw-io-model-configs", selectedModelId: "next-ai-draw-io-selected-model-id", + + // Chat input preferences + sendShortcut: "next-ai-draw-io-send-shortcut", } as const diff --git a/lib/token-counter.ts b/lib/token-counter.ts deleted file mode 100644 index 1f9b006f..00000000 --- a/lib/token-counter.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Token counting utilities using js-tiktoken - * - * Uses cl100k_base encoding (GPT-4) which is close to Claude's tokenization. - * This is a pure JavaScript implementation, no WASM required. - */ - -import { encodingForModel } from "js-tiktoken" -import { DEFAULT_SYSTEM_PROMPT, EXTENDED_SYSTEM_PROMPT } from "./system-prompts" - -const encoder = encodingForModel("gpt-4o") - -/** - * Count the number of tokens in a text string - * @param text - The text to count tokens for - * @returns The number of tokens - */ -export function countTextTokens(text: string): number { - return encoder.encode(text).length -} - -/** - * Get token counts for the system prompts - * Useful for debugging and optimizing prompt sizes - * @returns Object with token counts for default and extended prompts - */ -export function getSystemPromptTokenCounts(): { - default: number - extended: number - additions: number -} { - const defaultTokens = countTextTokens(DEFAULT_SYSTEM_PROMPT) - const extendedTokens = countTextTokens(EXTENDED_SYSTEM_PROMPT) - return { - default: defaultTokens, - extended: extendedTokens, - additions: extendedTokens - defaultTokens, - } -} diff --git a/lib/types/model-config.ts b/lib/types/model-config.ts index 6ea73da3..edb66822 100644 --- a/lib/types/model-config.ts +++ b/lib/types/model-config.ts @@ -6,6 +6,7 @@ export type ProviderName = | "google" | "azure" | "bedrock" + | "ollama" | "openrouter" | "deepseek" | "siliconflow" @@ -13,6 +14,7 @@ export type ProviderName = | "gateway" | "edgeone" | "doubao" + | "modelscope" // Individual model configuration export interface ModelConfig { @@ -75,11 +77,15 @@ export const PROVIDER_INFO: Record< google: { label: "Google" }, azure: { label: "Azure OpenAI" }, bedrock: { label: "Amazon Bedrock" }, + ollama: { + label: "Ollama", + defaultBaseUrl: "http://localhost:11434", + }, openrouter: { label: "OpenRouter" }, deepseek: { label: "DeepSeek" }, siliconflow: { label: "SiliconFlow", - defaultBaseUrl: "https://api.siliconflow.com/v1", + defaultBaseUrl: "https://api.siliconflow.cn/v1", }, sglang: { label: "SGLang", @@ -91,10 +97,14 @@ export const PROVIDER_INFO: Record< label: "Doubao (ByteDance)", defaultBaseUrl: "https://ark.cn-beijing.volces.com/api/v3", }, + modelscope: { + label: "ModelScope", + defaultBaseUrl: "https://api-inference.modelscope.cn/v1", + }, } // Suggested models per provider for quick add -export const SUGGESTED_MODELS: Record = { +export const SUGGESTED_MODELS: Partial> = { openai: [ "gpt-5.2-pro", "gpt-5.2-chat-latest", @@ -231,6 +241,17 @@ export const SUGGESTED_MODELS: Record = { "doubao-pro-32k-241215", "doubao-pro-256k-241215", ], + modelscope: [ + // Qwen + "Qwen/Qwen2.5-72B-Instruct", + "Qwen/Qwen2.5-32B-Instruct", + "Qwen/Qwen3-235B-A22B-Instruct-2507", + "Qwen/Qwen3-VL-235B-A22B-Instruct", + "Qwen/Qwen3-32B", + // DeepSeek + "deepseek-ai/DeepSeek-R1-0528", + "deepseek-ai/DeepSeek-V3.2", + ], } // Helper to generate UUID diff --git a/lib/url-utils.ts b/lib/url-utils.ts new file mode 100644 index 00000000..85f83bc3 --- /dev/null +++ b/lib/url-utils.ts @@ -0,0 +1,49 @@ +import { z } from "zod" + +export interface UrlData { + url: string + title: string + content: string + charCount: number + isExtracting: boolean +} + +const UrlResponseSchema = z.object({ + title: z.string().default("Untitled"), + content: z.string(), + charCount: z.number().int().nonnegative(), +}) + +export async function extractUrlContent(url: string): Promise { + const response = await fetch("/api/parse-url", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ url }), + }) + + // Try to parse JSON once + const raw = await response + .json() + .catch(() => ({ error: "Unexpected non-JSON response" })) + + if (!response.ok) { + const message = + typeof raw === "object" && raw && "error" in raw + ? String((raw as any).error) + : "Failed to extract URL content" + throw new Error(message) + } + + const parsed = UrlResponseSchema.safeParse(raw) + if (!parsed.success) { + throw new Error("Malformed response from URL extraction API") + } + + return { + url, + title: parsed.data.title, + content: parsed.data.content, + charCount: parsed.data.charCount, + isExtracting: false, + } +} diff --git a/lib/utils.ts b/lib/utils.ts index 4c643998..2c1f8b43 100644 --- a/lib/utils.ts +++ b/lib/utils.ts @@ -1,6 +1,9 @@ import { type ClassValue, clsx } from "clsx" import * as pako from "pako" import { twMerge } from "tailwind-merge" +import type { DiagramOperation } from "@/components/chat/types" + +export type { DiagramOperation } export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) @@ -473,12 +476,6 @@ export function replaceNodes(currentXML: string, nodes: string): string { // ID-based Diagram Operations // ============================================================================ -export interface DiagramOperation { - operation: "update" | "add" | "delete" - cell_id: string - new_xml?: string -} - export interface OperationError { type: "update" | "add" | "delete" cellId: string diff --git a/package-lock.json b/package-lock.json index c2ff5d82..f3cc9e05 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "next-ai-draw-io", - "version": "0.4.8", + "version": "0.4.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "next-ai-draw-io", - "version": "0.4.8", + "version": "0.4.10", "license": "Apache-2.0", "dependencies": { "@ai-sdk/amazon-bedrock": "^4.0.1", @@ -19,14 +19,15 @@ "@ai-sdk/react": "^3.0.1", "@aws-sdk/client-dynamodb": "^3.957.0", "@aws-sdk/credential-providers": "^3.943.0", + "@extractus/article-extractor": "^8.0.18", "@formatjs/intl-localematcher": "^0.7.2", "@langfuse/client": "^4.4.9", "@langfuse/otel": "^4.4.4", "@langfuse/tracing": "^4.4.9", "@next/third-parties": "^16.0.6", - "@opennextjs/cloudflare": "1.14.7", + "@opennextjs/cloudflare": "1.14.8", "@openrouter/ai-sdk-provider": "^1.5.4", - "@opentelemetry/exporter-trace-otlp-http": "^0.208.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.209.0", "@opentelemetry/sdk-trace-node": "^2.2.0", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-collapsible": "^1.1.12", @@ -46,11 +47,10 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "idb": "^8.0.3", - "js-tiktoken": "^1.0.21", - "jsdom": "^27.0.0", "jsonrepair": "^3.13.1", "lucide-react": "^0.562.0", "motion": "^12.23.25", + "nanoid": "^5.0.0", "negotiator": "^1.0.0", "next": "^16.0.7", "ollama-ai-provider-v2": "^2.0.0", @@ -67,19 +67,27 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", + "turndown": "^7.2.0", "unpdf": "^1.4.0", "zod": "^4.1.12" }, "devDependencies": { "@anthropic-ai/tokenizer": "^0.0.4", "@biomejs/biome": "^2.3.10", + "@playwright/test": "^1.57.0", "@tailwindcss/postcss": "^4", "@tailwindcss/typography": "^0.5.19", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.1", + "@testing-library/user-event": "^14.6.1", "@types/negotiator": "^0.6.4", "@types/node": "^24.0.0", "@types/pako": "^2.0.3", "@types/react": "^19", "@types/react-dom": "^19", + "@types/turndown": "^5.0.6", + "@vitejs/plugin-react": "^5.1.2", + "@vitest/coverage-v8": "^4.0.16", "concurrently": "^9.2.1", "cross-env": "^10.1.0", "electron": "^39.2.7", @@ -88,12 +96,15 @@ "eslint": "9.39.2", "eslint-config-next": "16.1.1", "husky": "^9.1.7", + "jsdom": "^27.4.0", "lint-staged": "^16.2.7", "shx": "^0.4.0", "tailwindcss": "^4", "typescript": "^5", + "vite-tsconfig-paths": "^6.0.3", + "vitest": "^4.0.16", "wait-on": "^9.0.3", - "wrangler": "4.54.0" + "wrangler": "4.58.0" }, "optionalDependencies": { "@tailwindcss/oxide-linux-x64-gnu": "^4.1.18", @@ -105,17 +116,18 @@ "version": "0.9.30", "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.30.tgz", "integrity": "sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==", + "dev": true, "license": "MIT" }, "node_modules/@ai-sdk/amazon-bedrock": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/@ai-sdk/amazon-bedrock/-/amazon-bedrock-4.0.4.tgz", - "integrity": "sha512-ssy90ibTrbszGJnYF98vS7bJQtmIp1355iWgKHd2cS8uG8FrBQyYWZZNOSq5dIB3SRzfqKjsyUHKJyF6f7J95w==", + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/@ai-sdk/amazon-bedrock/-/amazon-bedrock-4.0.13.tgz", + "integrity": "sha512-z5FQUoDBo5xwLBmR/PNFiicDpaxaUJzmH5lC4mKVz6h560lEfr25airIsGw3bS1oJc7GhBxak+4oqEqBrbTPYg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/anthropic": "3.0.2", - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2", + "@ai-sdk/anthropic": "3.0.9", + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4", "@smithy/eventstream-codec": "^4.0.1", "@smithy/util-utf8": "^4.0.0", "aws4fetch": "^1.0.20" @@ -128,13 +140,13 @@ } }, "node_modules/@ai-sdk/anthropic": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.2.tgz", - "integrity": "sha512-D6iSsrOYryBSPsFtOiEDv54jnjVCU/flIuXdjuRY7LdikB0KGjpazN8Dt4ONXzL+ux69ds2nzFNKke/w/fgLAA==", + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@ai-sdk/anthropic/-/anthropic-3.0.9.tgz", + "integrity": "sha512-QBD4qDnwIHd+N5PpjxXOaWJig1aRB43J0PM5ZUe6Yyl9Qq2bUmraQjvNznkuFKy+hMFDgj0AvgGogTiO5TC+qA==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2" + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4" }, "engines": { "node": ">=18" @@ -144,14 +156,14 @@ } }, "node_modules/@ai-sdk/azure": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/azure/-/azure-3.0.2.tgz", - "integrity": "sha512-R0cMZ+czZHwyiU6vzmzjnHZ0pWvKyoTgTrkbN0DPBJ4nUw5mzC48OBNZLKkI0jwEE0o0TWwPEJsi4vSATy7G8w==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@ai-sdk/azure/-/azure-3.0.7.tgz", + "integrity": "sha512-TuoW5wIe8EXMlcLbBy8f19JLN8qJXR+4sej2SPhkeZONIoWMUgkxDjCnRUlFb5WFNYMqWmlnTzpMEJUgnwqAvw==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/openai": "3.0.2", - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2" + "@ai-sdk/openai": "3.0.7", + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4" }, "engines": { "node": ">=18" @@ -161,13 +173,13 @@ } }, "node_modules/@ai-sdk/deepseek": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/deepseek/-/deepseek-2.0.2.tgz", - "integrity": "sha512-HznAFPbhOw/RUknLhSnYz3Ng78KBfouXlFRBL7WBw/jDbDKQIRl0vCux/DjjikbRBIl8EYewuPW7GnIEYMX5qA==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@ai-sdk/deepseek/-/deepseek-2.0.4.tgz", + "integrity": "sha512-fw5ayjMYkcDAbq5Qc6cNKSqcOkeJwBEfK1v9TC7RAvEqmIgFxNfCtnWzEobQ4nk0AknPJfg6uFjZl+YdwCdLaw==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2" + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4" }, "engines": { "node": ">=18" @@ -177,14 +189,14 @@ } }, "node_modules/@ai-sdk/gateway": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.5.tgz", - "integrity": "sha512-AtxA1wcoKTHr9uFoC5KZEXqJP4SMW4j3VbcliUECUYssbWbePJ9+b3AaCny1lxf1xhDK9EIyAgBOKhXoQSr9nA==", + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@ai-sdk/gateway/-/gateway-3.0.11.tgz", + "integrity": "sha512-gLrgNXA95wdo/zAlA0miX/SJEYKSYCHg+e0Y/uQeABLScZAMjPw3jWaeANta/Db1T4xfi8cBvY3nnV8Pa27z+w==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2", - "@vercel/oidc": "3.0.5" + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4", + "@vercel/oidc": "3.1.0" }, "engines": { "node": ">=18" @@ -194,13 +206,13 @@ } }, "node_modules/@ai-sdk/google": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.2.tgz", - "integrity": "sha512-KyV4AR8fBKVCABfav3zGn/PY7cMDMt9m7yYhH+FJ7jLfBrEVdjT4sM0ojPFRHYUelXHl42oOAgpy3GWkeG6vtw==", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@ai-sdk/google/-/google-3.0.6.tgz", + "integrity": "sha512-Nr7E+ouWd/bKO9SFlgLnJJ1+fiGHC07KAeFr08faT+lvkECWlxVox3aL0dec8uCgBDUghYbq7f4S5teUrCc+QQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2" + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4" }, "engines": { "node": ">=18" @@ -210,13 +222,13 @@ } }, "node_modules/@ai-sdk/openai": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.2.tgz", - "integrity": "sha512-GONwavgSWtcWO+t9+GpGK8l7nIYh+zNtCL/NYDSeHxHiw6ksQS9XMRWrZyE5NpJ0EXNxSAWCHIDmb1WvTqhq9Q==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-3.0.7.tgz", + "integrity": "sha512-CBoYn1U59Lop8yBL9KuVjHCKc/B06q9Qo0SasRwHoyMEq+X4I8LQZu3a8Ck1jwwcZTTxfyiExB70LtIRSynBDA==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2" + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4" }, "engines": { "node": ">=18" @@ -226,9 +238,9 @@ } }, "node_modules/@ai-sdk/provider": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.1.tgz", - "integrity": "sha512-2lR4w7mr9XrydzxBSjir4N6YMGdXD+Np1Sh0RXABh7tWdNFFwIeRI1Q+SaYZMbfL8Pg8RRLcrxQm51yxTLhokg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-3.0.2.tgz", + "integrity": "sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==", "license": "Apache-2.0", "dependencies": { "json-schema": "^0.4.0" @@ -238,12 +250,12 @@ } }, "node_modules/@ai-sdk/provider-utils": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.2.tgz", - "integrity": "sha512-KaykkuRBdF/ffpI5bwpL4aSCmO/99p8/ci+VeHwJO8tmvXtiVAb99QeyvvvXmL61e9Zrvv4GBGoajW19xdjkVQ==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-4.0.4.tgz", + "integrity": "sha512-VxhX0B/dWGbpNHxrKCWUAJKXIXV015J4e7qYjdIU9lLWeptk0KMLGcqkB4wFxff5Njqur8dt8wRi1MN9lZtDqg==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider": "3.0.1", + "@ai-sdk/provider": "3.0.2", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, @@ -255,13 +267,13 @@ } }, "node_modules/@ai-sdk/react": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.6.tgz", - "integrity": "sha512-ub88RCcT+v1xgsadRtXbcqOoFj3duVyGayOUtUCt2CTbyh+4zdxzXL9Oc/WH8Mqr4X+OKLVddRiLfqUYh0xmlA==", + "version": "3.0.29", + "resolved": "https://registry.npmjs.org/@ai-sdk/react/-/react-3.0.29.tgz", + "integrity": "sha512-e17Id+43xCjHApsjane3dVl5xuUdP9lXgZMtNcgMlg3NHhv6UYpRGuH4+d/5W8+VHhhpNfTZEf7J5DkKehGgJQ==", "license": "Apache-2.0", "dependencies": { - "@ai-sdk/provider-utils": "4.0.2", - "ai": "6.0.6", + "@ai-sdk/provider-utils": "4.0.4", + "ai": "6.0.27", "swr": "^2.2.5", "throttleit": "2.1.0" }, @@ -317,6 +329,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.1.tgz", "integrity": "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==", + "dev": true, "license": "MIT", "dependencies": { "@csstools/css-calc": "^2.1.4", @@ -330,6 +343,7 @@ "version": "11.2.4", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -339,6 +353,7 @@ "version": "6.7.6", "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", + "dev": true, "license": "MIT", "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", @@ -352,6 +367,7 @@ "version": "11.2.4", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", + "dev": true, "license": "BlueOak-1.0.0", "engines": { "node": "20 || >=22" @@ -361,6 +377,7 @@ "version": "2.3.9", "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, "license": "MIT" }, "node_modules/@ast-grep/napi": { @@ -1809,45 +1826,45 @@ "license": "MIT" }, "node_modules/@aws-sdk/client-cognito-identity": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.962.0.tgz", - "integrity": "sha512-gQKsnvC4Rlg0uVSDZIo5Ditp/oqea21omsJsftqkAXGyFQsNVLMd1Toz0Akg0ecbLoLhrWPCMylugH6El1buYw==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-cognito-identity/-/client-cognito-identity-3.966.0.tgz", + "integrity": "sha512-4DZytNO5CNMwDj3WB6Khz7sGMW74pybOGvZS7XXBV+TB41xslV1qmrpMLb1m2tdxETbjLZ7PSLPZUSGzl1Flgw==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-node": "3.962.0", - "@aws-sdk/middleware-host-header": "3.957.0", - "@aws-sdk/middleware-logger": "3.957.0", - "@aws-sdk/middleware-recursion-detection": "3.957.0", - "@aws-sdk/middleware-user-agent": "3.957.0", - "@aws-sdk/region-config-resolver": "3.957.0", - "@aws-sdk/types": "3.957.0", - "@aws-sdk/util-endpoints": "3.957.0", - "@aws-sdk/util-user-agent-browser": "3.957.0", - "@aws-sdk/util-user-agent-node": "3.957.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-node": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", "@smithy/config-resolver": "^4.4.5", - "@smithy/core": "^3.20.0", + "@smithy/core": "^3.20.1", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", - "@smithy/middleware-endpoint": "^4.4.1", - "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.16", - "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", @@ -1858,21 +1875,131 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.962.0.tgz", - "integrity": "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ==", + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/client-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.966.0.tgz", + "integrity": "sha512-hQZDQgqRJclALDo9wK+bb5O+VpO8JcjImp52w9KPSz9XveNRgE9AYfklRJd8qT2Bwhxe6IbnqYEino2wqUMA1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-login": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/core": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.966.0.tgz", + "integrity": "sha512-QaRVBHD1prdrFXIeFAY/1w4b4S0EFyo/ytzU+rCklEjMRT7DKGXGoHXTWLGz+HD7ovlS5u+9cf8a/LeSOEMzww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws-sdk/xml-builder": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.966.0.tgz", + "integrity": "sha512-sxVKc9PY0SH7jgN/8WxhbKQ7MWDIgaJv1AoAKJkhJ+GM5r09G5Vb2Vl8ALYpsy+r8b+iYpq5dGJj8k2VqxoQMg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.966.0.tgz", + "integrity": "sha512-VTJDP1jOibVtc5pn5TNE12rhqOO/n10IjkoJi8fFp9BMfmh3iqo70Ppvphz/Pe/R9LcK5Z3h0Z4EB9IXDR6kag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.966.0.tgz", + "integrity": "sha512-4oQKkYMCUx0mffKuH8LQag1M4Fo5daKVmsLAnjrIqKh91xmCrcWlAFNMgeEYvI1Yy125XeNSaFMfir6oNc2ODA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-login": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -1884,14 +2011,14 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-login": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.962.0.tgz", - "integrity": "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.966.0.tgz", + "integrity": "sha512-wD1KlqLyh23Xfns/ZAPxebwXixoJJCuDbeJHFrLDpP4D4h3vA2S8nSFgBSFR15q9FhgRfHleClycf6g5K4Ww6w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -1903,18 +2030,18 @@ } }, "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.962.0.tgz", - "integrity": "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.966.0.tgz", + "integrity": "sha512-7QCOERGddMw7QbjE+LSAFgwOBpPv4px2ty0GCK7ZiPJGsni2EYmM4TtYnQb9u1WNHmHqIPWMbZR0pKDbyRyHlQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-ini": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-ini": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -1925,48 +2052,327 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-dynamodb": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.962.0.tgz", - "integrity": "sha512-q2pI7t3Jdwi+sOWdfZSTtnQVUbgEP+Lg0IbU6f6zhPRKDz8UWWYpKHaImRTbiSILN6UlPhIll8odfpxWxFUiwg==", + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.966.0.tgz", + "integrity": "sha512-q5kCo+xHXisNbbPAh/DiCd+LZX4wdby77t7GLk0b2U0/mrel4lgy6o79CApe+0emakpOS1nPZS7voXA7vGPz4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.966.0.tgz", + "integrity": "sha512-Rv5aEfbpqsQZzxpX2x+FbSyVFOE3Dngome+exNA8jGzc00rrMZEUnm3J3yAsLp/I2l7wnTfI0r2zMe+T9/nZAQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.966.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/token-providers": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.966.0.tgz", + "integrity": "sha512-Yv1lc9iic9xg3ywMmIAeXN1YwuvfcClLVdiF2y71LqUgIOupW8B8my84XJr6pmOQuKzZa++c2znNhC9lGsbKyw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz", + "integrity": "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-logger": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz", + "integrity": "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz", + "integrity": "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.966.0.tgz", + "integrity": "sha512-MvGoy0vhMluVpSB5GaGJbYLqwbZfZjwEZhneDHdPhgCgQqmCtugnYIIjpUw7kKqWGsmaMQmNEgSFf1zYYmwOyg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/nested-clients": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.966.0.tgz", + "integrity": "sha512-FRzAWwLNoKiaEWbYhnpnfartIdOgiaBLnPcd3uG1Io+vvxQUeRPhQIy4EfKnT3AuA+g7gzSCjMG2JKoJOplDtQ==", "license": "Apache-2.0", "dependencies": { "@aws-crypto/sha256-browser": "5.2.0", "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-node": "3.962.0", - "@aws-sdk/dynamodb-codec": "3.957.0", - "@aws-sdk/middleware-endpoint-discovery": "3.957.0", - "@aws-sdk/middleware-host-header": "3.957.0", - "@aws-sdk/middleware-logger": "3.957.0", - "@aws-sdk/middleware-recursion-detection": "3.957.0", - "@aws-sdk/middleware-user-agent": "3.957.0", - "@aws-sdk/region-config-resolver": "3.957.0", - "@aws-sdk/types": "3.957.0", - "@aws-sdk/util-endpoints": "3.957.0", - "@aws-sdk/util-user-agent-browser": "3.957.0", - "@aws-sdk/util-user-agent-node": "3.957.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", "@smithy/config-resolver": "^4.4.5", - "@smithy/core": "^3.20.0", + "@smithy/core": "^3.20.1", "@smithy/fetch-http-handler": "^5.3.8", "@smithy/hash-node": "^4.2.7", "@smithy/invalid-dependency": "^4.2.7", "@smithy/middleware-content-length": "^4.2.7", - "@smithy/middleware-endpoint": "^4.4.1", - "@smithy/middleware-retry": "^4.4.17", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", "@smithy/middleware-serde": "^4.2.8", "@smithy/middleware-stack": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/node-http-handler": "^4.4.7", "@smithy/protocol-http": "^5.3.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "@smithy/url-parser": "^4.2.7", "@smithy/util-base64": "^4.3.0", "@smithy/util-body-length-browser": "^4.2.0", "@smithy/util-body-length-node": "^4.2.1", - "@smithy/util-defaults-mode-browser": "^4.3.16", - "@smithy/util-defaults-mode-node": "^4.2.19", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz", + "integrity": "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/token-providers": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.966.0.tgz", + "integrity": "sha512-8k5cBTicTGYJHhKaweO4gL4fud1KDnLS5fByT6/Xbiu59AxYM4E/h3ds+3jxDMnniCE3gIWpEnyfM9khtmw2lA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-endpoints": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz", + "integrity": "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-endpoints": "^3.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz", + "integrity": "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.966.0.tgz", + "integrity": "sha512-vPPe8V0GLj+jVS5EqFz2NUBgWH35favqxliUOvhp8xBdNRkEjiZm5TqitVtFlxS4RrLY3HOndrWbrP5ejbwl1Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-cognito-identity/node_modules/@aws-sdk/xml-builder": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz", + "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.966.0.tgz", + "integrity": "sha512-u5zA3T9L5pMDV7YBHkGec6cAhnEyiKcd+HjLdJsRBCmMvq8CDZ1+uNusiKqYc7hUi3b8RF5bzGBZphWgUJQWZA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-node": "3.966.0", + "@aws-sdk/dynamodb-codec": "3.966.0", + "@aws-sdk/middleware-endpoint-discovery": "3.965.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", "@smithy/util-endpoints": "^3.2.7", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", @@ -1978,21 +2384,131 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.962.0.tgz", - "integrity": "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ==", + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/client-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.966.0.tgz", + "integrity": "sha512-hQZDQgqRJclALDo9wK+bb5O+VpO8JcjImp52w9KPSz9XveNRgE9AYfklRJd8qT2Bwhxe6IbnqYEino2wqUMA1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-login": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/core": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.966.0.tgz", + "integrity": "sha512-QaRVBHD1prdrFXIeFAY/1w4b4S0EFyo/ytzU+rCklEjMRT7DKGXGoHXTWLGz+HD7ovlS5u+9cf8a/LeSOEMzww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws-sdk/xml-builder": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.966.0.tgz", + "integrity": "sha512-sxVKc9PY0SH7jgN/8WxhbKQ7MWDIgaJv1AoAKJkhJ+GM5r09G5Vb2Vl8ALYpsy+r8b+iYpq5dGJj8k2VqxoQMg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.966.0.tgz", + "integrity": "sha512-VTJDP1jOibVtc5pn5TNE12rhqOO/n10IjkoJi8fFp9BMfmh3iqo70Ppvphz/Pe/R9LcK5Z3h0Z4EB9IXDR6kag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.966.0.tgz", + "integrity": "sha512-4oQKkYMCUx0mffKuH8LQag1M4Fo5daKVmsLAnjrIqKh91xmCrcWlAFNMgeEYvI1Yy125XeNSaFMfir6oNc2ODA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-login": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -2004,14 +2520,14 @@ } }, "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-login": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.962.0.tgz", - "integrity": "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.966.0.tgz", + "integrity": "sha512-wD1KlqLyh23Xfns/ZAPxebwXixoJJCuDbeJHFrLDpP4D4h3vA2S8nSFgBSFR15q9FhgRfHleClycf6g5K4Ww6w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -2023,18 +2539,18 @@ } }, "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.962.0.tgz", - "integrity": "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.966.0.tgz", + "integrity": "sha512-7QCOERGddMw7QbjE+LSAFgwOBpPv4px2ty0GCK7ZiPJGsni2EYmM4TtYnQb9u1WNHmHqIPWMbZR0pKDbyRyHlQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-ini": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-ini": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -2045,6 +2561,285 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.966.0.tgz", + "integrity": "sha512-q5kCo+xHXisNbbPAh/DiCd+LZX4wdby77t7GLk0b2U0/mrel4lgy6o79CApe+0emakpOS1nPZS7voXA7vGPz4w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.966.0.tgz", + "integrity": "sha512-Rv5aEfbpqsQZzxpX2x+FbSyVFOE3Dngome+exNA8jGzc00rrMZEUnm3J3yAsLp/I2l7wnTfI0r2zMe+T9/nZAQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.966.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/token-providers": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.966.0.tgz", + "integrity": "sha512-Yv1lc9iic9xg3ywMmIAeXN1YwuvfcClLVdiF2y71LqUgIOupW8B8my84XJr6pmOQuKzZa++c2znNhC9lGsbKyw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz", + "integrity": "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-logger": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz", + "integrity": "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz", + "integrity": "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.966.0.tgz", + "integrity": "sha512-MvGoy0vhMluVpSB5GaGJbYLqwbZfZjwEZhneDHdPhgCgQqmCtugnYIIjpUw7kKqWGsmaMQmNEgSFf1zYYmwOyg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/nested-clients": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.966.0.tgz", + "integrity": "sha512-FRzAWwLNoKiaEWbYhnpnfartIdOgiaBLnPcd3uG1Io+vvxQUeRPhQIy4EfKnT3AuA+g7gzSCjMG2JKoJOplDtQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz", + "integrity": "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/token-providers": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.966.0.tgz", + "integrity": "sha512-8k5cBTicTGYJHhKaweO4gL4fud1KDnLS5fByT6/Xbiu59AxYM4E/h3ds+3jxDMnniCE3gIWpEnyfM9khtmw2lA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/util-endpoints": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz", + "integrity": "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-endpoints": "^3.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz", + "integrity": "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.966.0.tgz", + "integrity": "sha512-vPPe8V0GLj+jVS5EqFz2NUBgWH35favqxliUOvhp8xBdNRkEjiZm5TqitVtFlxS4RrLY3HOndrWbrP5ejbwl1Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/client-dynamodb/node_modules/@aws-sdk/xml-builder": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz", + "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/client-lambda": { "version": "3.958.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-lambda/-/client-lambda-3.958.0.tgz", @@ -3340,13 +4135,13 @@ } }, "node_modules/@aws-sdk/credential-provider-cognito-identity": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.962.0.tgz", - "integrity": "sha512-0B1iwgCNY3cg/s3JwWtBP1PaB4uldd0sgx6WgVVcnQ9rpyuCMOUF61enA1OcmSWgRRndylznGXjok8cva5Pw4w==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.966.0.tgz", + "integrity": "sha512-hXOdcaCwk3nAXJO9u2ZcsmUxTJ/T9ROsmZa5M9yAFUEudC5/JXE0YBS2cnUvvcL8ozst8geCzX1k9zrwMTw8Jw==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.962.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/client-cognito-identity": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" @@ -3355,6 +4150,19 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/credential-provider-cognito-identity/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/credential-provider-env": { "version": "3.957.0", "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.957.0.tgz", @@ -3514,26 +4322,26 @@ } }, "node_modules/@aws-sdk/credential-providers": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.962.0.tgz", - "integrity": "sha512-KIFu4zkMxJ9TeBm/TWv64W9en5fSP/pPWxm3tkFMleEmyotWmC2xkihZZYcHKgLhezA3fyZxTVz2v++6DpO76A==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.966.0.tgz", + "integrity": "sha512-rawjdixBs/3uYwgeQNaw1uGf6tKiPvFxX/sJkTC7LVBnz46ot2CAOSaDU94nIHl/VvZ1mMRN/KaaGG11I1grsg==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/client-cognito-identity": "3.962.0", - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-cognito-identity": "3.962.0", - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-ini": "3.962.0", - "@aws-sdk/credential-provider-login": "3.962.0", - "@aws-sdk/credential-provider-node": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/client-cognito-identity": "3.966.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-cognito-identity": "3.966.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-ini": "3.966.0", + "@aws-sdk/credential-provider-login": "3.966.0", + "@aws-sdk/credential-provider-node": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/config-resolver": "^4.4.5", - "@smithy/core": "^3.20.0", + "@smithy/core": "^3.20.1", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", @@ -3544,21 +4352,131 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.962.0.tgz", - "integrity": "sha512-h0kVnXLW2d3nxbcrR/Pfg3W/+YoCguasWz7/3nYzVqmdKarGrpJzaFdoZtLgvDSZ8VgWUC4lWOTcsDMV0UNqUQ==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/client-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.966.0.tgz", + "integrity": "sha512-hQZDQgqRJclALDo9wK+bb5O+VpO8JcjImp52w9KPSz9XveNRgE9AYfklRJd8qT2Bwhxe6IbnqYEino2wqUMA1w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-login": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/core": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.966.0.tgz", + "integrity": "sha512-QaRVBHD1prdrFXIeFAY/1w4b4S0EFyo/ytzU+rCklEjMRT7DKGXGoHXTWLGz+HD7ovlS5u+9cf8a/LeSOEMzww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws-sdk/xml-builder": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-env": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.966.0.tgz", + "integrity": "sha512-sxVKc9PY0SH7jgN/8WxhbKQ7MWDIgaJv1AoAKJkhJ+GM5r09G5Vb2Vl8ALYpsy+r8b+iYpq5dGJj8k2VqxoQMg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.966.0.tgz", + "integrity": "sha512-VTJDP1jOibVtc5pn5TNE12rhqOO/n10IjkoJi8fFp9BMfmh3iqo70Ppvphz/Pe/R9LcK5Z3h0Z4EB9IXDR6kag==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-stream": "^4.5.8", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.966.0.tgz", + "integrity": "sha512-4oQKkYMCUx0mffKuH8LQag1M4Fo5daKVmsLAnjrIqKh91xmCrcWlAFNMgeEYvI1Yy125XeNSaFMfir6oNc2ODA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-login": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -3570,14 +4488,14 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-login": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.962.0.tgz", - "integrity": "sha512-kHYH6Av2UifG3mPkpPUNRh/PuX6adaAcpmsclJdHdxlixMCRdh8GNeEihq480DC0GmfqdpoSf1w2CLmLLPIS6w==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.966.0.tgz", + "integrity": "sha512-wD1KlqLyh23Xfns/ZAPxebwXixoJJCuDbeJHFrLDpP4D4h3vA2S8nSFgBSFR15q9FhgRfHleClycf6g5K4Ww6w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@aws-sdk/nested-clients": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/property-provider": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -3589,18 +4507,18 @@ } }, "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-node": { - "version": "3.962.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.962.0.tgz", - "integrity": "sha512-CS78NsWRxLa+nWqeWBEYMZTLacMFIXs1C5WJuM9kD05LLiWL32ksljoPsvNN24Bc7rCSQIIMx/U3KGvkDVZMVg==", + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.966.0.tgz", + "integrity": "sha512-7QCOERGddMw7QbjE+LSAFgwOBpPv4px2ty0GCK7ZiPJGsni2EYmM4TtYnQb9u1WNHmHqIPWMbZR0pKDbyRyHlQ==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/credential-provider-env": "3.957.0", - "@aws-sdk/credential-provider-http": "3.957.0", - "@aws-sdk/credential-provider-ini": "3.962.0", - "@aws-sdk/credential-provider-process": "3.957.0", - "@aws-sdk/credential-provider-sso": "3.958.0", - "@aws-sdk/credential-provider-web-identity": "3.958.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/credential-provider-env": "3.966.0", + "@aws-sdk/credential-provider-http": "3.966.0", + "@aws-sdk/credential-provider-ini": "3.966.0", + "@aws-sdk/credential-provider-process": "3.966.0", + "@aws-sdk/credential-provider-sso": "3.966.0", + "@aws-sdk/credential-provider-web-identity": "3.966.0", + "@aws-sdk/types": "3.965.0", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/property-provider": "^4.2.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -3611,15 +4529,294 @@ "node": ">=18.0.0" } }, - "node_modules/@aws-sdk/dynamodb-codec": { - "version": "3.957.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.957.0.tgz", - "integrity": "sha512-xds1mkwEGzXrNy/gT6/ehaJ+cbYn/QM7AkdwNrO1NBlwJVLo3imO6hOnOQ/0KWG2ck1dbKv9H9f2hka67bAzEA==", + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-process": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.966.0.tgz", + "integrity": "sha512-q5kCo+xHXisNbbPAh/DiCd+LZX4wdby77t7GLk0b2U0/mrel4lgy6o79CApe+0emakpOS1nPZS7voXA7vGPz4w==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/core": "3.957.0", - "@smithy/core": "^3.20.0", - "@smithy/smithy-client": "^4.10.2", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.966.0.tgz", + "integrity": "sha512-Rv5aEfbpqsQZzxpX2x+FbSyVFOE3Dngome+exNA8jGzc00rrMZEUnm3J3yAsLp/I2l7wnTfI0r2zMe+T9/nZAQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.966.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/token-providers": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.966.0.tgz", + "integrity": "sha512-Yv1lc9iic9xg3ywMmIAeXN1YwuvfcClLVdiF2y71LqUgIOupW8B8my84XJr6pmOQuKzZa++c2znNhC9lGsbKyw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-host-header": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.965.0.tgz", + "integrity": "sha512-SfpSYqoPOAmdb3DBsnNsZ0vix+1VAtkUkzXM79JL3R5IfacpyKE2zytOgVAQx/FjhhlpSTwuXd+LRhUEVb3MaA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-logger": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.965.0.tgz", + "integrity": "sha512-gjUvJRZT1bUABKewnvkj51LAynFrfz2h5DYAg5/2F4Utx6UOGByTSr9Rq8JCLbURvvzAbCtcMkkIJRxw+8Zuzw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.965.0.tgz", + "integrity": "sha512-6dvD+18Ni14KCRu+tfEoNxq1sIGVp9tvoZDZ7aMvpnA7mDXuRLrOjRQ/TAZqXwr9ENKVGyxcPl0cRK8jk1YWjA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws/lambda-invoke-store": "^0.2.2", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.966.0.tgz", + "integrity": "sha512-MvGoy0vhMluVpSB5GaGJbYLqwbZfZjwEZhneDHdPhgCgQqmCtugnYIIjpUw7kKqWGsmaMQmNEgSFf1zYYmwOyg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/protocol-http": "^5.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/nested-clients": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.966.0.tgz", + "integrity": "sha512-FRzAWwLNoKiaEWbYhnpnfartIdOgiaBLnPcd3uG1Io+vvxQUeRPhQIy4EfKnT3AuA+g7gzSCjMG2JKoJOplDtQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.966.0", + "@aws-sdk/middleware-host-header": "3.965.0", + "@aws-sdk/middleware-logger": "3.965.0", + "@aws-sdk/middleware-recursion-detection": "3.965.0", + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/region-config-resolver": "3.965.0", + "@aws-sdk/types": "3.965.0", + "@aws-sdk/util-endpoints": "3.965.0", + "@aws-sdk/util-user-agent-browser": "3.965.0", + "@aws-sdk/util-user-agent-node": "3.966.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/core": "^3.20.1", + "@smithy/fetch-http-handler": "^5.3.8", + "@smithy/hash-node": "^4.2.7", + "@smithy/invalid-dependency": "^4.2.7", + "@smithy/middleware-content-length": "^4.2.7", + "@smithy/middleware-endpoint": "^4.4.2", + "@smithy/middleware-retry": "^4.4.18", + "@smithy/middleware-serde": "^4.2.8", + "@smithy/middleware-stack": "^4.2.7", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/node-http-handler": "^4.4.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-body-length-browser": "^4.2.0", + "@smithy/util-body-length-node": "^4.2.1", + "@smithy/util-defaults-mode-browser": "^4.3.17", + "@smithy/util-defaults-mode-node": "^4.2.20", + "@smithy/util-endpoints": "^3.2.7", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-retry": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/region-config-resolver": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.965.0.tgz", + "integrity": "sha512-RoMhu9ly2B0coxn8ctXosPP2WmDD0MkQlZGLjoYHQUOCBmty5qmCxOqBmBDa6wbWbB8xKtMQ/4VXloQOgzjHXg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/config-resolver": "^4.4.5", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/token-providers": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.966.0.tgz", + "integrity": "sha512-8k5cBTicTGYJHhKaweO4gL4fud1KDnLS5fByT6/Xbiu59AxYM4E/h3ds+3jxDMnniCE3gIWpEnyfM9khtmw2lA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@aws-sdk/nested-clients": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/property-provider": "^4.2.7", + "@smithy/shared-ini-file-loader": "^4.4.2", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-endpoints": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.965.0.tgz", + "integrity": "sha512-WqSCB0XIsGUwZWvrYkuoofi2vzoVHqyeJ2kN+WyoOsxPLTiQSBIoqm/01R/qJvoxwK/gOOF7su9i84Vw2NQQpQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "@smithy/url-parser": "^4.2.7", + "@smithy/util-endpoints": "^3.2.7", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.965.0.tgz", + "integrity": "sha512-Xiza/zMntQGpkd2dETQeAK8So1pg5+STTzpcdGWxj5q0jGO5ayjqT/q1Q7BrsX5KIr6PvRkl9/V7lLCv04wGjQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@smithy/types": "^4.11.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.966.0.tgz", + "integrity": "sha512-vPPe8V0GLj+jVS5EqFz2NUBgWH35favqxliUOvhp8xBdNRkEjiZm5TqitVtFlxS4RrLY3HOndrWbrP5ejbwl1Q==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-user-agent": "3.966.0", + "@aws-sdk/types": "3.965.0", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/credential-providers/node_modules/@aws-sdk/xml-builder": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz", + "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/dynamodb-codec": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/dynamodb-codec/-/dynamodb-codec-3.966.0.tgz", + "integrity": "sha512-wxVtcbBw4oUwq8+/4GH89ODdwXGQeknk27eIvP6471G7Ak4hNPlsshD8bZNeKbMlxTMqnu7Av5TTznfTtujjFw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "3.966.0", + "@smithy/core": "^3.20.1", + "@smithy/smithy-client": "^4.10.3", "@smithy/types": "^4.11.0", "@smithy/util-base64": "^4.3.0", "tslib": "^2.6.2" @@ -3628,13 +4825,64 @@ "node": ">=18.0.0" }, "peerDependencies": { - "@aws-sdk/client-dynamodb": "^3.957.0" + "@aws-sdk/client-dynamodb": "^3.966.0" + } + }, + "node_modules/@aws-sdk/dynamodb-codec/node_modules/@aws-sdk/core": { + "version": "3.966.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.966.0.tgz", + "integrity": "sha512-QaRVBHD1prdrFXIeFAY/1w4b4S0EFyo/ytzU+rCklEjMRT7DKGXGoHXTWLGz+HD7ovlS5u+9cf8a/LeSOEMzww==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.965.0", + "@aws-sdk/xml-builder": "3.965.0", + "@smithy/core": "^3.20.1", + "@smithy/node-config-provider": "^4.3.7", + "@smithy/property-provider": "^4.2.7", + "@smithy/protocol-http": "^5.3.7", + "@smithy/signature-v4": "^5.3.7", + "@smithy/smithy-client": "^4.10.3", + "@smithy/types": "^4.11.0", + "@smithy/util-base64": "^4.3.0", + "@smithy/util-middleware": "^4.2.7", + "@smithy/util-utf8": "^4.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/dynamodb-codec/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/dynamodb-codec/node_modules/@aws-sdk/xml-builder": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.965.0.tgz", + "integrity": "sha512-Tcod25/BTupraQwtb+Q+GX8bmEZfxIFjjJ/AvkhUZsZlkPeVluzq1uu3Oeqf145DCdMjzLIN6vab5MrykbDP+g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "fast-xml-parser": "5.2.5", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" } }, "node_modules/@aws-sdk/endpoint-cache": { - "version": "3.957.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.957.0.tgz", - "integrity": "sha512-QxvFejXYYBZp/GBfT7B15gvmvuq+0f2U8RPHqArf5IqBi51ZyBqUD805tQ8TlsVrlLoi+Z4fEFw4HEM5pGvPUg==", + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/endpoint-cache/-/endpoint-cache-3.965.0.tgz", + "integrity": "sha512-7bqt08b1aVgHHRbdUK9iIMI2CKpaeYs3cLNeZ/Js7GRAQIRQ0OsRILNxGdtWrkVbpp8ITM++iWJCGUw/X19EdA==", "license": "Apache-2.0", "dependencies": { "mnemonist": "0.38.3", @@ -3663,13 +4911,13 @@ } }, "node_modules/@aws-sdk/middleware-endpoint-discovery": { - "version": "3.957.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.957.0.tgz", - "integrity": "sha512-MJjlw4mVJNTyR5dW6wpzKLRzFPIYAMA8qUWqgG4hGscmm4GFHvWVJ9mhhdpDu7Ie4Uaikmzfy0C4xzZ+lkf1+w==", + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-endpoint-discovery/-/middleware-endpoint-discovery-3.965.0.tgz", + "integrity": "sha512-XVUV2FmJnDG0FCCeTw0wniP1EkDR+Dy3Pl91aTkRvUw9OYbTEPLGIZiABn1EKdQPOEc77Y1+FQQ6QbjSZKkJ/A==", "license": "Apache-2.0", "dependencies": { - "@aws-sdk/endpoint-cache": "3.957.0", - "@aws-sdk/types": "3.957.0", + "@aws-sdk/endpoint-cache": "3.965.0", + "@aws-sdk/types": "3.965.0", "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", @@ -3679,6 +4927,19 @@ "node": ">=18.0.0" } }, + "node_modules/@aws-sdk/middleware-endpoint-discovery/node_modules/@aws-sdk/types": { + "version": "3.965.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.965.0.tgz", + "integrity": "sha512-jvodoJdMavvg8faN7co58vVJRO5MVep4JFPRzUNCzpJ98BDqWDk/ad045aMJcmxkLzYLS2UAnUmqjJ/tUPNlzQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@aws-sdk/middleware-expect-continue": { "version": "3.957.0", "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-expect-continue/-/middleware-expect-continue-3.957.0.tgz", @@ -4306,6 +5567,7 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -4437,6 +5699,16 @@ "@babel/core": "^7.0.0" } }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", @@ -4497,6 +5769,48 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.28.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", + "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", @@ -4545,10 +5859,20 @@ "node": ">=6.9.0" } }, + "node_modules/@bcoe/v8-coverage": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-1.0.2.tgz", + "integrity": "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/@biomejs/biome": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.10.tgz", - "integrity": "sha512-/uWSUd1MHX2fjqNLHNL6zLYWBbrJeG412/8H7ESuK8ewoRoMPUgHDebqKrPTx/5n6f17Xzqc9hdg3MEqA5hXnQ==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.3.11.tgz", + "integrity": "sha512-/zt+6qazBWguPG6+eWmiELqO+9jRsMZ/DBU3lfuU2ngtIQYzymocHhKiZRyrbra4aCOoyTg/BmY+6WH5mv9xmQ==", "dev": true, "license": "MIT OR Apache-2.0", "bin": { @@ -4562,20 +5886,20 @@ "url": "https://opencollective.com/biome" }, "optionalDependencies": { - "@biomejs/cli-darwin-arm64": "2.3.10", - "@biomejs/cli-darwin-x64": "2.3.10", - "@biomejs/cli-linux-arm64": "2.3.10", - "@biomejs/cli-linux-arm64-musl": "2.3.10", - "@biomejs/cli-linux-x64": "2.3.10", - "@biomejs/cli-linux-x64-musl": "2.3.10", - "@biomejs/cli-win32-arm64": "2.3.10", - "@biomejs/cli-win32-x64": "2.3.10" + "@biomejs/cli-darwin-arm64": "2.3.11", + "@biomejs/cli-darwin-x64": "2.3.11", + "@biomejs/cli-linux-arm64": "2.3.11", + "@biomejs/cli-linux-arm64-musl": "2.3.11", + "@biomejs/cli-linux-x64": "2.3.11", + "@biomejs/cli-linux-x64-musl": "2.3.11", + "@biomejs/cli-win32-arm64": "2.3.11", + "@biomejs/cli-win32-x64": "2.3.11" } }, "node_modules/@biomejs/cli-darwin-arm64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.10.tgz", - "integrity": "sha512-M6xUjtCVnNGFfK7HMNKa593nb7fwNm43fq1Mt71kpLpb+4mE7odO8W/oWVDyBVO4ackhresy1ZYO7OJcVo/B7w==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.3.11.tgz", + "integrity": "sha512-/uXXkBcPKVQY7rc9Ys2CrlirBJYbpESEDme7RKiBD6MmqR2w3j0+ZZXRIL2xiaNPsIMMNhP1YnA+jRRxoOAFrA==", "cpu": [ "arm64" ], @@ -4590,9 +5914,9 @@ } }, "node_modules/@biomejs/cli-darwin-x64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.10.tgz", - "integrity": "sha512-Vae7+V6t/Avr8tVbFNjnFSTKZogZHFYl7MMH62P/J1kZtr0tyRQ9Fe0onjqjS2Ek9lmNLmZc/VR5uSekh+p1fg==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.3.11.tgz", + "integrity": "sha512-fh7nnvbweDPm2xEmFjfmq7zSUiox88plgdHF9OIW4i99WnXrAC3o2P3ag9judoUMv8FCSUnlwJCM1B64nO5Fbg==", "cpu": [ "x64" ], @@ -4607,9 +5931,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.10.tgz", - "integrity": "sha512-hhPw2V3/EpHKsileVOFynuWiKRgFEV48cLe0eA+G2wO4SzlwEhLEB9LhlSrVeu2mtSn205W283LkX7Fh48CaxA==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.3.11.tgz", + "integrity": "sha512-l4xkGa9E7Uc0/05qU2lMYfN1H+fzzkHgaJoy98wO+b/7Gl78srbCRRgwYSW+BTLixTBrM6Ede5NSBwt7rd/i6g==", "cpu": [ "arm64" ], @@ -4624,9 +5948,9 @@ } }, "node_modules/@biomejs/cli-linux-arm64-musl": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.10.tgz", - "integrity": "sha512-B9DszIHkuKtOH2IFeeVkQmSMVUjss9KtHaNXquYYWCjH8IstNgXgx5B0aSBQNr6mn4RcKKRQZXn9Zu1rM3O0/A==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.3.11.tgz", + "integrity": "sha512-XPSQ+XIPZMLaZ6zveQdwNjbX+QdROEd1zPgMwD47zvHV+tCGB88VH+aynyGxAHdzL+Tm/+DtKST5SECs4iwCLg==", "cpu": [ "arm64" ], @@ -4641,9 +5965,9 @@ } }, "node_modules/@biomejs/cli-linux-x64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.10.tgz", - "integrity": "sha512-wwAkWD1MR95u+J4LkWP74/vGz+tRrIQvr8kfMMJY8KOQ8+HMVleREOcPYsQX82S7uueco60L58Wc6M1I9WA9Dw==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.3.11.tgz", + "integrity": "sha512-/1s9V/H3cSe0r0Mv/Z8JryF5x9ywRxywomqZVLHAoa/uN0eY7F8gEngWKNS5vbbN/BsfpCG5yeBT5ENh50Frxg==", "cpu": [ "x64" ], @@ -4658,9 +5982,9 @@ } }, "node_modules/@biomejs/cli-linux-x64-musl": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.10.tgz", - "integrity": "sha512-QTfHZQh62SDFdYc2nfmZFuTm5yYb4eO1zwfB+90YxUumRCR171tS1GoTX5OD0wrv4UsziMPmrePMtkTnNyYG3g==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.3.11.tgz", + "integrity": "sha512-vU7a8wLs5C9yJ4CB8a44r12aXYb8yYgBn+WeyzbMjaCMklzCv1oXr8x+VEyWodgJt9bDmhiaW/I0RHbn7rsNmw==", "cpu": [ "x64" ], @@ -4675,9 +5999,9 @@ } }, "node_modules/@biomejs/cli-win32-arm64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.10.tgz", - "integrity": "sha512-o7lYc9n+CfRbHvkjPhm8s9FgbKdYZu5HCcGVMItLjz93EhgJ8AM44W+QckDqLA9MKDNFrR8nPbO4b73VC5kGGQ==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.3.11.tgz", + "integrity": "sha512-PZQ6ElCOnkYapSsysiTy0+fYX+agXPlWugh6+eQ6uPKI3vKAqNp6TnMhoM3oY2NltSB89hz59o8xIfOdyhi9Iw==", "cpu": [ "arm64" ], @@ -4692,9 +6016,9 @@ } }, "node_modules/@biomejs/cli-win32-x64": { - "version": "2.3.10", - "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.10.tgz", - "integrity": "sha512-pHEFgq7dUEsKnqG9mx9bXihxGI49X+ar+UBrEIj3Wqj3UCZp1rNgV+OoyjFgcXsjCWpuEAF4VJdkZr3TrWdCbQ==", + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.3.11.tgz", + "integrity": "sha512-43VrG813EW+b5+YbDbz31uUsheX+qFKCpXeY9kfdAx+ww3naKxeVkTD9zLIWxUPfJquANMHrmW3wbe/037G0Qg==", "cpu": [ "x64" ], @@ -4733,9 +6057,9 @@ } }, "node_modules/@cloudflare/unenv-preset": { - "version": "2.7.13", - "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.7.13.tgz", - "integrity": "sha512-NulO1H8R/DzsJguLC0ndMuk4Ufv0KSlN+E54ay9rn9ZCQo0kpAPwwh3LhgpZ96a3Dr6L9LqW57M4CqC34iLOvw==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@cloudflare/unenv-preset/-/unenv-preset-2.8.0.tgz", + "integrity": "sha512-oIAu6EdQ4zJuPwwKr9odIEqd8AV96z1aqi3RBEA4iKaJ+Vd3fvuI6m5EDC7/QCv+oaPIhy1SkYBYxmD09N+oZg==", "license": "MIT OR Apache-2.0", "peerDependencies": { "unenv": "2.0.0-rc.24", @@ -4748,9 +6072,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20251210.0.tgz", - "integrity": "sha512-Nn9X1moUDERA9xtFdCQ2XpQXgAS9pOjiCxvOT8sVx9UJLAiBLkfSCGbpsYdarODGybXCpjRlc77Yppuolvt7oQ==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20260107.1.tgz", + "integrity": "sha512-Srwe/IukVppkMU2qTndkFaKCmZBI7CnZoq4Y0U0gD/8158VGzMREHTqCii4IcCeHifwrtDqTWu8EcA1VBKI4mg==", "cpu": [ "x64" ], @@ -4764,9 +6088,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20251210.0.tgz", - "integrity": "sha512-Mg8iYIZQFnbevq/ls9eW/eneWTk/EE13Pej1MwfkY5et0jVpdHnvOLywy/o+QtMJFef1AjsqXGULwAneYyBfHw==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20260107.1.tgz", + "integrity": "sha512-aAYwU7zXW+UZFh/a4vHP5cs1ulTOcDRLzwU9547yKad06RlZ6ioRm7ovjdYvdqdmbI8mPd99v4LN9gMmecazQw==", "cpu": [ "arm64" ], @@ -4780,9 +6104,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20251210.0.tgz", - "integrity": "sha512-kjC2fCZhZ2Gkm1biwk2qByAYpGguK5Gf5ic8owzSCUw0FOUfQxTZUT9Lp3gApxsfTLbbnLBrX/xzWjywH9QR4g==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20260107.1.tgz", + "integrity": "sha512-Wh7xWtFOkk6WY3CXe3lSqZ1anMkFcwy+qOGIjtmvQ/3nCOaG34vKNwPIE9iwryPupqkSuDmEqkosI1UUnSTh1A==", "cpu": [ "x64" ], @@ -4796,9 +6120,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20251210.0.tgz", - "integrity": "sha512-2IB37nXi7PZVQLa1OCuO7/6pNxqisRSO8DmCQ5x/3sezI5op1vwOxAcb1osAnuVsVN9bbvpw70HJvhKruFJTuA==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20260107.1.tgz", + "integrity": "sha512-NI0/5rdssdZZKYHxNG4umTmMzODByq86vSCEk8u4HQbGhRCQo7rV1eXn84ntSBdyWBzWdYGISCbeZMsgfIjSTg==", "cpu": [ "arm64" ], @@ -4812,9 +6136,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20251210.0.tgz", - "integrity": "sha512-Uaz6/9XE+D6E7pCY4OvkCuJHu7HcSDzeGcCGY1HLhojXhHd7yL52c3yfiyJdS8hPatiAa0nn5qSI/42+aTdDSw==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20260107.1.tgz", + "integrity": "sha512-gmBMqs606Gd/IhBEBPSL/hJAqy2L8IyPUjKtoqd/Ccy7GQxbSc0rYlRkxbQ9YzmqnuhrTVYvXuLscyWrpmAJkw==", "cpu": [ "x64" ], @@ -4853,6 +6177,7 @@ "version": "5.1.0", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", + "dev": true, "funding": [ { "type": "github", @@ -4872,6 +6197,7 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", + "dev": true, "funding": [ { "type": "github", @@ -4895,6 +6221,7 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", + "dev": true, "funding": [ { "type": "github", @@ -4922,6 +6249,7 @@ "version": "3.0.5", "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", + "dev": true, "funding": [ { "type": "github", @@ -4933,6 +6261,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" }, @@ -4944,6 +6273,7 @@ "version": "1.0.22", "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.22.tgz", "integrity": "sha512-qBcx6zYlhleiFfdtzkRgwNC7VVoAwfK76Vmsw5t+PbvtdknO9StgRk7ROvq9so1iqbdW4uLIDAsXRsTfUrIoOw==", + "dev": true, "funding": [ { "type": "github", @@ -4963,6 +6293,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", + "dev": true, "funding": [ { "type": "github", @@ -4974,6 +6305,7 @@ } ], "license": "MIT", + "peer": true, "engines": { "node": ">=18" } @@ -5134,6 +6466,7 @@ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5177,9 +6510,9 @@ } }, "node_modules/@electron/asar": { - "version": "3.2.18", - "resolved": "https://registry.npmmirror.com/@electron/asar/-/asar-3.2.18.tgz", - "integrity": "sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==", + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", "dev": true, "license": "MIT", "dependencies": { @@ -5196,7 +6529,7 @@ }, "node_modules/@electron/asar/node_modules/commander": { "version": "5.1.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-5.1.0.tgz", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", "dev": true, "license": "MIT", @@ -5290,75 +6623,6 @@ "semver": "bin/semver.js" } }, - "node_modules/@electron/node-gyp": { - "version": "10.2.0-electron.1", - "resolved": "git+ssh://git@github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", - "integrity": "sha512-CrYo6TntjpoMO1SHjl5Pa/JoUsECNqNdB7Kx49WLQpWzPw53eEITJ2Hs9fh/ryUYDn4pxZz11StaBYBrLFJdqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^8.1.0", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^10.2.1", - "nopt": "^6.0.0", - "proc-log": "^2.0.1", - "semver": "^7.3.5", - "tar": "^6.2.1", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/node-gyp/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@electron/node-gyp/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@electron/node-gyp/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@electron/notarize": { "version": "2.5.0", "resolved": "https://registry.npmmirror.com/@electron/notarize/-/notarize-2.5.0.tgz", @@ -5414,9 +6678,9 @@ } }, "node_modules/@electron/osx-sign": { - "version": "1.3.1", - "resolved": "https://registry.npmmirror.com/@electron/osx-sign/-/osx-sign-1.3.1.tgz", - "integrity": "sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -5437,7 +6701,7 @@ }, "node_modules/@electron/osx-sign/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -5452,7 +6716,7 @@ }, "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", @@ -5465,7 +6729,7 @@ }, "node_modules/@electron/osx-sign/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -5478,7 +6742,7 @@ }, "node_modules/@electron/osx-sign/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -5487,21 +6751,21 @@ } }, "node_modules/@electron/rebuild": { - "version": "3.7.0", - "resolved": "https://registry.npmmirror.com/@electron/rebuild/-/rebuild-3.7.0.tgz", - "integrity": "sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.1.tgz", + "integrity": "sha512-iMGXb6Ib7H/Q3v+BKZJoETgF9g6KMNZVbsO4b7Dmpgb5qTFqyFTzqW9F3TOSHdybv2vKYKzSS9OiZL+dcJb+1Q==", "dev": true, "license": "MIT", "dependencies": { - "@electron/node-gyp": "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2", "@malept/cross-spawn-promise": "^2.0.0", "chalk": "^4.0.0", "debug": "^4.1.1", "detect-libc": "^2.0.1", - "fs-extra": "^10.0.0", "got": "^11.7.0", - "node-abi": "^3.45.0", - "node-api-version": "^0.2.0", + "graceful-fs": "^4.2.11", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^11.2.0", "ora": "^5.1.0", "read-binary-file-arch": "^1.0.6", "semver": "^7.3.5", @@ -5512,55 +6776,17 @@ "electron-rebuild": "lib/cli.js" }, "engines": { - "node": ">=12.13.0" - } - }, - "node_modules/@electron/rebuild/node_modules/fs-extra": { - "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", - "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@electron/rebuild/node_modules/jsonfile": { - "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", - "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/@electron/rebuild/node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10.0.0" + "node": ">=22.12.0" } }, "node_modules/@electron/universal": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@electron/universal/-/universal-2.0.1.tgz", - "integrity": "sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", "dev": true, "license": "MIT", "dependencies": { - "@electron/asar": "^3.2.7", + "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", @@ -5574,7 +6800,7 @@ }, "node_modules/@electron/universal/node_modules/brace-expansion": { "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", @@ -5584,7 +6810,7 @@ }, "node_modules/@electron/universal/node_modules/fs-extra": { "version": "11.3.3", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.3.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.3.tgz", "integrity": "sha512-VWSRii4t0AFm6ixFFmLLx1t7wS1gh+ckoa84aOeapGum0h+EZd1EhEumSB+ZdDLnEPuucsVB9oB7cxJHap6Afg==", "dev": true, "license": "MIT", @@ -5599,7 +6825,7 @@ }, "node_modules/@electron/universal/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -5612,7 +6838,7 @@ }, "node_modules/@electron/universal/node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", @@ -5628,7 +6854,7 @@ }, "node_modules/@electron/universal/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -5643,7 +6869,6 @@ "dev": true, "license": "BSD-2-Clause", "optional": true, - "peer": true, "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", @@ -5665,7 +6890,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -5682,7 +6906,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "universalify": "^2.0.0" }, @@ -5697,7 +6920,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": ">= 10.0.0" } @@ -6332,6 +7554,7 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.7.0.tgz", "integrity": "sha512-5i+BtvujK/vM07YCGDyz4C4AyDzLmhxHMtM5HpUyPRtJPBdFPsj290ffXW+UXY21/G7GtXeHD2nRmq0T1ShyQQ==", + "dev": true, "license": "MIT", "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" @@ -6345,6 +7568,22 @@ } } }, + "node_modules/@extractus/article-extractor": { + "version": "8.0.20", + "resolved": "https://registry.npmjs.org/@extractus/article-extractor/-/article-extractor-8.0.20.tgz", + "integrity": "sha512-oxHLZ3X5ctLVkQfFkOLf8afvQq6aJ2VBxwQhAaV6ZypaaMJboFz8uwpCGy7QBehmQIvzgWhCwuu8j4ayJFvPcg==", + "license": "MIT", + "dependencies": { + "@mozilla/readability": "^0.6.0", + "@ndaidong/bellajs": "^12.0.1", + "cross-fetch": "^4.1.0", + "linkedom": "^0.18.12", + "sanitize-html": "2.17.0" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/@floating-ui/core": { "version": "1.6.9", "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", @@ -6384,31 +7623,24 @@ "license": "MIT" }, "node_modules/@formatjs/fast-memoize": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.0.2.tgz", - "integrity": "sha512-YFApUDWFmjpPwAE7VcY7PYVjm6JaLZOAo0UfCQj1/OGi/1QtduG9kIBHmVC551M6AI01qvuP5kjbDebrZOT4Vg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-3.0.3.tgz", + "integrity": "sha512-CArYtQKGLAOruCMeq5/RxCg6vUXFx3OuKBdTm30Wn/+gCefehmZ8Y2xSMxMrO2iel7hRyE3HKfV56t3vAU6D4Q==", "license": "MIT", "dependencies": { "tslib": "^2.8.0" } }, "node_modules/@formatjs/intl-localematcher": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.7.4.tgz", - "integrity": "sha512-AWsSZupIBMU/y04Nj24CjohyNVyfItMJPxSzX5OJwedDEIbGLOHkPxCjAeLeiLF2dw4xmQA8psktdi9MaebBQw==", + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@formatjs/intl-localematcher/-/intl-localematcher-0.7.5.tgz", + "integrity": "sha512-7/nd90cn5CT7SVF71/ybUKAcnvBlr9nZlJJp8O8xIZHXFgYOC4SXExZlSdgHv2l6utjw1byidL06QzChvQMHwA==", "license": "MIT", "dependencies": { - "@formatjs/fast-memoize": "3.0.2", + "@formatjs/fast-memoize": "3.0.3", "tslib": "^2.8.0" } }, - "node_modules/@gar/promisify": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true, - "license": "MIT" - }, "node_modules/@hapi/address": { "version": "5.1.1", "resolved": "https://registry.npmmirror.com/@hapi/address/-/address-5.1.1.tgz", @@ -7065,6 +8297,19 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -7179,7 +8424,7 @@ }, "node_modules/@malept/cross-spawn-promise": { "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", "dev": true, "funding": [ @@ -7255,6 +8500,21 @@ "node": ">= 10.0.0" } }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "license": "BSD-2-Clause" + }, + "node_modules/@mozilla/readability": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@mozilla/readability/-/readability-0.6.0.tgz", + "integrity": "sha512-juG5VWh4qAivzTAeMzvY9xs9HY5rAcr2E4I7tiSSCokRFi7XIZCAu92ZkSTsIj1OPceCifL3cpfteP3pDT9/QQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/@napi-rs/wasm-runtime": { "version": "0.2.12", "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz", @@ -7268,6 +8528,12 @@ "@tybys/wasm-util": "^0.10.0" } }, + "node_modules/@ndaidong/bellajs": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/@ndaidong/bellajs/-/bellajs-12.0.1.tgz", + "integrity": "sha512-1iY42uiHz0cxNMbde7O3zVN+ZX1viOOUOBRt6ht6lkRZbSjwOnFV34Zv4URp3hGzEe6L9Byk7BOq/41H0PzAOQ==", + "license": "MIT" + }, "node_modules/@next/env": { "version": "16.1.1", "resolved": "https://registry.npmjs.org/@next/env/-/env-16.1.1.tgz", @@ -7423,6 +8689,7 @@ "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", "license": "MIT", + "peer": true, "engines": { "node": "^14.21.3 || >=16" }, @@ -7595,33 +8862,34 @@ "node": ">=12.4.0" } }, + "node_modules/@npmcli/agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-3.0.0.tgz", + "integrity": "sha512-S79NdEgDQd/NGCay6TCoVzXSj74skRZIKJcpJjC5lOq34SZzyI6MqtiiWoiVWoVrTcGjNeC4ipbh1VIHlpfF5Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/@npmcli/fs": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/@npmcli/fs/-/fs-2.1.2.tgz", - "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-4.0.0.tgz", + "integrity": "sha512-/xGlezI6xfGO9NwuJlnwz/K14qD1kCSAGtacBHnGzeAIuJGazcp45KP5NuyARXoKb7cwulAGWVsbeSxdG/cb0Q==", "dev": true, "license": "ISC", "dependencies": { - "@gar/promisify": "^1.1.3", "semver": "^7.3.5" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/@npmcli/move-file": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/@npmcli/move-file/-/move-file-2.0.1.tgz", - "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", - "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, - "license": "MIT", - "dependencies": { - "mkdirp": "^1.0.4", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/@opennextjs/aws": { @@ -8108,9 +9376,9 @@ } }, "node_modules/@opennextjs/cloudflare": { - "version": "1.14.7", - "resolved": "https://registry.npmjs.org/@opennextjs/cloudflare/-/cloudflare-1.14.7.tgz", - "integrity": "sha512-gHK1vx2nIYvr16IG71zRFVTq5diV8haYb6UV+DHw1JZTw1xrM5g6E+k7tDu5n8NX0u/9QH+cZIsJS7nmXUnc+A==", + "version": "1.14.8", + "resolved": "https://registry.npmjs.org/@opennextjs/cloudflare/-/cloudflare-1.14.8.tgz", + "integrity": "sha512-7M6VezThyL7gg86MMuZnBvbzRtC08HWLSJWlvRaiHMUGlEoE94JOwtoC0YcoEnP7F4UsrdRnp+VpvMIVoqsO4w==", "license": "MIT", "dependencies": { "@ast-grep/napi": "0.40.0", @@ -8212,15 +9480,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@opennextjs/cloudflare/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/@opennextjs/cloudflare/node_modules/path-scurry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.1.tgz", @@ -8310,14 +9569,15 @@ "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=8.0.0" } }, "node_modules/@opentelemetry/api-logs": { - "version": "0.208.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.208.0.tgz", - "integrity": "sha512-CjruKY9V6NMssL/T1kAFgzosF1v9o6oeN+aX5JB/C/xPNtmgIJqcXHG7fA82Ou1zCpWGl4lROQUKwUNE1pMCyg==", + "version": "0.209.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.209.0.tgz", + "integrity": "sha512-xomnUNi7TiAGtOgs0tb54LyrjRZLu9shJGGwkcN7NgtiPYOpNnKLkRJtzZvTjD/w6knSZH9sFZcUSUovYOPg6A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/api": "^1.3.0" @@ -8327,9 +9587,9 @@ } }, "node_modules/@opentelemetry/context-async-hooks": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.2.0.tgz", - "integrity": "sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-2.3.0.tgz", + "integrity": "sha512-hGcsT0qDP7Il1L+qT3JFpiGl1dCjF794Bb4yCRCYdr7XC0NwHtOF3ngF86Gk6TUnsakbyQsDQ0E/S4CU0F4d4g==", "license": "Apache-2.0", "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8339,10 +9599,11 @@ } }, "node_modules/@opentelemetry/core": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.2.0.tgz", - "integrity": "sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-2.3.0.tgz", + "integrity": "sha512-PcmxJQzs31cfD0R2dE91YGFcLxOSN4Bxz7gez5UwSUjCai8BwH/GI5HchfVshHkWdTkUs0qcaPJgVHKXUp7I3A==", "license": "Apache-2.0", + "peer": true, "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, @@ -8354,16 +9615,17 @@ } }, "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.208.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.208.0.tgz", - "integrity": "sha512-jbzDw1q+BkwKFq9yxhjAJ9rjKldbt5AgIy1gmEIJjEV/WRxQ3B6HcLVkwbjJ3RcMif86BDNKR846KJ0tY0aOJA==", + "version": "0.209.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.209.0.tgz", + "integrity": "sha512-mqTGX3brr+aoDZgrx+m/9OKgCAh/Ufv0OpqmozN9L9z39IGtkvcMMjFGio061PjOB9fBzrsB8jYapYscVeve2g==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/otlp-exporter-base": "0.208.0", - "@opentelemetry/otlp-transformer": "0.208.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0" + "@opentelemetry/core": "2.3.0", + "@opentelemetry/otlp-exporter-base": "0.209.0", + "@opentelemetry/otlp-transformer": "0.209.0", + "@opentelemetry/resources": "2.3.0", + "@opentelemetry/sdk-trace-base": "2.3.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8373,13 +9635,13 @@ } }, "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.208.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.208.0.tgz", - "integrity": "sha512-gMd39gIfVb2OgxldxUtOwGJYSH8P1kVFFlJLuut32L6KgUC4gl1dMhn+YC2mGn0bDOiQYSk/uHOdSjuKp58vvA==", + "version": "0.209.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.209.0.tgz", + "integrity": "sha512-co5H3wptA8itNf14dOBQBtNlEagMnRf52eo3BC8PwnROrcDfuPw27CjhkxX0+7ywoyOOunwzMWzvig2Qe/Gqlg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/otlp-transformer": "0.208.0" + "@opentelemetry/core": "2.3.0", + "@opentelemetry/otlp-transformer": "0.209.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8389,18 +9651,18 @@ } }, "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.208.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.208.0.tgz", - "integrity": "sha512-DCFPY8C6lAQHUNkzcNT9R+qYExvsk6C5Bto2pbNxgicpcSWbe2WHShLxkOxIdNcBiYPdVHv/e7vH7K6TI+C+fQ==", + "version": "0.209.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.209.0.tgz", + "integrity": "sha512-YITtvJIrzEa1Okbjv9lwJluZVXYM6SuafpQTi0hOTCosa7lu/EA7azvpoJx12EReBZqBm+3Wh0Zabm/01RjNJA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.208.0", - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0", - "@opentelemetry/sdk-logs": "0.208.0", - "@opentelemetry/sdk-metrics": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0", - "protobufjs": "^7.3.0" + "@opentelemetry/api-logs": "0.209.0", + "@opentelemetry/core": "2.3.0", + "@opentelemetry/resources": "2.3.0", + "@opentelemetry/sdk-logs": "0.209.0", + "@opentelemetry/sdk-metrics": "2.3.0", + "@opentelemetry/sdk-trace-base": "2.3.0", + "protobufjs": "8.0.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8410,12 +9672,12 @@ } }, "node_modules/@opentelemetry/resources": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.2.0.tgz", - "integrity": "sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-2.3.0.tgz", + "integrity": "sha512-shlr2l5g+87J8wqYlsLyaUsgKVRO7RtX70Ckd5CtDOWtImZgaUDmf4Z2ozuSKQLM2wPDR0TE/3bPVBNJtRm/cQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.2.0", + "@opentelemetry/core": "2.3.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -8426,14 +9688,14 @@ } }, "node_modules/@opentelemetry/sdk-logs": { - "version": "0.208.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.208.0.tgz", - "integrity": "sha512-QlAyL1jRpOeaqx7/leG1vJMp84g0xKP6gJmfELBpnI4O/9xPX+Hu5m1POk9Kl+veNkyth5t19hRlN6tNY1sjbA==", + "version": "0.209.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.209.0.tgz", + "integrity": "sha512-dGlYTZaLQaj1GlKWIcWDQofSyKu+Nbq28Rcqo6meQ60OhSune1Wn+dnOQPwQnI6nfhWoTxGR00EJm1UCrkR2Gg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.208.0", - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0" + "@opentelemetry/api-logs": "0.209.0", + "@opentelemetry/core": "2.3.0", + "@opentelemetry/resources": "2.3.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8443,13 +9705,13 @@ } }, "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.2.0.tgz", - "integrity": "sha512-G5KYP6+VJMZzpGipQw7Giif48h6SGQ2PFKEYCybeXJsOCB4fp8azqMAAzE5lnnHK3ZVwYQrgmFbsUJO/zOnwGw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-2.3.0.tgz", + "integrity": "sha512-P+bYQgJHf6hRKgsR7xDnbNPDP+x1DwGtse6gHAPZ/iwMGbtQPVvhyFK1lseow5o3kLxNEaQv4lDqAF/vpRdXxA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0" + "@opentelemetry/core": "2.3.0", + "@opentelemetry/resources": "2.3.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8459,13 +9721,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-base": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.2.0.tgz", - "integrity": "sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-2.3.0.tgz", + "integrity": "sha512-B0TQ2e9h0ETjpI+eGmCz8Ojb+lnYms0SE3jFwEKrN/PK4aSVHU28AAmnOoBmfub+I3jfgPwvDJgomBA5a7QehQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@opentelemetry/core": "2.2.0", - "@opentelemetry/resources": "2.2.0", + "@opentelemetry/core": "2.3.0", + "@opentelemetry/resources": "2.3.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "engines": { @@ -8476,14 +9739,14 @@ } }, "node_modules/@opentelemetry/sdk-trace-node": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.2.0.tgz", - "integrity": "sha512-+OaRja3f0IqGG2kptVeYsrZQK9nKRSpfFrKtRBq4uh6nIB8bTBgaGvYQrQoRrQWQMA5dK5yLhDMDc0dvYvCOIQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-2.3.0.tgz", + "integrity": "sha512-oGsG3vIiC8zYjOWE4CgtS6d2gQhp4pT04AI9UL1wtJOxTSNVZiiIPgHnOp/qKJSwkD4YJHSohi6inSilPmGM2Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/context-async-hooks": "2.2.0", - "@opentelemetry/core": "2.2.0", - "@opentelemetry/sdk-trace-base": "2.2.0" + "@opentelemetry/context-async-hooks": "2.3.0", + "@opentelemetry/core": "2.3.0", + "@opentelemetry/sdk-trace-base": "2.3.0" }, "engines": { "node": "^18.19.0 || >=20.6.0" @@ -8503,7 +9766,7 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmmirror.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, "license": "MIT", @@ -8512,6 +9775,23 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.57.0.tgz", + "integrity": "sha512-6TyEnHgd6SArQO8UO2OMTxshln3QMWBtPGrOCgs3wVEmQmwyuNtB10IZMfmYDE0riwNR1cu4q+pPcxMVtaG3TA==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "playwright": "1.57.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@poppinss/colors": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@poppinss/colors/-/colors-4.1.6.tgz", @@ -9543,6 +10823,321 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.54.0.tgz", + "integrity": "sha512-OywsdRHrFvCdvsewAInDKCNyR3laPA2mc9bRYJ6LBp5IyvF3fvXbbNR0bSzHlZVFtn6E0xw2oZlyjg4rKCVcng==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.54.0.tgz", + "integrity": "sha512-Skx39Uv+u7H224Af+bDgNinitlmHyQX1K/atIA32JP3JQw6hVODX5tkbi2zof/E69M1qH2UoN3Xdxgs90mmNYw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.54.0.tgz", + "integrity": "sha512-k43D4qta/+6Fq+nCDhhv9yP2HdeKeP56QrUUTW7E6PhZP1US6NDqpJj4MY0jBHlJivVJD5P8NxrjuobZBJTCRw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.54.0.tgz", + "integrity": "sha512-cOo7biqwkpawslEfox5Vs8/qj83M/aZCSSNIWpVzfU2CYHa2G3P1UN5WF01RdTHSgCkri7XOlTdtk17BezlV3A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.54.0.tgz", + "integrity": "sha512-miSvuFkmvFbgJ1BevMa4CPCFt5MPGw094knM64W9I0giUIMMmRYcGW/JWZDriaw/k1kOBtsWh1z6nIFV1vPNtA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.54.0.tgz", + "integrity": "sha512-KGXIs55+b/ZfZsq9aR026tmr/+7tq6VG6MsnrvF4H8VhwflTIuYh+LFUlIsRdQSgrgmtM3fVATzEAj4hBQlaqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.54.0.tgz", + "integrity": "sha512-EHMUcDwhtdRGlXZsGSIuXSYwD5kOT9NVnx9sqzYiwAc91wfYOE1g1djOEDseZJKKqtHAHGwnGPQu3kytmfaXLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.54.0.tgz", + "integrity": "sha512-+pBrqEjaakN2ySv5RVrj/qLytYhPKEUwk+e3SFU5jTLHIcAtqh2rLrd/OkbNuHJpsBgxsD8ccJt5ga/SeG0JmA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.54.0.tgz", + "integrity": "sha512-NSqc7rE9wuUaRBsBp5ckQ5CVz5aIRKCwsoa6WMF7G01sX3/qHUw/z4pv+D+ahL1EIKy6Enpcnz1RY8pf7bjwng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.54.0.tgz", + "integrity": "sha512-gr5vDbg3Bakga5kbdpqx81m2n9IX8M6gIMlQQIXiLTNeQW6CucvuInJ91EuCJ/JYvc+rcLLsDFcfAD1K7fMofg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.54.0.tgz", + "integrity": "sha512-gsrtB1NA3ZYj2vq0Rzkylo9ylCtW/PhpLEivlgWe0bpgtX5+9j9EZa0wtZiCjgu6zmSeZWyI/e2YRX1URozpIw==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.54.0.tgz", + "integrity": "sha512-y3qNOfTBStmFNq+t4s7Tmc9hW2ENtPg8FeUD/VShI7rKxNW7O4fFeaYbMsd3tpFlIg1Q8IapFgy7Q9i2BqeBvA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.54.0.tgz", + "integrity": "sha512-89sepv7h2lIVPsFma8iwmccN7Yjjtgz0Rj/Ou6fEqg3HDhpCa+Et+YSufy27i6b0Wav69Qv4WBNl3Rs6pwhebQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.54.0.tgz", + "integrity": "sha512-ZcU77ieh0M2Q8Ur7D5X7KvK+UxbXeDHwiOt/CPSBTI1fBmeDMivW0dPkdqkT4rOgDjrDDBUed9x4EgraIKoR2A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.54.0.tgz", + "integrity": "sha512-2AdWy5RdDF5+4YfG/YesGDDtbyJlC9LHmL6rZw6FurBJ5n4vFGupsOBGfwMRjBYH7qRQowT8D/U4LoSvVwOhSQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.54.0.tgz", + "integrity": "sha512-WGt5J8Ij/rvyqpFexxk3ffKqqbLf9AqrTBbWDk7ApGUzaIs6V+s2s84kAxklFwmMF/vBNGrVdYgbblCOFFezMQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.54.0.tgz", + "integrity": "sha512-JzQmb38ATzHjxlPHuTH6tE7ojnMKM2kYNzt44LO/jJi8BpceEC8QuXYA908n8r3CNuG/B3BV8VR3Hi1rYtmPiw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.54.0.tgz", + "integrity": "sha512-huT3fd0iC7jigGh7n3q/+lfPcXxBi+om/Rs3yiFxjvSxbSB6aohDFXbWvlspaqjeOh+hx7DDHS+5Es5qRkWkZg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.54.0.tgz", + "integrity": "sha512-c2V0W1bsKIKfbLMBu/WGBz6Yci8nJ/ZJdheE0EwB73N3MvHYKiKGs3mVilX4Gs70eGeDaMqEob25Tw2Gb9Nqyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.54.0.tgz", + "integrity": "sha512-woEHgqQqDCkAzrDhvDipnSirm5vxUXtSKDYTVpZG3nUdW/VVB5VdCYA2iReSj/u3yCZzXID4kuKG7OynPnB3WQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.54.0.tgz", + "integrity": "sha512-dzAc53LOuFvHwbCEOS0rPbXp6SIhAf2txMP5p6mGyOXXw5mWY8NGGbPMPrs4P1WItkfApDathBj/NzMLUZ9rtQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.54.0.tgz", + "integrity": "sha512-hYT5d3YNdSh3mbCU1gwQyPgQd3T2ne0A3KG8KSBdav5TiBg6eInVmV+TeR5uHufiIgSFg0XsOWGW5/RhNcSvPg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -9619,9 +11214,9 @@ } }, "node_modules/@smithy/core": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.0.tgz", - "integrity": "sha512-WsSHCPq/neD5G/MkK4csLI5Y5Pkd9c1NMfpYEKeghSGaD4Ja1qLIohRQf2D5c1Uy5aXp76DeKHkzWZ9KAlHroQ==", + "version": "3.20.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.20.2.tgz", + "integrity": "sha512-nc99TseyTwL1bg+T21cyEA5oItNy1XN4aUeyOlXJnvyRW5VSK1oRKRoSM/Iq0KFPuqZMxjBemSZHZCOZbSyBMw==", "license": "Apache-2.0", "dependencies": { "@smithy/middleware-serde": "^4.2.8", @@ -9839,12 +11434,12 @@ } }, "node_modules/@smithy/middleware-endpoint": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.1.tgz", - "integrity": "sha512-gpLspUAoe6f1M6H0u4cVuFzxZBrsGZmjx2O9SigurTx4PbntYa4AJ+o0G0oGm1L2oSX6oBhcGHwrfJHup2JnJg==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-4.4.3.tgz", + "integrity": "sha512-Zb8R35hjBhp1oFhiaAZ9QhClpPHdEDmNDC2UrrB2fqV0oNDUUPH12ovZHB5xi/Rd+pg/BJHOR1q+SfsieSKPQg==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.20.0", + "@smithy/core": "^3.20.2", "@smithy/middleware-serde": "^4.2.8", "@smithy/node-config-provider": "^4.3.7", "@smithy/shared-ini-file-loader": "^4.4.2", @@ -9858,15 +11453,15 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "4.4.17", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.17.tgz", - "integrity": "sha512-MqbXK6Y9uq17h+4r0ogu/sBT6V/rdV+5NvYL7ZV444BKfQygYe8wAhDrVXagVebN6w2RE0Fm245l69mOsPGZzg==", + "version": "4.4.19", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-4.4.19.tgz", + "integrity": "sha512-QtisFIjIw2tjMm/ESatjWFVIQb5Xd093z8xhxq/SijLg7Mgo2C2wod47Ib/AHpBLFhwYXPzd7Hp2+JVXfeZyMQ==", "license": "Apache-2.0", "dependencies": { "@smithy/node-config-provider": "^4.3.7", "@smithy/protocol-http": "^5.3.7", "@smithy/service-error-classification": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.4", "@smithy/types": "^4.11.0", "@smithy/util-middleware": "^4.2.7", "@smithy/util-retry": "^4.2.7", @@ -10033,13 +11628,13 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "4.10.2", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.2.tgz", - "integrity": "sha512-D5z79xQWpgrGpAHb054Fn2CCTQZpog7JELbVQ6XAvXs5MNKWf28U9gzSBlJkOyMl9LA1TZEjRtwvGXfP0Sl90g==", + "version": "4.10.4", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-4.10.4.tgz", + "integrity": "sha512-rHig+BWjhjlHlah67ryaW9DECYixiJo5pQCTEwsJyarRBAwHMMC3iYz5MXXAHXe64ZAMn1NhTUSTFIu1T6n6jg==", "license": "Apache-2.0", "dependencies": { - "@smithy/core": "^3.20.0", - "@smithy/middleware-endpoint": "^4.4.1", + "@smithy/core": "^3.20.2", + "@smithy/middleware-endpoint": "^4.4.3", "@smithy/middleware-stack": "^4.2.7", "@smithy/protocol-http": "^5.3.7", "@smithy/types": "^4.11.0", @@ -10140,13 +11735,13 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "4.3.16", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.16.tgz", - "integrity": "sha512-/eiSP3mzY3TsvUOYMeL4EqUX6fgUOj2eUOU4rMMgVbq67TiRLyxT7Xsjxq0bW3OwuzK009qOwF0L2OgJqperAQ==", + "version": "4.3.18", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-4.3.18.tgz", + "integrity": "sha512-Ao1oLH37YmLyHnKdteMp6l4KMCGBeZEAN68YYe00KAaKFijFELDbRQRm3CNplz7bez1HifuBV0l5uR6eVJLhIg==", "license": "Apache-2.0", "dependencies": { "@smithy/property-provider": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.4", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, @@ -10155,16 +11750,16 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "4.2.19", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.19.tgz", - "integrity": "sha512-3a4+4mhf6VycEJyHIQLypRbiwG6aJvbQAeRAVXydMmfweEPnLLabRbdyo/Pjw8Rew9vjsh5WCdhmDaHkQnhhhA==", + "version": "4.2.21", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-4.2.21.tgz", + "integrity": "sha512-e21ASJDirE96kKXZLcYcnn4Zt0WGOvMYc1P8EK0gQeQ3I8PbJWqBKx9AUr/YeFpDkpYwEu1RsPe4UXk2+QL7IA==", "license": "Apache-2.0", "dependencies": { "@smithy/config-resolver": "^4.4.5", "@smithy/credential-provider-imds": "^4.2.7", "@smithy/node-config-provider": "^4.3.7", "@smithy/property-provider": "^4.2.7", - "@smithy/smithy-client": "^4.10.2", + "@smithy/smithy-client": "^4.10.4", "@smithy/types": "^4.11.0", "tslib": "^2.6.2" }, @@ -10672,14 +12267,77 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" } }, - "node_modules/@tootallnate/once": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/@tootallnate/once/-/once-2.0.0.tgz", - "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.1.tgz", + "integrity": "sha512-gr4KtAWqIOQoucWYD/f6ki+j5chXfcPc74Col/6poTyqTmn7zRmodWahWRCp8tYd+GMqBonw6hstNzqjbs6gjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 10" + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" } }, "node_modules/@tsconfig/node18": { @@ -10699,6 +12357,58 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, "node_modules/@types/cacheable-request": { "version": "6.0.3", "resolved": "https://registry.npmmirror.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", @@ -10712,6 +12422,17 @@ "@types/responselike": "^1.0.0" } }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/debug": { "version": "4.1.12", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", @@ -10721,6 +12442,13 @@ "@types/ms": "*" } }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -10738,7 +12466,7 @@ }, "node_modules/@types/fs-extra": { "version": "9.0.13", - "resolved": "https://registry.npmmirror.com/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", "dev": true, "license": "MIT", @@ -10809,9 +12537,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "24.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", - "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", + "version": "24.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.6.tgz", + "integrity": "sha512-B8h60xgJMR/xmgyX9fncRzEW9gCxoJjdenUhke2v1JGOd/V66KopmWrLPXi5oUI4VuiGK+d+HlXJjDRZMj21EQ==", "license": "MIT", "dependencies": { "undici-types": "~7.16.0" @@ -10842,7 +12570,7 @@ }, "node_modules/@types/plist": { "version": "3.0.5", - "resolved": "https://registry.npmmirror.com/@types/plist/-/plist-3.0.5.tgz", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", "dev": true, "license": "MIT", @@ -10859,10 +12587,11 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "19.2.7", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.7.tgz", - "integrity": "sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==", + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.8.tgz", + "integrity": "sha512-3MbSL37jEchWZz2p2mjntRZtPt837ij10ApxKfgmXCTuHWagYg7iA5bqPw6C8BMPfwidlvfPI/fxOc42HLhcyg==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -10873,6 +12602,7 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "devOptional": true, "license": "MIT", + "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -10887,6 +12617,13 @@ "@types/node": "*" } }, + "node_modules/@types/turndown": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@types/turndown/-/turndown-5.0.6.tgz", + "integrity": "sha512-ru00MoyeeouE5BX4gRL+6m/BsDfbRayOskWqUvh7CLGW+UXxHQItqALa38kKnOiZPqJrtzJUgAC2+F0rL1S4Pg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -10895,7 +12632,7 @@ }, "node_modules/@types/verror": { "version": "1.10.11", - "resolved": "https://registry.npmmirror.com/@types/verror/-/verror-1.10.11.tgz", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", "dev": true, "license": "MIT", @@ -10958,6 +12695,7 @@ "integrity": "sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.48.0", "@typescript-eslint/types": "8.48.0", @@ -11445,14 +13183,178 @@ ] }, "node_modules/@vercel/oidc": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.0.5.tgz", - "integrity": "sha512-fnYhv671l+eTTp48gB4zEsTW/YtRgRPnkI2nT7x6qw5rkI1Lq2hTmQIpHPgyThI0znLK+vX2n9XxKdXZ7BUbbw==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vercel/oidc/-/oidc-3.1.0.tgz", + "integrity": "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==", "license": "Apache-2.0", "engines": { "node": ">= 20" } }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.53", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitest/coverage-v8": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.16.tgz", + "integrity": "sha512-2rNdjEIsPRzsdu6/9Eq0AYAzYdpP6Bx9cje9tL3FE5XzXRQF1fNU9pe/1yE8fCrS0HD+fBtt6gLPh6LI57tX7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.0.16", + "ast-v8-to-istanbul": "^0.3.8", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.1", + "obug": "^2.1.1", + "std-env": "^3.10.0", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@vitest/browser": "4.0.16", + "vitest": "4.0.16" + }, + "peerDependenciesMeta": { + "@vitest/browser": { + "optional": true + } + } + }, + "node_modules/@vitest/expect": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", + "integrity": "sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.16", + "@vitest/utils": "4.0.16", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.16.tgz", + "integrity": "sha512-yb6k4AZxJTB+q9ycAvsoxGn+j/po0UaPgajllBgt1PzoMAAmJGYFdDk0uCcRcxb3BrME34I6u8gHZTQlkqSZpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.16", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.16.tgz", + "integrity": "sha512-eNCYNsSty9xJKi/UdVD8Ou16alu7AYiS2fCPRs0b1OdhJiV89buAXQLpTbe+X8V9L6qrs9CqyvU7OaAopJYPsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.16.tgz", + "integrity": "sha512-VWEDm5Wv9xEo80ctjORcTQRJ539EGPB3Pb9ApvVRAY1U/WkHXmmYISqU5E79uCwcW7xYUV38gwZD+RV755fu3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.16", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.16.tgz", + "integrity": "sha512-sf6NcrYhYBsSYefxnry+DR8n3UV4xWZwWxYbCJUt2YdvtqzSPR7VfGrY0zsv090DAbjFZsi7ZaMi1KnSRyK1XA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.16", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.16.tgz", + "integrity": "sha512-4jIOWjKP0ZUaEmJm00E0cOBLU+5WE0BpeNr3XN6TEF05ltro6NJqHWxXD0kA8/Zc8Nh23AT8WQxwNG+WeROupw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.16.tgz", + "integrity": "sha512-h8z9yYhV3e1LEfaQ3zdypIrnAg/9hguReGZoS7Gl0aBG5xgA410zBqECqmaF/+RkTggRsfnzc1XaAHA6bmUufA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.16", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, "node_modules/@xmldom/xmldom": { "version": "0.9.8", "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.8.tgz", @@ -11464,17 +13366,20 @@ }, "node_modules/7zip-bin": { "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/7zip-bin/-/7zip-bin-5.2.0.tgz", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", "dev": true, "license": "MIT" }, "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-3.0.1.tgz", + "integrity": "sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==", "dev": true, - "license": "ISC" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } }, "node_modules/abort-controller": { "version": "3.0.0", @@ -11531,6 +13436,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -11561,6 +13467,7 @@ "version": "7.1.3", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "dev": true, "license": "MIT", "engines": { "node": ">= 14" @@ -11578,29 +13485,16 @@ "node": ">= 8.0.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ai": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.6.tgz", - "integrity": "sha512-LM0eAMWVn3RTj+0X5O1m/8g+7QiTeWG5aN5FsDbdmCkAQHVg93XxLbljFOLzi0NMjuJgf7fKLKmWoPsrdMyqfw==", + "version": "6.0.27", + "resolved": "https://registry.npmjs.org/ai/-/ai-6.0.27.tgz", + "integrity": "sha512-a4ToMt5+4xOzHuYdoTy2GQXuNa2/Tpuhxfs5QESHtEV/Vf2HAzSwmTwikrIs8CDKPuMWV1I9YqAvaN5xexMCiQ==", "license": "Apache-2.0", + "peer": true, "dependencies": { - "@ai-sdk/gateway": "3.0.5", - "@ai-sdk/provider": "3.0.1", - "@ai-sdk/provider-utils": "4.0.2", + "@ai-sdk/gateway": "3.0.11", + "@ai-sdk/provider": "3.0.2", + "@ai-sdk/provider-utils": "4.0.4", "@opentelemetry/api": "1.9.0" }, "engines": { @@ -11616,6 +13510,7 @@ "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -11691,58 +13586,59 @@ }, "node_modules/app-builder-bin": { "version": "5.0.0-alpha.12", - "resolved": "https://registry.npmmirror.com/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", "dev": true, "license": "MIT" }, "node_modules/app-builder-lib": { - "version": "26.0.12", - "resolved": "https://registry.npmmirror.com/app-builder-lib/-/app-builder-lib-26.0.12.tgz", - "integrity": "sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.4.0.tgz", + "integrity": "sha512-Uas6hNe99KzP3xPWxh5LGlH8kWIVjZixzmMJHNB9+6hPyDpjc7NQMkVgi16rQDdpCFy22ZU5sp8ow7tvjeMgYQ==", "dev": true, "license": "MIT", "dependencies": { "@develar/schema-utils": "~2.6.5", - "@electron/asar": "3.2.18", + "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/notarize": "2.5.0", - "@electron/osx-sign": "1.3.1", - "@electron/rebuild": "3.7.0", - "@electron/universal": "2.0.1", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "4.0.1", + "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@types/fs-extra": "9.0.13", "async-exit-hook": "^2.0.1", - "builder-util": "26.0.11", - "builder-util-runtime": "9.3.1", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", "chromium-pickle-js": "^0.2.0", - "config-file-ts": "0.2.8-rc1", + "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", - "electron-publish": "26.0.11", + "electron-publish": "26.3.4", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", - "is-ci": "^3.0.0", "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", - "minimatch": "^10.0.0", + "minimatch": "^10.0.3", "plist": "3.1.0", "resedit": "^1.7.0", - "semver": "^7.3.8", + "semver": "~7.7.3", "tar": "^6.1.12", "temp-file": "^3.4.0", - "tiny-async-pool": "1.3.0" + "tiny-async-pool": "1.3.0", + "which": "^5.0.0" }, "engines": { "node": ">=14.0.0" }, "peerDependencies": { - "dmg-builder": "26.0.12", - "electron-builder-squirrel-windows": "26.0.12" + "dmg-builder": "26.4.0", + "electron-builder-squirrel-windows": "26.4.0" } }, "node_modules/app-builder-lib/node_modules/fs-extra": { @@ -11760,6 +13656,16 @@ "node": ">=12" } }, + "node_modules/app-builder-lib/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, "node_modules/app-builder-lib/node_modules/jsonfile": { "version": "6.2.0", "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", @@ -11799,6 +13705,22 @@ "node": ">= 10.0.0" } }, + "node_modules/app-builder-lib/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -11990,7 +13912,7 @@ }, "node_modules/assert-plus": { "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "license": "MIT", @@ -11999,6 +13921,16 @@ "node": ">=0.8" } }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/ast-types-flow": { "version": "0.0.8", "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", @@ -12006,9 +13938,28 @@ "dev": true, "license": "MIT" }, + "node_modules/ast-v8-to-istanbul": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.10.tgz", + "integrity": "sha512-p4K7vMz2ZSk3wN8l5o3y2bJAoZXT3VuJI5OLTATY/01CYWumWvwkUw0SqDBnNq6IiTO3qDa1eSQDibAV8g7XOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^9.0.1" + } + }, + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, "node_modules/astral-regex": { "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, "license": "MIT", @@ -12026,7 +13977,7 @@ }, "node_modules/async-exit-hook": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", "dev": true, "license": "MIT", @@ -12140,6 +14091,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, "funding": [ { "type": "github", @@ -12169,6 +14121,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, "license": "MIT", "dependencies": { "require-from-string": "^2.0.2" @@ -12176,7 +14129,7 @@ }, "node_modules/bl": { "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", @@ -12232,6 +14185,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "license": "ISC" + }, "node_modules/boolean": { "version": "3.2.0", "resolved": "https://registry.npmmirror.com/boolean/-/boolean-3.2.0.tgz", @@ -12291,6 +14250,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.25", "caniuse-lite": "^1.0.30001754", @@ -12307,7 +14267,7 @@ }, "node_modules/buffer": { "version": "5.7.1", - "resolved": "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, "funding": [ @@ -12347,23 +14307,22 @@ "license": "MIT" }, "node_modules/builder-util": { - "version": "26.0.11", - "resolved": "https://registry.npmmirror.com/builder-util/-/builder-util-26.0.11.tgz", - "integrity": "sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==", + "version": "26.3.4", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.3.4.tgz", + "integrity": "sha512-aRn88mYMktHxzdqDMF6Ayj0rKoX+ZogJ75Ck7RrIqbY/ad0HBvnS2xA4uHfzrGr5D2aLL3vU6OBEH4p0KMV2XQ==", "dev": true, "license": "MIT", "dependencies": { "@types/debug": "^4.1.6", "7zip-bin": "~5.2.0", "app-builder-bin": "5.0.0-alpha.12", - "builder-util-runtime": "9.3.1", + "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", - "is-ci": "^3.0.0", "js-yaml": "^4.1.0", "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", @@ -12373,9 +14332,9 @@ } }, "node_modules/builder-util-runtime": { - "version": "9.3.1", - "resolved": "https://registry.npmmirror.com/builder-util-runtime/-/builder-util-runtime-9.3.1.tgz", - "integrity": "sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==", + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12388,7 +14347,7 @@ }, "node_modules/builder-util/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -12403,7 +14362,7 @@ }, "node_modules/builder-util/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -12416,7 +14375,7 @@ }, "node_modules/builder-util/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -12434,38 +14393,32 @@ } }, "node_modules/cacache": { - "version": "16.1.3", - "resolved": "https://registry.npmmirror.com/cacache/-/cacache-16.1.3.tgz", - "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "version": "19.0.1", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-19.0.1.tgz", + "integrity": "sha512-hdsUxulXCi5STId78vRVYEtDAjq99ICAUktLTeTYsLoTE6Z8dS0c8pWNCxwdrk9YfJeobDZc2Y186hD/5ZQgFQ==", "dev": true, "license": "ISC", "dependencies": { - "@npmcli/fs": "^2.1.0", - "@npmcli/move-file": "^2.0.0", - "chownr": "^2.0.0", - "fs-minipass": "^2.1.0", - "glob": "^8.0.1", - "infer-owner": "^1.0.4", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", + "@npmcli/fs": "^4.0.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "mkdirp": "^1.0.4", - "p-map": "^4.0.0", - "promise-inflight": "^1.0.1", - "rimraf": "^3.0.2", - "ssri": "^9.0.0", - "tar": "^6.1.11", - "unique-filename": "^2.0.0" + "p-map": "^7.0.2", + "ssri": "^12.0.0", + "tar": "^7.4.3", + "unique-filename": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/cacache/node_modules/brace-expansion": { "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", @@ -12473,48 +14426,78 @@ "balanced-match": "^1.0.0" } }, + "node_modules/cacache/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/cacache/node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, - "engines": { - "node": ">=12" + "bin": { + "glob": "dist/esm/bin.mjs" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/cacache/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, "node_modules/cacache/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cacache/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, "node_modules/cacheable-lookup": { @@ -12634,6 +14617,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -12693,7 +14686,7 @@ }, "node_modules/chownr": { "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", "dev": true, "license": "ISC", @@ -12709,9 +14702,9 @@ "license": "MIT" }, "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmmirror.com/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", "dev": true, "funding": [ { @@ -12736,16 +14729,6 @@ "url": "https://polar.sh/cva" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", @@ -12764,7 +14747,7 @@ }, "node_modules/cli-spinners": { "version": "2.9.2", - "resolved": "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.2.tgz", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "dev": true, "license": "MIT", @@ -12888,7 +14871,7 @@ }, "node_modules/clone": { "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", "dev": true, "license": "MIT", @@ -13046,7 +15029,7 @@ }, "node_modules/compare-version": { "version": "0.1.2", - "resolved": "https://registry.npmmirror.com/compare-version/-/compare-version-0.1.2.tgz", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", "dev": true, "license": "MIT", @@ -13102,74 +15085,6 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/config-file-ts": { - "version": "0.2.8-rc1", - "resolved": "https://registry.npmmirror.com/config-file-ts/-/config-file-ts-0.2.8-rc1.tgz", - "integrity": "sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "glob": "^10.3.12", - "typescript": "^5.4.3" - } - }, - "node_modules/config-file-ts/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/config-file-ts/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmmirror.com/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/config-file-ts/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/content-disposition": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.1.tgz", @@ -13223,7 +15138,7 @@ }, "node_modules/core-util-is": { "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", "dev": true, "license": "MIT", @@ -13231,7 +15146,7 @@ }, "node_modules/crc": { "version": "3.8.0", - "resolved": "https://registry.npmmirror.com/crc/-/crc-3.8.0.tgz", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", "dev": true, "license": "MIT", @@ -13246,8 +15161,7 @@ "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", "dev": true, "license": "MIT", - "optional": true, - "peer": true + "optional": true }, "node_modules/cross-env": { "version": "10.1.0", @@ -13267,6 +15181,15 @@ "node": ">=20" } }, + "node_modules/cross-fetch": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.1.0.tgz", + "integrity": "sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.7.0" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -13281,10 +15204,27 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/css-tree": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", + "dev": true, "license": "MIT", "dependencies": { "mdn-data": "2.12.2", @@ -13294,6 +15234,18 @@ "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/cssesc": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", @@ -13307,10 +15259,17 @@ "node": ">=4" } }, + "node_modules/cssom": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", + "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", + "license": "MIT" + }, "node_modules/cssstyle": { "version": "5.3.5", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.5.tgz", "integrity": "sha512-GlsEptulso7Jg0VaOZ8BXQi3AkYM5BOJKEO/rjMidSCq70FkIC5y0eawrCXeYzxgt3OCf4Ls+eoxN+/05vN0Ag==", + "dev": true, "license": "MIT", "dependencies": { "@asamuzakjp/css-color": "^4.1.1", @@ -13338,6 +15297,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", + "dev": true, "license": "MIT", "dependencies": { "whatwg-mimetype": "^4.0.0", @@ -13422,6 +15382,7 @@ "version": "10.6.0", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, "license": "MIT" }, "node_modules/decode-named-character-reference": { @@ -13473,9 +15434,18 @@ "dev": true, "license": "MIT" }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defaults": { "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", "dev": true, "license": "MIT", @@ -13597,7 +15567,7 @@ }, "node_modules/dir-compare": { "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/dir-compare/-/dir-compare-4.2.0.tgz", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", "dev": true, "license": "MIT", @@ -13607,15 +15577,15 @@ } }, "node_modules/dmg-builder": { - "version": "26.0.12", - "resolved": "https://registry.npmmirror.com/dmg-builder/-/dmg-builder-26.0.12.tgz", - "integrity": "sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.4.0.tgz", + "integrity": "sha512-ce4Ogns4VMeisIuCSK0C62umG0lFy012jd8LMZ6w/veHUeX4fqfDrGe+HTWALAEwK6JwKP+dhPvizhArSOsFbg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { - "app-builder-lib": "26.0.12", - "builder-util": "26.0.11", - "builder-util-runtime": "9.3.1", + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", "fs-extra": "^10.1.0", "iconv-lite": "^0.6.2", "js-yaml": "^4.1.0" @@ -13626,7 +15596,7 @@ }, "node_modules/dmg-builder/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -13641,7 +15611,7 @@ }, "node_modules/dmg-builder/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -13654,7 +15624,7 @@ }, "node_modules/dmg-builder/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -13664,7 +15634,7 @@ }, "node_modules/dmg-license": { "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/dmg-license/-/dmg-license-1.0.11.tgz", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", "dev": true, "license": "MIT", @@ -13702,6 +15672,80 @@ "node": ">=0.10.0" } }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmmirror.com/dotenv/-/dotenv-16.6.1.tgz", @@ -13815,19 +15859,19 @@ } }, "node_modules/electron-builder": { - "version": "26.0.12", - "resolved": "https://registry.npmmirror.com/electron-builder/-/electron-builder-26.0.12.tgz", - "integrity": "sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.4.0.tgz", + "integrity": "sha512-FCUqvdq2AULL+Db2SUGgjOYTbrgkPxZtCjqIZGnjH9p29pTWyesQqBIfvQBKa6ewqde87aWl49n/WyI/NyUBog==", "dev": true, "license": "MIT", "dependencies": { - "app-builder-lib": "26.0.12", - "builder-util": "26.0.11", - "builder-util-runtime": "9.3.1", + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", - "dmg-builder": "26.0.12", + "ci-info": "^4.2.0", + "dmg-builder": "26.4.0", "fs-extra": "^10.1.0", - "is-ci": "^3.0.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" @@ -13841,21 +15885,21 @@ } }, "node_modules/electron-builder-squirrel-windows": { - "version": "26.0.12", - "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.0.12.tgz", - "integrity": "sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==", + "version": "26.4.0", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.4.0.tgz", + "integrity": "sha512-7dvalY38xBzWNaoOJ4sqy2aGIEpl2S1gLPkkB0MHu1Hu5xKQ82il1mKSFlXs6fLpXUso/NmyjdHGlSHDRoG8/w==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "app-builder-lib": "26.0.12", - "builder-util": "26.0.11", + "app-builder-lib": "26.4.0", + "builder-util": "26.3.4", "electron-winstaller": "5.4.0" } }, "node_modules/electron-builder/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -13870,7 +15914,7 @@ }, "node_modules/electron-builder/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -13883,7 +15927,7 @@ }, "node_modules/electron-builder/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -13892,15 +15936,15 @@ } }, "node_modules/electron-publish": { - "version": "26.0.11", - "resolved": "https://registry.npmmirror.com/electron-publish/-/electron-publish-26.0.11.tgz", - "integrity": "sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==", + "version": "26.3.4", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.3.4.tgz", + "integrity": "sha512-5/ouDPb73SkKuay2EXisPG60LTFTMNHWo2WLrK5GDphnWK9UC+yzYrzVeydj078Yk4WUXi0+TaaZsNd6Zt5k/A==", "dev": true, "license": "MIT", "dependencies": { "@types/fs-extra": "^9.0.11", - "builder-util": "26.0.11", - "builder-util-runtime": "9.3.1", + "builder-util": "26.3.4", + "builder-util-runtime": "9.5.1", "chalk": "^4.1.2", "form-data": "^4.0.0", "fs-extra": "^10.1.0", @@ -13910,7 +15954,7 @@ }, "node_modules/electron-publish/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -13925,7 +15969,7 @@ }, "node_modules/electron-publish/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -13938,7 +15982,7 @@ }, "node_modules/electron-publish/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -13960,7 +16004,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", @@ -13981,7 +16024,6 @@ "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", @@ -14240,6 +16282,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -14381,6 +16430,7 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -14566,6 +16616,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -14832,6 +16883,16 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -15000,9 +17061,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/exponential-backoff": { "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", "dev": true, "license": "Apache-2.0" @@ -15113,7 +17184,7 @@ }, "node_modules/extsprintf": { "version": "1.4.1", - "resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.4.1.tgz", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", "dev": true, "engines": [ @@ -15427,13 +17498,13 @@ } }, "node_modules/framer-motion": { - "version": "12.23.26", - "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.23.26.tgz", - "integrity": "sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==", + "version": "12.25.0", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-12.25.0.tgz", + "integrity": "sha512-mlWqd0rApIjeyhTCSNCqPYsUAEhkcUukZxH3ke6KbstBRPcxhEpuIjmiUQvB+1E9xkEm5SpNHBgHCapH/QHTWg==", "license": "MIT", "dependencies": { - "motion-dom": "^12.23.23", - "motion-utils": "^12.23.6", + "motion-dom": "^12.24.11", + "motion-utils": "^12.24.10", "tslib": "^2.4.0" }, "peerDependencies": { @@ -15478,16 +17549,16 @@ } }, "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, "node_modules/fs.realpath": { @@ -15686,7 +17757,7 @@ }, "node_modules/glob": { "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, @@ -15774,6 +17845,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -16026,6 +18104,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, "license": "MIT", "dependencies": { "@exodus/bytes": "^1.6.0" @@ -16034,6 +18113,13 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, "node_modules/html-url-attributes": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/html-url-attributes/-/html-url-attributes-3.0.1.tgz", @@ -16044,6 +18130,25 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, "node_modules/http-cache-semantics": { "version": "4.2.0", "resolved": "https://registry.npmmirror.com/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", @@ -16075,6 +18180,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.0", @@ -16102,6 +18208,7 @@ "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, "license": "MIT", "dependencies": { "agent-base": "^7.1.2", @@ -16147,7 +18254,7 @@ }, "node_modules/iconv-corefoundation": { "version": "1.1.7", - "resolved": "https://registry.npmmirror.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", "dev": true, "license": "MIT", @@ -16165,7 +18272,7 @@ }, "node_modules/iconv-corefoundation/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", @@ -16176,7 +18283,7 @@ }, "node_modules/iconv-corefoundation/node_modules/cli-truncate": { "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/cli-truncate/-/cli-truncate-2.1.0.tgz", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", "dev": true, "license": "MIT", @@ -16194,7 +18301,7 @@ }, "node_modules/iconv-corefoundation/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true, "license": "MIT", @@ -16202,7 +18309,7 @@ }, "node_modules/iconv-corefoundation/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", @@ -16213,7 +18320,7 @@ }, "node_modules/iconv-corefoundation/node_modules/slice-ansi": { "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-3.0.0.tgz", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", "dev": true, "license": "MIT", @@ -16229,7 +18336,7 @@ }, "node_modules/iconv-corefoundation/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", @@ -16245,7 +18352,7 @@ }, "node_modules/iconv-corefoundation/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", @@ -16261,7 +18368,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -16278,7 +18385,7 @@ }, "node_modules/ieee754": { "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", "dev": true, "funding": [ @@ -16333,26 +18440,9 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/infer-owner": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true, - "license": "ISC" - }, "node_modules/inflight": { "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, @@ -16401,7 +18491,7 @@ }, "node_modules/ip-address": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", "dev": true, "license": "MIT", @@ -16542,19 +18632,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-ci": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/is-ci/-/is-ci-3.0.1.tgz", - "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ci-info": "^3.2.0" - }, - "bin": { - "is-ci": "bin.js" - } - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -16703,7 +18780,7 @@ }, "node_modules/is-interactive": { "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", "dev": true, "license": "MIT", @@ -16711,13 +18788,6 @@ "node": ">=8" } }, - "node_modules/is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true, - "license": "MIT" - }, "node_modules/is-map": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", @@ -16783,10 +18853,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-plain-object": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", + "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/is-potential-custom-element-name": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, "license": "MIT" }, "node_modules/is-promise": { @@ -16906,7 +18986,7 @@ }, "node_modules/is-unicode-supported": { "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", "dev": true, "license": "MIT", @@ -16989,6 +19069,60 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/iterator.prototype": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", @@ -17009,7 +19143,7 @@ }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmmirror.com/jackspeak/-/jackspeak-3.4.3.tgz", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, "license": "BlueOak-1.0.0", @@ -17070,15 +19204,6 @@ "node": ">= 20" } }, - "node_modules/js-tiktoken": { - "version": "1.0.21", - "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.21.tgz", - "integrity": "sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.5.1" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -17103,7 +19228,9 @@ "version": "27.4.0", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", + "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@acemir/cssom": "^0.9.28", "@asamuzakjp/dom-selector": "^6.7.6", @@ -17544,6 +19671,36 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/linkedom": { + "version": "0.18.12", + "resolved": "https://registry.npmjs.org/linkedom/-/linkedom-0.18.12.tgz", + "integrity": "sha512-jalJsOwIKuQJSeTvsgzPe9iJzyfVaEJiEXl+25EkKevsULHvMJzpNqwvj1jOESWdmgKDiXObyjOYwlUqG7wo1Q==", + "license": "ISC", + "dependencies": { + "css-select": "^5.1.0", + "cssom": "^0.5.0", + "html-escaper": "^3.0.3", + "htmlparser2": "^10.0.0", + "uhyphen": "^0.2.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": ">= 2" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/linkedom/node_modules/html-escaper": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-3.0.3.tgz", + "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", + "license": "MIT" + }, "node_modules/lint-staged": { "version": "16.2.7", "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz", @@ -17619,7 +19776,7 @@ }, "node_modules/log-symbols": { "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", "dev": true, "license": "MIT", @@ -17708,6 +19865,16 @@ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, "node_modules/magic-string": { "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", @@ -17718,94 +19885,55 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, + "node_modules/magicast": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.1.tgz", + "integrity": "sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", + "source-map-js": "^1.2.1" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/make-fetch-happen": { - "version": "10.2.1", - "resolved": "https://registry.npmmirror.com/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", - "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", + "integrity": "sha512-QMjGbFTP0blj97EeidG5hk/QhKQ3T4ICckQGLgz38QF7Vgbk6e6FTARN8KhKxyBbWn8R0HU+bnw8aSoFPD4qtQ==", "dev": true, "license": "ISC", "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^16.1.0", - "http-cache-semantics": "^4.1.0", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^3.1.6", - "minipass-collect": "^1.0.2", - "minipass-fetch": "^2.0.3", + "@npmcli/agent": "^3.0.0", + "cacache": "^19.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^4.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", + "negotiator": "^1.0.0", + "proc-log": "^5.0.0", "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^9.0.0" + "ssri": "^12.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/make-fetch-happen/node_modules/http-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", - "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/make-fetch-happen/node_modules/lru-cache": { - "version": "7.18.3", - "resolved": "https://registry.npmmirror.com/lru-cache/-/lru-cache-7.18.3.tgz", - "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/make-fetch-happen/node_modules/negotiator": { - "version": "0.6.4", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.4.tgz", - "integrity": "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/markdown-table": { @@ -18129,6 +20257,7 @@ "version": "2.12.2", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "dev": true, "license": "CC0-1.0" }, "node_modules/media-typer": { @@ -18747,7 +20876,7 @@ }, "node_modules/mime": { "version": "2.6.0", - "resolved": "https://registry.npmmirror.com/mime/-/mime-2.6.0.tgz", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "license": "MIT", @@ -18812,9 +20941,9 @@ } }, "node_modules/miniflare": { - "version": "4.20251210.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20251210.0.tgz", - "integrity": "sha512-k6kIoXwGVqlPZb0hcn+X7BmnK+8BjIIkusQPY22kCo2RaQJ/LzAjtxHQdGXerlHSnJyQivDQsL6BJHMpQfUFyw==", + "version": "4.20260107.0", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-4.20260107.0.tgz", + "integrity": "sha512-X93sXczqbBq9ixoM6jnesmdTqp+4baVC/aM/DuPpRS0LK0XtcqaO75qPzNEvDEzBAHxwMAWRIum/9hg32YB8iA==", "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -18825,10 +20954,10 @@ "sharp": "^0.33.5", "stoppable": "1.1.0", "undici": "7.14.0", - "workerd": "1.20251210.0", + "workerd": "1.20260107.1", "ws": "8.18.0", "youch": "4.1.0-beta.10", - "zod": "3.22.3" + "zod": "^3.25.76" }, "bin": { "miniflare": "bootstrap.js" @@ -19271,9 +21400,9 @@ } }, "node_modules/miniflare/node_modules/zod": { - "version": "3.22.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.3.tgz", - "integrity": "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==", + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" @@ -19303,44 +21432,40 @@ } }, "node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dev": true, + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">= 8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/minipass-fetch": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/minipass-fetch/-/minipass-fetch-2.1.2.tgz", - "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-4.0.1.tgz", + "integrity": "sha512-j7U11C5HXigVuutxebFadoYBbd7VSdZWggSe64NVdvWNBqGAiXPL2QVCehjmw7lY1oF9gOllYbORh+hiNgfPgQ==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.1.6", + "minipass": "^7.0.3", "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minizlib": "^3.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -19348,7 +21473,7 @@ }, "node_modules/minipass-flush": { "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/minipass-flush/-/minipass-flush-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "dev": true, "license": "ISC", @@ -19359,9 +21484,29 @@ "node": ">= 8" } }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-flush/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-pipeline": { "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", "dev": true, "license": "ISC", @@ -19372,9 +21517,29 @@ "node": ">=8" } }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, "node_modules/minipass-sized": { "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/minipass-sized/-/minipass-sized-1.0.3.tgz", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", "dev": true, "license": "ISC", @@ -19385,34 +21550,39 @@ "node": ">=8" } }, - "node_modules/minipass/node_modules/yallist": { + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" }, "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", "dev": true, "license": "MIT", "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">= 8" + "node": ">= 18" } }, - "node_modules/minizlib/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true, - "license": "ISC" - }, "node_modules/mkdirp": { "version": "1.0.4", "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", @@ -19435,12 +21605,12 @@ } }, "node_modules/motion": { - "version": "12.23.26", - "resolved": "https://registry.npmjs.org/motion/-/motion-12.23.26.tgz", - "integrity": "sha512-Ll8XhVxY8LXMVYTCfme27WH2GjBrCIzY4+ndr5QKxsK+YwCtOi2B/oBi5jcIbik5doXuWT/4KKDOVAZJkeY5VQ==", + "version": "12.25.0", + "resolved": "https://registry.npmjs.org/motion/-/motion-12.25.0.tgz", + "integrity": "sha512-jBFohEYklpZ+TL64zv03sHdqr1Tsc8/yDy7u68hVzi7hTJYtv53AduchqCiY3aWi4vY1hweS8DWtgCuckusYdQ==", "license": "MIT", "dependencies": { - "framer-motion": "^12.23.26", + "framer-motion": "^12.25.0", "tslib": "^2.4.0" }, "peerDependencies": { @@ -19461,18 +21631,18 @@ } }, "node_modules/motion-dom": { - "version": "12.23.23", - "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.23.23.tgz", - "integrity": "sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==", + "version": "12.24.11", + "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-12.24.11.tgz", + "integrity": "sha512-DlWOmsXMJrV8lzZyd+LKjG2CXULUs++bkq8GZ2Sr0R0RRhs30K2wtY+LKiTjhmJU3W61HK+rB0GLz6XmPvTA1A==", "license": "MIT", "dependencies": { - "motion-utils": "^12.23.6" + "motion-utils": "^12.24.10" } }, "node_modules/motion-utils": { - "version": "12.23.6", - "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.23.6.tgz", - "integrity": "sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==", + "version": "12.24.10", + "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-12.24.10.tgz", + "integrity": "sha512-x5TFgkCIP4pPsRLpKoI86jv/q8t8FQOiM/0E8QKBzfMozWHfkKap2gA1hOki+B5g3IsBNpxbUnfOum1+dgvYww==", "license": "MIT" }, "node_modules/ms": { @@ -19504,9 +21674,9 @@ } }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.1.6.tgz", + "integrity": "sha512-c7+7RQ+dMB5dPwwCp4ee1/iV/q2P6aK1mTZcfr1BTuVlyW9hJYiMPybJCcnBlQtuSmTIWNeazm/zqNoZSSElBg==", "funding": [ { "type": "github", @@ -19515,10 +21685,10 @@ ], "license": "MIT", "bin": { - "nanoid": "bin/nanoid.cjs" + "nanoid": "bin/nanoid.js" }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": "^18 || >=20" } }, "node_modules/napi-postinstall": { @@ -19558,6 +21728,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-16.1.1.tgz", "integrity": "sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "16.1.1", "@swc/helpers": "0.5.15", @@ -19606,6 +21777,24 @@ } } }, + "node_modules/next/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -19642,21 +21831,21 @@ "license": "MIT" }, "node_modules/node-abi": { - "version": "3.85.0", - "resolved": "https://registry.npmmirror.com/node-abi/-/node-abi-3.85.0.tgz", - "integrity": "sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.24.0.tgz", + "integrity": "sha512-u2EC1CeNe25uVtX3EZbdQ275c74zdZmmpzrHEQh2aIYqoVjlglfUpOX9YY85x1nlBydEKDVaSmMNhR7N82Qj8A==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.3.5" + "semver": "^7.6.3" }, "engines": { - "node": ">=10" + "node": ">=22.12.0" } }, "node_modules/node-addon-api": { "version": "1.7.2", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-1.7.2.tgz", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", "dev": true, "license": "MIT", @@ -19664,7 +21853,7 @@ }, "node_modules/node-api-version": { "version": "0.2.1", - "resolved": "https://registry.npmmirror.com/node-api-version/-/node-api-version-0.2.1.tgz", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", "dev": true, "license": "MIT", @@ -19734,6 +21923,94 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/node-gyp": { + "version": "11.5.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-11.5.0.tgz", + "integrity": "sha512-ra7Kvlhxn5V9Slyus0ygMa2h+UqExPqUIkfk7Pc8QTLT956JLSy51uWFwHtIYy0vI8cB4BDhc/S03+880My/LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^14.0.3", + "nopt": "^8.0.0", + "proc-log": "^5.0.0", + "semver": "^7.3.5", + "tar": "^7.4.3", + "tinyglobby": "^0.2.12", + "which": "^5.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/tar": { + "version": "7.5.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.2.tgz", + "integrity": "sha512-7NyxrTE4Anh8km8iEy7o0QYPs+0JKBTj5ZaqHg6B39erLg0qYXN3BijtShwbsNSvQ+LN75+KV+C4QR/f6Gwnpg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/node-gyp/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/node-releases": { "version": "2.0.27", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", @@ -19742,19 +22019,19 @@ "license": "MIT" }, "node_modules/nopt": { - "version": "6.0.0", - "resolved": "https://registry.npmmirror.com/nopt/-/nopt-6.0.0.tgz", - "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-8.1.0.tgz", + "integrity": "sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==", "dev": true, "license": "ISC", "dependencies": { - "abbrev": "^1.0.0" + "abbrev": "^3.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/normalize-url": { @@ -19793,6 +22070,18 @@ "node": ">=4" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -19930,6 +22219,17 @@ "integrity": "sha512-9WXswnqINnnhOG/5SLimUlzuU1hFJUc8zkwyD59Sd+dPOMf05PmnYG/d6Q7HZ+KmgkZJa1PxRso6QdM3sTNHig==", "license": "MIT" }, + "node_modules/obug": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.1.tgz", + "integrity": "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT" + }, "node_modules/ollama-ai-provider-v2": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ollama-ai-provider-v2/-/ollama-ai-provider-v2-2.0.0.tgz", @@ -20004,7 +22304,7 @@ }, "node_modules/ora": { "version": "5.4.1", - "resolved": "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", "dev": true, "license": "MIT", @@ -20028,7 +22328,7 @@ }, "node_modules/ora/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", @@ -20038,7 +22338,7 @@ }, "node_modules/ora/node_modules/cli-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", "dev": true, "license": "MIT", @@ -20051,7 +22351,7 @@ }, "node_modules/ora/node_modules/onetime": { "version": "5.1.2", - "resolved": "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "license": "MIT", @@ -20067,7 +22367,7 @@ }, "node_modules/ora/node_modules/restore-cursor": { "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", "dev": true, "license": "MIT", @@ -20081,14 +22381,14 @@ }, "node_modules/ora/node_modules/signal-exit": { "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true, "license": "ISC" }, "node_modules/ora/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", @@ -20170,16 +22470,13 @@ } }, "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.4.tgz", + "integrity": "sha512-tkAQEw8ysMzmkhgw8k+1U/iPhWNhykKnSk4Rd5zLoPJCuJaGRPo6YposrZgaxHKzDHdDWWZvE/Sk7hsL2X/CpQ==", "dev": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -20235,10 +22532,17 @@ "integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==", "license": "MIT" }, + "node_modules/parse-srcset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz", + "integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==", + "license": "MIT" + }, "node_modules/parse5": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "dev": true, "license": "MIT", "dependencies": { "entities": "^6.0.0" @@ -20268,7 +22572,7 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", @@ -20308,15 +22612,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", @@ -20383,9 +22678,56 @@ "node": ">=0.10" } }, + "node_modules/playwright": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.57.0.tgz", + "integrity": "sha512-ilYQj1s8sr2ppEJ2YVadYBN0Mb3mdo9J0wQ+UuDhzYqURwSoW4n1Xs5vs7ORwgDGmyEh33tRMeS8KhdkMoLXQw==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.57.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.57.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.57.0.tgz", + "integrity": "sha512-agTcKlMw/mjBWOnD6kFZttAAGHgi/Nw0CZ2o6JqWSbMlI219lAFLZZCyqByTsvVAJq5XA5H8cA6PrvBRpBWEuQ==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/plist": { "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/plist/-/plist-3.1.0.tgz", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", "dev": true, "license": "MIT", @@ -20400,7 +22742,7 @@ }, "node_modules/plist/node_modules/@xmldom/xmldom": { "version": "0.8.11", - "resolved": "https://registry.npmmirror.com/@xmldom/xmldom/-/xmldom-0.8.11.tgz", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.11.tgz", "integrity": "sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==", "dev": true, "license": "MIT", @@ -20419,10 +22761,9 @@ } }, "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "dev": true, + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "funding": [ { "type": "opencollective", @@ -20439,7 +22780,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.8", + "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -20461,6 +22802,24 @@ "node": ">=4" } }, + "node_modules/postcss/node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, "node_modules/postject": { "version": "1.0.0-alpha.6", "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", @@ -20468,7 +22827,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "commander": "^9.4.0" }, @@ -20486,7 +22844,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "engines": { "node": "^12.20.0 || >=14" } @@ -20501,6 +22858,51 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, "node_modules/prism-react-renderer": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/prism-react-renderer/-/prism-react-renderer-2.4.1.tgz", @@ -20515,13 +22917,13 @@ } }, "node_modules/proc-log": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/proc-log/-/proc-log-2.0.1.tgz", - "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-5.0.0.tgz", + "integrity": "sha512-Azwzvl90HaF0aCz1JrDdXQykFakSSNPaPoiZ9fm5qJIMHioDZEi7OAdRwSm6rSoPtY3Qutnm3L7ogmg3dc+wbQ==", "dev": true, "license": "ISC", "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/progress": { @@ -20534,13 +22936,6 @@ "node": ">=0.4.0" } }, - "node_modules/promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true, - "license": "ISC" - }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmmirror.com/promise-retry/-/promise-retry-2.0.1.tgz", @@ -20578,9 +22973,9 @@ } }, "node_modules/protobufjs": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.4.tgz", - "integrity": "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.0.0.tgz", + "integrity": "sha512-jx6+sE9h/UryaCZhsJWbJtTEy47yXoGNYI4z8ZaRncM0zBKeRqjO2JEcOUYwrYGb1WLhXM1FfMzW3annvFv0rw==", "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { @@ -20636,6 +23031,7 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -20735,6 +23131,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.3.tgz", "integrity": "sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -20803,6 +23200,16 @@ "react": ">=18" } }, + "node_modules/react-refresh": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-remove-scroll": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.6.3.tgz", @@ -20884,7 +23291,7 @@ }, "node_modules/read-binary-file-arch": { "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", "dev": true, "license": "MIT", @@ -20897,7 +23304,7 @@ }, "node_modules/readable-stream": { "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dev": true, "license": "MIT", @@ -21046,6 +23453,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -21176,9 +23584,9 @@ "license": "MIT" }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", @@ -21187,9 +23595,6 @@ }, "bin": { "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/roarr": { @@ -21211,6 +23616,48 @@ "node": ">=8.0" } }, + "node_modules/rollup": { + "version": "4.54.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.54.0.tgz", + "integrity": "sha512-3nk8Y3a9Ea8szgKhinMlGMhGMw89mqule3KWczxhIzqudyHdCIOHw8WJlj/r329fACjKLEh13ZSk7oE22kyeIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.54.0", + "@rollup/rollup-android-arm64": "4.54.0", + "@rollup/rollup-darwin-arm64": "4.54.0", + "@rollup/rollup-darwin-x64": "4.54.0", + "@rollup/rollup-freebsd-arm64": "4.54.0", + "@rollup/rollup-freebsd-x64": "4.54.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.54.0", + "@rollup/rollup-linux-arm-musleabihf": "4.54.0", + "@rollup/rollup-linux-arm64-gnu": "4.54.0", + "@rollup/rollup-linux-arm64-musl": "4.54.0", + "@rollup/rollup-linux-loong64-gnu": "4.54.0", + "@rollup/rollup-linux-ppc64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-gnu": "4.54.0", + "@rollup/rollup-linux-riscv64-musl": "4.54.0", + "@rollup/rollup-linux-s390x-gnu": "4.54.0", + "@rollup/rollup-linux-x64-gnu": "4.54.0", + "@rollup/rollup-linux-x64-musl": "4.54.0", + "@rollup/rollup-openharmony-arm64": "4.54.0", + "@rollup/rollup-win32-arm64-msvc": "4.54.0", + "@rollup/rollup-win32-ia32-msvc": "4.54.0", + "@rollup/rollup-win32-x64-gnu": "4.54.0", + "@rollup/rollup-win32-x64-msvc": "4.54.0", + "fsevents": "~2.3.2" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -21293,7 +23740,7 @@ }, "node_modules/safe-buffer": { "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, "funding": [ @@ -21355,7 +23802,7 @@ }, "node_modules/sanitize-filename": { "version": "1.6.3", - "resolved": "https://registry.npmmirror.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz", "integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==", "dev": true, "license": "WTFPL OR ISC", @@ -21363,17 +23810,78 @@ "truncate-utf8-bytes": "^1.0.0" } }, + "node_modules/sanitize-html": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.17.0.tgz", + "integrity": "sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==", + "license": "MIT", + "dependencies": { + "deepmerge": "^4.2.2", + "escape-string-regexp": "^4.0.0", + "htmlparser2": "^8.0.0", + "is-plain-object": "^5.0.0", + "parse-srcset": "^1.0.2", + "postcss": "^8.3.11" + } + }, + "node_modules/sanitize-html/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/sanitize-html/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sanitize-html/node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, "node_modules/sax": { - "version": "1.4.3", - "resolved": "https://registry.npmmirror.com/sax/-/sax-1.4.3.tgz", - "integrity": "sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==", + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.4.tgz", + "integrity": "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==", "dev": true, - "license": "BlueOak-1.0.0" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, "license": "ISC", "dependencies": { "xmlchars": "^2.2.0" @@ -21773,6 +24281,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -21839,7 +24354,7 @@ }, "node_modules/smart-buffer": { "version": "4.2.0", - "resolved": "https://registry.npmmirror.com/smart-buffer/-/smart-buffer-4.2.0.tgz", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true, "license": "MIT", @@ -21850,7 +24365,7 @@ }, "node_modules/socks": { "version": "2.8.7", - "resolved": "https://registry.npmmirror.com/socks/-/socks-2.8.7.tgz", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.7.tgz", "integrity": "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==", "dev": true, "license": "MIT", @@ -21864,31 +24379,18 @@ } }, "node_modules/socks-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmmirror.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", - "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz", + "integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">= 10" - } - }, - "node_modules/socks-proxy-agent/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" + "node": ">= 14" } }, "node_modules/sonner": { @@ -21948,16 +24450,16 @@ "optional": true }, "node_modules/ssri": { - "version": "9.0.1", - "resolved": "https://registry.npmmirror.com/ssri/-/ssri-9.0.1.tgz", - "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-12.0.0.tgz", + "integrity": "sha512-S7iGNosepx9RadX82oimUkvr0Ct7IjJbEbs4mJcTxst8um95J3sDYU1RBEOvdu6oL1Wek2ODI5i4MAw+dZ6cAQ==", "dev": true, "license": "ISC", "dependencies": { - "minipass": "^3.1.1" + "minipass": "^7.0.3" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/stable-hash": { @@ -21967,9 +24469,16 @@ "dev": true, "license": "MIT" }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/stat-mode": { "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/stat-mode/-/stat-mode-1.0.0.tgz", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", "dev": true, "license": "MIT", @@ -21986,6 +24495,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "dev": true, + "license": "MIT" + }, "node_modules/stop-iteration-iterator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", @@ -22012,7 +24528,7 @@ }, "node_modules/string_decoder": { "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "license": "MIT", @@ -22413,6 +24929,7 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, "license": "MIT" }, "node_modules/tailwind-merge": { @@ -22429,7 +24946,8 @@ "version": "4.1.18", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.18.tgz", "integrity": "sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tailwindcss-animate": { "version": "1.0.7", @@ -22456,7 +24974,7 @@ }, "node_modules/tar": { "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", "dev": true, "license": "ISC", @@ -22472,9 +24990,35 @@ "node": ">=10" } }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar/node_modules/minipass": { "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", "dev": true, "license": "ISC", @@ -22482,9 +25026,36 @@ "node": ">=8" } }, + "node_modules/tar/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/tar/node_modules/yallist": { "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true, "license": "ISC" @@ -22495,7 +25066,6 @@ "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" @@ -22506,7 +25076,7 @@ }, "node_modules/temp-file": { "version": "3.4.0", - "resolved": "https://registry.npmmirror.com/temp-file/-/temp-file-3.4.0.tgz", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", "dev": true, "license": "MIT", @@ -22517,7 +25087,7 @@ }, "node_modules/temp-file/node_modules/fs-extra": { "version": "10.1.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", "dev": true, "license": "MIT", @@ -22532,7 +25102,7 @@ }, "node_modules/temp-file/node_modules/jsonfile": { "version": "6.2.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.2.0.tgz", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.0.tgz", "integrity": "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==", "dev": true, "license": "MIT", @@ -22545,7 +25115,7 @@ }, "node_modules/temp-file/node_modules/universalify": { "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", @@ -22559,7 +25129,6 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -22567,21 +25136,6 @@ "mkdirp": "bin/cmd.js" } }, - "node_modules/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "peer": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/terser": { "version": "5.16.9", "resolved": "https://registry.npmjs.org/terser/-/terser-5.16.9.tgz", @@ -22633,7 +25187,7 @@ }, "node_modules/tiny-async-pool": { "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", "dev": true, "license": "MIT", @@ -22643,7 +25197,7 @@ }, "node_modules/tiny-async-pool/node_modules/semver": { "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/semver/-/semver-5.7.2.tgz", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", @@ -22651,6 +25205,23 @@ "semver": "bin/semver" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", + "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.15", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", @@ -22692,6 +25263,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -22699,10 +25271,21 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/tinyrainbow": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", + "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/tldts": { "version": "7.0.19", "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", + "dev": true, "license": "MIT", "dependencies": { "tldts-core": "^7.0.19" @@ -22715,6 +25298,7 @@ "version": "7.0.19", "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", + "dev": true, "license": "MIT" }, "node_modules/tmp": { @@ -22763,6 +25347,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "dev": true, "license": "BSD-3-Clause", "dependencies": { "tldts": "^7.0.5" @@ -22775,6 +25360,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, "license": "MIT", "dependencies": { "punycode": "^2.3.1" @@ -22815,7 +25401,7 @@ }, "node_modules/truncate-utf8-bytes": { "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", "dev": true, "license": "WTFPL", @@ -22842,6 +25428,27 @@ "integrity": "sha512-3X3M1PZcHtgQbnwizL+xU8CAgbYbeLHrrDwL9xxcZZrV5J+e7loJm1XrXozHjSkl44J0Zg0SgA8rXbh83kCkcQ==", "license": "MIT" }, + "node_modules/tsconfck": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.6.tgz", + "integrity": "sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==", + "dev": true, + "license": "MIT", + "bin": { + "tsconfck": "bin/tsconfck.js" + }, + "engines": { + "node": "^18 || >=20" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -22874,6 +25481,15 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, + "node_modules/turndown": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.2.tgz", + "integrity": "sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==", + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -23024,6 +25640,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -23056,6 +25673,12 @@ "typescript": ">=4.8.4 <6.0.0" } }, + "node_modules/uhyphen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/uhyphen/-/uhyphen-0.2.0.tgz", + "integrity": "sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==", + "license": "ISC" + }, "node_modules/unbox-primitive": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", @@ -23096,6 +25719,7 @@ "resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz", "integrity": "sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==", "license": "MIT", + "peer": true, "dependencies": { "pathe": "^2.0.3" } @@ -23120,29 +25744,29 @@ } }, "node_modules/unique-filename": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/unique-filename/-/unique-filename-2.0.1.tgz", - "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-4.0.0.tgz", + "integrity": "sha512-XSnEewXmQ+veP7xX2dS5Q4yZAvO40cBN2MWkJ7D/6sW4Dg6wYBNwM1Vrnz1FhH5AdeLIlUXRI9e28z1YZi71NQ==", "dev": true, "license": "ISC", "dependencies": { - "unique-slug": "^3.0.0" + "unique-slug": "^5.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/unique-slug": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/unique-slug/-/unique-slug-3.0.0.tgz", - "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-5.0.0.tgz", + "integrity": "sha512-9OdaqO5kwqR+1kVgHAhsp5vPNU0hnxRa26rBFNfNgM7M6pNtgzeBn3s/xbyCQL3dcjzOatcef6UUHpB/6MaETg==", "dev": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/unist-util-is": { @@ -23382,7 +26006,7 @@ }, "node_modules/utf8-byte-length": { "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", "dev": true, "license": "(WTFPL OR MIT)" @@ -23418,7 +26042,7 @@ }, "node_modules/verror": { "version": "1.10.1", - "resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.1.tgz", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", "dev": true, "license": "MIT", @@ -23460,10 +26084,232 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/vite": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.0.tgz", + "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-tsconfig-paths": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-6.0.4.tgz", + "integrity": "sha512-iIsEJ+ek5KqRTK17pmxtgIxXtqr3qDdE6OxrP9mVeGhVDNXRJTKN/l9oMbujTQNzMLe6XZ8qmpztfbkPu2TiFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "globrex": "^0.1.2", + "tsconfck": "^3.0.3", + "vite": "*" + }, + "peerDependencies": { + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/vitest": { + "version": "4.0.16", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.16.tgz", + "integrity": "sha512-E4t7DJ9pESL6E3I8nFjPa4xGUd3PmiWDLsDztS2qXSJWfHtbQnwAWylaBvSNY48I3vr8PTqIZlyK8TE3V3CA4Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@vitest/expect": "4.0.16", + "@vitest/mocker": "4.0.16", + "@vitest/pretty-format": "4.0.16", + "@vitest/runner": "4.0.16", + "@vitest/snapshot": "4.0.16", + "@vitest/spy": "4.0.16", + "@vitest/utils": "4.0.16", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.16", + "@vitest/browser-preview": "4.0.16", + "@vitest/browser-webdriverio": "4.0.16", + "@vitest/ui": "4.0.16", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vitest/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/w3c-xmlserializer": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, "license": "MIT", "dependencies": { "xml-name-validator": "^5.0.0" @@ -23494,7 +26340,7 @@ }, "node_modules/wcwidth": { "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", "dev": true, "license": "MIT", @@ -23515,6 +26361,7 @@ "version": "8.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", + "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=20" @@ -23524,6 +26371,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -23533,6 +26381,7 @@ "version": "15.1.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "dev": true, "license": "MIT", "dependencies": { "tr46": "^6.0.0", @@ -23646,6 +26495,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -23657,11 +26523,12 @@ } }, "node_modules/workerd": { - "version": "1.20251210.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20251210.0.tgz", - "integrity": "sha512-9MUUneP1BnRE9XAYi94FXxHmiLGbO75EHQZsgWqSiOXjoXSqJCw8aQbIEPxCy19TclEl/kHUFYce8ST2W+Qpjw==", + "version": "1.20260107.1", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20260107.1.tgz", + "integrity": "sha512-4ylAQJDdJZdMAUl2SbJgTa77YHpa88l6qmhiuCLNactP933+rifs7I0w1DslhUIFgydArUX5dNLAZnZhT7Bh7g==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "bin": { "workerd": "bin/workerd" }, @@ -23669,27 +26536,28 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20251210.0", - "@cloudflare/workerd-darwin-arm64": "1.20251210.0", - "@cloudflare/workerd-linux-64": "1.20251210.0", - "@cloudflare/workerd-linux-arm64": "1.20251210.0", - "@cloudflare/workerd-windows-64": "1.20251210.0" + "@cloudflare/workerd-darwin-64": "1.20260107.1", + "@cloudflare/workerd-darwin-arm64": "1.20260107.1", + "@cloudflare/workerd-linux-64": "1.20260107.1", + "@cloudflare/workerd-linux-arm64": "1.20260107.1", + "@cloudflare/workerd-windows-64": "1.20260107.1" } }, "node_modules/wrangler": { - "version": "4.54.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.54.0.tgz", - "integrity": "sha512-bANFsjDwJLbprYoBK+hUDZsVbUv2SqJd8QvArLIcZk+fPq4h/Ohtj5vkKXD3k0s2bD1DXLk08D+hYmeNH+xC6A==", + "version": "4.58.0", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-4.58.0.tgz", + "integrity": "sha512-Jm6EYtlt8iUcznOCPSMYC54DYkwrMNESzbH0Vh3GFHv/7XVw5gBC13YJAB+nWMRGJ+6B2dMzy/NVQS4ONL51Pw==", "license": "MIT OR Apache-2.0", + "peer": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.4.1", - "@cloudflare/unenv-preset": "2.7.13", + "@cloudflare/unenv-preset": "2.8.0", "blake3-wasm": "2.1.5", "esbuild": "0.27.0", - "miniflare": "4.20251210.0", + "miniflare": "4.20260107.0", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", - "workerd": "1.20251210.0" + "workerd": "1.20260107.1" }, "bin": { "wrangler": "bin/wrangler.js", @@ -23702,7 +26570,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20251210.0" + "@cloudflare/workers-types": "^4.20260107.1" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -24297,6 +27165,7 @@ "version": "8.18.3", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" @@ -24318,6 +27187,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, "license": "Apache-2.0", "engines": { "node": ">=18" @@ -24325,7 +27195,7 @@ }, "node_modules/xmlbuilder": { "version": "15.1.1", - "resolved": "https://registry.npmmirror.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", "dev": true, "license": "MIT", @@ -24337,6 +27207,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, "license": "MIT" }, "node_modules/y18n": { @@ -24502,10 +27373,11 @@ } }, "node_modules/zod": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.4.tgz", - "integrity": "sha512-Zw/uYiiyF6pUT1qmKbZziChgNPRu+ZRneAsMUDU6IwmXdWt5JwcUfy2bvLOCUtz5UniaN/Zx5aFttZYbYc7O/A==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", + "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/package.json b/package.json index 984d0417..615524d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "next-ai-draw-io", - "version": "0.4.9", + "version": "0.4.10", "license": "Apache-2.0", "private": true, "main": "dist-electron/main/index.js", @@ -24,8 +24,11 @@ "dist": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml", "dist:mac": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --mac", "dist:win": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --win", + "dist:win:build": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --win --publish never", "dist:linux": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --linux", - "dist:all": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --mac --win --linux" + "dist:all": "npm run electron:build && npm run electron:prepare && npx electron-builder --config electron/electron-builder.yml --mac --win --linux", + "test": "vitest", + "test:e2e": "playwright test" }, "dependencies": { "@ai-sdk/amazon-bedrock": "^4.0.1", @@ -38,14 +41,15 @@ "@ai-sdk/react": "^3.0.1", "@aws-sdk/client-dynamodb": "^3.957.0", "@aws-sdk/credential-providers": "^3.943.0", + "@extractus/article-extractor": "^8.0.18", "@formatjs/intl-localematcher": "^0.7.2", "@langfuse/client": "^4.4.9", "@langfuse/otel": "^4.4.4", "@langfuse/tracing": "^4.4.9", "@next/third-parties": "^16.0.6", - "@opennextjs/cloudflare": "1.14.7", + "@opennextjs/cloudflare": "1.14.8", "@openrouter/ai-sdk-provider": "^1.5.4", - "@opentelemetry/exporter-trace-otlp-http": "^0.208.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.209.0", "@opentelemetry/sdk-trace-node": "^2.2.0", "@radix-ui/react-alert-dialog": "^1.1.15", "@radix-ui/react-collapsible": "^1.1.12", @@ -65,11 +69,10 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "idb": "^8.0.3", - "js-tiktoken": "^1.0.21", - "jsdom": "^27.0.0", "jsonrepair": "^3.13.1", "lucide-react": "^0.562.0", "motion": "^12.23.25", + "nanoid": "^5.0.0", "negotiator": "^1.0.0", "next": "^16.0.7", "ollama-ai-provider-v2": "^2.0.0", @@ -86,6 +89,7 @@ "sonner": "^2.0.7", "tailwind-merge": "^3.0.2", "tailwindcss-animate": "^1.0.7", + "turndown": "^7.2.0", "unpdf": "^1.4.0", "zod": "^4.1.12" }, @@ -103,13 +107,20 @@ "devDependencies": { "@anthropic-ai/tokenizer": "^0.0.4", "@biomejs/biome": "^2.3.10", + "@playwright/test": "^1.57.0", "@tailwindcss/postcss": "^4", "@tailwindcss/typography": "^0.5.19", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.1", + "@testing-library/user-event": "^14.6.1", "@types/negotiator": "^0.6.4", "@types/node": "^24.0.0", "@types/pako": "^2.0.3", "@types/react": "^19", "@types/react-dom": "^19", + "@types/turndown": "^5.0.6", + "@vitejs/plugin-react": "^5.1.2", + "@vitest/coverage-v8": "^4.0.16", "concurrently": "^9.2.1", "cross-env": "^10.1.0", "electron": "^39.2.7", @@ -118,12 +129,15 @@ "eslint": "9.39.2", "eslint-config-next": "16.1.1", "husky": "^9.1.7", + "jsdom": "^27.4.0", "lint-staged": "^16.2.7", "shx": "^0.4.0", "tailwindcss": "^4", "typescript": "^5", + "vite-tsconfig-paths": "^6.0.3", + "vitest": "^4.0.16", "wait-on": "^9.0.3", - "wrangler": "4.54.0" + "wrangler": "4.58.0" }, "overrides": { "@openrouter/ai-sdk-provider": { diff --git a/packages/claude-plugin/.claude-plugin/plugin.json b/packages/claude-plugin/.claude-plugin/plugin.json new file mode 100644 index 00000000..b1c7c207 --- /dev/null +++ b/packages/claude-plugin/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "next-ai-drawio", + "version": "1.0.0", + "description": "AI-powered Draw.io diagram generation with real-time browser preview. Create flowcharts, architecture diagrams, and more through natural language.", + "author": { + "name": "DayuanJiang" + }, + "repository": "https://github.com/DayuanJiang/next-ai-draw-io", + "homepage": "https://next-ai-drawio.jiang.jp", + "license": "Apache-2.0" +} diff --git a/packages/claude-plugin/.mcp.json b/packages/claude-plugin/.mcp.json new file mode 100644 index 00000000..f3df8432 --- /dev/null +++ b/packages/claude-plugin/.mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "drawio": { + "command": "npx", + "args": ["@next-ai-drawio/mcp-server@latest"] + } + } +} diff --git a/packages/claude-plugin/README.md b/packages/claude-plugin/README.md new file mode 100644 index 00000000..db4de05b --- /dev/null +++ b/packages/claude-plugin/README.md @@ -0,0 +1,107 @@ +# Next AI Draw.io - Claude Code Plugin + +AI-powered Draw.io diagram generation with real-time browser preview for Claude Code. + +## Installation + +### From Plugin Directory (Coming Soon) + +Once approved, install via: +``` +/plugin install next-ai-drawio +``` + +### Manual Installation + +```bash +claude --plugin-dir /path/to/packages/claude-plugin +``` + +Or add the MCP server directly: +```bash +claude mcp add drawio -- npx @next-ai-drawio/mcp-server@latest +``` + +## Features + +- **Real-time Preview**: Diagrams appear and update in your browser as Claude creates them +- **Version History**: Restore previous diagram versions with visual thumbnails +- **Natural Language**: Describe diagrams in plain text - flowcharts, architecture diagrams, etc. +- **Edit Support**: Modify existing diagrams with natural language instructions +- **Export**: Save diagrams as `.drawio` files +- **Self-contained**: Embedded server, no external dependencies required + +## Use Case Examples + +### 1. Create Architecture Diagrams + +``` +Generate an AWS architecture diagram with Lambda, API Gateway, DynamoDB, +and S3 for a serverless REST API +``` + +### 2. Flowchart Generation + +``` +Create a flowchart showing the CI/CD pipeline: code commit -> build -> +test -> staging deploy -> production deploy with approval gates +``` + +### 3. System Design Documentation + +``` +Design a microservices e-commerce system with user service, product catalog, +shopping cart, order processing, and payment gateway +``` + +### 4. Cloud Architecture (AWS/GCP/Azure) + +``` +Generate a GCP architecture diagram with Cloud Run, Cloud SQL, and +Cloud Storage for a web application +``` + +### 5. Sequence Diagrams + +``` +Create a sequence diagram showing OAuth 2.0 authorization code flow +between user, client app, auth server, and resource server +``` + +## Available Tools + +| Tool | Description | +|------|-------------| +| `start_session` | Opens browser with real-time diagram preview | +| `create_new_diagram` | Create a new diagram from XML | +| `edit_diagram` | Edit diagram by ID-based operations | +| `get_diagram` | Get the current diagram XML | +| `export_diagram` | Save diagram to a `.drawio` file | + +## How It Works + +``` +Claude Code <--stdio--> MCP Server <--http--> Browser (draw.io) +``` + +1. Ask Claude to create a diagram +2. Claude calls `start_session` to open a browser window +3. Claude generates diagram XML and sends it to the browser +4. You see the diagram update in real-time! + +## Configuration + +| Variable | Default | Description | +|----------|---------|-------------| +| `PORT` | `6002` | Port for the embedded HTTP server | +| `DRAWIO_BASE_URL` | `https://embed.diagrams.net` | Base URL for draw.io (for self-hosted deployments) | + +## Links + +- [Homepage](https://next-ai-drawio.jiang.jp) +- [GitHub Repository](https://github.com/DayuanJiang/next-ai-draw-io) +- [MCP Server Documentation](https://github.com/DayuanJiang/next-ai-draw-io/tree/main/packages/mcp-server) + +## License + +Apache-2.0 diff --git a/packages/mcp-server/package-lock.json b/packages/mcp-server/package-lock.json index e886b086..305d9944 100644 --- a/packages/mcp-server/package-lock.json +++ b/packages/mcp-server/package-lock.json @@ -1,18 +1,18 @@ { "name": "@next-ai-drawio/mcp-server", - "version": "0.1.6", + "version": "0.1.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@next-ai-drawio/mcp-server", - "version": "0.1.6", + "version": "0.1.12", "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.0.4", "linkedom": "^0.18.0", "open": "^11.0.0", - "zod": "^3.24.0" + "zod": "^4.0.0" }, "bin": { "next-ai-drawio-mcp": "dist/index.js" @@ -481,9 +481,9 @@ } }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.1.tgz", - "integrity": "sha512-yO28oVFFC7EBoiKdAn+VqRm+plcfv4v0xp6osG/VsCB0NlPZWi87ajbCZZ8f/RvOFLEu7//rSRmuZZ7lMoe3gQ==", + "version": "1.25.2", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.25.2.tgz", + "integrity": "sha512-LZFeo4F9M5qOhC/Uc1aQSrBHxMrvxett+9KLHt7OhcExtoiRN9DKgbZffMP/nxjutWDQpfMDfP3nkHI4X9ijww==", "license": "MIT", "dependencies": { "@hono/node-server": "^1.19.7", @@ -520,9 +520,9 @@ } }, "node_modules/@types/node": { - "version": "24.10.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.4.tgz", - "integrity": "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg==", + "version": "24.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.10.6.tgz", + "integrity": "sha512-B8h60xgJMR/xmgyX9fncRzEW9gCxoJjdenUhke2v1JGOd/V66KopmWrLPXi5oUI4VuiGK+d+HlXJjDRZMj21EQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2051,9 +2051,9 @@ } }, "node_modules/zod": { - "version": "3.25.76", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", - "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.5.tgz", + "integrity": "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g==", "license": "MIT", "peer": true, "funding": { diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 10157842..d425a4fe 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "@next-ai-drawio/mcp-server", - "version": "0.1.11", + "version": "0.1.12", "description": "MCP server for Next AI Draw.io - AI-powered diagram generation with real-time browser preview", "type": "module", "main": "dist/index.js", @@ -21,16 +21,16 @@ "claude", "model-context-protocol" ], - "author": "Biki-dev", + "author": "DayuanJiang", "license": "Apache-2.0", "repository": { "type": "git", - "url": "https://github.com/Biki-dev/next-ai-draw-io", + "url": "https://github.com/DayuanJiang/next-ai-draw-io", "directory": "packages/mcp-server" }, "homepage": "https://next-ai-drawio.jiang.jp", "bugs": { - "url": "https://github.com/Biki-dev/next-ai-draw-io/issues" + "url": "https://github.com/DayuanJiang/next-ai-draw-io/issues" }, "publishConfig": { "access": "public" @@ -39,7 +39,7 @@ "@modelcontextprotocol/sdk": "^1.0.4", "linkedom": "^0.18.0", "open": "^11.0.0", - "zod": "^3.24.0" + "zod": "^4.0.0" }, "devDependencies": { "@types/node": "^24.0.0", diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 00000000..012b8cdf --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,28 @@ +import { defineConfig } from "@playwright/test" + +export default defineConfig({ + testDir: "./tests/e2e", + fullyParallel: true, + forbidOnly: !!process.env.CI, + retries: process.env.CI ? 2 : 0, + workers: process.env.CI ? 1 : undefined, + reporter: process.env.CI ? [["list"], ["html"]] : "html", + webServer: { + command: process.env.CI ? "npm run start" : "npm run dev", + port: process.env.CI ? 6001 : 6002, + reuseExistingServer: !process.env.CI, + timeout: 120 * 1000, + }, + use: { + baseURL: process.env.CI + ? "http://localhost:6001" + : "http://localhost:6002", + trace: "on-first-retry", + }, + projects: [ + { + name: "chromium", + use: { browserName: "chromium" }, + }, + ], +}) diff --git a/scripts/prepare-electron-build.mjs b/scripts/prepare-electron-build.mjs index 6cb5eafe..f2ed4c1a 100644 --- a/scripts/prepare-electron-build.mjs +++ b/scripts/prepare-electron-build.mjs @@ -38,4 +38,12 @@ const targetStaticDir = join(targetDir, ".next", "static") mkdirSync(targetStaticDir, { recursive: true }) cpSync(staticDir, targetStaticDir, { recursive: true }) +// Copy public folder (required for favicon-white.svg and other assets) +console.log("Copying public folder...") +const publicDir = join(rootDir, "public") +const targetPublicDir = join(targetDir, "public") +if (existsSync(publicDir)) { + cpSync(publicDir, targetPublicDir, { recursive: true }) +} + console.log("Done! Files prepared in electron-standalone/") diff --git a/tests/e2e/chat.spec.ts b/tests/e2e/chat.spec.ts new file mode 100644 index 00000000..b2d125a3 --- /dev/null +++ b/tests/e2e/chat.spec.ts @@ -0,0 +1,22 @@ +import { expect, getIframe, test } from "./lib/fixtures" + +test.describe("Chat Panel", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("page has interactive elements", async ({ page }) => { + const buttons = page.locator("button") + const count = await buttons.count() + expect(count).toBeGreaterThan(0) + }) + + test("draw.io iframe is interactive", async ({ page }) => { + const iframe = getIframe(page) + await expect(iframe).toBeVisible() + + const src = await iframe.getAttribute("src") + expect(src).toBeTruthy() + }) +}) diff --git a/tests/e2e/copy-paste.spec.ts b/tests/e2e/copy-paste.spec.ts new file mode 100644 index 00000000..bfe8124d --- /dev/null +++ b/tests/e2e/copy-paste.spec.ts @@ -0,0 +1,137 @@ +import { SINGLE_BOX_XML } from "./fixtures/diagrams" +import { + expect, + getChatInput, + getIframe, + sendMessage, + test, +} from "./lib/fixtures" +import { createMockSSEResponse } from "./lib/helpers" + +test.describe("Copy/Paste Functionality", () => { + test("can paste text into chat input", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await chatInput.focus() + await page.keyboard.insertText("Create a flowchart diagram") + + await expect(chatInput).toHaveValue("Create a flowchart diagram") + }) + + test("can paste multiline text into chat input", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await chatInput.focus() + const multilineText = "Line 1\nLine 2\nLine 3" + await page.keyboard.insertText(multilineText) + + await expect(chatInput).toHaveValue(multilineText) + }) + + test("copy button copies response text", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "Here is your diagram with a test box.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Create a test box") + + // Wait for response + await expect( + page.locator('text="Here is your diagram with a test box."'), + ).toBeVisible({ timeout: 15000 }) + + // Find copy button in message + const copyButton = page.locator( + '[data-testid="copy-button"], button[aria-label*="Copy"], button:has(svg.lucide-copy), button:has(svg.lucide-clipboard)', + ) + + // Copy button feature may not exist - skip if not available + const buttonCount = await copyButton.count() + if (buttonCount === 0) { + test.skip() + return + } + + await copyButton.first().click() + await expect( + page.locator('text="Copied"').or(page.locator("svg.lucide-check")), + ).toBeVisible({ timeout: 3000 }) + }) + + test("keyboard shortcuts work in chat input", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await chatInput.fill("Hello world") + await chatInput.press("ControlOrMeta+a") + await chatInput.fill("New text") + + await expect(chatInput).toHaveValue("New text") + }) + + test("can undo/redo in chat input", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await chatInput.fill("First text") + await chatInput.press("Tab") + + await chatInput.focus() + await chatInput.fill("Second text") + await chatInput.press("ControlOrMeta+z") + + // Verify page is still functional after undo + await expect(chatInput).toBeVisible() + }) + + test("chat input handles special characters", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + const specialText = "Test <>&\"' special chars 日本語 中文 🎉" + await chatInput.fill(specialText) + + await expect(chatInput).toHaveValue(specialText) + }) + + test("long text in chat input scrolls", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + const longText = "This is a very long text. ".repeat(50) + await chatInput.fill(longText) + + const value = await chatInput.inputValue() + expect(value.length).toBeGreaterThan(500) + }) +}) diff --git a/tests/e2e/diagram-generation.spec.ts b/tests/e2e/diagram-generation.spec.ts new file mode 100644 index 00000000..81629642 --- /dev/null +++ b/tests/e2e/diagram-generation.spec.ts @@ -0,0 +1,128 @@ +import { + CAT_DIAGRAM_XML, + FLOWCHART_XML, + NEW_NODE_XML, +} from "./fixtures/diagrams" +import { + createMultiTurnMock, + expect, + getChatInput, + sendMessage, + test, + waitForComplete, + waitForCompleteCount, +} from "./lib/fixtures" +import { createMockSSEResponse } from "./lib/helpers" + +test.describe("Diagram Generation", () => { + test.beforeEach(async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + CAT_DIAGRAM_XML, + "I'll create a diagram for you.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + }) + + test("generates and displays a diagram", async ({ page }) => { + await sendMessage(page, "Draw a cat") + await expect(page.locator('text="Generate Diagram"')).toBeVisible({ + timeout: 15000, + }) + await waitForComplete(page) + }) + + test("chat input clears after sending", async ({ page }) => { + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await chatInput.fill("Draw a cat") + await chatInput.press("ControlOrMeta+Enter") + + await expect(chatInput).toHaveValue("", { timeout: 5000 }) + }) + + test("user message appears in chat", async ({ page }) => { + await sendMessage(page, "Draw a cute cat") + await expect(page.locator('text="Draw a cute cat"')).toBeVisible({ + timeout: 10000, + }) + }) + + test("assistant text message appears in chat", async ({ page }) => { + await sendMessage(page, "Draw a cat") + await expect( + page.locator('text="I\'ll create a diagram for you."'), + ).toBeVisible({ timeout: 10000 }) + }) +}) + +test.describe("Diagram Edit", () => { + test.beforeEach(async ({ page }) => { + await page.route( + "**/api/chat", + createMultiTurnMock([ + { xml: FLOWCHART_XML, text: "I'll create a diagram for you." }, + { + xml: FLOWCHART_XML.replace("Process", "Updated Process"), + text: "I'll create a diagram for you.", + }, + ]), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + }) + + test("can edit an existing diagram", async ({ page }) => { + // First: create initial diagram + await sendMessage(page, "Create a flowchart") + await waitForComplete(page) + + // Second: edit the diagram + await sendMessage(page, "Change Process to Updated Process") + await waitForCompleteCount(page, 2) + }) +}) + +test.describe("Diagram Append", () => { + test.beforeEach(async ({ page }) => { + await page.route( + "**/api/chat", + createMultiTurnMock([ + { xml: FLOWCHART_XML, text: "I'll create a diagram for you." }, + { + xml: NEW_NODE_XML, + text: "I'll create a diagram for you.", + toolName: "append_diagram", + }, + ]), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + }) + + test("can append to an existing diagram", async ({ page }) => { + // First: create initial diagram + await sendMessage(page, "Create a flowchart") + await waitForComplete(page) + + // Second: append to diagram + await sendMessage(page, "Add a new node to the right") + await waitForCompleteCount(page, 2) + }) +}) diff --git a/tests/e2e/error-handling.spec.ts b/tests/e2e/error-handling.spec.ts new file mode 100644 index 00000000..e5dd5f23 --- /dev/null +++ b/tests/e2e/error-handling.spec.ts @@ -0,0 +1,136 @@ +import { TRUNCATED_XML } from "./fixtures/diagrams" +import { + createErrorMock, + expect, + getChatInput, + getIframe, + sendMessage, + test, +} from "./lib/fixtures" + +test.describe("Error Handling", () => { + test("displays error message when API returns 500", async ({ page }) => { + await page.route( + "**/api/chat", + createErrorMock(500, "Internal server error"), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Draw a cat") + + // Should show error indication + const errorIndicator = page + .locator('[role="alert"]') + .or(page.locator("[data-sonner-toast]")) + .or(page.locator("text=/error|failed|something went wrong/i")) + await expect(errorIndicator.first()).toBeVisible({ timeout: 10000 }) + + // User should be able to type again + const chatInput = getChatInput(page) + await chatInput.fill("Retry message") + await expect(chatInput).toHaveValue("Retry message") + }) + + test("displays error message when API returns 429 rate limit", async ({ + page, + }) => { + await page.route( + "**/api/chat", + createErrorMock(429, "Rate limit exceeded"), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Draw a cat") + + // Should show error indication for rate limit + const errorIndicator = page + .locator('[role="alert"]') + .or(page.locator("[data-sonner-toast]")) + .or(page.locator("text=/rate limit|too many|try again/i")) + await expect(errorIndicator.first()).toBeVisible({ timeout: 10000 }) + + // User should be able to type again + const chatInput = getChatInput(page) + await chatInput.fill("Retry after rate limit") + await expect(chatInput).toHaveValue("Retry after rate limit") + }) + + test("handles network timeout gracefully", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await new Promise((resolve) => setTimeout(resolve, 2000)) + await route.abort("timedout") + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Draw a cat") + + // Should show error indication for network failure + const errorIndicator = page + .locator('[role="alert"]') + .or(page.locator("[data-sonner-toast]")) + .or(page.locator("text=/error|failed|network|timeout/i")) + await expect(errorIndicator.first()).toBeVisible({ timeout: 10000 }) + + // After timeout, user should be able to type again + const chatInput = getChatInput(page) + await chatInput.fill("Try again after timeout") + await expect(chatInput).toHaveValue("Try again after timeout") + }) + + test("shows truncated badge for incomplete XML", async ({ page }) => { + const toolCallId = `call_${Date.now()}` + const textId = `text_${Date.now()}` + const messageId = `msg_${Date.now()}` + + const events = [ + { type: "start", messageId }, + { type: "text-start", id: textId }, + { type: "text-delta", id: textId, delta: "Creating diagram..." }, + { type: "text-end", id: textId }, + { + type: "tool-input-start", + toolCallId, + toolName: "display_diagram", + }, + { + type: "tool-input-available", + toolCallId, + toolName: "display_diagram", + input: { xml: TRUNCATED_XML }, + }, + { + type: "tool-output-error", + toolCallId, + error: "XML validation failed", + }, + { type: "finish" }, + ] + + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: + events + .map((e) => `data: ${JSON.stringify(e)}\n\n`) + .join("") + "data: [DONE]\n\n", + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Draw something") + + // Should show truncated badge + await expect(page.locator('text="Truncated"')).toBeVisible({ + timeout: 15000, + }) + }) +}) diff --git a/tests/e2e/file-upload.spec.ts b/tests/e2e/file-upload.spec.ts new file mode 100644 index 00000000..6348a752 --- /dev/null +++ b/tests/e2e/file-upload.spec.ts @@ -0,0 +1,152 @@ +import { SINGLE_BOX_XML } from "./fixtures/diagrams" +import { + expect, + getChatInput, + getIframe, + sendMessage, + test, +} from "./lib/fixtures" +import { createMockSSEResponse } from "./lib/helpers" + +test.describe("File Upload", () => { + test("upload button opens file picker", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const uploadButton = page.locator( + 'button[aria-label="Upload file"], button:has(svg.lucide-image)', + ) + await expect(uploadButton.first()).toBeVisible({ timeout: 10000 }) + await expect(uploadButton.first()).toBeEnabled() + }) + + test("shows file preview after selecting image", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const fileInput = page.locator('input[type="file"]') + + await fileInput.setInputFiles({ + name: "test-image.png", + mimeType: "image/png", + buffer: Buffer.from( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", + "base64", + ), + }) + + await expect( + page.locator('[role="alert"][data-type="error"]'), + ).not.toBeVisible({ timeout: 2000 }) + }) + + test("can remove uploaded file", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const fileInput = page.locator('input[type="file"]') + + await fileInput.setInputFiles({ + name: "test-image.png", + mimeType: "image/png", + buffer: Buffer.from( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", + "base64", + ), + }) + + await expect( + page.locator('[role="alert"][data-type="error"]'), + ).not.toBeVisible({ timeout: 2000 }) + + const removeButton = page.locator( + '[data-testid="remove-file-button"], button[aria-label*="Remove"], button:has(svg.lucide-x)', + ) + + const removeButtonCount = await removeButton.count() + if (removeButtonCount === 0) { + test.skip() + return + } + + await removeButton.first().click() + await expect(removeButton.first()).not.toBeVisible({ timeout: 2000 }) + }) + + test("sends file with message to API", async ({ page }) => { + let capturedRequest: any = null + + await page.route("**/api/chat", async (route) => { + capturedRequest = route.request() + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "Based on your image, here is a diagram:", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const fileInput = page.locator('input[type="file"]') + + await fileInput.setInputFiles({ + name: "architecture.png", + mimeType: "image/png", + buffer: Buffer.from( + "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==", + "base64", + ), + }) + + await sendMessage(page, "Convert this to a diagram") + + await expect( + page.locator('text="Based on your image, here is a diagram:"'), + ).toBeVisible({ timeout: 15000 }) + + expect(capturedRequest).not.toBeNull() + }) + + test("shows error for oversized file", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const fileInput = page.locator('input[type="file"]') + const largeBuffer = Buffer.alloc(3 * 1024 * 1024, "x") + + await fileInput.setInputFiles({ + name: "large-image.png", + mimeType: "image/png", + buffer: largeBuffer, + }) + + await expect( + page.locator('[role="alert"], [data-sonner-toast]').first(), + ).toBeVisible({ timeout: 5000 }) + }) + + test("drag and drop file upload works", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatForm = page.locator("form").first() + + const dataTransfer = await page.evaluateHandle(() => { + const dt = new DataTransfer() + const file = new File(["test content"], "dropped-image.png", { + type: "image/png", + }) + dt.items.add(file) + return dt + }) + + await chatForm.dispatchEvent("dragover", { dataTransfer }) + await chatForm.dispatchEvent("drop", { dataTransfer }) + + await expect(getChatInput(page)).toBeVisible({ timeout: 3000 }) + }) +}) diff --git a/tests/e2e/fixtures/diagrams.ts b/tests/e2e/fixtures/diagrams.ts new file mode 100644 index 00000000..70092532 --- /dev/null +++ b/tests/e2e/fixtures/diagrams.ts @@ -0,0 +1,50 @@ +/** + * Shared XML diagram fixtures for E2E tests + */ + +// Simple cat diagram +export const CAT_DIAGRAM_XML = ` + + + + +` + +// Simple flowchart +export const FLOWCHART_XML = ` + + + + + + + +` + +// Simple single box +export const SINGLE_BOX_XML = ` + +` + +// Test node for iframe interaction tests +export const TEST_NODE_XML = ` + +` + +// Architecture box +export const ARCHITECTURE_XML = ` + +` + +// New node for append tests +export const NEW_NODE_XML = ` + +` + +// Truncated XML for error tests +export const TRUNCATED_XML = ` + + `` diff --git a/tests/e2e/history-restore.spec.ts b/tests/e2e/history-restore.spec.ts new file mode 100644 index 00000000..2fce5158 --- /dev/null +++ b/tests/e2e/history-restore.spec.ts @@ -0,0 +1,215 @@ +import { SINGLE_BOX_XML } from "./fixtures/diagrams" +import { + expect, + expectBeforeAndAfterReload, + getChatInput, + getIframe, + getIframeContent, + openSettings, + sendMessage, + test, + waitForComplete, + waitForText, +} from "./lib/fixtures" +import { createMockSSEResponse } from "./lib/helpers" + +test.describe("History and Session Restore", () => { + test("new chat button clears conversation", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "Created your test diagram.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await test.step("create a conversation", async () => { + await sendMessage(page, "Create a test diagram") + await waitForText(page, "Created your test diagram.") + }) + + await test.step("click new chat button", async () => { + const newChatButton = page.locator( + '[data-testid="new-chat-button"]', + ) + await expect(newChatButton).toBeVisible({ timeout: 5000 }) + await newChatButton.click() + }) + + await test.step("verify conversation is cleared", async () => { + await expect( + page.locator('text="Created your test diagram."'), + ).not.toBeVisible({ timeout: 5000 }) + }) + }) + + test("chat history sidebar shows past conversations", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const historyButton = page.locator( + 'button[aria-label*="History"]:not([disabled]), button:has(svg.lucide-history):not([disabled]), button:has(svg.lucide-menu):not([disabled]), button:has(svg.lucide-sidebar):not([disabled]), button:has(svg.lucide-panel-left):not([disabled])', + ) + + const buttonCount = await historyButton.count() + if (buttonCount === 0) { + test.skip() + return + } + + await historyButton.first().click() + await expect(getChatInput(page)).toBeVisible({ timeout: 3000 }) + }) + + test("conversation persists after page reload", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "This message should persist.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await test.step("create conversation", async () => { + await sendMessage(page, "Create persistent diagram") + await waitForText(page, "This message should persist.") + }) + + await test.step("verify message appears before reload", async () => { + await expect(getChatInput(page)).toBeVisible({ timeout: 10000 }) + await expect( + page.locator('text="This message should persist."'), + ).toBeVisible({ timeout: 10000 }) + }) + + // Note: After reload, mocked responses won't persist since we're not + // testing with real localStorage. We just verify the app loads correctly. + await test.step("verify app loads after reload", async () => { + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + await expect(getChatInput(page)).toBeVisible({ timeout: 10000 }) + }) + }) + + test("diagram state persists after reload", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "Created a diagram that should be saved.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Create saveable diagram") + await waitForComplete(page) + + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const frame = getIframeContent(page) + await expect( + frame + .locator(".geMenubarContainer, .geDiagramContainer, canvas") + .first(), + ).toBeVisible({ timeout: 30000 }) + }) + + test("can restore from browser back/forward", async ({ page }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + SINGLE_BOX_XML, + "Testing browser navigation.", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Test navigation") + await waitForText(page, "Testing browser navigation.") + + await page.goto("/about", { waitUntil: "networkidle" }) + await page.goBack({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await expect(getChatInput(page)).toBeVisible({ timeout: 10000 }) + }) + + test("settings are restored after reload", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + await page.keyboard.press("Escape") + + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + }) + + test("model selection persists", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const modelSelector = page.locator( + 'button[aria-label*="Model"], [data-testid="model-selector"], button:has-text("Claude")', + ) + + const selectorCount = await modelSelector.count() + if (selectorCount === 0) { + test.skip() + return + } + + const initialModel = await modelSelector.first().textContent() + + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const modelAfterReload = await modelSelector.first().textContent() + expect(modelAfterReload).toBe(initialModel) + }) + + test("handles localStorage quota exceeded gracefully", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await page.evaluate(() => { + try { + const largeData = "x".repeat(5 * 1024 * 1024) + localStorage.setItem("test-large-data", largeData) + } catch { + // Expected to fail on some browsers + } + }) + + await expect(getChatInput(page)).toBeVisible({ timeout: 10000 }) + + await page.evaluate(() => { + localStorage.removeItem("test-large-data") + }) + }) +}) diff --git a/tests/e2e/history.spec.ts b/tests/e2e/history.spec.ts new file mode 100644 index 00000000..bbd55e6a --- /dev/null +++ b/tests/e2e/history.spec.ts @@ -0,0 +1,18 @@ +import { expect, getIframe, test } from "./lib/fixtures" + +test.describe("History Dialog", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("history button exists in UI", async ({ page }) => { + // History button may be disabled initially (no history) + // Just verify it exists in the DOM + const historyButton = page + .locator("button") + .filter({ has: page.locator("svg") }) + const count = await historyButton.count() + expect(count).toBeGreaterThan(0) + }) +}) diff --git a/tests/e2e/iframe-interaction.spec.ts b/tests/e2e/iframe-interaction.spec.ts new file mode 100644 index 00000000..134dabd7 --- /dev/null +++ b/tests/e2e/iframe-interaction.spec.ts @@ -0,0 +1,122 @@ +import { TEST_NODE_XML } from "./fixtures/diagrams" +import { + expect, + getChatInput, + getIframe, + getIframeContent, + sendMessage, + test, + waitForComplete, +} from "./lib/fixtures" +import { createMockSSEResponse } from "./lib/helpers" + +test.describe("Iframe Interaction", () => { + test("draw.io iframe loads successfully", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + + const iframe = getIframe(page) + await expect(iframe).toBeVisible({ timeout: 30000 }) + + // iframe should have loaded draw.io content + const frame = getIframeContent(page) + await expect( + frame + .locator(".geMenubarContainer, .geDiagramContainer, canvas") + .first(), + ).toBeVisible({ timeout: 30000 }) + }) + + test("can interact with draw.io toolbar", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const frame = getIframeContent(page) + + // Draw.io menu items should be accessible + await expect( + frame + .locator('text="Diagram"') + .or(frame.locator('[title*="Diagram"]')), + ).toBeVisible({ timeout: 10000 }) + }) + + test("diagram XML is rendered in iframe after generation", async ({ + page, + }) => { + await page.route("**/api/chat", async (route) => { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + TEST_NODE_XML, + "Here is your diagram:", + ), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await sendMessage(page, "Create a test node") + await waitForComplete(page) + + // Give draw.io time to render + await page.waitForTimeout(1000) + }) + + test("zoom controls work in draw.io", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const frame = getIframeContent(page) + + // draw.io should be loaded and functional - check for diagram container + await expect( + frame.locator(".geDiagramContainer, canvas").first(), + ).toBeVisible({ timeout: 10000 }) + }) + + test("can resize the panel divider", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + // Find the resizer/divider between panels + const resizer = page.locator( + '[role="separator"], [data-panel-resize-handle-id], .resize-handle', + ) + + if ((await resizer.count()) > 0) { + await expect(resizer.first()).toBeVisible() + + const box = await resizer.first().boundingBox() + if (box) { + await page.mouse.move( + box.x + box.width / 2, + box.y + box.height / 2, + ) + await page.mouse.down() + await page.mouse.move(box.x + 50, box.y + box.height / 2) + await page.mouse.up() + } + } + }) + + test("iframe responds to window resize", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const iframe = getIframe(page) + const initialBox = await iframe.boundingBox() + + // Resize window + await page.setViewportSize({ width: 800, height: 600 }) + await page.waitForTimeout(500) + + const newBox = await iframe.boundingBox() + + expect(newBox).toBeDefined() + if (initialBox && newBox) { + expect(newBox.width).toBeLessThanOrEqual(800) + } + }) +}) diff --git a/tests/e2e/keyboard.spec.ts b/tests/e2e/keyboard.spec.ts new file mode 100644 index 00000000..236b2983 --- /dev/null +++ b/tests/e2e/keyboard.spec.ts @@ -0,0 +1,26 @@ +import { expect, getIframe, openSettings, test } from "./lib/fixtures" + +test.describe("Keyboard Interactions", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("Escape closes settings dialog", async ({ page }) => { + await openSettings(page) + + const dialog = page.locator('[role="dialog"]') + await expect(dialog).toBeVisible({ timeout: 5000 }) + + await page.keyboard.press("Escape") + await expect(dialog).not.toBeVisible({ timeout: 2000 }) + }) + + test("page is keyboard accessible", async ({ page }) => { + const focusableElements = page.locator( + 'button, [tabindex="0"], input, textarea, a[href]', + ) + const count = await focusableElements.count() + expect(count).toBeGreaterThan(0) + }) +}) diff --git a/tests/e2e/language.spec.ts b/tests/e2e/language.spec.ts new file mode 100644 index 00000000..145b855c --- /dev/null +++ b/tests/e2e/language.spec.ts @@ -0,0 +1,105 @@ +import { + expect, + expectBeforeAndAfterReload, + getChatInput, + getIframe, + openSettings, + sleep, + test, +} from "./lib/fixtures" + +test.describe("Language Switching", () => { + test("loads English by default", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + + await expect(page.locator('button:has-text("Send")')).toBeVisible() + }) + + test("can switch to Japanese", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await test.step("open settings and select Japanese", async () => { + await openSettings(page) + const languageSelector = page.locator('button:has-text("English")') + await languageSelector.first().click() + await page.locator('text="日本語"').click() + }) + + await test.step("verify UI is in Japanese", async () => { + await expect(page.locator('button:has-text("送信")')).toBeVisible({ + timeout: 5000, + }) + }) + }) + + test("can switch to Chinese", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await test.step("open settings and select Chinese", async () => { + await openSettings(page) + const languageSelector = page.locator('button:has-text("English")') + await languageSelector.first().click() + await page.locator('text="中文"').click() + }) + + await test.step("verify UI is in Chinese", async () => { + await expect(page.locator('button:has-text("发送")')).toBeVisible({ + timeout: 5000, + }) + }) + }) + + test("language persists after reload", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await test.step("switch to Japanese", async () => { + await openSettings(page) + const languageSelector = page.locator('button:has-text("English")') + await languageSelector.first().click() + await page.locator('text="日本語"').click() + await page.keyboard.press("Escape") + await sleep(500) + }) + + await test.step("verify Japanese before reload", async () => { + await expect(page.locator('button:has-text("送信")')).toBeVisible({ + timeout: 10000, + }) + }) + + await test.step("reload and verify Japanese persists", async () => { + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + // Wait for hydration and localStorage to be read + await sleep(1000) + await expect(page.locator('button:has-text("送信")')).toBeVisible({ + timeout: 10000, + }) + }) + }) + + test("Japanese locale URL works", async ({ page }) => { + await page.goto("/ja", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await expect(page.locator('button:has-text("送信")')).toBeVisible({ + timeout: 10000, + }) + }) + + test("Chinese locale URL works", async ({ page }) => { + await page.goto("/zh", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await expect(page.locator('button:has-text("发送")')).toBeVisible({ + timeout: 10000, + }) + }) +}) diff --git a/tests/e2e/lib/fixtures.ts b/tests/e2e/lib/fixtures.ts new file mode 100644 index 00000000..f63f3acc --- /dev/null +++ b/tests/e2e/lib/fixtures.ts @@ -0,0 +1,208 @@ +/** + * Playwright test fixtures for E2E tests + * Uses test.extend to provide common setup and helpers + */ + +import { test as base, expect, type Page, type Route } from "@playwright/test" +import { createMockSSEResponse, createTextOnlyResponse } from "./helpers" + +/** + * Extended test with common fixtures + */ +export const test = base.extend<{ + /** Page with iframe already loaded */ + appPage: Page +}>({ + appPage: async ({ page }, use) => { + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + await use(page) + }, +}) + +export { expect } + +// ============================================ +// Locator helpers +// ============================================ + +/** Get the chat input textarea */ +export function getChatInput(page: Page) { + return page.locator('textarea[aria-label="Chat input"]') +} + +/** Get the draw.io iframe */ +export function getIframe(page: Page) { + return page.locator("iframe") +} + +/** Get the iframe's frame locator for internal queries */ +export function getIframeContent(page: Page) { + return page.frameLocator("iframe") +} + +/** Get the settings button */ +export function getSettingsButton(page: Page) { + return page.locator('[data-testid="settings-button"]') +} + +// ============================================ +// Action helpers +// ============================================ + +/** Send a message in the chat input */ +export async function sendMessage(page: Page, message: string) { + const chatInput = getChatInput(page) + await expect(chatInput).toBeVisible({ timeout: 10000 }) + await chatInput.fill(message) + await chatInput.press("ControlOrMeta+Enter") +} + +/** Wait for diagram generation to complete */ +export async function waitForComplete(page: Page, timeout = 15000) { + await expect(page.locator('text="Complete"')).toBeVisible({ timeout }) +} + +/** Wait for N "Complete" badges */ +export async function waitForCompleteCount( + page: Page, + count: number, + timeout = 15000, +) { + await expect(page.locator('text="Complete"')).toHaveCount(count, { + timeout, + }) +} + +/** Wait for a specific text to appear */ +export async function waitForText(page: Page, text: string, timeout = 15000) { + await expect(page.locator(`text="${text}"`)).toBeVisible({ timeout }) +} + +/** Open settings dialog */ +export async function openSettings(page: Page) { + await getSettingsButton(page).click() + await expect(page.locator('[role="dialog"]')).toBeVisible({ timeout: 5000 }) +} + +// ============================================ +// Mock helpers +// ============================================ + +interface MockResponse { + xml: string + text: string + toolName?: string +} + +/** + * Create a multi-turn mock handler + * Each request gets the next response in the array + */ +export function createMultiTurnMock(responses: MockResponse[]) { + let requestCount = 0 + return async (route: Route) => { + const response = + responses[requestCount] || responses[responses.length - 1] + requestCount++ + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse( + response.xml, + response.text, + response.toolName, + ), + }) + } +} + +/** + * Create a mock that returns text-only responses + */ +export function createTextOnlyMock(responses: string[]) { + let requestCount = 0 + return async (route: Route) => { + const text = responses[requestCount] || responses[responses.length - 1] + requestCount++ + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createTextOnlyResponse(text), + }) + } +} + +/** + * Create a mock that alternates between text and diagram responses + */ +export function createMixedMock( + responses: Array< + | { type: "text"; text: string } + | { type: "diagram"; xml: string; text: string } + >, +) { + let requestCount = 0 + return async (route: Route) => { + const response = + responses[requestCount] || responses[responses.length - 1] + requestCount++ + if (response.type === "text") { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createTextOnlyResponse(response.text), + }) + } else { + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createMockSSEResponse(response.xml, response.text), + }) + } + } +} + +/** + * Create a mock that returns an error + */ +export function createErrorMock(status: number, error: string) { + return async (route: Route) => { + await route.fulfill({ + status, + contentType: "application/json", + body: JSON.stringify({ error }), + }) + } +} + +// ============================================ +// Persistence helpers +// ============================================ + +/** + * Test that state persists across page reload. + * Runs assertions before reload, reloads page, then runs assertions again. + * Keep assertions narrow and explicit - test one specific thing. + * + * @param page - Playwright page + * @param description - What persistence is being tested (for debugging) + * @param assertion - Async function with expect() calls + */ +export async function expectBeforeAndAfterReload( + page: Page, + description: string, + assertion: () => Promise, +) { + await test.step(`verify ${description} before reload`, assertion) + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + await test.step(`verify ${description} after reload`, assertion) +} + +/** Simple sleep helper */ +export function sleep(ms: number): Promise { + return new Promise((resolve) => setTimeout(resolve, ms)) +} diff --git a/tests/e2e/lib/helpers.ts b/tests/e2e/lib/helpers.ts new file mode 100644 index 00000000..70cbaedf --- /dev/null +++ b/tests/e2e/lib/helpers.ts @@ -0,0 +1,88 @@ +/** + * Shared test helpers for E2E tests + */ + +/** + * Creates a mock SSE response for the chat API + * Format matches AI SDK UI message stream protocol + */ +export function createMockSSEResponse( + xml: string, + text: string, + toolName = "display_diagram", +) { + const messageId = `msg_${Date.now()}` + const toolCallId = `call_${Date.now()}` + const textId = `text_${Date.now()}` + + const events = [ + { type: "start", messageId }, + { type: "text-start", id: textId }, + { type: "text-delta", id: textId, delta: text }, + { type: "text-end", id: textId }, + { type: "tool-input-start", toolCallId, toolName }, + { type: "tool-input-available", toolCallId, toolName, input: { xml } }, + { + type: "tool-output-available", + toolCallId, + output: "Successfully displayed the diagram", + }, + { type: "finish" }, + ] + + return ( + events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("") + + "data: [DONE]\n\n" + ) +} + +/** + * Creates a text-only SSE response (no tool call) + */ +export function createTextOnlyResponse(text: string) { + const messageId = `msg_${Date.now()}` + const textId = `text_${Date.now()}` + + const events = [ + { type: "start", messageId }, + { type: "text-start", id: textId }, + { type: "text-delta", id: textId, delta: text }, + { type: "text-end", id: textId }, + { type: "finish" }, + ] + + return ( + events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("") + + "data: [DONE]\n\n" + ) +} + +/** + * Creates a mock SSE response with a tool error + */ +export function createToolErrorResponse(text: string, errorMessage: string) { + const messageId = `msg_${Date.now()}` + const toolCallId = `call_${Date.now()}` + const textId = `text_${Date.now()}` + + const events = [ + { type: "start", messageId }, + { type: "text-start", id: textId }, + { type: "text-delta", id: textId, delta: text }, + { type: "text-end", id: textId }, + { type: "tool-input-start", toolCallId, toolName: "display_diagram" }, + { + type: "tool-input-available", + toolCallId, + toolName: "display_diagram", + input: { xml: "" }, + }, + { type: "tool-output-error", toolCallId, error: errorMessage }, + { type: "finish" }, + ] + + return ( + events.map((e) => `data: ${JSON.stringify(e)}\n\n`).join("") + + "data: [DONE]\n\n" + ) +} diff --git a/tests/e2e/model-config.spec.ts b/tests/e2e/model-config.spec.ts new file mode 100644 index 00000000..9b974ecf --- /dev/null +++ b/tests/e2e/model-config.spec.ts @@ -0,0 +1,19 @@ +import { expect, getIframe, openSettings, test } from "./lib/fixtures" + +test.describe("Model Configuration", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("settings dialog opens and shows configuration options", async ({ + page, + }) => { + await openSettings(page) + + const dialog = page.locator('[role="dialog"]') + const buttons = dialog.locator("button") + const buttonCount = await buttons.count() + expect(buttonCount).toBeGreaterThan(0) + }) +}) diff --git a/tests/e2e/multi-turn.spec.ts b/tests/e2e/multi-turn.spec.ts new file mode 100644 index 00000000..a58ba228 --- /dev/null +++ b/tests/e2e/multi-turn.spec.ts @@ -0,0 +1,113 @@ +import { ARCHITECTURE_XML, createBoxXml } from "./fixtures/diagrams" +import { + createMixedMock, + createMultiTurnMock, + expect, + getChatInput, + sendMessage, + test, + waitForComplete, + waitForText, +} from "./lib/fixtures" +import { createTextOnlyResponse } from "./lib/helpers" + +test.describe("Multi-turn Conversation", () => { + test("handles multiple diagram requests in sequence", async ({ page }) => { + await page.route( + "**/api/chat", + createMultiTurnMock([ + { + xml: createBoxXml("box1", "First"), + text: "Creating diagram 1...", + }, + { + xml: createBoxXml("box2", "Second", 200), + text: "Creating diagram 2...", + }, + ]), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + + // First request + await sendMessage(page, "Draw first box") + await waitForText(page, "Creating diagram 1...") + + // Second request + await sendMessage(page, "Draw second box") + await waitForText(page, "Creating diagram 2...") + + // Both messages should be visible + await expect(page.locator('text="Draw first box"')).toBeVisible() + await expect(page.locator('text="Draw second box"')).toBeVisible() + }) + + test("preserves conversation history", async ({ page }) => { + let requestCount = 0 + await page.route("**/api/chat", async (route) => { + requestCount++ + const request = route.request() + const body = JSON.parse(request.postData() || "{}") + + // Verify messages array grows with each request + if (requestCount === 2) { + expect(body.messages?.length).toBeGreaterThan(1) + } + + await route.fulfill({ + status: 200, + contentType: "text/event-stream", + body: createTextOnlyResponse(`Response ${requestCount}`), + }) + }) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + + // First message + await sendMessage(page, "Hello") + await waitForText(page, "Response 1") + + // Second message (should include history) + await sendMessage(page, "Follow up question") + await waitForText(page, "Response 2") + }) + + test("can continue after a text-only response", async ({ page }) => { + await page.route( + "**/api/chat", + createMixedMock([ + { + type: "text", + text: "I understand. Let me explain the architecture first.", + }, + { + type: "diagram", + xml: ARCHITECTURE_XML, + text: "Here is the diagram:", + }, + ]), + ) + + await page.goto("/", { waitUntil: "networkidle" }) + await page + .locator("iframe") + .waitFor({ state: "visible", timeout: 30000 }) + + // Ask for explanation first + await sendMessage(page, "Explain the architecture") + await waitForText( + page, + "I understand. Let me explain the architecture first.", + ) + + // Then ask for diagram + await sendMessage(page, "Now show it as a diagram") + await waitForComplete(page) + }) +}) diff --git a/tests/e2e/save.spec.ts b/tests/e2e/save.spec.ts new file mode 100644 index 00000000..995f3389 --- /dev/null +++ b/tests/e2e/save.spec.ts @@ -0,0 +1,16 @@ +import { expect, getIframe, test } from "./lib/fixtures" + +test.describe("Save Dialog", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("save/download buttons exist", async ({ page }) => { + const buttons = page + .locator("button") + .filter({ has: page.locator("svg") }) + const count = await buttons.count() + expect(count).toBeGreaterThan(0) + }) +}) diff --git a/tests/e2e/settings.spec.ts b/tests/e2e/settings.spec.ts new file mode 100644 index 00000000..41ea0922 --- /dev/null +++ b/tests/e2e/settings.spec.ts @@ -0,0 +1,34 @@ +import { + expect, + getIframe, + getSettingsButton, + openSettings, + test, +} from "./lib/fixtures" + +test.describe("Settings", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("settings dialog opens", async ({ page }) => { + await openSettings(page) + // openSettings already verifies dialog is visible + }) + + test("language selection is available", async ({ page }) => { + await openSettings(page) + + const dialog = page.locator('[role="dialog"]') + await expect(dialog.locator('text="English"')).toBeVisible() + }) + + test("draw.io theme toggle exists", async ({ page }) => { + await openSettings(page) + + const dialog = page.locator('[role="dialog"]') + const themeText = dialog.locator("text=/sketch|minimal/i") + await expect(themeText.first()).toBeVisible() + }) +}) diff --git a/tests/e2e/smoke.spec.ts b/tests/e2e/smoke.spec.ts new file mode 100644 index 00000000..ffc4795a --- /dev/null +++ b/tests/e2e/smoke.spec.ts @@ -0,0 +1,36 @@ +import { expect, getIframe, openSettings, test } from "./lib/fixtures" + +test.describe("Smoke Tests", () => { + test("homepage loads without errors", async ({ page }) => { + const errors: string[] = [] + page.on("pageerror", (err) => errors.push(err.message)) + + await page.goto("/", { waitUntil: "networkidle" }) + await expect(page).toHaveTitle(/Draw\.io/i, { timeout: 10000 }) + + const iframe = getIframe(page) + await expect(iframe).toBeVisible({ timeout: 30000 }) + + expect(errors).toEqual([]) + }) + + test("Japanese locale page loads", async ({ page }) => { + const errors: string[] = [] + page.on("pageerror", (err) => errors.push(err.message)) + + await page.goto("/ja", { waitUntil: "networkidle" }) + await expect(page).toHaveTitle(/Draw\.io/i, { timeout: 10000 }) + + const iframe = getIframe(page) + await expect(iframe).toBeVisible({ timeout: 30000 }) + + expect(errors).toEqual([]) + }) + + test("settings dialog opens", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + }) +}) diff --git a/tests/e2e/theme.spec.ts b/tests/e2e/theme.spec.ts new file mode 100644 index 00000000..2c7a8a43 --- /dev/null +++ b/tests/e2e/theme.spec.ts @@ -0,0 +1,88 @@ +import { expect, getIframe, openSettings, sleep, test } from "./lib/fixtures" + +test.describe("Theme Switching", () => { + test("can toggle app dark mode", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + + const html = page.locator("html") + const initialClass = await html.getAttribute("class") + + const themeButton = page.locator( + "button:has(svg.lucide-sun), button:has(svg.lucide-moon)", + ) + + if ((await themeButton.count()) > 0) { + await test.step("toggle theme", async () => { + await themeButton.first().click() + await sleep(500) + }) + + await test.step("verify theme changed", async () => { + const newClass = await html.getAttribute("class") + expect(newClass).not.toBe(initialClass) + }) + } + }) + + test("theme persists after page reload", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + + const themeButton = page.locator( + "button:has(svg.lucide-sun), button:has(svg.lucide-moon)", + ) + + if ((await themeButton.count()) > 0) { + let themeClass: string | null + + await test.step("change theme", async () => { + await themeButton.first().click() + await sleep(300) + themeClass = await page.locator("html").getAttribute("class") + await page.keyboard.press("Escape") + }) + + await test.step("reload page", async () => { + await page.reload({ waitUntil: "networkidle" }) + await getIframe(page).waitFor({ + state: "visible", + timeout: 30000, + }) + }) + + await test.step("verify theme persisted", async () => { + const reloadedClass = await page + .locator("html") + .getAttribute("class") + expect(reloadedClass).toBe(themeClass) + }) + } + }) + + test("draw.io theme toggle exists", async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + await openSettings(page) + + await expect( + page.locator('[role="dialog"], [role="menu"], form').first(), + ).toBeVisible({ timeout: 5000 }) + }) + + test("system theme preference is respected", async ({ page }) => { + await page.emulateMedia({ colorScheme: "dark" }) + + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + + const html = page.locator("html") + const classes = await html.getAttribute("class") + expect(classes).toBeDefined() + }) +}) diff --git a/tests/e2e/upload.spec.ts b/tests/e2e/upload.spec.ts new file mode 100644 index 00000000..ec2a3395 --- /dev/null +++ b/tests/e2e/upload.spec.ts @@ -0,0 +1,20 @@ +import { expect, getIframe, test } from "./lib/fixtures" + +test.describe("File Upload Area", () => { + test.beforeEach(async ({ page }) => { + await page.goto("/", { waitUntil: "networkidle" }) + await getIframe(page).waitFor({ state: "visible", timeout: 30000 }) + }) + + test("page loads without console errors", async ({ page }) => { + const errors: string[] = [] + page.on("pageerror", (err) => errors.push(err.message)) + + await page.waitForTimeout(1000) + + const criticalErrors = errors.filter( + (e) => !e.includes("ResizeObserver") && !e.includes("Script error"), + ) + expect(criticalErrors).toEqual([]) + }) +}) diff --git a/tests/unit/ai-providers.test.ts b/tests/unit/ai-providers.test.ts new file mode 100644 index 00000000..46bbf93e --- /dev/null +++ b/tests/unit/ai-providers.test.ts @@ -0,0 +1,50 @@ +import { describe, expect, it } from "vitest" +import { supportsImageInput, supportsPromptCaching } from "@/lib/ai-providers" + +describe("supportsPromptCaching", () => { + it("returns true for Claude models", () => { + expect(supportsPromptCaching("claude-sonnet-4-5")).toBe(true) + expect(supportsPromptCaching("anthropic.claude-3-5-sonnet")).toBe(true) + expect(supportsPromptCaching("us.anthropic.claude-3-5-sonnet")).toBe( + true, + ) + expect(supportsPromptCaching("eu.anthropic.claude-3-5-sonnet")).toBe( + true, + ) + }) + + it("returns false for non-Claude models", () => { + expect(supportsPromptCaching("gpt-4o")).toBe(false) + expect(supportsPromptCaching("gemini-pro")).toBe(false) + expect(supportsPromptCaching("deepseek-chat")).toBe(false) + }) +}) + +describe("supportsImageInput", () => { + it("returns true for models with vision capability", () => { + expect(supportsImageInput("gpt-4-vision")).toBe(true) + expect(supportsImageInput("qwen-vl")).toBe(true) + expect(supportsImageInput("deepseek-vl")).toBe(true) + }) + + it("returns false for Kimi K2 models without vision", () => { + expect(supportsImageInput("kimi-k2")).toBe(false) + expect(supportsImageInput("moonshot/kimi-k2")).toBe(false) + }) + + it("returns false for DeepSeek text models", () => { + expect(supportsImageInput("deepseek-chat")).toBe(false) + expect(supportsImageInput("deepseek-coder")).toBe(false) + }) + + it("returns false for Qwen text models", () => { + expect(supportsImageInput("qwen-turbo")).toBe(false) + expect(supportsImageInput("qwen-plus")).toBe(false) + }) + + it("returns true for Claude and GPT models by default", () => { + expect(supportsImageInput("claude-sonnet-4-5")).toBe(true) + expect(supportsImageInput("gpt-4o")).toBe(true) + expect(supportsImageInput("gemini-pro")).toBe(true) + }) +}) diff --git a/tests/unit/cached-responses.test.ts b/tests/unit/cached-responses.test.ts new file mode 100644 index 00000000..2e0f8730 --- /dev/null +++ b/tests/unit/cached-responses.test.ts @@ -0,0 +1,54 @@ +import { describe, expect, it } from "vitest" +import { + CACHED_EXAMPLE_RESPONSES, + findCachedResponse, +} from "@/lib/cached-responses" + +describe("findCachedResponse", () => { + it("returns cached response for exact match without image", () => { + const result = findCachedResponse( + "Give me a **animated connector** diagram of transformer's architecture", + false, + ) + expect(result).toBeDefined() + expect(result?.xml).toContain("Transformer Architecture") + }) + + it("returns cached response for exact match with image", () => { + const result = findCachedResponse("Replicate this in aws style", true) + expect(result).toBeDefined() + expect(result?.xml).toContain("AWS") + }) + + it("returns undefined for non-matching prompt", () => { + const result = findCachedResponse( + "random prompt that doesn't exist", + false, + ) + expect(result).toBeUndefined() + }) + + it("returns undefined when hasImage doesn't match", () => { + // This prompt exists but requires hasImage=true + const result = findCachedResponse("Replicate this in aws style", false) + expect(result).toBeUndefined() + }) + + it("returns undefined for partial match", () => { + const result = findCachedResponse("Give me a diagram", false) + expect(result).toBeUndefined() + }) + + it("returns response for Draw a cat prompt", () => { + const result = findCachedResponse("Draw a cat for me", false) + expect(result).toBeDefined() + expect(result?.xml).toContain("ellipse") + }) + + it("all cached responses have non-empty xml", () => { + for (const response of CACHED_EXAMPLE_RESPONSES) { + expect(response.xml).not.toBe("") + expect(response.xml.length).toBeGreaterThan(0) + } + }) +}) diff --git a/tests/unit/chat-helpers.test.ts b/tests/unit/chat-helpers.test.ts new file mode 100644 index 00000000..9bf9d47d --- /dev/null +++ b/tests/unit/chat-helpers.test.ts @@ -0,0 +1,171 @@ +// @vitest-environment node +import { describe, expect, it } from "vitest" +import { + isMinimalDiagram, + replaceHistoricalToolInputs, + validateFileParts, +} from "@/lib/chat-helpers" + +describe("validateFileParts", () => { + it("returns valid for no files", () => { + const messages = [ + { role: "user", parts: [{ type: "text", text: "hello" }] }, + ] + expect(validateFileParts(messages)).toEqual({ valid: true }) + }) + + it("returns valid for files under limit", () => { + const smallBase64 = btoa("x".repeat(100)) + const messages = [ + { + role: "user", + parts: [ + { + type: "file", + url: `data:image/png;base64,${smallBase64}`, + }, + ], + }, + ] + expect(validateFileParts(messages)).toEqual({ valid: true }) + }) + + it("returns error for too many files", () => { + const messages = [ + { + role: "user", + parts: Array(6) + .fill(null) + .map(() => ({ + type: "file", + url: "data:image/png;base64,abc", + })), + }, + ] + const result = validateFileParts(messages) + expect(result.valid).toBe(false) + expect(result.error).toContain("Too many files") + }) + + it("returns error for file exceeding size limit", () => { + // Create base64 that decodes to > 2MB + const largeBase64 = btoa("x".repeat(3 * 1024 * 1024)) + const messages = [ + { + role: "user", + parts: [ + { + type: "file", + url: `data:image/png;base64,${largeBase64}`, + }, + ], + }, + ] + const result = validateFileParts(messages) + expect(result.valid).toBe(false) + expect(result.error).toContain("exceeds") + }) +}) + +describe("isMinimalDiagram", () => { + it("returns true for empty diagram", () => { + const xml = '' + expect(isMinimalDiagram(xml)).toBe(true) + }) + + it("returns false for diagram with content", () => { + const xml = + '' + expect(isMinimalDiagram(xml)).toBe(false) + }) + + it("handles whitespace correctly", () => { + const xml = ' ' + expect(isMinimalDiagram(xml)).toBe(true) + }) +}) + +describe("replaceHistoricalToolInputs", () => { + it("replaces display_diagram tool inputs with placeholder", () => { + const messages = [ + { + role: "assistant", + content: [ + { + type: "tool-call", + toolName: "display_diagram", + input: { xml: "" }, + }, + ], + }, + ] + const result = replaceHistoricalToolInputs(messages) + expect(result[0].content[0].input.placeholder).toContain( + "XML content replaced", + ) + }) + + it("replaces edit_diagram tool inputs with placeholder", () => { + const messages = [ + { + role: "assistant", + content: [ + { + type: "tool-call", + toolName: "edit_diagram", + input: { operations: [] }, + }, + ], + }, + ] + const result = replaceHistoricalToolInputs(messages) + expect(result[0].content[0].input.placeholder).toContain( + "XML content replaced", + ) + }) + + it("removes tool calls with invalid inputs", () => { + const messages = [ + { + role: "assistant", + content: [ + { + type: "tool-call", + toolName: "display_diagram", + input: {}, + }, + { + type: "tool-call", + toolName: "display_diagram", + input: null, + }, + ], + }, + ] + const result = replaceHistoricalToolInputs(messages) + expect(result[0].content).toHaveLength(0) + }) + + it("preserves non-assistant messages", () => { + const messages = [{ role: "user", content: "hello" }] + const result = replaceHistoricalToolInputs(messages) + expect(result).toEqual(messages) + }) + + it("preserves other tool calls", () => { + const messages = [ + { + role: "assistant", + content: [ + { + type: "tool-call", + toolName: "other_tool", + input: { foo: "bar" }, + }, + ], + }, + ] + const result = replaceHistoricalToolInputs(messages) + expect(result[0].content[0].input).toEqual({ foo: "bar" }) + }) +}) diff --git a/tests/unit/utils.test.ts b/tests/unit/utils.test.ts new file mode 100644 index 00000000..1176de39 --- /dev/null +++ b/tests/unit/utils.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, it } from "vitest" +import { cn, isMxCellXmlComplete, wrapWithMxFile } from "@/lib/utils" + +describe("isMxCellXmlComplete", () => { + it("returns false for empty/null input", () => { + expect(isMxCellXmlComplete("")).toBe(false) + expect(isMxCellXmlComplete(null)).toBe(false) + expect(isMxCellXmlComplete(undefined)).toBe(false) + }) + + it("returns true for self-closing mxCell", () => { + const xml = + '' + expect(isMxCellXmlComplete(xml)).toBe(true) + }) + + it("returns true for mxCell with closing tag", () => { + const xml = ` + + ` + expect(isMxCellXmlComplete(xml)).toBe(true) + }) + + it("returns false for truncated mxCell", () => { + const xml = + ' { + const xml = ` + { + const xml = ` + ` + expect(isMxCellXmlComplete(xml)).toBe(true) + }) +}) + +describe("wrapWithMxFile", () => { + it("wraps empty string with default structure", () => { + const result = wrapWithMxFile("") + expect(result).toContain("") + expect(result).toContain("") + expect(result).toContain('') + expect(result).toContain('') + }) + + it("wraps raw mxCell content", () => { + const xml = '' + const result = wrapWithMxFile(xml) + expect(result).toContain("") + expect(result).toContain(xml) + expect(result).toContain("") + }) + + it("returns full mxfile unchanged", () => { + const fullXml = + '' + const result = wrapWithMxFile(fullXml) + expect(result).toBe(fullXml) + }) + + it("handles whitespace in input", () => { + const result = wrapWithMxFile(" ") + expect(result).toContain("") + }) +}) + +describe("cn (class name utility)", () => { + it("merges class names", () => { + expect(cn("foo", "bar")).toBe("foo bar") + }) + + it("handles conditional classes", () => { + expect(cn("foo", false && "bar", "baz")).toBe("foo baz") + }) + + it("merges tailwind classes correctly", () => { + expect(cn("px-2", "px-4")).toBe("px-4") + expect(cn("text-red-500", "text-blue-500")).toBe("text-blue-500") + }) +}) diff --git a/vitest.config.mts b/vitest.config.mts new file mode 100644 index 00000000..790e1e80 --- /dev/null +++ b/vitest.config.mts @@ -0,0 +1,17 @@ +import react from "@vitejs/plugin-react" +import tsconfigPaths from "vite-tsconfig-paths" +import { defineConfig } from "vitest/config" + +export default defineConfig({ + plugins: [tsconfigPaths(), react()], + test: { + environment: "jsdom", + include: ["tests/**/*.test.{ts,tsx}"], + coverage: { + provider: "v8", + reporter: ["text", "json", "html"], + include: ["lib/**/*.ts", "app/**/*.ts", "app/**/*.tsx"], + exclude: ["**/*.test.ts", "**/*.test.tsx", "**/*.d.ts"], + }, + }, +})