From bf063304b8f7c5ee6f4a352799d361f2b36f0bcc Mon Sep 17 00:00:00 2001 From: Hunter Date: Wed, 22 Jul 2026 10:00:30 -0500 Subject: [PATCH] Release chartgpu-react 0.3.0 for ChartGPU 0.3.6 Align the React bindings with @chartgpu/chartgpu ^0.3.6, expand 0.3.x handle/hook surface and types, modernize the examples demo site, and add CI plus mock-based unit coverage for forwarding and multi-chart hooks. Tooling: upgrade to TypeScript 7.0 (^7.0.2), Vite 7, and Vitest 4; drop vite-plugin-dts (incompatible with TS 7's slim package API) and emit declarations via tsc. Fix useGPUContext StrictMode init via a shared promise. Package name restored to chartgpu-react for npmjs.org. --- .github/workflows/ci.yml | 38 + .gitignore | 1 + CHANGELOG.md | 30 + README.md | 44 +- docs/GETTING_STARTED.md | 27 +- docs/api/hooks.md | 5 +- examples/assets/chartgpu.png | Bin 0 -> 112298 bytes examples/index.html | 251 +- examples/main.tsx | 1546 +++++---- examples/styles.css | 859 +++++ examples/tokens.css | 74 + package-lock.json | 4105 ++++++++++------------- package.json | 58 +- src/ChartGPU.tsx | 8 +- src/ChartGPUChart.tsx | 5 +- src/__tests__/ChartGPU.test.tsx | 302 +- src/__tests__/exports.test.ts | 76 + src/__tests__/useChartGPU.test.tsx | 49 + src/__tests__/useConnectCharts.test.tsx | 181 + src/__tests__/useGPUContext.test.tsx | 198 ++ src/index.ts | 35 +- src/types.ts | 100 +- src/useChartGPU.ts | 4 +- src/useGPUContext.ts | 78 +- src/utils.ts | 8 +- tsconfig.build.json | 6 +- tsconfig.json | 13 +- tsconfig.node.json | 13 +- vite.config.ts | 14 +- 29 files changed, 4726 insertions(+), 3402 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 CHANGELOG.md create mode 100644 examples/assets/chartgpu.png create mode 100644 examples/styles.css create mode 100644 examples/tokens.css create mode 100644 src/__tests__/exports.test.ts create mode 100644 src/__tests__/useConnectCharts.test.tsx create mode 100644 src/__tests__/useGPUContext.test.tsx diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..5c5f667 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + typecheck-and-test: + name: Typecheck & test + runs-on: ubuntu-latest + timeout-minutes: 15 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "20.x" + cache: "npm" + + - name: Install dependencies + run: npm ci + + - name: Typecheck + run: npm run typecheck + + - name: Test + run: npm test + + - name: Build + run: npm run build diff --git a/.gitignore b/.gitignore index 19d82a0..9584a4a 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ coverage *.swp *.swo *~ +.hallmark # Claude diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..663252f --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +## 0.3.0 + +Aligned with **@chartgpu/chartgpu ^0.3.6** and modern React/TypeScript tooling. + +### Dependencies + +- Peer: `@chartgpu/chartgpu` **^0.3.6** (was ^0.2.8) +- Peer: React **≥18** (dev/tested on **React 19.2**) +- Dev: **TypeScript 7.0**, Vite 7, Vitest 4, `@types/react` 19 + +### API + +- `ChartGPUHandle.appendData` accepts optional `{ maxPoints }` for FIFO / fixed-capacity streaming (ChartGPU 0.3.x) +- `ChartGPUHandle.setZoomRange` passes optional `source` through to core +- `CartesianSeriesData` allows `null` gaps (matches core) +- Expanded type re-exports: heatmap, band, errorBar, impulse, OHLC, 3D series, `ZoomChangeSourceKind`, etc. +- New exported type: `ChartGPUAppendDataOptions` + +### Tooling + +- Build: Vite (ESM bundle) + `tsc` declaration emit + (`vite-plugin-dts` is incompatible with TypeScript 7’s slim package API) +- Package name restored to **`chartgpu-react`** for npmjs.org (GitHub Packages still scopes at publish) +- Test coverage for handle/hooks 0.3.x: `appendData`/`maxPoints`, `setZoomRange` source, external render, `useConnectCharts`, `useGPUContext`, `gpuContext` create path, `onDataAppend`/`onDeviceLost`, export smoke + +### Examples + +- Streaming multi-chart demos use `appendData(..., { maxPoints })` diff --git a/README.md b/README.md index af9629e..a7e1abe 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,9 @@ - **`ChartGPU` component (recommended)**: async create/dispose lifecycle + debounced `ResizeObserver` sizing - **Event props**: `onClick`, `onCrosshairMove`, `onZoomChange`, `onDataAppend`, `onDeviceLost`, etc. -- **Imperative `ref` API**: `ChartGPUHandle` (`getChart`, `getContainer`, `appendData`, `setOption`, `setZoomRange`, `setInteractionX`, `getInteractionX`, `hitTest`, `needsRender`, `renderFrame`, `getRenderMode`, `setRenderMode`) +- **Imperative `ref` API**: `ChartGPUHandle` (`getChart`, `getContainer`, `appendData` with optional `{ maxPoints }` FIFO, `setOption`, `setZoomRange`, `setInteractionX`, `getInteractionX`, `hitTest`, `needsRender`, `renderFrame`, `getRenderMode`, `setRenderMode`) - **Hooks**: `useChartGPU(...)`, `useGPUContext()`, `useConnectCharts(..., syncOptions?)` +- **Multi-chart + streaming**: share a `GPUDevice` via `gpuContext` / `useGPUContext`, sync with `useConnectCharts`, stream with `appendData(..., { maxPoints })` - **Helper re-exports (from `@chartgpu/chartgpu`)**: `createChart`, `connectCharts`, `createPipelineCache`, `getPipelineCacheStats`, `destroyPipelineCache`, `createAnnotationAuthoring` ## Quick start @@ -70,13 +71,16 @@ function MyChart() { npm install chartgpu-react @chartgpu/chartgpu react react-dom ``` +Peer dependency: **`@chartgpu/chartgpu` ^0.3.6** (aligned with this package’s 0.3.x line). + ### Requirements -- React 18.0.0 or higher +- **React 18 or 19** (`react` / `react-dom` ≥ 18) +- **TypeScript 5+** for consumers (this package is built and typechecked with **TypeScript 7**) - Browser with WebGPU support: - Chrome/Edge 113+ - Safari 18+ - - Firefox (not yet supported) + - Firefox: Windows 114+, Mac 145+, Linux nightly Check browser compatibility at [caniuse.com/webgpu](https://caniuse.com/webgpu). @@ -135,6 +139,40 @@ disconnect(); If you prefer a hook-driven approach, you can use `onReady` (or `useChartGPU`) to capture instances, then call `useConnectCharts(...)` once both are available. +### Streaming append with FIFO window (`maxPoints`) + +```tsx +import { useEffect, useRef } from 'react'; +import { ChartGPU } from 'chartgpu-react'; +import type { ChartGPUHandle } from 'chartgpu-react'; + +function StreamingChart() { + const ref = useRef(null); + const xRef = useRef(0); + + useEffect(() => { + const id = window.setInterval(() => { + const x = xRef.current++; + ref.current?.appendData(0, [{ x, y: Math.sin(x * 0.05) }], { maxPoints: 50_000 }); + }, 16); + return () => window.clearInterval(id); + }, []); + + return ( + + ); +} +``` + ### External render mode (app-owned render loop) ```tsx diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md index a9d7d6a..02df990 100644 --- a/docs/GETTING_STARTED.md +++ b/docs/GETTING_STARTED.md @@ -10,8 +10,9 @@ npm install chartgpu-react @chartgpu/chartgpu react react-dom ## Requirements -- **React**: 18+ -- **WebGPU**: a browser with `navigator.gpu` support (Chrome/Edge 113+, Safari 18+) +- **@chartgpu/chartgpu**: ^0.3.6 (peer) +- **React**: 18 or 19 +- **WebGPU**: a browser with `navigator.gpu` support (Chrome/Edge 113+, Safari 18+, modern Firefox) If WebGPU is not available, chart creation will fail. @@ -65,7 +66,27 @@ See [Streaming recipe](./recipes/streaming.md). ## React 18 StrictMode -In development, React 18 StrictMode intentionally runs effects twice (mount → unmount → mount). `ChartGPU` and `useChartGPU` are written to be safe under this behavior (async create + cleanup ordering). +In development, React 18 StrictMode intentionally runs effects twice (mount → unmount → mount). `ChartGPU`, `useChartGPU`, and `useGPUContext` are written to be safe under this behavior: + +- **`ChartGPU` / `useChartGPU`**: async create + cleanup ordering (dispose if unmounted before create resolves). +- **`useGPUContext`**: a shared init promise so StrictMode remount reuses one adapter/device/`PipelineCache` acquisition instead of requesting a second device. + +## Testing (unit coverage map) + +Unit tests live under `src/__tests__/` (Vitest + jsdom). They mock `@chartgpu/chartgpu` and do **not** require a real WebGPU device (except `useGPUContext`, which stubs `navigator.gpu`). + +| Area | File | +|------|------| +| Create / `setOption` race (issue #16) | `src/__tests__/ChartGPU.test.tsx`, `src/__tests__/useChartGPU.test.tsx` | +| Handle `appendData` + `{ maxPoints }`, `setZoomRange` source, external render | `src/__tests__/ChartGPU.test.tsx` | +| Handle smoke (`getChart`, `setOption`, interaction X, `hitTest`) | `src/__tests__/ChartGPU.test.tsx` | +| Event props (`onDataAppend`, `onDeviceLost`) | `src/__tests__/ChartGPU.test.tsx` | +| `gpuContext` → `ChartGPU.create` third arg | `src/__tests__/ChartGPU.test.tsx`, `src/__tests__/useChartGPU.test.tsx` | +| `useConnectCharts` | `src/__tests__/useConnectCharts.test.tsx` | +| `useGPUContext` | `src/__tests__/useGPUContext.test.tsx` | +| Public export surface | `src/__tests__/exports.test.ts` | + +Run: `npm test`, `npm run typecheck`, `npm run build`. ## Next steps diff --git a/docs/api/hooks.md b/docs/api/hooks.md index 7964552..2b11f86 100644 --- a/docs/api/hooks.md +++ b/docs/api/hooks.md @@ -113,8 +113,9 @@ function useGPUContext(): { - On mount, requests a `GPUAdapter` (high-performance preference) and `GPUDevice`, then creates a `PipelineCache`. - All fields are `null` until initialization completes. `isReady` becomes `true` once both `adapter` and `device` are available. - If WebGPU is not supported or adapter/device acquisition fails, `error` is set and other fields remain `null`. -- Safe in React 18 StrictMode dev (uses a ref guard to prevent double-initialization). -- Initialization runs once on mount and cannot be re-triggered. +- Safe in React 18 StrictMode dev: a **shared in-flight/completed init promise** ensures a single adapter/device/`PipelineCache` acquisition. The first effect may be cancelled by StrictMode’s simulated unmount; the second effect re-subscribes to the **same** promise and applies the result (it does **not** call `requestAdapter` again). +- Initialization runs once per hook instance and cannot be re-triggered. +- **Lifecycle / resource ownership:** the hook does **not** call `GPUDevice.destroy()` or `destroyPipelineCache` on unmount. It is intended for a **long-lived dashboard parent**. Mounting briefly and unmounting mid-init can leave a native device alive until page unload (auto-destroy would race with StrictMode remount, which reuses the shared promise). Keep `useGPUContext()` mounted for the process lifetime of the shared charts, or manage teardown yourself if you truly need a short-lived context. ### Usage with `` diff --git a/examples/assets/chartgpu.png b/examples/assets/chartgpu.png new file mode 100644 index 0000000000000000000000000000000000000000..5fa0e5bd1a21d07f97e5254caab070d96981f354 GIT binary patch literal 112298 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 - ChartGPU React - Examples - - - -
-

ChartGPU React

-

WebGPU-powered charting for React applications

- -
-
- + diff --git a/examples/main.tsx b/examples/main.tsx index 9be2a56..8373a13 100644 --- a/examples/main.tsx +++ b/examples/main.tsx @@ -1,11 +1,8 @@ -import React, { useEffect, useMemo, useRef, useState } from 'react'; +import React, { useCallback, useEffect, useMemo, useRef, useState, type ReactNode } from 'react'; import { createRoot } from 'react-dom/client'; -import { ChartGPU, connectCharts, createAnnotationAuthoring, useGPUContext, useConnectCharts } from '../src'; +import { ChartGPU, useGPUContext, useConnectCharts } from '../src'; import type { - ChartGPUCrosshairMovePayload, ChartGPUCreateContext, - ChartGPUDataAppendPayload, - ChartGPUDeviceLostPayload, ChartGPUHandle, ChartGPUInstance, ChartGPUOptions, @@ -18,786 +15,871 @@ type Candle = Extract< { timestamp: number; open: number; close: number; low: number; high: number } >; +type ExampleStatus = 'idle' | 'loading' | 'ok' | 'error'; + +const DEMO_THEME = { + backgroundColor: '#05060a', + gridLineColor: 'rgba(255,255,255,0.06)', + axisLineColor: 'rgba(224,224,224,0.14)', + axisTickColor: 'rgba(224,224,224,0.22)', + textColor: 'rgba(224,224,224,0.82)', +} as const; + function generateLineData(points: number, seed: number): Array<{ x: number; y: number }> { const data: Array<{ x: number; y: number }> = []; for (let i = 0; i < points; i++) { - const x = i; - const y = Math.sin(i * 0.02 + seed) * 50 + Math.cos(i * 0.01 + seed) * 10; - data.push({ x, y }); + data.push({ + x: i, + y: Math.sin(i * 0.02 + seed) * 50 + Math.cos(i * 0.01 + seed) * 10, + }); } return data; } -function CrosshairMoveExample() { - const [chart, setChart] = useState(null); - const [crosshairX, setCrosshairX] = useState(null); +function ExampleCard(props: { + id: string; + index: string; + title: string; + description: string; + tags?: string[]; + status?: ExampleStatus; + statusLabel?: string; + meta?: ReactNode; + stack?: boolean; + featured?: boolean; + tall?: boolean; + bleed?: boolean; + children: ReactNode; +}) { + const { + id, + index, + title, + description, + tags = [], + status = 'idle', + statusLabel, + meta, + stack, + featured, + tall, + bleed, + children, + } = props; + + const statusClass = + status === 'ok' + ? 'example-status example-status--ok' + : status === 'error' + ? 'example-status example-status--error' + : status === 'loading' + ? 'example-status example-status--loading' + : 'example-status'; + + const resolvedLabel = + statusLabel ?? + (status === 'ok' + ? 'Live' + : status === 'loading' + ? 'Initializing…' + : status === 'error' + ? 'Unavailable' + : 'Ready'); + + const className = [ + 'example', + featured ? 'example--featured' : '', + tall ? 'example--tall' : '', + ] + .filter(Boolean) + .join(' '); + + const canvasClass = [ + 'example-canvas', + stack ? 'example-canvas--stack' : '', + bleed ? 'example-canvas--bleed' : '', + ] + .filter(Boolean) + .join(' '); - const options: ChartGPUOptions = useMemo( - () => ({ - series: [ - { - type: 'line', - name: 'Signal', - data: generateLineData(2000, 0.3), - lineStyle: { width: 2, color: '#667eea' }, - areaStyle: { color: 'rgba(102, 126, 234, 0.15)' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside' }, { type: 'slider' }], - grid: { left: 60, right: 40, top: 40, bottom: 40 }, - }), - [] + return ( +
+
+
+

{index}

+

{title}

+

{description}

+
+
+
+
+ + {meta ?
{meta}
: null} + + {tags.length > 0 ? ( +
+ {tags.map((tag) => ( + + {tag} + + ))} +
+ ) : null} + +
{children}
+
); +} +function ChartHost(props: { children: ReactNode; style?: React.CSSProperties }) { return ( -
-

Crosshair move + dataZoom

- -
- Features: 'crosshairMove' event, tooltip, inside+slider zoom -
- Crosshair X:{' '} - {crosshairX === null ? none : crosshairX.toFixed(2)} -
- {chart && !chart.disposed && ( - ✓ Chart Active - )} -
- -
- setCrosshairX(p.x)} - theme="dark" - /> -
+
+ {props.children}
); } -function ConnectedChartsExample() { - const [topChart, setTopChart] = useState(null); - const [bottomChart, setBottomChart] = useState(null); +// ─── 3D terrain + LiDAR (hero plate) ───────────────────────────────────────── + +const SURF_COLS = 96; +const SURF_ROWS = 64; +const SEED_CLOUD = 14_000; - const topOptions: ChartGPUOptions = useMemo( +function heightAt(u: number, v: number, t: number): number { + const g1 = Math.exp(-((u - 0.25) ** 2 + (v + 0.15) ** 2) / 0.12); + const g2 = 0.65 * Math.exp(-((u + 0.35) ** 2 + (v - 0.3) ** 2) / 0.09); + const ridge = 0.2 * Math.sin((u + t) * 5) * Math.cos(v * 4); + return g1 + g2 + ridge - 0.15 * (u * u + v * v); +} + +function fillTerrain(y: Float32Array, columns: number, rows: number, t = 0): void { + for (let j = 0; j < rows; j++) { + for (let i = 0; i < columns; i++) { + const u = (i / Math.max(1, columns - 1)) * 2 - 1; + const v = (j / Math.max(1, rows - 1)) * 2 - 1; + y[j * columns + i] = heightAt(u, v, t); + } + } +} + +function makeSeedCloud( + n: number, + yField: Float32Array, + columns: number, + rows: number, + xStart: number, + xStep: number, + zStart: number, + zStep: number +) { + const x = new Float32Array(n); + const y = new Float32Array(n); + const z = new Float32Array(n); + const value = new Float32Array(n); + for (let i = 0; i < n; i++) { + const ii = Math.floor(Math.random() * columns); + const jj = Math.floor(Math.random() * rows); + const wx = xStart + ii * xStep; + const wz = zStart + jj * zStep; + const h = yField[jj * columns + ii]! + (Math.random() - 0.5) * 0.08; + x[i] = wx + (Math.random() - 0.5) * 0.04; + y[i] = h + 0.05; + z[i] = wz + (Math.random() - 0.5) * 0.04; + value[i] = h; + } + return { x, y, z, value }; +} + +function Hero3DExample() { + const plateRef = useRef(null); + const [ready, setReady] = useState(false); + const chartRef = useRef(null); + const yFieldRef = useRef(new Float32Array(SURF_COLS * SURF_ROWS)); + const surfaceXStartRef = useRef(-1); + const streamTRef = useRef(0); + + const surfaceData = useMemo(() => { + fillTerrain(yFieldRef.current, SURF_COLS, SURF_ROWS, 0); + return { + xStart: -1, + xStep: 2 / Math.max(1, SURF_COLS - 1), + zStart: -1, + zStep: 2 / Math.max(1, SURF_ROWS - 1), + columns: SURF_COLS, + rows: SURF_ROWS, + y: yFieldRef.current, + }; + }, []); + + const cloudData = useMemo(() => { + const arrays = makeSeedCloud( + SEED_CLOUD, + yFieldRef.current, + SURF_COLS, + SURF_ROWS, + surfaceData.xStart, + surfaceData.xStep, + surfaceData.zStart, + surfaceData.zStep + ); + return arrays; + }, [surfaceData]); + + const options: ChartGPUOptions = useMemo( () => ({ + coordinateSystem: 'cartesian3d', + theme: DEMO_THEME, + legend: { show: false }, + tooltip: { show: true }, + // Wheel zoom would capture the page scroll on a full-viewport hero. + interaction3d: { orbit: true, pan: true, zoom: false }, + camera: { + type: 'perspective', + eye: [2.4, 1.6, 2.2], + target: [0, 0.15, 0], + up: [0, 1, 0], + fovY: Math.PI / 4, + }, + axes3d: { + showBox: true, + showGrid: true, + labelMode: 'auto', + x: { name: 'X (m)', tickCount: 5 }, + y: { name: 'Height', tickCount: 5 }, + z: { name: 'Y (m)', tickCount: 5 }, + }, series: [ { - type: 'line', - name: 'Top', - data: generateLineData(1000, 0.1), - lineStyle: { width: 2, color: '#4facfe' }, + type: 'surface3d', + name: 'Terrain', + data: surfaceData, + colormap: 'viridis', + lighting: 0.72, + opacity: 1, + contours: { + show: true, + levels: 10, + color: '#e2e8f0', + width: 1.5, + opacity: 0.85, + }, }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - grid: { left: 60, right: 40, top: 40, bottom: 40 }, - }), - [] - ); - - const bottomOptions: ChartGPUOptions = useMemo( - () => ({ - series: [ { - type: 'line', - name: 'Bottom', - data: generateLineData(1000, 1.2), - lineStyle: { width: 2, color: '#f093fb' }, - areaStyle: { color: 'rgba(240, 147, 251, 0.12)' }, + type: 'pointCloud3d', + name: 'LiDAR', + data: cloudData, + pointStyle: { size: 2.5, color: '#38bdf8', opacity: 0.92 }, + colorBy: { colormap: 'plasma', min: -0.2, max: 1.2 }, }, ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - grid: { left: 60, right: 40, top: 40, bottom: 40 }, }), - [] + [surfaceData, cloudData] ); + const onReady = useCallback((chart: ChartGPUInstance) => { + chart.setCamera?.({ + type: 'perspective', + eye: [2.4, 1.6, 2.2], + target: [0, 0.15, 0], + up: [0, 1, 0], + fovY: Math.PI / 4, + }); + setReady(true); + plateRef.current?.classList.add('is-ready'); + }, []); + + // Live surface strip (always on for the hero) useEffect(() => { - if (!topChart || topChart.disposed) return; - if (!bottomChart || bottomChart.disposed) return; + if (!ready) return; + + let raf = 0; + const tick = () => { + const c = chartRef.current?.getChart() ?? null; + if (c && !c.disposed && c.updateSurface3D) { + streamTRef.current += 0.006; + const col = new Float32Array(SURF_ROWS); + const nextI = SURF_COLS; + const uEdge = + -1 + (nextI / Math.max(1, SURF_COLS - 1)) * 2 + streamTRef.current * 0.08; + for (let r = 0; r < SURF_ROWS; r++) { + const v = (r / Math.max(1, SURF_ROWS - 1)) * 2 - 1; + col[r] = heightAt(uEdge, v, streamTRef.current); + } + const yField = yFieldRef.current; + for (let r = 0; r < SURF_ROWS; r++) { + const row = r * SURF_COLS; + yField.copyWithin(row, row + 1, row + SURF_COLS); + yField[row + SURF_COLS - 1] = col[r]!; + } + const dx = surfaceData.xStep; + surfaceXStartRef.current += dx; + c.updateSurface3D(0, { + mode: 'appendColumns', + columns: 1, + y: col, + scrollX: true, + }); + const cam = c.getCamera?.(); + if (cam?.eye && cam.target) { + c.setCamera?.({ + eye: [cam.eye[0]! + dx, cam.eye[1]!, cam.eye[2]!], + target: [cam.target[0]! + dx, cam.target[1]!, cam.target[2]!], + }); + } + } + raf = requestAnimationFrame(tick); + }; + raf = requestAnimationFrame(tick); + return () => cancelAnimationFrame(raf); + }, [ready, surfaceData.xStep]); - const disconnect = connectCharts([topChart, bottomChart]); - return () => disconnect(); - }, [topChart, bottomChart]); + // Bind plate ref for is-ready class + useEffect(() => { + plateRef.current = document.getElementById('hero'); + }, []); return ( -
-

connectCharts (sync crosshair)

- -
- Features: Shared interaction-x between two charts via connectCharts -
- Try it: Move your mouse over either chart -
- -
- -
- + <> +
Initializing WebGPU 3D…
+
+

cartesian3d

+

surface3d + pointCloud3d

+

+ Drag to orbit · scroll the page to leave · live updateSurface3D strip +

-
+ + ); } -function SyncedDashboardExample() { - const { adapter, device, pipelineCache, isReady, error } = useGPUContext(); - - const [chartA, setChartA] = useState(null); - const [chartB, setChartB] = useState(null); - const [chartC, setChartC] = useState(null); - - // Sync crosshair and zoom across all three charts - useConnectCharts([chartA, chartB, chartC], { syncZoom: true }); - - const optionsA: ChartGPUOptions = useMemo( - () => ({ - series: [ - { - type: 'line', - name: 'Series A', - data: generateLineData(500, 0.5), - lineStyle: { width: 2, color: '#4facfe' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside' }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), - [] - ); +// ─── 3D helix point cloud ──────────────────────────────────────────────────── + +function makeHelixCloud(n: number) { + const x = new Float32Array(n); + const y = new Float32Array(n); + const z = new Float32Array(n); + const value = new Float32Array(n); + for (let i = 0; i < n; i++) { + const t = i / n; + const ang = t * Math.PI * 10; + const r = 0.25 + t * 1.35; + const nx = (Math.random() - 0.5) * 0.12; + const ny = (Math.random() - 0.5) * 0.12; + const nz = (Math.random() - 0.5) * 0.12; + x[i] = Math.cos(ang) * r + nx; + y[i] = (t - 0.5) * 2.8 + ny; + z[i] = Math.sin(ang) * r + nz; + value[i] = Math.hypot(x[i]!, z[i]!); + } + return { x, y, z, value }; +} - const optionsB: ChartGPUOptions = useMemo( - () => ({ - series: [ - { - type: 'line', - name: 'Series B', - data: generateLineData(500, 2.1), - lineStyle: { width: 2, color: '#f093fb' }, - areaStyle: { color: 'rgba(240, 147, 251, 0.12)' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside' }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), - [] - ); +function PointCloud3DExample() { + const [ready, setReady] = useState(false); + const POINT_COUNT = 80_000; + const cloud = useMemo(() => makeHelixCloud(POINT_COUNT), []); - const optionsC: ChartGPUOptions = useMemo( + const options: ChartGPUOptions = useMemo( () => ({ + coordinateSystem: 'cartesian3d', + theme: DEMO_THEME, + legend: { show: false }, + tooltip: { show: true }, + camera: { type: 'perspective' }, + axes3d: { + showBox: true, + showGrid: true, + labelMode: 'auto', + x: { name: 'X' }, + y: { name: 'Y' }, + z: { name: 'Z' }, + }, series: [ { - type: 'line', - name: 'Series C', - data: generateLineData(500, 4.0), - lineStyle: { width: 2, color: '#40d17c' }, + type: 'pointCloud3d', + name: 'Helix', + data: cloud, + pointStyle: { size: 2.2, color: '#38bdf8', opacity: 0.9 }, + colorBy: { colormap: 'viridis', min: 0, max: 1.8 }, }, ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside' }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, }), - [] - ); - - if (error) return ( -
-

Synced dashboard (shared GPU + useConnectCharts)

-
- WebGPU not supported: {error.message} -
-
- ); - - if (!isReady) return ( -
-

Synced dashboard (shared GPU + useConnectCharts)

-
Initializing GPU...
-
+ [cloud] ); - const gpuContext = { adapter: adapter!, device: device!, pipelineCache: pipelineCache! }; - return ( -
-

Synced dashboard (shared GPU + useConnectCharts)

- -
- Features: useGPUContext() + useConnectCharts() +{' '} - gpuContext prop -
- Try it: Move crosshair or zoom on any chart — all three stay in sync -
- -
- -
+ + -
- setReady(true)} /> -
-
+ + ); } -function StreamingSyncedDashboardExample() { - const { adapter, device, pipelineCache, isReady, error } = useGPUContext(); +// ─── Scatter density ───────────────────────────────────────────────────────── - const [chartA, setChartA] = useState(null); - const [chartB, setChartB] = useState(null); - const [chartC, setChartC] = useState(null); - - const refA = useRef(null); - const refB = useRef(null); - const refC = useRef(null); +function generateScatterPoints(count: number, seed: number): ScatterPointTuple[] { + const mulberry32 = (a: number) => () => { + a |= 0; + a = (a + 0x6d2b79f5) | 0; + let t = Math.imul(a ^ (a >>> 15), 1 | a); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; - // Sync crosshair and zoom across all three charts - useConnectCharts([chartA, chartB, chartC], { syncZoom: true }); + const rand = mulberry32(Math.floor(seed * 1_000_000)); + const normal = () => { + const u1 = Math.max(1e-12, rand()); + const u2 = rand(); + const r = Math.sqrt(-2.0 * Math.log(u1)); + const theta = 2.0 * Math.PI * u2; + return r * Math.cos(theta); + }; + const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v)); - const optionsA: ChartGPUOptions = useMemo( - () => ({ - autoScroll: true, - series: [ - { - type: 'line', - name: 'latency(ms)', - data: generateLineData(200, 0.1), - lineStyle: { width: 2, color: '#4facfe' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), - [] - ); + const points: ScatterPointTuple[] = []; + for (let i = 0; i < count; i++) { + const blob = rand() < 0.55 ? 0 : rand() < 0.7 ? 1 : 2; + const centers = [ + [30, 55, 9, 11], + [68, 38, 6, 8], + [50, 72, 5, 4], + ] as const; + const [cx, cy, sx, sy] = centers[blob]!; + points.push([clamp(cx + normal() * sx, 0, 100), clamp(cy + normal() * sy, 0, 100)]); + } + return points; +} - const optionsB: ChartGPUOptions = useMemo( - () => ({ - autoScroll: true, - series: [ - { - type: 'line', - name: 'throughput', - data: generateLineData(200, 1.7), - lineStyle: { width: 2, color: '#f093fb' }, - areaStyle: { color: 'rgba(240, 147, 251, 0.12)' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), - [] - ); +function ScatterDensityExample() { + const POINT_COUNT = 500_000; + const scatterData = useMemo(() => generateScatterPoints(POINT_COUNT, 0.42), []); + const [ready, setReady] = useState(false); - const optionsC: ChartGPUOptions = useMemo( + const options: ChartGPUOptions = useMemo( () => ({ - autoScroll: true, + theme: DEMO_THEME, series: [ { - type: 'line', - name: 'errors', - data: generateLineData(200, 3.2), - lineStyle: { width: 2, color: '#ff6b6b' }, + type: 'scatter', + name: 'Density', + data: scatterData, + mode: 'density', + binSize: 2, + densityColormap: 'inferno', + densityNormalization: 'log', + sampling: 'none', }, ], xAxis: { type: 'value' }, yAxis: { type: 'value' }, tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, + dataZoom: [{ type: 'inside' }], + grid: { left: 56, right: 28, top: 28, bottom: 40 }, }), - [] - ); - - // Stream data into all three charts via refs - const xRef = useRef(200); - useEffect(() => { - const timer = window.setInterval(() => { - const x = xRef.current++; - refA.current?.appendData(0, [{ x, y: 40 + Math.sin(x * 0.03) * 25 + Math.random() * 5 }]); - refB.current?.appendData(0, [{ x, y: 55 + Math.cos(x * 0.02) * 22 + Math.random() * 6 }]); - refC.current?.appendData(0, [{ x, y: 10 + Math.abs(Math.sin(x * 0.05)) * 8 + Math.random() * 3 }]); - }, 120); - - return () => window.clearInterval(timer); - }, []); - - if (error) return ( -
-

Streaming synced dashboard (shared GPU + useConnectCharts + appendData)

-
- WebGPU not supported: {error.message} -
-
- ); - - if (!isReady) return ( -
-

Streaming synced dashboard (shared GPU + useConnectCharts + appendData)

-
Initializing GPU...
-
+ [scatterData] ); - const gpuContext = { adapter: adapter!, device: device!, pipelineCache: pipelineCache! }; - return ( -
-

Streaming synced dashboard (shared GPU + useConnectCharts + appendData)

- -
- Features: useGPUContext() + useConnectCharts() +{' '} - appendData streaming -
- Try it: Move crosshair or zoom on any chart while data streams — all three stay in sync -
- -
- -
- -
+ + setReady(true)} /> -
-
+ + ); } -function ExternalRenderModeExample() { - const ref = useRef(null); - const [mode, setMode] = useState<'auto' | 'external'>('external'); +// ─── Live spectrogram ──────────────────────────────────────────────────────── + +const TIME_BINS = 256; +const FREQ_BINS = 128; +const DT = 0.02; +const DF = 8; + +function fillSpectrogramColumn(column: Float32Array, t: number): void { + const rows = column.length; + for (let j = 0; j < rows; j++) { + const fNorm = j / Math.max(1, rows - 1); + const chirp = 0.15 + 0.7 * (0.5 + 0.5 * Math.sin(t * 0.7)); + const main = Math.exp(-((fNorm - chirp) ** 2) / 0.0015); + const harm = 0.45 * Math.exp(-((fNorm - chirp * 0.55) ** 2) / 0.002); + const noise = 0.04 * Math.random(); + column[j] = -100 + Math.min(1, main + harm + noise) * 100; + } +} + +function SpectrogramExample() { + const chartRef = useRef(null); + const [ready, setReady] = useState(false); + const liveT = useRef(0); + const z = useMemo(() => { + const buf = new Float32Array(TIME_BINS * FREQ_BINS); + buf.fill(-100); + return buf; + }, []); - const initial = useMemo(() => generateLineData(300, 0.9), []); - const lastXRef = useRef(initial.length); + const heatmapData = useMemo( + () => ({ + xStart: 0, + xStep: DT, + yStart: 20, + yStep: DF, + columns: TIME_BINS, + rows: FREQ_BINS, + z, + }), + [z] + ); const options: ChartGPUOptions = useMemo( () => ({ - renderMode: 'external', - autoScroll: true, + theme: DEMO_THEME, + animation: { duration: 0 }, + grid: { left: 64, right: 24, top: 28, bottom: 48 }, + xAxis: { type: 'value', name: 'Time (s)' }, + yAxis: { type: 'value', name: 'Frequency (Hz)' }, + tooltip: { show: true, trigger: 'item' }, series: [ { - type: 'line', - name: 'External loop', - data: initial, - lineStyle: { width: 2, color: '#ffd166' }, + type: 'heatmap', + name: 'Spectrogram', + data: heatmapData, + colormap: 'viridis', + zMin: -100, + zMax: 0, + opacity: 1, + cellAnchor: 'corner', + nullHandling: 'transparent', }, ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }, { type: 'slider', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 40 }, }), - [initial] + [heatmapData] ); - // App-owned render loop (requestAnimationFrame). Only runs in external mode. - useEffect(() => { - if (mode !== 'external') return; - - let rafId = 0; - const loop = () => { - const h = ref.current; - if (h && h.needsRender()) { - h.renderFrame(); - } - rafId = window.requestAnimationFrame(loop); - }; - rafId = window.requestAnimationFrame(loop); - return () => window.cancelAnimationFrame(rafId); - }, [mode]); - - // Stream data to force the chart dirty. useEffect(() => { + if (!ready) return; + const column = new Float32Array(FREQ_BINS); const timer = window.setInterval(() => { - const x = lastXRef.current++; - const y = Math.sin(x * 0.02) * 40 + Math.cos(x * 0.013) * 12; - ref.current?.appendData(0, [{ x, y }]); - }, 120); - + const c = chartRef.current?.getChart(); + if (!c || c.disposed || !c.updateHeatmap) return; + liveT.current += DT; + fillSpectrogramColumn(column, liveT.current); + c.updateHeatmap(0, { + mode: 'appendColumns', + columns: 1, + z: column, + scrollX: true, + }); + }, 40); return () => window.clearInterval(timer); - }, []); + }, [ready]); return ( -
-

External render mode (app-owned RAF loop)

- -
- Features: renderMode: 'external',{' '} - needsRender() + renderFrame() -
- Mode: {mode}{' '} - -
- -
+ + setReady(true)} /> -
-
+ + ); } -function StreamingDashboardExample() { - const { adapter, device, pipelineCache, isReady, error } = useGPUContext(); - - const gpuContext = useMemo(() => { - if (!adapter || !device) return undefined; - return pipelineCache - ? { adapter, device, pipelineCache } - : { adapter, device }; - }, [adapter, device, pipelineCache]); - - const [lastAppend, setLastAppend] = useState(null); - const [lost, setLost] = useState(null); +// ─── Streaming APM multi-chart ─────────────────────────────────────────────── +function StreamingAPMExample() { + const { adapter, device, pipelineCache, isReady, error } = useGPUContext(); const aRef = useRef(null); const bRef = useRef(null); const cRef = useRef(null); + const [chartA, setChartA] = useState(null); + const [chartB, setChartB] = useState(null); + const [chartC, setChartC] = useState(null); - const aOptions: ChartGPUOptions = useMemo( - () => ({ - autoScroll: true, - series: [ - { - type: 'line', - name: 'latency(ms)', - data: generateLineData(300, 0.1), - lineStyle: { width: 2, color: '#4facfe' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), - [] - ); + useConnectCharts([chartA, chartB, chartC], { syncZoom: true }); - const bOptions: ChartGPUOptions = useMemo( - () => ({ - autoScroll: true, - series: [ - { - type: 'line', - name: 'cpu(%)', - data: generateLineData(300, 1.7), - lineStyle: { width: 2, color: '#f093fb' }, - areaStyle: { color: 'rgba(240, 147, 251, 0.12)' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), + const gpuContext = useMemo(() => { + if (!adapter || !device) return undefined; + return pipelineCache ? { adapter, device, pipelineCache } : { adapter, device }; + }, [adapter, device, pipelineCache]); + + const mkOptions = (name: string, color: string, seed: number, area?: string): ChartGPUOptions => ({ + theme: DEMO_THEME, + autoScroll: true, + series: [ + { + type: 'line', + name, + data: generateLineData(280, seed), + lineStyle: { width: 2, color }, + ...(area ? { areaStyle: { color: area } } : {}), + }, + ], + xAxis: { type: 'value' }, + yAxis: { type: 'value' }, + tooltip: { show: true, trigger: 'axis' }, + dataZoom: [{ type: 'inside', start: 70, end: 100 }], + grid: { left: 52, right: 20, top: 28, bottom: 24 }, + legend: { show: true }, + }); + + const optionsA = useMemo(() => mkOptions('p99 latency', '#4facfe', 0.1), []); + const optionsB = useMemo( + () => mkOptions('throughput', '#c9a227', 1.7, 'rgba(201,162,39,0.12)'), [] ); - - const cOptions: ChartGPUOptions = useMemo( - () => ({ - autoScroll: true, - series: [ - { - type: 'line', - name: 'mem(%)', - data: generateLineData(300, 3.2), - lineStyle: { width: 2, color: '#40d17c' }, - areaStyle: { color: 'rgba(64, 209, 124, 0.12)' }, - }, - ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside', start: 70, end: 100 }], - grid: { left: 60, right: 40, top: 40, bottom: 30 }, - }), + const optionsC = useMemo( + () => mkOptions('error rate', '#f093fb', 2.8, 'rgba(240,147,251,0.1)'), [] ); - // Stream data into all charts. Demonstrates multi-chart sharing via gpuContext. useEffect(() => { - let x = 300; + if (!isReady) return; + let x = 280; const timer = window.setInterval(() => { x += 1; - aRef.current?.appendData(0, [{ x, y: 40 + Math.sin(x * 0.03) * 25 + Math.random() * 5 }]); - bRef.current?.appendData(0, [{ x, y: 55 + Math.cos(x * 0.02) * 22 + Math.random() * 6 }]); - cRef.current?.appendData(0, [{ x, y: 50 + Math.sin(x * 0.017) * 18 + Math.random() * 4 }]); - }, 140); - + const maxPoints = 500; + aRef.current?.appendData( + 0, + [{ x, y: 40 + Math.sin(x * 0.03) * 25 + Math.random() * 5 }], + { maxPoints } + ); + bRef.current?.appendData( + 0, + [{ x, y: 55 + Math.cos(x * 0.02) * 22 + Math.random() * 6 }], + { maxPoints } + ); + cRef.current?.appendData( + 0, + [{ x, y: 8 + Math.abs(Math.sin(x * 0.05)) * 6 + Math.random() * 2 }], + { maxPoints } + ); + }, 80); return () => window.clearInterval(timer); - }, []); + }, [isReady]); - return ( -
-

Streaming multi-chart dashboard (shared GPUDevice + pipeline cache)

- -
- Features: useGPUContext() + gpuContext prop,{' '} - onDataAppend, onDeviceLost -
- GPU context:{' '} - {error ? ( - {error.message} - ) : isReady ? ( - ready - ) : ( - initializing… - )} - {lost && ( - <> -
- Device lost:{' '} - {lost.reason} {lost.message ? `— ${lost.message}` : ''} - - )} - {lastAppend && ( - <> -
- Last append:{' '} - series {lastAppend.seriesIndex}, count {lastAppend.count}, xExtent{' '} - - [{lastAppend.xExtent.min.toFixed(2)}, {lastAppend.xExtent.max.toFixed(2)}] - - - )} -
+ const status: ExampleStatus = error ? 'error' : isReady ? 'ok' : 'loading'; -
- {gpuContext ? ( - <> + return ( + {error.message}

: undefined} + > + {gpuContext ? ( + <> + setLastAppend(p)} - onDeviceLost={(p) => setLost(p)} /> -
+ + setLastAppend(p)} - onDeviceLost={(p) => setLost(p)} /> -
+ + setLastAppend(p)} - onDeviceLost={(p) => setLost(p)} /> - - ) : ( -
- {error ? 'WebGPU unavailable.' : isReady ? 'Preparing shared context…' : 'Initializing WebGPU…'} -
- )} -
-
+
+ + ) : ( +
+ {error ? 'WebGPU unavailable.' : 'Initializing shared GPU context…'} +
+ )} +
); } -function AnnotationAuthoringExample() { - const chartRef = useRef(null); - const [chart, setChart] = useState(null); +// ─── Confidence band ───────────────────────────────────────────────────────── + +function BandConfidenceExample() { + const n = 200; + const series = useMemo(() => { + const x = new Float64Array(n); + const mean = new Float64Array(n); + const lo = new Float64Array(n); + const hi = new Float64Array(n); + for (let i = 0; i < n; i++) { + const t = i / (n - 1); + x[i] = t * 10; + const m = Math.sin(t * Math.PI * 2.2) * 0.45 + Math.cos(t * Math.PI * 0.8) * 0.2 + 0.5; + const s = 0.08 + 0.06 * Math.sin(t * 6); + mean[i] = m; + lo[i] = m - s; + hi[i] = m + s; + } + return { x, mean, lo, hi }; + }, []); const options: ChartGPUOptions = useMemo( () => ({ + theme: DEMO_THEME, + animation: false, + grid: { left: 56, right: 24, top: 28, bottom: 44 }, + xAxis: { type: 'value', name: 't' }, + yAxis: { type: 'value', name: 'Value' }, + tooltip: { show: true, trigger: 'axis' }, + legend: { show: true }, + dataZoom: [{ type: 'inside' }], series: [ + { + type: 'band', + name: '±1σ', + data: { x: series.x, y: series.lo, y1: series.hi }, + areaStyle: { color: '#38bdf8', opacity: 0.28 }, + lineStyle: { width: 1.2, color: '#38bdf8', opacity: 0.7 }, + lineStyleY1: { width: 1.2, color: '#f472b6', opacity: 0.7 }, + sampling: 'none', + }, { type: 'line', - name: 'Annotate me', - data: generateLineData(800, 0.6), - lineStyle: { width: 2, color: '#40d17c' }, + name: 'Mean', + data: { x: series.x, y: series.mean }, + lineStyle: { width: 2.2, color: '#f8fafc' }, + sampling: 'none', }, ], - xAxis: { type: 'value' }, - yAxis: { type: 'value' }, - tooltip: { show: true, trigger: 'axis' }, - dataZoom: [{ type: 'inside' }, { type: 'slider' }], - // Note: annotations are managed by createAnnotationAuthoring, so we don't - // include them in options to avoid overwriting them when options update. - grid: { left: 60, right: 40, top: 40, bottom: 40 }, }), - [] + [series] ); - useEffect(() => { - const container = chartRef.current?.getContainer(); - const instance = chartRef.current?.getChart(); - if (!container || !instance || instance.disposed) return; - - const authoring = createAnnotationAuthoring(container, instance, { - enableContextMenu: true, - menuZIndex: 1000, - }); - - // Important: dispose authoring before the chart disposes. - return () => authoring.dispose(); - }, [chart]); - return ( -
-

Annotation authoring

- -
- Features: Right-click context menu + drag + undo/redo via{' '} - createAnnotationAuthoring -
- Try it: Right-click in the plot area to add annotations, right-click existing annotations to edit -
- -
- -
-
+ + + + + ); } +// ─── Candlestick streaming ─────────────────────────────────────────────────── + function seedCandles(count: number, intervalMs: number, startPrice: number): Candle[] { const now = Date.now(); const startTs = now - count * intervalMs; const out: Candle[] = []; - let lastClose = startPrice; for (let i = 0; i < count; i++) { const ts = startTs + i * intervalMs; const open = lastClose; const delta = (Math.sin(i * 0.35) + Math.cos(i * 0.22)) * 0.8; const close = open + delta; - const high = Math.max(open, close) + 0.6; - const low = Math.min(open, close) - 0.6; - out.push({ timestamp: ts, open, close, high, low }); + out.push({ + timestamp: ts, + open, + close, + high: Math.max(open, close) + 0.6, + low: Math.min(open, close) - 0.6, + }); lastClose = close; } - return out; } -function CandlestickStreamingExample() { +function CandlestickExample() { const ref = useRef(null); - const initial = useMemo(() => seedCandles(80, 1000, 100), []); + const initial = useMemo(() => seedCandles(100, 1000, 100), []); const last = initial[initial.length - 1]!; - const lastCloseRef = useRef(last.close); - const lastTsRef = useRef(last.timestamp); + const lastCloseRef = useRef(last.close); + const lastTsRef = useRef(last.timestamp); const options: ChartGPUOptions = useMemo( () => ({ + theme: DEMO_THEME, + legend: { show: false }, xAxis: { type: 'time' }, yAxis: { type: 'value' }, tooltip: { show: true, trigger: 'axis' }, dataZoom: [ - { type: 'inside', start: 80, end: 100 }, - { type: 'slider', start: 80, end: 100 }, + { type: 'inside', start: 75, end: 100 }, + { type: 'slider', start: 75, end: 100 }, ], autoScroll: true, series: [ @@ -808,7 +890,8 @@ function CandlestickStreamingExample() { data: initial, }, ], - grid: { left: 60, right: 40, top: 40, bottom: 40 }, + // Extra right gutter for the auto priceLabel badge + last candle wick. + grid: { left: 56, right: 72, top: 28, bottom: 52 }, }), [initial] ); @@ -816,153 +899,170 @@ function CandlestickStreamingExample() { useEffect(() => { const timer = window.setInterval(() => { const open = lastCloseRef.current; - const drift = (Math.random() - 0.5) * 2; - const close = open + drift; + const close = open + (Math.random() - 0.5) * 2; const high = Math.max(open, close) + Math.random() * 1.2; const low = Math.min(open, close) - Math.random() * 1.2; - const timestamp = lastTsRef.current + 1000; lastTsRef.current = timestamp; lastCloseRef.current = close; - - const next: Candle = { timestamp, open, close, high, low }; - ref.current?.appendData(0, [next]); - }, 500); - + ref.current?.appendData(0, [{ timestamp, open, close, high, low }]); + }, 450); return () => window.clearInterval(timer); }, []); return ( -
-

Candlestick streaming (appendData)

- -
- Features: Candlestick series + OHLC sampling + streaming{' '} - appendData (v0.2.3) -
- Note: Auto-scroll keeps the view pinned when zoomed to the end -
- -
- -
-
+ + + + + ); } -function generateScatterPoints(count: number, seed: number): ScatterPointTuple[] { - // Deterministic RNG so the example is stable across hot reloads. - const mulberry32 = (a: number) => () => { - a |= 0; - a = (a + 0x6d2b79f5) | 0; - let t = Math.imul(a ^ (a >>> 15), 1 | a); - t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; - return ((t ^ (t >>> 14)) >>> 0) / 4294967296; - }; - - const rand = mulberry32(Math.floor(seed * 1_000_000)); - const normal = () => { - // Box–Muller transform - const u1 = Math.max(1e-12, rand()); - const u2 = rand(); - const r = Math.sqrt(-2.0 * Math.log(u1)); - const theta = 2.0 * Math.PI * u2; - return r * Math.cos(theta); - }; - - const clamp = (v: number, lo: number, hi: number) => Math.min(hi, Math.max(lo, v)); - - const points: ScatterPointTuple[] = []; - for (let i = 0; i < count; i++) { - // Two Gaussian blobs so density mode shows structure. - const blob = rand() < 0.6 ? 0 : 1; - const cx = blob === 0 ? 35 : 70; - const cy = blob === 0 ? 55 : 35; - const sx = blob === 0 ? 8 : 5; - const sy = blob === 0 ? 10 : 7; - - const x = clamp(cx + normal() * sx, 0, 100); - const y = clamp(cy + normal() * sy, 0, 100); - points.push([x, y]); - } - - return points; -} +// ─── Synced hooks (React-specific) ─────────────────────────────────────────── -function ScatterDensityExample() { - const POINT_COUNT = 250_000; +function SyncedHooksExample() { + const { adapter, device, pipelineCache, isReady, error } = useGPUContext(); + const [a, setA] = useState(null); + const [b, setB] = useState(null); + useConnectCharts([a, b], { syncZoom: true }); - const scatterData = useMemo(() => generateScatterPoints(POINT_COUNT, 0.42), []); + const gpuContext = useMemo(() => { + if (!adapter || !device) return undefined; + return pipelineCache ? { adapter, device, pipelineCache } : { adapter, device }; + }, [adapter, device, pipelineCache]); - const options: ChartGPUOptions = useMemo( - () => ({ + const top = useMemo( + (): ChartGPUOptions => ({ + theme: DEMO_THEME, series: [ { - type: 'scatter', - name: 'Density', - data: scatterData, - mode: 'density', - binSize: 2, - densityColormap: 'viridis', - densityNormalization: 'log', - sampling: 'none', + type: 'line', + name: 'Alpha', + data: generateLineData(1200, 0.2), + lineStyle: { width: 2, color: '#4facfe' }, + areaStyle: { color: 'rgba(79,172,254,0.1)' }, }, ], xAxis: { type: 'value' }, yAxis: { type: 'value' }, tooltip: { show: true, trigger: 'axis' }, - grid: { left: 60, right: 40, top: 40, bottom: 40 }, + dataZoom: [{ type: 'inside' }], + grid: { left: 52, right: 24, top: 28, bottom: 28 }, }), - [scatterData] + [] ); - return ( -
-

Scatter density

+ const bottom = useMemo( + (): ChartGPUOptions => ({ + theme: DEMO_THEME, + series: [ + { + type: 'line', + name: 'Beta', + data: generateLineData(1200, 1.4), + lineStyle: { width: 2, color: '#c9a227' }, + }, + ], + xAxis: { type: 'value' }, + yAxis: { type: 'value' }, + tooltip: { show: true, trigger: 'axis' }, + dataZoom: [{ type: 'inside' }], + grid: { left: 52, right: 24, top: 28, bottom: 28 }, + }), + [] + ); -
- Features: Scatter series with mode: 'density', density colormap, binning -
- Point count: {POINT_COUNT.toLocaleString()} (adjust in code to increase) -
+ if (error) { + return ( + {error.message}

} + > +
WebGPU not supported.
+
+ ); + } -
- -
-
+ return ( + + {gpuContext && isReady ? ( + <> + + + + + + + + ) : ( +
Initializing GPU…
+ )} +
); } -function App() { +// ─── Mount ─────────────────────────────────────────────────────────────────── + +function DemosApp() { return ( <> - - - - - - - - + + + +
+ + +
+ ); } -// Mount React app +const heroRoot = document.getElementById('hero-root'); +if (heroRoot) { + createRoot(heroRoot).render(); +} + const rootElement = document.getElementById('root'); if (rootElement) { - const root = createRoot(rootElement); - root.render(); + createRoot(rootElement).render(); } else { console.error('Root element not found'); } diff --git a/examples/styles.css b/examples/styles.css new file mode 100644 index 0000000..bb23890 --- /dev/null +++ b/examples/styles.css @@ -0,0 +1,859 @@ +/* Hallmark · pre-emit critique: P5 H5 E5 S5 R4 V5 + * Hallmark · genre: atmospheric · macrostructure: Photographic + * tone: technical · theme: studied-DNA (ChartGPU brand) · enrichment: live WebGPU plates + * nav: N5 floating pill · footer: Ft5 · differs from: Component Playground + */ + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +html, +body { + overflow-x: clip; + min-width: 0; +} + +html { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + scroll-behavior: smooth; + scroll-padding-top: calc(var(--nav-height) + var(--space-md)); +} + +body { + font-family: var(--font-body); + background: var(--color-paper); + color: var(--color-ink); + line-height: 1.5; + min-height: 100vh; +} + +a { + color: inherit; + text-decoration: none; +} + +button { + font: inherit; + border: none; + background: none; + cursor: pointer; + color: inherit; +} + +img { + display: block; + max-width: 100%; +} + +code { + font-family: var(--font-mono); + font-size: 0.9em; + color: var(--color-accent); + background: var(--color-accent-soft); + padding: 0.1em 0.35em; + border-radius: 4px; +} + +:focus-visible { + outline: 2px solid var(--color-focus); + outline-offset: 3px; +} + +/* Soft atmospheric blooms */ +body::before, +body::after { + content: ''; + position: fixed; + pointer-events: none; + z-index: 0; + width: min(52vw, 560px); + height: min(52vw, 560px); + border-radius: 50%; + filter: blur(90px); + opacity: 0.18; +} + +body::before { + top: -10%; + left: -8%; + background: var(--color-accent-soft); +} + +body::after { + bottom: 8%; + right: -10%; + background: var(--color-blue-soft); +} + +/* ── N5 Floating pill nav ── */ +.nav { + position: fixed; + top: var(--space-sm); + left: 50%; + transform: translateX(-50%); + z-index: var(--z-nav); + display: flex; + align-items: center; + justify-content: space-between; + gap: var(--space-sm); + width: min(calc(100% - 2 * var(--page-gutter)), 1080px); + height: 52px; + padding: 0 var(--space-xs) 0 var(--space-sm); + background: oklch(14% 0.014 265 / 0.78); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-pill); + backdrop-filter: blur(14px); + -webkit-backdrop-filter: blur(14px); + box-shadow: 0 12px 40px oklch(0% 0 0 / 0.35); + min-width: 0; +} + +.nav-brand { + display: flex; + align-items: center; + gap: var(--space-2xs); + min-width: 0; +} + +.nav-brand img { + height: 22px; + width: auto; +} + +.nav-version { + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-2); + padding: 2px 8px; + background: var(--color-paper); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-sm); + letter-spacing: 0.02em; + white-space: nowrap; +} + +.nav-actions { + display: flex; + align-items: center; + gap: 2px; + min-width: 0; +} + +.nav-link { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 6px 11px; + font-family: var(--font-display); + font-size: var(--text-sm); + font-weight: 500; + color: var(--color-ink-2); + border-radius: var(--radius-pill); + white-space: nowrap; + transition: + color var(--dur-short) var(--ease-out), + background var(--dur-short) var(--ease-out); +} + +.nav-link:hover { + color: var(--color-ink); + background: var(--color-paper-3); +} + +.nav-link:active { + transform: translateY(1px); +} + +.nav-link svg { + width: 14px; + height: 14px; + fill: currentColor; + flex-shrink: 0; +} + +.nav-cta { + display: inline-flex; + align-items: center; + padding: 7px 14px; + font-family: var(--font-display); + font-size: var(--text-sm); + font-weight: 600; + color: var(--color-accent-ink); + background: var(--color-accent); + border-radius: var(--radius-pill); + white-space: nowrap; + transition: + filter var(--dur-short) var(--ease-out), + transform var(--dur-short) var(--ease-out); +} + +.nav-cta:hover { + filter: brightness(1.08); +} + +.nav-cta:active { + transform: translateY(1px); +} + +/* ── Photographic hero plate ── */ +.plate-hero { + position: relative; + z-index: 1; + width: 100%; + min-height: 100vh; + min-height: 100dvh; + isolation: isolate; + background: #03040a; + overflow: hidden; +} + +.plate-hero__canvas { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + min-width: 0; +} + +/* ChartGPU host is the only in-flow child; overlays are absolute */ +.plate-hero__canvas > div:not(.plate-hero__status):not(.plate-hero__caption) { + position: absolute !important; + inset: 0 !important; + width: 100% !important; + height: 100% !important; + border: none !important; + border-radius: 0 !important; + background: transparent !important; +} + +.plate-hero__canvas canvas { + display: block; + width: 100% !important; + height: 100% !important; +} + +.plate-hero__caption { + position: absolute; + z-index: 3; + left: var(--page-gutter); + bottom: var(--space-xl); + max-width: min(38ch, calc(100% - 2 * var(--page-gutter))); + min-width: 0; + padding: var(--space-sm) var(--space-md); + background: oklch(8% 0.01 265 / 0.72); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-md); + backdrop-filter: blur(10px); + -webkit-backdrop-filter: blur(10px); + pointer-events: none; +} + +.plate-hero__meta { + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-accent); + letter-spacing: 0.05em; + margin-bottom: var(--space-3xs); +} + +.plate-hero__title { + font-family: var(--font-display); + font-style: normal; + font-size: var(--text-xl); + font-weight: 600; + letter-spacing: -0.02em; + line-height: 1.2; + color: var(--color-ink); + overflow-wrap: anywhere; + min-width: 0; +} + +.plate-hero__note { + margin-top: var(--space-3xs); + font-size: var(--text-sm); + color: var(--color-ink-2); +} + +.plate-hero__status { + position: absolute; + z-index: 3; + inset: 0; + display: grid; + place-items: center; + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-3); + letter-spacing: 0.08em; + text-transform: uppercase; + pointer-events: none; + background: #03040a; + transition: opacity var(--dur-mid) var(--ease-out); +} + +.plate-hero.is-ready .plate-hero__status { + opacity: 0; + visibility: hidden; +} + +/* ── Page body ── */ +.page { + position: relative; + z-index: 1; + padding: var(--space-2xl) var(--page-gutter) var(--space-3xl); + max-width: var(--max-width); + margin: 0 auto; + min-width: 0; +} + +.intro { + margin-bottom: var(--space-xl); + min-width: 0; +} + +.intro-title { + font-family: var(--font-display); + font-style: normal; + font-size: var(--text-2xl); + font-weight: 600; + letter-spacing: -0.03em; + line-height: 1.12; + color: var(--color-ink); + overflow-wrap: anywhere; + min-width: 0; + margin-bottom: var(--space-2xs); +} + +.intro-lede { + font-size: var(--text-md); + color: var(--color-ink-2); + max-width: 56ch; + margin-bottom: var(--space-md); +} + +.intro-lede code { + font-size: 0.88em; +} + +.hero-install { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-2xs); +} + +.install-bar { + display: inline-flex; + align-items: center; + gap: var(--space-xs); + padding: 10px 14px; + background: var(--color-paper-2); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-md); + min-width: 0; +} + +.install-prompt { + color: var(--color-ink-3); + font-family: var(--font-mono); + font-size: var(--text-sm); + user-select: none; +} + +.install-cmd { + font-family: var(--font-mono); + font-size: var(--text-sm); + color: var(--color-ink); + letter-spacing: 0.01em; + background: none; + padding: 0; +} + +.install-copy { + padding: 5px 11px; + font-family: var(--font-display); + font-size: var(--text-xs); + font-weight: 600; + color: var(--color-ink-2); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-sm); + transition: + color var(--dur-short), + background var(--dur-short), + border-color var(--dur-short); + white-space: nowrap; +} + +.install-copy:hover { + color: var(--color-accent); + border-color: var(--color-accent-soft); + background: var(--color-accent-soft); +} + +.install-copy:active { + transform: translateY(1px); +} + +.install-copy.is-copied { + color: var(--color-ok); + border-color: transparent; +} + +/* ── Jump index ── */ +.index { + margin-bottom: var(--space-2xl); + min-width: 0; +} + +.index-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: var(--space-sm); + margin-bottom: var(--space-md); + flex-wrap: wrap; +} + +.index-title { + font-family: var(--font-display); + font-style: normal; + font-size: var(--text-xl); + font-weight: 600; + letter-spacing: -0.02em; + color: var(--color-ink); +} + +.index-count { + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-3); + letter-spacing: 0.04em; +} + +.index-grid { + list-style: none; + display: grid; + grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); + gap: var(--space-2xs); +} + +.index-card { + display: flex; + flex-direction: column; + gap: 4px; + min-width: 0; + padding: var(--space-sm) var(--space-md); + background: var(--color-paper-2); + border: var(--rule-hair) solid var(--color-rule); + border-radius: var(--radius-md); + transition: + background var(--dur-short) var(--ease-out), + border-color var(--dur-short) var(--ease-out), + transform var(--dur-short) var(--ease-out); +} + +.index-card:hover { + background: var(--color-paper-3); + border-color: var(--color-rule-strong); + transform: translateY(-1px); +} + +.index-card:active { + transform: translateY(0); +} + +.index-card__title { + font-family: var(--font-display); + font-size: var(--text-sm); + font-weight: 600; + color: var(--color-ink); + letter-spacing: -0.01em; + min-width: 0; + overflow-wrap: anywhere; +} + +.index-card__desc { + font-size: var(--text-xs); + color: var(--color-ink-2); + line-height: 1.4; + min-width: 0; +} + +.index-card__api { + font-family: var(--font-mono); + font-size: 0.625rem; + color: var(--color-accent); + letter-spacing: 0.02em; + margin-top: 2px; +} + +/* ── Live example cards ── */ +.examples { + display: flex; + flex-direction: column; + gap: var(--space-xl); + min-width: 0; +} + +.example { + scroll-margin-top: calc(var(--nav-height) + var(--space-lg)); + min-width: 0; + background: var(--color-paper-2); + border: var(--rule-hair) solid var(--color-rule); + border-radius: var(--radius-lg); + overflow: hidden; +} + +.example--featured { + border-color: oklch(74% 0.14 85 / 0.28); + box-shadow: 0 0 0 1px oklch(74% 0.14 85 / 0.08), 0 24px 80px oklch(0% 0 0 / 0.35); +} + +.example--tall .example-canvas { + min-height: min(62vh, 560px); +} + +.example--tall .example-canvas .chart-host { + min-height: min(58vh, 520px); +} + +.example--tall .example-canvas .chart-host > div { + min-height: inherit; +} + +.example-header { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + justify-content: space-between; + gap: var(--space-sm); + padding: var(--space-md) var(--space-md) var(--space-sm); + border-bottom: var(--rule-hair) solid var(--color-rule); + min-width: 0; +} + +.example-header__main { + min-width: 0; + flex: 1 1 16rem; +} + +.example-id { + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-3); + letter-spacing: 0.04em; + margin-bottom: var(--space-3xs); +} + +.example-title { + font-family: var(--font-display); + font-style: normal; + font-size: var(--text-lg); + font-weight: 600; + letter-spacing: -0.02em; + color: var(--color-ink); + line-height: 1.25; + overflow-wrap: anywhere; + min-width: 0; + margin-bottom: var(--space-3xs); +} + +.example-desc { + font-size: var(--text-sm); + color: var(--color-ink-2); + max-width: 62ch; +} + +.example-status { + display: inline-flex; + align-items: center; + gap: 6px; + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-2); + padding: 5px 10px; + border-radius: var(--radius-pill); + border: var(--rule-hair) solid var(--color-rule-strong); + background: var(--color-paper); + white-space: nowrap; + flex-shrink: 0; +} + +.example-status__dot { + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--color-ink-3); + flex-shrink: 0; +} + +.example-status--ok { + color: var(--color-ok); + border-color: oklch(72% 0.14 155 / 0.35); +} + +.example-status--ok .example-status__dot { + background: var(--color-ok); + box-shadow: 0 0 8px oklch(72% 0.14 155 / 0.5); +} + +.example-status--error { + color: var(--color-danger); + border-color: oklch(68% 0.16 25 / 0.4); +} + +.example-status--error .example-status__dot { + background: var(--color-danger); +} + +.example-status--loading .example-status__dot { + background: var(--color-accent); + animation: pulse-dot 1.2s var(--ease-in-out) infinite; +} + +@keyframes pulse-dot { + 0%, + 100% { + opacity: 0.4; + } + 50% { + opacity: 1; + } +} + +.example-meta { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--space-xs) var(--space-md); + padding: var(--space-sm) var(--space-md); + background: oklch(10% 0.012 265 / 0.55); + border-bottom: var(--rule-hair) solid var(--color-rule); + font-size: var(--text-sm); + color: var(--color-ink-2); + min-width: 0; +} + +.example-meta strong { + font-family: var(--font-display); + font-weight: 500; + color: var(--color-ink); + margin-right: 0.35em; +} + +.example-meta p { + min-width: 0; + flex: 1 1 100%; +} + +.example-meta__row { + min-width: 0; + flex: 1 1 auto; + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px; +} + +.example-tags { + display: flex; + flex-wrap: wrap; + gap: 6px; + padding: 0 var(--space-md) var(--space-sm); +} + +.example-tag { + font-family: var(--font-mono); + font-size: 0.625rem; + color: var(--color-ink-2); + padding: 3px 8px; + border-radius: var(--radius-sm); + border: var(--rule-hair) solid var(--color-rule-strong); + background: var(--color-paper); + letter-spacing: 0.02em; + white-space: nowrap; +} + +.example-canvas { + padding: var(--space-sm) var(--space-md) var(--space-md); + min-width: 0; + background: oklch(10% 0.01 265); +} + +.example-canvas--stack { + display: flex; + flex-direction: column; + gap: var(--space-2xs); +} + +.example-canvas--bleed { + padding: 0; + background: #05060a; +} + +.example-canvas--bleed .chart-host { + border: none; + border-radius: 0; +} + +.example-canvas .chart-host { + min-width: 0; + border-radius: var(--radius-sm); + /* Do not clip priceLabel / legend overlays (they sit outside the plot grid). */ + overflow: visible; + border: var(--rule-hair) solid var(--color-rule); + background: var(--color-paper); +} + +.example-canvas .chart-host > canvas { + display: block; + border-radius: var(--radius-sm); +} + +.example-empty { + padding: var(--space-lg); + font-family: var(--font-mono); + font-size: var(--text-xs); + color: var(--color-ink-3); + letter-spacing: 0.04em; + text-align: center; +} + +.btn { + display: inline-flex; + align-items: center; + gap: 6px; + padding: 5px 11px; + font-family: var(--font-display); + font-size: var(--text-xs); + font-weight: 600; + color: var(--color-ink); + background: var(--color-paper-3); + border: var(--rule-hair) solid var(--color-rule-strong); + border-radius: var(--radius-sm); + transition: + background var(--dur-short) var(--ease-out), + border-color var(--dur-short) var(--ease-out), + color var(--dur-short) var(--ease-out); + white-space: nowrap; +} + +.btn:hover { + color: var(--color-accent); + border-color: var(--color-accent-soft); + background: var(--color-accent-soft); +} + +.btn:active { + transform: translateY(1px); +} + +.btn:disabled { + opacity: 0.45; + cursor: not-allowed; + transform: none; +} + +.btn--on { + color: var(--color-accent-ink); + background: var(--color-accent); + border-color: transparent; +} + +.btn--on:hover { + color: var(--color-accent-ink); + filter: brightness(1.06); + background: var(--color-accent); + border-color: transparent; +} + +.btn--ghost { + background: oklch(12% 0.012 265 / 0.65); + border-color: var(--color-rule-strong); + backdrop-filter: blur(8px); +} + +/* ── Split pair plates ── */ +.pair { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--space-md); + min-width: 0; +} + +.pair > .example { + min-width: 0; +} + +/* ── Footer ── */ +.footer { + position: relative; + z-index: 1; + margin-top: var(--space-xl); + padding: var(--space-md) var(--page-gutter) var(--space-xl); + border-top: var(--rule-hair) solid var(--color-rule); + max-width: var(--max-width); + margin-left: auto; + margin-right: auto; + min-width: 0; +} + +.footer-meta { + display: flex; + flex-wrap: wrap; + gap: var(--space-sm) var(--space-md); + font-size: var(--text-sm); + color: var(--color-ink-2); +} + +.footer-meta a { + color: var(--color-ink-2); + border-bottom: 1px solid transparent; + transition: color var(--dur-short), border-color var(--dur-short); + white-space: nowrap; +} + +.footer-meta a:hover { + color: var(--color-accent); + border-bottom-color: var(--color-accent); +} + +@media (max-width: 900px) { + .pair { + grid-template-columns: 1fr; + } +} + +@media (max-width: 640px) { + .nav-link--hide-sm { + display: none; + } + + .plate-hero__caption { + bottom: var(--space-md); + max-width: calc(100% - 2 * var(--page-gutter)); + } + + .example-header { + flex-direction: column; + } +} + +@media (prefers-reduced-motion: reduce) { + html { + scroll-behavior: auto; + } + + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} diff --git a/examples/tokens.css b/examples/tokens.css new file mode 100644 index 0000000..f9135c5 --- /dev/null +++ b/examples/tokens.css @@ -0,0 +1,74 @@ +/* Hallmark · pre-emit critique: P5 H5 E5 S5 R4 V5 + * Hallmark · genre: atmospheric · macrostructure: Photographic + * tone: technical · theme: studied-DNA (source: chart-gpu/dev-site) + * paper: oklch(12% 0.012 265) · accent: oklch(74% 0.14 85) · display: Space Grotesk + body: DM Sans + * axes: dark / geometric-sans / warm · enrichment: live WebGPU 3D plates · nav: N5 · footer: Ft5 + * theme_axes: dark / geometric-sans / warm · studied: yes · DNA-source: local dev-site + */ + +:root { + /* Brand paper / surfaces */ + --color-paper: oklch(12% 0.012 265); + --color-paper-2: oklch(15% 0.014 265); + --color-paper-3: oklch(19% 0.016 265); + --color-paper-hover: oklch(22% 0.018 265); + + /* Ink */ + --color-ink: oklch(92% 0.01 265); + --color-ink-2: oklch(62% 0.02 265); + --color-ink-3: oklch(42% 0.015 265); + + /* Brand accents — gold primary, blue secondary */ + --color-accent: oklch(74% 0.14 85); + --color-accent-soft: oklch(74% 0.14 85 / 0.14); + --color-accent-ink: oklch(18% 0.03 85); + --color-blue: oklch(58% 0.14 250); + --color-blue-soft: oklch(58% 0.14 250 / 0.16); + --color-focus: oklch(74% 0.14 85); + --color-ok: oklch(72% 0.14 155); + --color-danger: oklch(68% 0.16 25); + + --color-rule: oklch(92% 0.01 265 / 0.08); + --color-rule-strong: oklch(92% 0.01 265 / 0.14); + --color-overlay: oklch(0% 0 0 / 0.72); + + /* Type */ + --font-display: 'Space Grotesk', system-ui, sans-serif; + --font-body: 'DM Sans', system-ui, sans-serif; + --font-mono: 'SF Mono', 'Cascadia Code', 'Fira Mono', Consolas, monospace; + + --text-xs: 0.6875rem; + --text-sm: 0.8125rem; + --text-md: 0.9375rem; + --text-lg: 1.125rem; + --text-xl: 1.5rem; + --text-2xl: clamp(1.75rem, 3.5vw, 2.5rem); + --text-display: clamp(2rem, 4.5vw, 3.25rem); + + /* 4pt scale */ + --space-3xs: 0.25rem; + --space-2xs: 0.5rem; + --space-xs: 0.75rem; + --space-sm: 1rem; + --space-md: 1.5rem; + --space-lg: 2rem; + --space-xl: 3rem; + --space-2xl: 4.5rem; + --space-3xl: 7rem; + + --page-gutter: clamp(1rem, 4vw, 3rem); + --max-width: 1120px; + --radius-sm: 6px; + --radius-md: 10px; + --radius-lg: 14px; + --radius-pill: 999px; + + --ease-out: cubic-bezier(0.16, 1, 0.3, 1); + --ease-in-out: cubic-bezier(0.45, 0, 0.55, 1); + --dur-short: 180ms; + --dur-mid: 280ms; + + --rule-hair: 1px; + --nav-height: 56px; + --z-nav: 100; +} diff --git a/package-lock.json b/package-lock.json index 76f504f..62798e5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,98 +1,91 @@ { - "name": "@chartgpu/chartgpu-react", - "version": "0.1.4", + "name": "chartgpu-react", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@chartgpu/chartgpu-react", - "version": "0.1.4", + "name": "chartgpu-react", + "version": "0.3.0", "license": "MIT", "devDependencies": { - "@chartgpu/chartgpu": "^0.2.8", + "@chartgpu/chartgpu": "^0.3.6", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@vitejs/plugin-react": "^4.2.1", - "@vitest/coverage-v8": "^4.0.18", - "jsdom": "^28.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "typescript": "^5.3.3", - "vite": "^5.1.4", - "vite-plugin-dts": "^3.7.3", - "vitest": "^4.0.18" + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.0.3", + "@vitest/coverage-v8": "^4.1.10", + "jsdom": "^29.1.1", + "react": "^19.2.8", + "react-dom": "^19.2.8", + "typescript": "^7.0.2", + "vite": "^7.1.5", + "vitest": "^4.1.10" + }, + "engines": { + "node": ">=20" }, "peerDependencies": { - "@chartgpu/chartgpu": "^0.2.8", + "@chartgpu/chartgpu": "^0.3.6", "react": ">=18.0.0", "react-dom": ">=18.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": false + } } }, - "node_modules/@acemir/cssom": { - "version": "0.9.31", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.31.tgz", - "integrity": "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==", - "dev": true, - "license": "MIT" - }, "node_modules/@adobe/css-tools": { - "version": "4.4.4", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.4.tgz", - "integrity": "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", "dev": true, "license": "MIT" }, "node_modules/@asamuzakjp/css-color": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.0.1.tgz", - "integrity": "sha512-2SZFvqMyvboVV1d15lMf7XiI3m7SDqXUuKaTymJYLN6dSGadqp+fVojqJlVoMlbZnlTmu3S0TLwLTJpvBMO1Aw==", + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", "dev": true, "license": "MIT", "dependencies": { - "@csstools/css-calc": "^3.1.1", - "@csstools/css-color-parser": "^4.0.2", + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0", - "lru-cache": "^11.2.6" + "@csstools/css-tokenizer": "^4.0.0" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, "node_modules/@asamuzakjp/dom-selector": { - "version": "6.8.1", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", - "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", "dev": true, "license": "MIT", "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", - "css-tree": "^3.1.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.6" + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", "engines": { - "node": "20 || >=22" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/@asamuzakjp/nwsapi": { @@ -103,11 +96,13 @@ "license": "MIT" }, "node_modules/@babel/code-frame": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -116,7 +111,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -124,20 +121,21 @@ } }, "node_modules/@babel/core": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -154,12 +152,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -169,12 +169,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -184,7 +186,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -192,25 +196,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -220,7 +228,9 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", "dev": true, "license": "MIT", "engines": { @@ -228,7 +238,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -236,7 +248,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -244,7 +258,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -252,25 +268,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", - "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -280,11 +298,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -294,11 +314,13 @@ } }, "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -308,9 +330,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.6.tgz", - "integrity": "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", "dev": true, "license": "MIT", "engines": { @@ -318,29 +340,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.6", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/generator": "^7.28.6", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.6", - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -348,14 +374,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -385,16 +411,16 @@ } }, "node_modules/@chartgpu/chartgpu": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/@chartgpu/chartgpu/-/chartgpu-0.2.8.tgz", - "integrity": "sha512-of5E6UjWbkya2xrFsLcBlCR2fouR2vUHSVjsY+S9pLsGkGb3F1kzSeDV/s/7iyyrimHjXs2ZyUrhEjaiYN7wVg==", + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@chartgpu/chartgpu/-/chartgpu-0.3.6.tgz", + "integrity": "sha512-YLHpU4mCduWN/LiLdI64qy1SOOFAVlTEbxtDDVBK4fX/npAzkzIXj2dK9dfcWxGA7V4miMjTOhqqk8S8m3gfsA==", "dev": true, "license": "MIT" }, "node_modules/@csstools/color-helpers": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", - "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", "dev": true, "funding": [ { @@ -412,9 +438,9 @@ } }, "node_modules/@csstools/css-calc": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.1.1.tgz", - "integrity": "sha512-HJ26Z/vmsZQqs/o3a6bgKslXGFAungXGbinULZO3eMsOyNJHeBBZfup5FiZInOghgoM4Hwnmw+OgbJCNg1wwUQ==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", "dev": true, "funding": [ { @@ -436,9 +462,9 @@ } }, "node_modules/@csstools/css-color-parser": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.0.2.tgz", - "integrity": "sha512-0GEfbBLmTFf0dJlpsNU7zwxRIH0/BGEMuXLTCvFYxuL1tNhqzTbtnFICyJLTNK4a+RechKP75e7w42ClXSnJQw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.9.tgz", + "integrity": "sha512-paQcIaOO53Rk5+YrBaBjm/SgrV4INImjo2BT1DtQRYr+XeTRbeAYlS+jxXp9drqvKmtFnWRJKIalDLhZZDu42A==", "dev": true, "funding": [ { @@ -452,8 +478,8 @@ ], "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.0.2", - "@csstools/css-calc": "^3.1.1" + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.2.1" }, "engines": { "node": ">=20.19.0" @@ -479,7 +505,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" }, @@ -488,9 +513,9 @@ } }, "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.29", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.29.tgz", - "integrity": "sha512-jx9GjkkP5YHuTmko2eWAvpPnb0mB4mGRr2U7XwVNwevm8nlpobZEVk+GNmiYMk2VuA75v+plfXWyroWKmICZXg==", + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.6.tgz", + "integrity": "sha512-TcJCWFbXLPpJYq6z7bfOyjWYJDiDg2/I4gyUC9pqPNqHFRIey0EB0q0L5cSnQDfWJg8Jd6VadakxdIez/3zkqQ==", "dev": true, "funding": [ { @@ -502,7 +527,15 @@ "url": "https://opencollective.com/csstools" } ], - "license": "MIT-0" + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } }, "node_modules/@csstools/css-tokenizer": { "version": "4.0.0", @@ -520,15 +553,14 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=20.19.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", "cpu": [ "ppc64" ], @@ -539,13 +571,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", "cpu": [ "arm" ], @@ -556,13 +588,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", "cpu": [ "arm64" ], @@ -573,13 +605,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", "cpu": [ "x64" ], @@ -590,11 +622,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", "cpu": [ "arm64" ], @@ -605,13 +639,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", "cpu": [ "x64" ], @@ -622,13 +656,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", "cpu": [ "arm64" ], @@ -639,13 +673,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", "cpu": [ "x64" ], @@ -656,13 +690,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", "cpu": [ "arm" ], @@ -673,13 +707,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", "cpu": [ "arm64" ], @@ -690,13 +724,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", "cpu": [ "ia32" ], @@ -707,13 +741,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", "cpu": [ "loong64" ], @@ -724,13 +758,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", "cpu": [ "mips64el" ], @@ -741,13 +775,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", "cpu": [ "ppc64" ], @@ -758,13 +792,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", "cpu": [ "riscv64" ], @@ -775,13 +809,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", "cpu": [ "s390x" ], @@ -792,13 +826,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", "cpu": [ "x64" ], @@ -809,13 +843,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", "cpu": [ "arm64" ], @@ -830,9 +864,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", "cpu": [ "x64" ], @@ -843,13 +877,13 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", "cpu": [ "arm64" ], @@ -864,9 +898,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", "cpu": [ "x64" ], @@ -877,13 +911,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", "cpu": [ "arm64" ], @@ -898,9 +932,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", "cpu": [ "x64" ], @@ -911,13 +945,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", "cpu": [ "arm64" ], @@ -928,13 +962,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", "cpu": [ "ia32" ], @@ -945,13 +979,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", "cpu": [ "x64" ], @@ -962,13 +996,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@exodus/bytes": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.14.1.tgz", - "integrity": "sha512-OhkBFWI6GcRMUroChZiopRiSp2iAMvEBK47NhJooDqz1RERO4QuZIZnjP63TXX8GAiLABkYmX+fuQsdJ1dd2QQ==", + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", "dev": true, "license": "MIT", "engines": { @@ -985,6 +1019,8 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { @@ -994,6 +1030,8 @@ }, "node_modules/@jridgewell/remapping": { "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1003,6 +1041,8 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "license": "MIT", "engines": { @@ -1011,11 +1051,15 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -1023,139 +1067,17 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@microsoft/api-extractor": { - "version": "7.43.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/api-extractor-model": "7.28.13", - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2", - "@rushstack/rig-package": "0.5.2", - "@rushstack/terminal": "0.10.0", - "@rushstack/ts-command-line": "4.19.1", - "lodash": "~4.17.15", - "minimatch": "~3.0.3", - "resolve": "~1.22.1", - "semver": "~7.5.4", - "source-map": "~0.6.1", - "typescript": "5.4.2" - }, - "bin": { - "api-extractor": "bin/api-extractor" - } - }, - "node_modules/@microsoft/api-extractor-model": { - "version": "7.28.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "@microsoft/tsdoc-config": "~0.16.1", - "@rushstack/node-core-library": "4.0.2" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/semver": { - "version": "7.5.4", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/typescript": { - "version": "5.4.2", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/@microsoft/api-extractor/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@microsoft/tsdoc": { - "version": "0.14.2", - "dev": true, - "license": "MIT" - }, - "node_modules/@microsoft/tsdoc-config": { - "version": "0.16.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/tsdoc": "0.14.2", - "ajv": "~6.12.6", - "jju": "~1.4.0", - "resolve": "~1.19.0" - } - }, - "node_modules/@microsoft/tsdoc-config/node_modules/resolve": { - "version": "1.19.0", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.1.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", + "version": "1.0.0-rc.3", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.3.tgz", + "integrity": "sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==", "dev": true, "license": "MIT" }, - "node_modules/@rollup/pluginutils": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.55.1.tgz", - "integrity": "sha512-9R0DM/ykwfGIlNu6+2U09ga0WXeZ9MRC2Ter8jnz8415VbuIykVuc6bhdrbORFZANDmTDvq26mJrEVTl8TdnDg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.62.2.tgz", + "integrity": "sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==", "cpu": [ "arm" ], @@ -1167,9 +1089,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.55.1.tgz", - "integrity": "sha512-eFZCb1YUqhTysgW3sj/55du5cG57S7UTNtdMjCW7LwVcj3dTTcowCsC8p7uBdzKsZYa8J7IDE8lhMI+HX1vQvg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.62.2.tgz", + "integrity": "sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==", "cpu": [ "arm64" ], @@ -1181,7 +1103,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.55.1", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.62.2.tgz", + "integrity": "sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==", "cpu": [ "arm64" ], @@ -1193,9 +1117,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.55.1.tgz", - "integrity": "sha512-rDUjG25C9qoTm+e02Esi+aqTKSBYwVTaoS1wxcN47/Luqef57Vgp96xNANwt5npq9GDxsH7kXxNkJVEsWEOEaQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.62.2.tgz", + "integrity": "sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==", "cpu": [ "x64" ], @@ -1207,9 +1131,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.55.1.tgz", - "integrity": "sha512-+JiU7Jbp5cdxekIgdte0jfcu5oqw4GCKr6i3PJTlXTCU5H5Fvtkpbs4XJHRmWNXF+hKmn4v7ogI5OQPaupJgOg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.62.2.tgz", + "integrity": "sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==", "cpu": [ "arm64" ], @@ -1221,9 +1145,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.55.1.tgz", - "integrity": "sha512-V5xC1tOVWtLLmr3YUk2f6EJK4qksksOYiz/TCsFHu/R+woubcLWdC9nZQmwjOAbmExBIVKsm1/wKmEy4z4u4Bw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.62.2.tgz", + "integrity": "sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==", "cpu": [ "x64" ], @@ -1235,13 +1159,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.55.1.tgz", - "integrity": "sha512-Rn3n+FUk2J5VWx+ywrG/HGPTD9jXNbicRtTM11e/uorplArnXZYsVifnPPqNNP5BsO3roI4n8332ukpY/zN7rQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.62.2.tgz", + "integrity": "sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1249,13 +1176,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.55.1.tgz", - "integrity": "sha512-grPNWydeKtc1aEdrJDWk4opD7nFtQbMmV7769hiAaYyUKCT1faPRm2av8CX1YJsZ4TLAZcg9gTR1KvEzoLjXkg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.62.2.tgz", + "integrity": "sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==", "cpu": [ "arm" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1263,13 +1193,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.55.1.tgz", - "integrity": "sha512-a59mwd1k6x8tXKcUxSyISiquLwB5pX+fJW9TkWU46lCqD/GRDe9uDN31jrMmVP3feI3mhAdvcCClhV8V5MhJFQ==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.62.2.tgz", + "integrity": "sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1277,13 +1210,16 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.55.1.tgz", - "integrity": "sha512-puS1MEgWX5GsHSoiAsF0TYrpomdvkaXm0CofIMG5uVkP6IBV+ZO9xhC5YEN49nsgYo1DuuMquF9+7EDBVYu4uA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.62.2.tgz", + "integrity": "sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==", "cpu": [ "arm64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1291,13 +1227,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.55.1.tgz", - "integrity": "sha512-r3Wv40in+lTsULSb6nnoudVbARdOwb2u5fpeoOAZjFLznp6tDU8kd+GTHmJoqZ9lt6/Sys33KdIHUaQihFcu7g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.62.2.tgz", + "integrity": "sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1305,13 +1244,16 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.55.1.tgz", - "integrity": "sha512-MR8c0+UxAlB22Fq4R+aQSPBayvYa3+9DrwG/i1TKQXFYEaoW3B5b/rkSRIypcZDdWjWnpcvxbNaAJDcSbJU3Lw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.62.2.tgz", + "integrity": "sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==", "cpu": [ "loong64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1319,13 +1261,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.55.1.tgz", - "integrity": "sha512-3KhoECe1BRlSYpMTeVrD4sh2Pw2xgt4jzNSZIIPLFEsnQn9gAnZagW9+VqDqAHgm1Xc77LzJOo2LdigS5qZ+gw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.62.2.tgz", + "integrity": "sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1333,13 +1278,16 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.55.1.tgz", - "integrity": "sha512-ziR1OuZx0vdYZZ30vueNZTg73alF59DicYrPViG0NEgDVN8/Jl87zkAPu4u6VjZST2llgEUjaiNl9JM6HH1Vdw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.62.2.tgz", + "integrity": "sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==", "cpu": [ "ppc64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1347,13 +1295,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.55.1.tgz", - "integrity": "sha512-uW0Y12ih2XJRERZ4jAfKamTyIHVMPQnTZcQjme2HMVDAHY4amf5u414OqNYC+x+LzRdRcnIG1YodLrrtA8xsxw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.62.2.tgz", + "integrity": "sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1361,13 +1312,16 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.55.1.tgz", - "integrity": "sha512-u9yZ0jUkOED1BFrqu3BwMQoixvGHGZ+JhJNkNKY/hyoEgOwlqKb62qu+7UjbPSHYjiVy8kKJHvXKv5coH4wDeg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.62.2.tgz", + "integrity": "sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==", "cpu": [ "riscv64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1375,13 +1329,16 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.55.1.tgz", - "integrity": "sha512-/0PenBCmqM4ZUd0190j7J0UsQ/1nsi735iPRakO8iPciE7BQ495Y6msPzaOmvx0/pn+eJVVlZrNrSh4WSYLxNg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.62.2.tgz", + "integrity": "sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==", "cpu": [ "s390x" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1389,13 +1346,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.55.1.tgz", - "integrity": "sha512-a8G4wiQxQG2BAvo+gU6XrReRRqj+pLS2NGXKm8io19goR+K8lw269eTrPkSdDTALwMmJp4th2Uh0D8J9bEV1vg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.2.tgz", + "integrity": "sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -1403,13 +1363,16 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.55.1.tgz", - "integrity": "sha512-bD+zjpFrMpP/hqkfEcnjXWHMw5BIghGisOKPj+2NaNDuVT+8Ds4mPf3XcPHuat1tz89WRL+1wbcxKY3WSbiT7w==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.62.2.tgz", + "integrity": "sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==", "cpu": [ "x64" ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -1417,9 +1380,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.55.1.tgz", - "integrity": "sha512-eLXw0dOiqE4QmvikfQ6yjgkg/xDM+MdU9YJuP4ySTibXU0oAvnEWXt7UDJmD4UkYialMfOGFPJnIHSe/kdzPxg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.62.2.tgz", + "integrity": "sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==", "cpu": [ "x64" ], @@ -1431,9 +1394,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.55.1.tgz", - "integrity": "sha512-xzm44KgEP11te3S2HCSyYf5zIzWmx3n8HDCc7EE59+lTcswEWNpvMLfd9uJvVX8LCg9QWG67Xt75AuHn4vgsXw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.62.2.tgz", + "integrity": "sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==", "cpu": [ "arm64" ], @@ -1445,9 +1408,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.55.1.tgz", - "integrity": "sha512-yR6Bl3tMC/gBok5cz/Qi0xYnVbIxGx5Fcf/ca0eB6/6JwOY+SRUcJfI0OpeTpPls7f194as62thCt/2BjxYN8g==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.62.2.tgz", + "integrity": "sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==", "cpu": [ "arm64" ], @@ -1459,9 +1422,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.55.1.tgz", - "integrity": "sha512-3fZBidchE0eY0oFZBnekYCfg+5wAB0mbpCBuofh5mZuzIU/4jIVkbESmd2dOsFNS78b53CYv3OAtwqkZZmU5nA==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.62.2.tgz", + "integrity": "sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==", "cpu": [ "ia32" ], @@ -1473,9 +1436,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.55.1.tgz", - "integrity": "sha512-xGGY5pXj69IxKb4yv/POoocPy/qmEGhimy/FoTpTSVju3FYXUQQMFCaZZXJVidsmGxRioZAwpThl/4zX41gRKg==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.62.2.tgz", + "integrity": "sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==", "cpu": [ "x64" ], @@ -1487,9 +1450,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.55.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.55.1.tgz", - "integrity": "sha512-SPEpaL6DX4rmcXtnhdrQYgzQ5W2uW3SCJch88lB2zImhJRhIIK44fkUrgIV/Q8yUNfw5oyZ5vkeQsZLhCb06lw==", + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.62.2.tgz", + "integrity": "sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==", "cpu": [ "x64" ], @@ -1500,94 +1463,6 @@ "win32" ] }, - "node_modules/@rushstack/node-core-library": { - "version": "4.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "fs-extra": "~7.0.1", - "import-lazy": "~4.0.0", - "jju": "~1.4.0", - "resolve": "~1.22.1", - "semver": "~7.5.4", - "z-schema": "~5.0.2" - }, - "peerDependencies": { - "@types/node": "*" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@rushstack/node-core-library/node_modules/lru-cache": { - "version": "6.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/semver": { - "version": "7.5.4", - "dev": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@rushstack/node-core-library/node_modules/yallist": { - "version": "4.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/@rushstack/rig-package": { - "version": "0.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "resolve": "~1.22.1", - "strip-json-comments": "~3.1.1" - } - }, - "node_modules/@rushstack/terminal": { - "version": "0.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rushstack/node-core-library": "4.0.2", - "supports-color": "~8.1.1" - }, - "peerDependencies": { - "@types/node": "*" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@rushstack/ts-command-line": { - "version": "4.19.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@rushstack/terminal": "0.10.0", - "@types/argparse": "1.0.38", - "argparse": "~1.0.9", - "string-argv": "~0.3.1" - } - }, "node_modules/@standard-schema/spec": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", @@ -1671,20 +1546,18 @@ } } }, - "node_modules/@types/argparse": { - "version": "1.0.38", - "dev": true, - "license": "MIT" - }, "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" + "license": "MIT", + "peer": true }, "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": { @@ -1697,6 +1570,8 @@ }, "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": { @@ -1705,6 +1580,8 @@ }, "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": { @@ -1714,6 +1591,8 @@ }, "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": { @@ -1739,1248 +1618,637 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "dev": true, "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.27", + "version": "19.2.17", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", + "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@types/prop-types": "*", "csstype": "^3.2.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.7", + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.2.0" } }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "node_modules/@vitest/coverage-v8": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.0.18.tgz", - "integrity": "sha512-7i+N2i0+ME+2JFZhfuz7Tg/FqKtilHjGyGvoHYQ6iLV0zahbsJ9sljC9OcFcPDbhYKCet+sG8SsVqlyGvPflZg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.0.18", - "ast-v8-to-istanbul": "^0.3.10", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "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.18", - "vitest": "4.0.18" - }, - "peerDependenciesMeta": { - "@vitest/browser": { - "optional": true - } - } - }, - "node_modules/@vitest/expect": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", - "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", - "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", - "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.18", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", - "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", - "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", - "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.18", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@volar/language-core": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/source-map": "1.11.1" - } - }, - "node_modules/@volar/source-map": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "muggle-string": "^0.3.1" - } - }, - "node_modules/@volar/typescript": { - "version": "1.11.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "1.11.1", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@vue/compiler-core": { - "version": "3.5.26", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@vue/shared": "3.5.26", - "entities": "^7.0.0", - "estree-walker": "^2.0.2", - "source-map-js": "^1.2.1" - } - }, - "node_modules/@vue/compiler-dom": { - "version": "3.5.26", - "dev": true, - "license": "MIT", - "dependencies": { - "@vue/compiler-core": "3.5.26", - "@vue/shared": "3.5.26" - } - }, - "node_modules/@vue/language-core": { - "version": "1.8.27", - "dev": true, - "license": "MIT", - "dependencies": { - "@volar/language-core": "~1.11.1", - "@volar/source-map": "~1.11.1", - "@vue/compiler-dom": "^3.3.0", - "@vue/shared": "^3.3.0", - "computeds": "^0.0.1", - "minimatch": "^9.0.3", - "muggle-string": "^0.3.1", - "path-browserify": "^1.0.1", - "vue-template-compiler": "^2.7.14" - }, - "peerDependencies": { - "typescript": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@vue/language-core/node_modules/brace-expansion": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@vue/language-core/node_modules/minimatch": { - "version": "9.0.5", - "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/@vue/shared": { - "version": "3.5.26", - "dev": true, - "license": "MIT" - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "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/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/argparse": { - "version": "1.0.10", - "dev": true, - "license": "MIT", - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "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/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-v8-to-istanbul": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-0.3.12.tgz", - "integrity": "sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.31", - "estree-walker": "^3.0.3", - "js-tokens": "^10.0.0" - } - }, - "node_modules/ast-v8-to-istanbul/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/ast-v8-to-istanbul/node_modules/js-tokens": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", - "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.15", - "dev": true, - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.js" - } - }, - "node_modules/bidi-js": { - "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" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "peer": true, - "dependencies": { - "baseline-browser-mapping": "^2.9.0", - "caniuse-lite": "^1.0.30001759", - "electron-to-chromium": "^1.5.263", - "node-releases": "^2.0.27", - "update-browserslist-db": "^1.2.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001765", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" - }, - "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/commander": { - "version": "9.5.0", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/computeds": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "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", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, - "node_modules/css.escape": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", - "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cssstyle": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-6.2.0.tgz", - "integrity": "sha512-Fm5NvhYathRnXNVndkUsCCuR63DCLVVwGOOwQw782coXFi5HhkXdu289l59HlXZBawsyNccXfWRYvLzcDCdDig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^5.0.1", - "@csstools/css-syntax-patches-for-csstree": "^1.0.28", - "css-tree": "^3.1.0", - "lru-cache": "^11.2.6" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/cssstyle/node_modules/lru-cache": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", - "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/csstype": { - "version": "3.2.3", - "dev": true, - "license": "MIT" - }, - "node_modules/data-urls": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", - "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/de-indent": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/debug": { - "version": "4.4.3", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "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/dequal": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=6" + "node": ">=16.20.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/electron-to-chromium": { - "version": "1.5.267", - "dev": true, - "license": "ISC" - }, - "node_modules/entities": { - "version": "7.0.0", + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-2-Clause", + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "node": ">=16.20.0" } }, - "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/esbuild": { - "version": "0.21.5", + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "cpu": [ + "x64" + ], "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "node": ">=16.20.0" } }, - "node_modules/escalade": { - "version": "3.2.0", + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6" + "node": ">=16.20.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "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==", + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "cpu": [ + "x64" + ], "dev": true, "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=12.0.0" + "node": ">=16.20.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "node": ">=16.20.0" } }, - "node_modules/fs-extra": { - "version": "7.0.1", + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.1.2", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6 <7 || >=8" + "node": ">=16.20.0" } }, - "node_modules/fsevents": { - "version": "2.3.3", + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "cpu": [ + "loong64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=16.20.0" } }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "cpu": [ + "mips64el" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.9.0" + "node": ">=16.20.0" } }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "dev": true, - "license": "ISC" - }, - "node_modules/has-flag": { - "version": "4.0.0", + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/hasown": { - "version": "2.0.2", + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "cpu": [ + "riscv64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "dev": true, - "license": "MIT", - "bin": { - "he": "bin/he" + "node": ">=16.20.0" } }, - "node_modules/html-encoding-sniffer": { - "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==", + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" + ], "dev": true, - "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.6.0" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=16.20.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==", + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/http-proxy-agent": { + "node_modules/@typescript/typescript-netbsd-arm64": { "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==", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 14" + "node": ">=16.20.0" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">= 14" + "node": ">=16.20.0" } }, - "node_modules/import-lazy": { - "version": "4.0.0", + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "node_modules/is-core-module": { - "version": "2.16.1", + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=16.20.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/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==", + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BSD-3-Clause", + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=8" + "node": ">=16.20.0" } }, - "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==", + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, + "license": "Apache-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" + "node": ">=16.20.0" } }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "node_modules/@vitejs/plugin-react": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.2.0.tgz", + "integrity": "sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "@babel/core": "^7.29.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-rc.3", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.18.0" }, "engines": { - "node": ">=8" - } - }, - "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" + "node": "^20.19.0 || >=22.12.0" }, - "engines": { - "node": ">=8" + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/jju": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/jsdom": { - "version": "28.1.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-28.1.0.tgz", - "integrity": "sha512-0+MoQNYyr2rBHqO1xilltfDjV9G7ymYGlAUazgcDLQaUf8JDHbuGwsxN6U9qWaElZ4w1B2r7yEGIL3GdeW3Rug==", + "node_modules/@vitest/coverage-v8": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.10.tgz", + "integrity": "sha512-IM49HmthevbgAO4anp1hwtoT9wYe59w0LR00gr+eagHE+ZJ5lK4sLPeO0ubgoJcwLk6dehU3R24N+FbEEKDc8g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@acemir/cssom": "^0.9.31", - "@asamuzakjp/dom-selector": "^6.8.1", - "@bramus/specificity": "^2.4.2", - "@exodus/bytes": "^1.11.0", - "cssstyle": "^6.0.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^6.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "parse5": "^8.0.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.0", - "undici": "^7.21.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.1", - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0", - "xml-name-validator": "^5.0.0" + "@bcoe/v8-coverage": "^1.0.2", + "@vitest/utils": "4.1.10", + "ast-v8-to-istanbul": "^1.0.0", + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-reports": "^3.2.0", + "magicast": "^0.5.2", + "obug": "^2.1.1", + "std-env": "^4.0.0-rc.1", + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "funding": { + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "canvas": "^3.0.0" + "@vitest/browser": "4.1.10", + "vitest": "4.1.10" }, "peerDependenciesMeta": { - "canvas": { + "@vitest/browser": { "optional": true } } }, - "node_modules/jsesc": { - "version": "3.1.0", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/json5": { - "version": "2.2.3", - "dev": true, - "license": "MIT", - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/kolorist": { - "version": "1.8.0", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash": { - "version": "4.17.21", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isequal": { - "version": "4.5.0", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", "dev": true, "license": "MIT", "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/lru-cache": { - "version": "5.1.1", - "dev": true, - "license": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "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" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/magic-string": { - "version": "0.30.21", + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "@vitest/spy": "4.1.10", + "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 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } } }, - "node_modules/magicast": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.2.tgz", - "integrity": "sha512-E3ZJh4J3S9KfwdjZhe2afj6R9lGIN5Pher1pF39UGrXRqq/VDaGVIGN13BjHd2u8B61hArAGOnso7nBOouW3TQ==", + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", - "source-map-js": "^1.2.1" + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" } }, - "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==", + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", "dev": true, "license": "MIT", "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/vitest" } }, - "node_modules/make-dir/node_modules/semver": { - "version": "7.7.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", - "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" }, - "engines": { - "node": ">=10" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/mdn-data": { - "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/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", "dev": true, "license": "MIT", - "engines": { - "node": ">=4" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/minimatch": { - "version": "3.0.8", + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" }, - "engines": { - "node": "*" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/ms": { - "version": "2.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/muggle-string": { - "version": "0.3.1", - "dev": true, - "license": "MIT" - }, - "node_modules/nanoid": { - "version": "3.3.11", + "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, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, + "peer": true, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=8" } }, - "node_modules/node-releases": { - "version": "2.0.27", - "dev": true, - "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/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", + "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", - "dependencies": { - "entities": "^6.0.0" + "peer": true, + "engines": { + "node": ">=10" }, "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/parse5/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "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": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" } }, - "node_modules/path-browserify": { - "version": "1.0.1", + "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" + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "node_modules/path-parse": { - "version": "1.0.7", + "node_modules/ast-v8-to-istanbul": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/ast-v8-to-istanbul/-/ast-v8-to-istanbul-1.0.5.tgz", + "integrity": "sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "estree-walker": "^3.0.3", + "js-tokens": "^10.0.0" + } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "node_modules/ast-v8-to-istanbul/node_modules/js-tokens": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-10.0.0.tgz", + "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "dev": true, "license": "MIT" }, - "node_modules/picocolors": { - "version": "1.1.1", + "node_modules/baseline-browser-mapping": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.0.tgz", + "integrity": "sha512-oCu2wfipvX3AePSgmOuKkIywOu+8n9psz7hXYmk56ghpu3+7KzNIBopaOs4c9BrtdnTtW30unG9GTfHo7EwERQ==", "dev": true, - "license": "ISC" + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } }, - "node_modules/picomatch": { - "version": "4.0.3", + "node_modules/bidi-js": { + "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", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "dependencies": { + "require-from-string": "^2.0.2" } }, - "node_modules/postcss": { - "version": "8.5.6", + "node_modules/browserslist": { + "version": "4.28.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.7.tgz", + "integrity": "sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==", "dev": true, "funding": [ { "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "url": "https://opencollective.com/browserslist" }, { "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "url": "https://tidelift.com/funding/github/npm/browserslist" }, { "type": "github", @@ -2989,1106 +2257,1066 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "baseline-browser-mapping": "^2.10.44", + "caniuse-lite": "^1.0.30001806", + "electron-to-chromium": "^1.5.393", + "node-releases": "^2.0.51", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "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==", + "node_modules/caniuse-lite": { + "version": "1.0.30001806", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001806.tgz", + "integrity": "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==", "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" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" }, - "node_modules/punycode": { - "version": "2.3.1", + "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": ">=6" + "node": ">=18" } }, - "node_modules/react": { - "version": "18.3.1", + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "loose-envify": "^1.1.0" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/react-dom": { - "version": "18.3.1", + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } + "license": "MIT" }, - "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==", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "dev": true, "license": "MIT" }, - "node_modules/react-refresh": { - "version": "0.17.0", + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "ms": "^2.1.3" }, "engines": { - "node": ">=8" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/require-from-string": { - "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==", + "node_modules/decimal.js": { + "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/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/resolve": { - "version": "1.22.11", + "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", - "dependencies": { - "is-core-module": "^2.16.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, + "peer": true + }, + "node_modules/electron-to-chromium": { + "version": "1.5.395", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.395.tgz", + "integrity": "sha512-7zt9Aw+SrmxLWLN0zhaTWZQiCdryLVrYTq5R7iZakLvi2UQPYMMsROYV/2qVCzMeCiSXHwKOU+sZ4zOVVlrtKA==", + "dev": true, + "license": "ISC" + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "dev": true, + "license": "BSD-2-Clause", "engines": { - "node": ">= 0.4" + "node": ">=20.19.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/rollup": { - "version": "4.55.1", + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", "dev": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, "bin": { - "rollup": "dist/bin/rollup" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" + "node": ">=18" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.55.1", - "@rollup/rollup-android-arm64": "4.55.1", - "@rollup/rollup-darwin-arm64": "4.55.1", - "@rollup/rollup-darwin-x64": "4.55.1", - "@rollup/rollup-freebsd-arm64": "4.55.1", - "@rollup/rollup-freebsd-x64": "4.55.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.55.1", - "@rollup/rollup-linux-arm-musleabihf": "4.55.1", - "@rollup/rollup-linux-arm64-gnu": "4.55.1", - "@rollup/rollup-linux-arm64-musl": "4.55.1", - "@rollup/rollup-linux-loong64-gnu": "4.55.1", - "@rollup/rollup-linux-loong64-musl": "4.55.1", - "@rollup/rollup-linux-ppc64-gnu": "4.55.1", - "@rollup/rollup-linux-ppc64-musl": "4.55.1", - "@rollup/rollup-linux-riscv64-gnu": "4.55.1", - "@rollup/rollup-linux-riscv64-musl": "4.55.1", - "@rollup/rollup-linux-s390x-gnu": "4.55.1", - "@rollup/rollup-linux-x64-gnu": "4.55.1", - "@rollup/rollup-linux-x64-musl": "4.55.1", - "@rollup/rollup-openbsd-x64": "4.55.1", - "@rollup/rollup-openharmony-arm64": "4.55.1", - "@rollup/rollup-win32-arm64-msvc": "4.55.1", - "@rollup/rollup-win32-ia32-msvc": "4.55.1", - "@rollup/rollup-win32-x64-gnu": "4.55.1", - "@rollup/rollup-win32-x64-msvc": "4.55.1", - "fsevents": "~2.3.2" + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, + "license": "MIT", "engines": { - "node": ">=v12.22.7" + "node": ">=6" } }, - "node_modules/scheduler": { - "version": "0.23.2", + "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": { - "loose-envify": "^1.1.0" + "@types/estree": "^1.0.0" } }, - "node_modules/semver": { - "version": "6.3.1", + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" } }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "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": "ISC" + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } }, - "node_modules/source-map": { - "version": "0.6.1", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "license": "BSD-3-Clause", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=0.10.0" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/source-map-js": { - "version": "1.2.1", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=6.9.0" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "BSD-3-Clause" + "license": "MIT", + "engines": { + "node": ">=8" + } }, - "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==", + "node_modules/html-encoding-sniffer": { + "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" + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } }, - "node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "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/string-argv": { - "version": "0.3.2", + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.6.19" + "node": ">=8" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "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", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/strip-json-comments": { - "version": "3.1.1", + "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": "MIT", + "license": "BSD-3-Clause", "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-color": { - "version": "8.1.1", + "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": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "has-flag": "^4.0.0" + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" }, "engines": { "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", + "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": "MIT", - "engines": { - "node": ">= 0.4" + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=8" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "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==", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", "dev": true, - "license": "MIT", + "license": "BlueOak-1.0.0", "engines": { - "node": ">=18" + "node": "20 || >=22" } }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", "dev": true, "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" + "node": ">=6" } }, - "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==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, "engines": { - "node": ">=14.0.0" + "node": ">=6" } }, - "node_modules/tldts": { - "version": "7.0.24", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.24.tgz", - "integrity": "sha512-1r6vQTTt1rUiJkI5vX7KG8PR342Ru/5Oh13kEQP2SMbRSZpOey9SrBe27IDxkoWulx8ShWu4K6C0BkctP8Z1bQ==", + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "tldts-core": "^7.0.24" - }, + "yallist": "^3.0.2" + } + }, + "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", + "peer": true, "bin": { - "tldts": "bin/cli.js" + "lz-string": "bin/bin.js" } }, - "node_modules/tldts-core": { - "version": "7.0.24", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.24.tgz", - "integrity": "sha512-pj7yygNMoMRqG7ML2SDQ0xNIOfN3IBDUcPVM2Sg6hP96oFNN2nqnzHreT3z9xLq85IWJyNTvD38O002DdOrPMw==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } }, - "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", + "node_modules/magicast": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.5.3.tgz", + "integrity": "sha512-pVKE4UdSQ7DvHzivsCIFx2BJn1mHG6KsyrFcaxFx6tONdneEuThrDx0Cj3AMg58KyN4pzYT+LHOotxDQDjNvkw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" + "@babel/parser": "^7.29.3", + "@babel/types": "^7.29.0", + "source-map-js": "^1.2.1" } }, - "node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "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": { - "punycode": "^2.3.1" + "semver": "^7.5.3" }, "engines": { - "node": ">=20" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typescript": { - "version": "5.9.3", + "node_modules/make-dir/node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", "dev": true, - "license": "Apache-2.0", - "peer": true, + "license": "ISC", "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" + "semver": "bin/semver.js" }, "engines": { - "node": ">=14.17" + "node": ">=10" } }, - "node_modules/undici": { - "version": "7.22.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", - "integrity": "sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==", + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=20.18.1" - } + "license": "CC0-1.0" }, - "node_modules/universalify": { - "version": "0.1.2", + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", "dev": true, "license": "MIT", "engines": { - "node": ">= 4.0.0" + "node": ">=4" } }, - "node_modules/update-browserslist-db": { - "version": "1.2.3", + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "dev": true, "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "escalade": "^3.2.0", - "picocolors": "^1.1.1" - }, "bin": { - "update-browserslist-db": "cli.js" + "nanoid": "bin/nanoid.cjs" }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/uri-js": { - "version": "4.4.1", + "node_modules/node-releases": { + "version": "2.0.51", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.51.tgz", + "integrity": "sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "node_modules/validator": { - "version": "13.15.26", + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">=12.20.0" } }, - "node_modules/vite": { - "version": "5.4.21", + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" + "entities": "^8.0.0" }, "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/vite-plugin-dts": { - "version": "3.9.1", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, - "license": "MIT", - "dependencies": { - "@microsoft/api-extractor": "7.43.0", - "@rollup/pluginutils": "^5.1.0", - "@vue/language-core": "^1.8.27", - "debug": "^4.3.4", - "kolorist": "^1.8.0", - "magic-string": "^0.30.8", - "vue-tsc": "^1.8.27" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "typescript": "*", - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } + "license": "MIT" }, - "node_modules/vitest": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", - "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.18", - "@vitest/mocker": "4.0.18", - "@vitest/pretty-format": "4.0.18", - "@vitest/runner": "4.0.18", - "@vitest/snapshot": "4.0.18", - "@vitest/spy": "4.0.18", - "@vitest/utils": "4.0.18", - "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.18", - "@vitest/browser-preview": "4.0.18", - "@vitest/browser-webdriverio": "4.0.18", - "@vitest/ui": "4.0.18", - "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 - } - } + "license": "ISC" }, - "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", - "cpu": [ - "ppc64" - ], + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "aix" - ], "engines": { - "node": ">=18" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/vitest/node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], + "node_modules/postcss": { + "version": "8.5.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.21.tgz", + "integrity": "sha512-v4sDNP3fdNiWMfabO7OwOQdOX8TiQSztKyT1Wj0w+j7LDallJThJRBBBmzVGyYj0crMh7jlV4zepPkiNu9UwDQ==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, "engines": { - "node": ">=18" + "node": "^10 || ^12 || >=14" } }, - "node_modules/vitest/node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], + "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", - "optional": true, - "os": [ - "android" - ], + "peer": true, + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, "engines": { - "node": ">=18" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/vitest/node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": ">=6" } }, - "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/vitest/node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" } }, - "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], + "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", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } + "peer": true }, - "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], + "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", - "optional": true, - "os": [ - "freebsd" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/vitest/node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/vitest/node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], + "node_modules/require-from-string": { + "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", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/vitest/node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/rollup": { + "version": "4.62.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.62.2.tgz", + "integrity": "sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">=18" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.62.2", + "@rollup/rollup-android-arm64": "4.62.2", + "@rollup/rollup-darwin-arm64": "4.62.2", + "@rollup/rollup-darwin-x64": "4.62.2", + "@rollup/rollup-freebsd-arm64": "4.62.2", + "@rollup/rollup-freebsd-x64": "4.62.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.62.2", + "@rollup/rollup-linux-arm-musleabihf": "4.62.2", + "@rollup/rollup-linux-arm64-gnu": "4.62.2", + "@rollup/rollup-linux-arm64-musl": "4.62.2", + "@rollup/rollup-linux-loong64-gnu": "4.62.2", + "@rollup/rollup-linux-loong64-musl": "4.62.2", + "@rollup/rollup-linux-ppc64-gnu": "4.62.2", + "@rollup/rollup-linux-ppc64-musl": "4.62.2", + "@rollup/rollup-linux-riscv64-gnu": "4.62.2", + "@rollup/rollup-linux-riscv64-musl": "4.62.2", + "@rollup/rollup-linux-s390x-gnu": "4.62.2", + "@rollup/rollup-linux-x64-gnu": "4.62.2", + "@rollup/rollup-linux-x64-musl": "4.62.2", + "@rollup/rollup-openbsd-x64": "4.62.2", + "@rollup/rollup-openharmony-arm64": "4.62.2", + "@rollup/rollup-win32-arm64-msvc": "4.62.2", + "@rollup/rollup-win32-ia32-msvc": "4.62.2", + "@rollup/rollup-win32-x64-gnu": "4.62.2", + "@rollup/rollup-win32-x64-msvc": "4.62.2", + "fsevents": "~2.3.2" } }, - "node_modules/vitest/node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, "engines": { - "node": ">=18" + "node": ">=v12.22.7" } }, - "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "MIT" }, - "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], + "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": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "ISC" }, - "node_modules/vitest/node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "license": "BSD-3-Clause", "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, - "node_modules/vitest/node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "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/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "min-indent": "^1.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, - "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "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.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], "engines": { "node": ">=18" } }, - "node_modules/vitest/node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, "engines": { - "node": ">=18" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/vitest/node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=18" + "node": ">=14.0.0" } }, - "node_modules/vitest/node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], + "node_modules/tldts": { + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.9.tgz", + "integrity": "sha512-3kZ8wQQ/k5DrChD4X4FVvr2D7E5uoRgAqkPyLpSCGUvqOvqu+JEdr3mwMUaVWb+vMHZaKhF5fp2PBigKsui7hA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" + "dependencies": { + "tldts-core": "^7.4.9" + }, + "bin": { + "tldts": "bin/cli.js" } }, - "node_modules/vitest/node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], + "node_modules/tldts-core": { + "version": "7.4.9", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.9.tgz", + "integrity": "sha512-DxKfPBI52p2msTEu7MPhdpdDTBhhVQg1a/8PjQckeyAvO13eMYElX545grIp6nnTGIMZlRvFZPvFhvI/WIz2Vg==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "license": "MIT" + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, "engines": { - "node": ">=18" + "node": ">=16" } }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "4.0.18", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", - "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "node_modules/tr46": { + "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": { - "@vitest/spy": "4.0.18", - "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" + "punycode": "^2.3.1" }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } + "engines": { + "node": ">=20" } }, - "node_modules/vitest/node_modules/esbuild": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", - "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, - "hasInstallScript": true, - "license": "MIT", + "license": "Apache-2.0", "bin": { - "esbuild": "bin/esbuild" + "tsc": "bin/tsc" }, "engines": { - "node": ">=18" + "node": ">=16.20.0" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.27.3", - "@esbuild/android-arm": "0.27.3", - "@esbuild/android-arm64": "0.27.3", - "@esbuild/android-x64": "0.27.3", - "@esbuild/darwin-arm64": "0.27.3", - "@esbuild/darwin-x64": "0.27.3", - "@esbuild/freebsd-arm64": "0.27.3", - "@esbuild/freebsd-x64": "0.27.3", - "@esbuild/linux-arm": "0.27.3", - "@esbuild/linux-arm64": "0.27.3", - "@esbuild/linux-ia32": "0.27.3", - "@esbuild/linux-loong64": "0.27.3", - "@esbuild/linux-mips64el": "0.27.3", - "@esbuild/linux-ppc64": "0.27.3", - "@esbuild/linux-riscv64": "0.27.3", - "@esbuild/linux-s390x": "0.27.3", - "@esbuild/linux-x64": "0.27.3", - "@esbuild/netbsd-arm64": "0.27.3", - "@esbuild/netbsd-x64": "0.27.3", - "@esbuild/openbsd-arm64": "0.27.3", - "@esbuild/openbsd-x64": "0.27.3", - "@esbuild/openharmony-arm64": "0.27.3", - "@esbuild/sunos-x64": "0.27.3", - "@esbuild/win32-arm64": "0.27.3", - "@esbuild/win32-ia32": "0.27.3", - "@esbuild/win32-x64": "0.27.3" - } - }, - "node_modules/vitest/node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "node_modules/undici": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.28.0.tgz", + "integrity": "sha512-cRZYrTDwWznlnRiPjggAGxZXanty6M8RV1ff8Wm4LWXBp7/IG8v5DnOm74DtUBp9OONpK75YlPnIjQqX0dBDtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "@types/estree": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/vitest/node_modules/vite": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", - "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "esbuild": "^0.27.0", + "esbuild": "^0.27.0 || ^0.28.0", "fdir": "^6.5.0", "picomatch": "^4.0.3", "postcss": "^8.5.6", @@ -4156,40 +3384,94 @@ } } }, - "node_modules/vue-template-compiler": { - "version": "2.7.16", - "dev": true, - "license": "MIT", - "dependencies": { - "de-indent": "^1.0.2", - "he": "^1.2.0" - } - }, - "node_modules/vue-tsc": { - "version": "1.8.27", + "node_modules/vitest": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.10.tgz", + "integrity": "sha512-R9jUTe5S4Qb0HCd4TNqpC7oGcrMssMRGXLW80ubjWsW9VH5GF8y1Y0SFLY9AbqSk6nt0PnOx4H4WNJYZ13GUPw==", "dev": true, "license": "MIT", "dependencies": { - "@volar/typescript": "~1.11.1", - "@vue/language-core": "1.8.27", - "semver": "^7.5.4" + "@vitest/expect": "4.1.10", + "@vitest/mocker": "4.1.10", + "@vitest/pretty-format": "4.1.10", + "@vitest/runner": "4.1.10", + "@vitest/snapshot": "4.1.10", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" }, "bin": { - "vue-tsc": "bin/vue-tsc.js" + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "typescript": "*" - } - }, - "node_modules/vue-tsc/node_modules/semver": { - "version": "7.7.3", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.10", + "@vitest/browser-preview": "4.1.10", + "@vitest/browser-webdriverio": "4.1.10", + "@vitest/coverage-istanbul": "4.1.10", + "@vitest/coverage-v8": "4.1.10", + "@vitest/ui": "4.1.10", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, - "engines": { - "node": ">=10" + "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/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } } }, "node_modules/w3c-xmlserializer": { @@ -4276,27 +3558,10 @@ }, "node_modules/yallist": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true, "license": "ISC" - }, - "node_modules/z-schema": { - "version": "5.0.5", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.get": "^4.4.2", - "lodash.isequal": "^4.5.0", - "validator": "^13.7.0" - }, - "bin": { - "z-schema": "bin/z-schema" - }, - "engines": { - "node": ">=8.0.0" - }, - "optionalDependencies": { - "commander": "^9.4.1" - } } } } diff --git a/package.json b/package.json index 48c7769..31a5765 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "name": "@chartgpu/chartgpu-react", - "version": "0.1.4", - "description": "React bindings for ChartGPU - WebGPU-powered charting library", + "name": "chartgpu-react", + "version": "0.3.0", + "description": "React bindings for ChartGPU — WebGPU-powered high-performance charts", "license": "MIT", "author": "", "type": "module", @@ -21,35 +21,53 @@ "react", "chart", "webgpu", - "visualization" + "visualization", + "streaming", + "typescript" ], + "repository": { + "type": "git", + "url": "https://github.com/ChartGPU/chartgpu-react.git" + }, + "homepage": "https://github.com/ChartGPU/chartgpu-react#readme", + "bugs": { + "url": "https://github.com/ChartGPU/chartgpu-react/issues" + }, "scripts": { "dev": "vite", - "build": "npm run typecheck && vite build", - "typecheck": "tsc --noEmit", + "build": "npm run typecheck && vite build && tsc -p tsconfig.build.json", + "typecheck": "tsc --noEmit -p tsconfig.json", "preview": "vite preview", "test": "vitest run", "test:watch": "vitest" }, "peerDependencies": { - "@chartgpu/chartgpu": "^0.2.8", + "@chartgpu/chartgpu": "^0.3.6", "react": ">=18.0.0", "react-dom": ">=18.0.0" }, + "peerDependenciesMeta": { + "react-dom": { + "optional": false + } + }, "devDependencies": { - "@chartgpu/chartgpu": "^0.2.8", + "@chartgpu/chartgpu": "^0.3.6", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.2", - "@types/react": "^18.2.66", - "@types/react-dom": "^18.2.22", - "@vitejs/plugin-react": "^4.2.1", - "@vitest/coverage-v8": "^4.0.18", - "jsdom": "^28.1.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "typescript": "^5.3.3", - "vite": "^5.1.4", - "vite-plugin-dts": "^3.7.3", - "vitest": "^4.0.18" - } + "@types/react": "^19.2.17", + "@types/react-dom": "^19.2.3", + "@vitejs/plugin-react": "^5.0.3", + "@vitest/coverage-v8": "^4.1.10", + "jsdom": "^29.1.1", + "react": "^19.2.8", + "react-dom": "^19.2.8", + "typescript": "^7.0.2", + "vite": "^7.1.5", + "vitest": "^4.1.10" + }, + "engines": { + "node": ">=20" + }, + "sideEffects": false } diff --git a/src/ChartGPU.tsx b/src/ChartGPU.tsx index 919b201..2407dd1 100644 --- a/src/ChartGPU.tsx +++ b/src/ChartGPU.tsx @@ -100,10 +100,10 @@ export const ChartGPU = forwardRef( () => ({ getChart: () => instanceRef.current, getContainer: () => containerRef.current, - appendData: (seriesIndex: number, newPoints) => { + appendData: (seriesIndex, newPoints, options) => { const instance = instanceRef.current; if (instance && !instance.disposed) { - instance.appendData(seriesIndex, newPoints); + instance.appendData(seriesIndex, newPoints, options); } }, renderFrame: () => { @@ -139,10 +139,10 @@ export const ChartGPU = forwardRef( instance.setOption(newOptions); } }, - setZoomRange: (start: number, end: number) => { + setZoomRange: (start: number, end: number, source?: unknown) => { const instance = instanceRef.current; if (instance && !instance.disposed) { - instance.setZoomRange(start, end); + instance.setZoomRange(start, end, source); } }, setInteractionX: (x: number | null, source?: unknown) => { diff --git a/src/ChartGPUChart.tsx b/src/ChartGPUChart.tsx index e37f2a9..fcb55f8 100644 --- a/src/ChartGPUChart.tsx +++ b/src/ChartGPUChart.tsx @@ -1,5 +1,4 @@ -import { useCallback, useEffect, useMemo, useRef } from 'react'; -import type { CSSProperties } from 'react'; +import { useCallback, useEffect, useMemo, useRef, type CSSProperties, type ReactElement } from 'react'; import type { ChartGPUOptions, ChartGPUInstance } from '@chartgpu/chartgpu'; import { ChartGPU } from './ChartGPU'; @@ -74,7 +73,7 @@ export function ChartGPUChart({ style, onInit, onDispose, -}: ChartGPUChartProps): JSX.Element { +}: ChartGPUChartProps): ReactElement { const didInitRef = useRef(false); const onInitRef = useRef(onInit); diff --git a/src/__tests__/ChartGPU.test.tsx b/src/__tests__/ChartGPU.test.tsx index acba555..13a1c75 100644 --- a/src/__tests__/ChartGPU.test.tsx +++ b/src/__tests__/ChartGPU.test.tsx @@ -1,19 +1,13 @@ /** - * Tests for ChartGPU.tsx — verifying the createdWithOptionsRef race-condition fix. - * - * The fix: ChartGPU.create() is async. When it resolves, React schedules a - * setOption effect. Without the fix, that effect would redundantly call - * setOption(options) even though create() already initialised with those - * options, potentially crashing during the internal init sequence. - * - * createdWithOptionsRef snapshots { options, theme } before the async create - * call. The first post-create invocation of the setOption effect is - * unconditionally skipped (issue #16). + * Tests for ChartGPU.tsx — race-condition fix (issue #16), 0.3.x handle + * forwarding, gpuContext create path, and event prop wiring. */ +import { createRef, type ComponentProps } from 'react'; import { render, act, waitFor } from '@testing-library/react'; import { vi, describe, it, expect, beforeEach } from 'vitest'; import { ChartGPU } from '../ChartGPU'; +import type { ChartGPUHandle } from '../types'; import type { ChartGPUOptions } from '@chartgpu/chartgpu'; // --------------------------------------------------------------------------- @@ -87,6 +81,14 @@ async function waitForChartInit() { }); } +async function renderWithHandle(props: ComponentProps = { options: makeOptions() }) { + const ref = createRef(); + const result = render(); + await waitForChartInit(); + expect(ref.current).not.toBeNull(); + return { ref, ...result }; +} + // --------------------------------------------------------------------------- // Setup // --------------------------------------------------------------------------- @@ -197,3 +199,283 @@ describe('ChartGPU component — createdWithOptionsRef race-condition fix', () = expect(mockInstance.setOption).not.toHaveBeenCalled(); }); }); + +describe('ChartGPU handle — appendData (0.3.x maxPoints)', () => { + it('forwards seriesIndex, points, and { maxPoints } to the instance', async () => { + const { ref } = await renderWithHandle(); + const points = [{ x: 1, y: 2 }]; + + ref.current!.appendData(0, points, { maxPoints: 50_000 }); + + expect(mockInstance.appendData).toHaveBeenCalledTimes(1); + expect(mockInstance.appendData).toHaveBeenCalledWith(0, points, { maxPoints: 50_000 }); + }); + + it('forwards a two-arg call (options may be undefined)', async () => { + const { ref } = await renderWithHandle(); + const points = [{ x: 3, y: 4 }]; + + ref.current!.appendData(1, points); + + expect(mockInstance.appendData).toHaveBeenCalledTimes(1); + // Implementation always passes the options parameter (undefined when omitted). + expect(mockInstance.appendData).toHaveBeenCalledWith(1, points, undefined); + }); + + it('no-ops after the instance is disposed without throwing', async () => { + const { ref } = await renderWithHandle(); + mockInstance.disposed = true; + + expect(() => { + ref.current!.appendData(0, [{ x: 1, y: 2 }], { maxPoints: 100 }); + }).not.toThrow(); + expect(mockInstance.appendData).not.toHaveBeenCalled(); + }); + + it('no-ops after unmount without throwing', async () => { + const { ref, unmount } = await renderWithHandle(); + // React clears ref.current on unmount; keep the handle object to exercise no-ops. + const handle = ref.current!; + unmount(); + + expect(() => { + handle.appendData(0, [{ x: 1, y: 2 }], { maxPoints: 100 }); + }).not.toThrow(); + expect(mockInstance.appendData).not.toHaveBeenCalled(); + }); +}); + +describe('ChartGPU handle — setZoomRange source', () => { + it('forwards start, end, and source to the instance', async () => { + const { ref } = await renderWithHandle(); + + ref.current!.setZoomRange(10, 90, 'test-source'); + + expect(mockInstance.setZoomRange).toHaveBeenCalledTimes(1); + expect(mockInstance.setZoomRange).toHaveBeenCalledWith(10, 90, 'test-source'); + }); + + it('forwards a two-arg call (source may be undefined)', async () => { + const { ref } = await renderWithHandle(); + + ref.current!.setZoomRange(0, 100); + + expect(mockInstance.setZoomRange).toHaveBeenCalledTimes(1); + expect(mockInstance.setZoomRange).toHaveBeenCalledWith(0, 100, undefined); + }); +}); + +describe('ChartGPU handle — external render methods', () => { + it('forwards setRenderMode / getRenderMode / needsRender / renderFrame when ready', async () => { + mockInstance.getRenderMode.mockReturnValue('auto'); + mockInstance.needsRender.mockReturnValue(true); + mockInstance.renderFrame.mockReturnValue(true); + + const { ref } = await renderWithHandle(); + + ref.current!.setRenderMode('external'); + expect(mockInstance.setRenderMode).toHaveBeenCalledTimes(1); + expect(mockInstance.setRenderMode).toHaveBeenCalledWith('external'); + + expect(ref.current!.getRenderMode()).toBe('auto'); + expect(mockInstance.getRenderMode).toHaveBeenCalledTimes(1); + + expect(ref.current!.needsRender()).toBe(true); + expect(mockInstance.needsRender).toHaveBeenCalledTimes(1); + + expect(ref.current!.renderFrame()).toBe(true); + expect(mockInstance.renderFrame).toHaveBeenCalledTimes(1); + }); + + it('returns disposed defaults when the instance is null (unmount)', async () => { + const { ref, unmount } = await renderWithHandle(); + const handle = ref.current!; + unmount(); + + expect(handle.needsRender()).toBe(false); + expect(handle.renderFrame()).toBe(false); + expect(handle.getRenderMode()).toBe('auto'); + // setRenderMode should no-op without throwing + expect(() => handle.setRenderMode('external')).not.toThrow(); + expect(mockInstance.setRenderMode).not.toHaveBeenCalled(); + expect(mockInstance.needsRender).not.toHaveBeenCalled(); + expect(mockInstance.renderFrame).not.toHaveBeenCalled(); + expect(mockInstance.getRenderMode).not.toHaveBeenCalled(); + }); + + it('returns disposed defaults when the live instance has disposed: true', async () => { + mockInstance.needsRender.mockReturnValue(true); + mockInstance.renderFrame.mockReturnValue(true); + mockInstance.getRenderMode.mockReturnValue('external' as never); + + const { ref } = await renderWithHandle(); + // Instance still referenced by the handle, but marked disposed (short-circuit path). + mockInstance.disposed = true; + + expect(ref.current!.needsRender()).toBe(false); + expect(ref.current!.renderFrame()).toBe(false); + expect(ref.current!.getRenderMode()).toBe('auto'); + expect(() => ref.current!.setRenderMode('auto')).not.toThrow(); + + expect(mockInstance.needsRender).not.toHaveBeenCalled(); + expect(mockInstance.renderFrame).not.toHaveBeenCalled(); + expect(mockInstance.getRenderMode).not.toHaveBeenCalled(); + expect(mockInstance.setRenderMode).not.toHaveBeenCalled(); + }); +}); + +describe('ChartGPU — gpuContext create path', () => { + it('passes gpuContext as the third argument to ChartGPU.create', async () => { + const gpuContext = { + adapter: { id: 'adapter' } as any, + device: { id: 'device' } as any, + pipelineCache: { id: 'cache' } as any, + }; + + render(); + await waitForChartInit(); + + expect(mockCreate).toHaveBeenCalledTimes(1); + const args = mockCreate.mock.calls[0]; + expect(args).toHaveLength(3); + expect(args[0]).toBeInstanceOf(HTMLElement); + expect(args[1]).toEqual(expect.objectContaining({ _testLabel: 'ctx' })); + expect(args[2]).toBe(gpuContext); + }); + + it('calls create with two args when gpuContext is not provided', async () => { + render(); + await waitForChartInit(); + + expect(mockCreate).toHaveBeenCalledTimes(1); + const args = mockCreate.mock.calls[0]; + expect(args).toHaveLength(2); + expect(args[0]).toBeInstanceOf(HTMLElement); + expect(args[1]).toEqual(expect.objectContaining({ _testLabel: 'no-ctx' })); + }); +}); + +describe('ChartGPU events — onDataAppend / onDeviceLost', () => { + it('subscribes to dataAppend and deviceLost and invokes prop handlers', async () => { + const onDataAppend = vi.fn(); + const onDeviceLost = vi.fn(); + + render( + + ); + await waitForChartInit(); + + const onCalls = mockInstance.on.mock.calls as Array<[string, (...args: unknown[]) => void]>; + const dataAppendCall = onCalls.find(([event]) => event === 'dataAppend'); + const deviceLostCall = onCalls.find(([event]) => event === 'deviceLost'); + + expect(dataAppendCall).toBeDefined(); + expect(typeof dataAppendCall![1]).toBe('function'); + expect(deviceLostCall).toBeDefined(); + expect(typeof deviceLostCall![1]).toBe('function'); + + const appendPayload = { + seriesIndex: 0, + count: 3, + xExtent: { min: 0, max: 2 }, + }; + const lostPayload = { reason: 'destroyed' }; + + dataAppendCall![1](appendPayload); + deviceLostCall![1](lostPayload); + + expect(onDataAppend).toHaveBeenCalledTimes(1); + expect(onDataAppend).toHaveBeenCalledWith(appendPayload); + expect(onDeviceLost).toHaveBeenCalledTimes(1); + expect(onDeviceLost).toHaveBeenCalledWith(lostPayload); + }); + + it('unsubscribes dataAppend and deviceLost handlers on unmount', async () => { + const { unmount } = render( + {}} + onDeviceLost={() => {}} + /> + ); + await waitForChartInit(); + + const dataAppendOn = (mockInstance.on.mock.calls as Array<[string, unknown]>).find( + ([event]) => event === 'dataAppend' + ); + const deviceLostOn = (mockInstance.on.mock.calls as Array<[string, unknown]>).find( + ([event]) => event === 'deviceLost' + ); + expect(dataAppendOn).toBeDefined(); + expect(deviceLostOn).toBeDefined(); + + unmount(); + + const offCalls = mockInstance.off.mock.calls as Array<[string, unknown]>; + expect(offCalls).toContainEqual(['dataAppend', dataAppendOn![1]]); + expect(offCalls).toContainEqual(['deviceLost', deviceLostOn![1]]); + }); +}); + +describe('ChartGPU handle — smoke surface', () => { + it('forwards getChart, getContainer, setOption, interaction X, and hitTest', async () => { + const hitResult = { + isInGrid: true, + canvasX: 10, + canvasY: 20, + gridX: 1, + gridY: 2, + match: { seriesIndex: 0, dataIndex: 1 }, + }; + mockInstance.getInteractionX.mockReturnValue(42 as never); + mockInstance.hitTest.mockReturnValue(hitResult as never); + + const { ref } = await renderWithHandle(); + + expect(ref.current!.getChart()).toBe(mockInstance); + + const container = ref.current!.getContainer(); + expect(container).toBeInstanceOf(HTMLDivElement); + + const nextOpts = makeOptions('handle-setOption'); + ref.current!.setOption(nextOpts); + expect(mockInstance.setOption).toHaveBeenCalledWith(nextOpts); + + ref.current!.setInteractionX(1); + expect(mockInstance.setInteractionX).toHaveBeenCalledWith(1, undefined); + + ref.current!.setInteractionX(null); + expect(mockInstance.setInteractionX).toHaveBeenCalledWith(null, undefined); + + expect(ref.current!.getInteractionX()).toBe(42); + expect(mockInstance.getInteractionX).toHaveBeenCalled(); + + const event = new MouseEvent('click'); + expect(ref.current!.hitTest(event)).toBe(hitResult); + expect(mockInstance.hitTest).toHaveBeenCalledWith(event); + }); + + it('returns null chart / empty hitTest after unmount', async () => { + const { ref, unmount } = await renderWithHandle(); + const handle = ref.current!; + unmount(); + + expect(handle.getChart()).toBeNull(); + expect(handle.getInteractionX()).toBeNull(); + + const empty = handle.hitTest(new MouseEvent('click')); + expect(empty).toEqual({ + isInGrid: false, + canvasX: NaN, + canvasY: NaN, + gridX: NaN, + gridY: NaN, + match: null, + }); + expect(mockInstance.hitTest).not.toHaveBeenCalled(); + }); +}); diff --git a/src/__tests__/exports.test.ts b/src/__tests__/exports.test.ts new file mode 100644 index 0000000..63fbf91 --- /dev/null +++ b/src/__tests__/exports.test.ts @@ -0,0 +1,76 @@ +/** + * Export smoke test — fails CI if documented public surface is renamed/removed. + * Runtime values are asserted; types are compile-only imports (typecheck gate). + */ + +import { describe, it, expect, vi } from 'vitest'; + +// Mock peer package so re-exports resolve without a real WebGPU runtime. +vi.mock('@chartgpu/chartgpu', () => { + return { + ChartGPU: { create: vi.fn() }, + createChart: vi.fn(), + connectCharts: vi.fn(), + createPipelineCache: vi.fn(), + destroyPipelineCache: vi.fn(), + getPipelineCacheStats: vi.fn(), + }; +}); + +import * as pkg from '../index'; + +// Compile-only: ensure 0.3.x types remain importable from the package root. +import type { + ChartGPUAppendDataOptions, + ChartGPUHandle, + ChartGPUProps, + ChartGPUCreateContext, + HeatmapUpdate, + RenderMode, + ChartSyncOptions, + UseGPUContextResult, + UseChartGPUResult, +} from '../index'; + +// Keep type imports "used" for noUnusedLocals without runtime cost. +type _Surface = [ + ChartGPUAppendDataOptions, + ChartGPUHandle, + ChartGPUProps, + ChartGPUCreateContext, + HeatmapUpdate, + RenderMode, + ChartSyncOptions, + UseGPUContextResult, + UseChartGPUResult, +]; +const _typesOk: _Surface | undefined = undefined; +void _typesOk; + +describe('package exports', () => { + it('exports the primary React component and hooks', () => { + // forwardRef components are objects (exotic component), not plain functions + expect(pkg.ChartGPU).toBeTruthy(); + expect(typeof pkg.ChartGPU === 'function' || typeof pkg.ChartGPU === 'object').toBe(true); + + expect(pkg.useChartGPU).toBeTypeOf('function'); + expect(pkg.useGPUContext).toBeTypeOf('function'); + expect(pkg.useConnectCharts).toBeTypeOf('function'); + }); + + it('re-exports documented ChartGPU helpers', () => { + expect(pkg.connectCharts).toBeTypeOf('function'); + expect(pkg.createChart).toBeTypeOf('function'); + expect(pkg.createPipelineCache).toBeTypeOf('function'); + expect(pkg.destroyPipelineCache).toBeTypeOf('function'); + expect(pkg.getPipelineCacheStats).toBeTypeOf('function'); + expect(pkg.createAnnotationAuthoring).toBeTypeOf('function'); + }); + + it('still exports the deprecated ChartGPUChart adapter', () => { + expect(pkg.ChartGPUChart).toBeTruthy(); + expect(typeof pkg.ChartGPUChart === 'function' || typeof pkg.ChartGPUChart === 'object').toBe( + true + ); + }); +}); diff --git a/src/__tests__/useChartGPU.test.tsx b/src/__tests__/useChartGPU.test.tsx index 4924088..ecbafa7 100644 --- a/src/__tests__/useChartGPU.test.tsx +++ b/src/__tests__/useChartGPU.test.tsx @@ -190,3 +190,52 @@ describe('useChartGPU hook — createdWithOptionsRef race-condition fix', () => unmount(); }); }); + +describe('useChartGPU — gpuContext create path', () => { + it('passes gpuContext as the third argument to ChartGPU.create', async () => { + const container = document.createElement('div'); + document.body.appendChild(container); + const gpuContext = { + adapter: { id: 'adapter' } as any, + device: { id: 'device' } as any, + pipelineCache: { id: 'cache' } as any, + }; + const opts = makeOptions('hook-ctx'); + + const { result, unmount } = renderHook( + ({ options }: { options: ChartGPUOptions }) => { + const containerRef = useRef(container); + return useChartGPU(containerRef, options, gpuContext); + }, + { initialProps: { options: opts } } + ); + + await waitFor(() => { + expect(result.current.isReady).toBe(true); + }); + + expect(mockCreate).toHaveBeenCalledTimes(1); + const args = mockCreate.mock.calls[0]; + expect(args).toHaveLength(3); + expect(args[0]).toBe(container); + expect(args[1]).toBe(opts); + expect(args[2]).toBe(gpuContext); + + unmount(); + container.remove(); + }); + + it('calls create with two args when gpuContext is omitted', async () => { + const opts = makeOptions('hook-no-ctx'); + const { result, unmount } = renderUseChartGPU(opts); + + await waitFor(() => { + expect(result.current.isReady).toBe(true); + }); + + expect(mockCreate).toHaveBeenCalledTimes(1); + expect(mockCreate.mock.calls[0]).toHaveLength(2); + + unmount(); + }); +}); diff --git a/src/__tests__/useConnectCharts.test.tsx b/src/__tests__/useConnectCharts.test.tsx new file mode 100644 index 0000000..98f6b52 --- /dev/null +++ b/src/__tests__/useConnectCharts.test.tsx @@ -0,0 +1,181 @@ +/** + * Tests for useConnectCharts — multi-chart sync wiring around connectCharts(). + */ + +import { renderHook } from '@testing-library/react'; +import { vi, describe, it, expect, beforeEach } from 'vitest'; +import { useConnectCharts } from '../useConnectCharts'; +import type { ChartGPUInstance } from '@chartgpu/chartgpu'; + +// --------------------------------------------------------------------------- +// Mock @chartgpu/chartgpu +// --------------------------------------------------------------------------- + +const mockDisconnect = vi.fn(); +const mockConnectCharts = vi.fn((..._args: unknown[]) => mockDisconnect); + +vi.mock('@chartgpu/chartgpu', () => { + return { + connectCharts: (charts: unknown, options?: unknown) => mockConnectCharts(charts, options), + }; +}); + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +function makeMockChart(label: string, disposed = false): ChartGPUInstance { + return { + disposed, + // Minimal identity object; only disposed is read by the hook. + _label: label, + } as unknown as ChartGPUInstance; +} + +// --------------------------------------------------------------------------- +// Setup +// --------------------------------------------------------------------------- + +beforeEach(() => { + vi.clearAllMocks(); + mockConnectCharts.mockImplementation(() => mockDisconnect); +}); + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe('useConnectCharts', () => { + it('calls connectCharts once with resolved instances and undefined options', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + renderHook(() => useConnectCharts([a, b])); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledWith([a, b], undefined); + }); + + it('reconnects when syncOptions change', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + const { rerender } = renderHook( + ({ opts }: { opts?: { syncZoom?: boolean } }) => useConnectCharts([a, b], opts), + { initialProps: { opts: undefined as { syncZoom?: boolean } | undefined } } + ); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledWith([a, b], undefined); + + rerender({ opts: { syncZoom: true } }); + + expect(mockDisconnect).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledTimes(2); + expect(mockConnectCharts).toHaveBeenLastCalledWith([a, b], { syncZoom: true }); + }); + + it('does not call connectCharts when any chart is null', () => { + const a = makeMockChart('a'); + + renderHook(() => useConnectCharts([a, null])); + + expect(mockConnectCharts).not.toHaveBeenCalled(); + }); + + it('does not call connectCharts when any chart is disposed', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b', true); + + renderHook(() => useConnectCharts([a, b])); + + expect(mockConnectCharts).not.toHaveBeenCalled(); + }); + + it('calls disconnect on unmount', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + const { unmount } = renderHook(() => useConnectCharts([a, b])); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + unmount(); + expect(mockDisconnect).toHaveBeenCalledTimes(1); + }); + + it('disconnects the old connection and connects new instance identity', () => { + const a = makeMockChart('a'); + const b1 = makeMockChart('b1'); + const b2 = makeMockChart('b2'); + + const { rerender } = renderHook( + ({ charts }: { charts: Array }) => useConnectCharts(charts), + { initialProps: { charts: [a, b1] as Array } } + ); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledWith([a, b1], undefined); + + rerender({ charts: [a, b2] }); + + expect(mockDisconnect).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledTimes(2); + expect(mockConnectCharts).toHaveBeenLastCalledWith([a, b2], undefined); + }); + + it('does not reconnect when the same instances are passed in a new array', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + const { rerender } = renderHook( + ({ charts }: { charts: Array }) => useConnectCharts(charts), + { initialProps: { charts: [a, b] as Array } } + ); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + + // New array identity, same chart objects — signature is stable. + rerender({ charts: [a, b] }); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + expect(mockDisconnect).not.toHaveBeenCalled(); + }); + + it('disconnects without reconnecting when a live chart becomes disposed', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + const { rerender } = renderHook( + ({ charts }: { charts: Array }) => useConnectCharts(charts), + { initialProps: { charts: [a, b] as Array } } + ); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + expect(mockDisconnect).not.toHaveBeenCalled(); + + // Same object identities; disposed bit flips → signature changes. + (b as { disposed: boolean }).disposed = true; + rerender({ charts: [a, b] }); + + // Effect teardown disconnects; early-return because b is disposed → no reconnect. + expect(mockDisconnect).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + }); + + it('disconnects without reconnecting when a live chart becomes null', () => { + const a = makeMockChart('a'); + const b = makeMockChart('b'); + + const { rerender } = renderHook( + ({ charts }: { charts: Array }) => useConnectCharts(charts), + { initialProps: { charts: [a, b] as Array } } + ); + + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + + rerender({ charts: [a, null] }); + + expect(mockDisconnect).toHaveBeenCalledTimes(1); + expect(mockConnectCharts).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/__tests__/useGPUContext.test.tsx b/src/__tests__/useGPUContext.test.tsx new file mode 100644 index 0000000..811dee4 --- /dev/null +++ b/src/__tests__/useGPUContext.test.tsx @@ -0,0 +1,198 @@ +/** + * Tests for useGPUContext — shared adapter/device + pipeline cache init paths. + * Stubs navigator.gpu; never requires a real WebGPU device. + */ + +import { StrictMode } from 'react'; +import { renderHook, waitFor, act } from '@testing-library/react'; +import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest'; +import { useGPUContext } from '../useGPUContext'; + +// --------------------------------------------------------------------------- +// Mock @chartgpu/chartgpu +// --------------------------------------------------------------------------- + +const mockCreatePipelineCache = vi.fn(); + +vi.mock('@chartgpu/chartgpu', () => { + return { + createPipelineCache: (...args: unknown[]) => mockCreatePipelineCache(...args), + }; +}); + +// --------------------------------------------------------------------------- +// GPU stubs +// --------------------------------------------------------------------------- + +const originalGpuDescriptor = Object.getOwnPropertyDescriptor(navigator, 'gpu'); + +function stubGpu(gpu: unknown) { + Object.defineProperty(navigator, 'gpu', { + value: gpu, + configurable: true, + writable: true, + }); +} + +function restoreGpu() { + if (originalGpuDescriptor) { + Object.defineProperty(navigator, 'gpu', originalGpuDescriptor); + } else { + // setup.ts installs a default stub; reinstall empty object if needed + Object.defineProperty(navigator, 'gpu', { + value: {}, + configurable: true, + writable: true, + }); + } +} + +// --------------------------------------------------------------------------- +// Setup +// --------------------------------------------------------------------------- + +beforeEach(() => { + vi.clearAllMocks(); + mockCreatePipelineCache.mockReturnValue({ id: 'pipeline-cache' }); +}); + +afterEach(() => { + restoreGpu(); +}); + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe('useGPUContext', () => { + it('happy path: acquires adapter/device/cache and sets isReady', async () => { + const adapter = { + requestDevice: vi.fn(async () => ({ id: 'device' })), + }; + const requestAdapter = vi.fn(async () => adapter); + stubGpu({ requestAdapter }); + + const { result } = renderHook(() => useGPUContext()); + + await waitFor(() => { + expect(result.current.isReady).toBe(true); + }); + + expect(result.current.error).toBeNull(); + expect(result.current.adapter).toBe(adapter); + expect(result.current.device).toEqual({ id: 'device' }); + expect(result.current.pipelineCache).toEqual({ id: 'pipeline-cache' }); + expect(requestAdapter).toHaveBeenCalledWith({ powerPreference: 'high-performance' }); + expect(adapter.requestDevice).toHaveBeenCalledTimes(1); + expect(mockCreatePipelineCache).toHaveBeenCalledTimes(1); + expect(mockCreatePipelineCache).toHaveBeenCalledWith({ id: 'device' }); + }); + + it('sets a WebGPU error when navigator.gpu is absent', async () => { + stubGpu(undefined); + + const { result } = renderHook(() => useGPUContext()); + + await waitFor(() => { + expect(result.current.error).not.toBeNull(); + }); + + expect(result.current.error!.message).toMatch(/WebGPU/i); + expect(result.current.isReady).toBe(false); + expect(result.current.adapter).toBeNull(); + expect(result.current.device).toBeNull(); + expect(result.current.pipelineCache).toBeNull(); + expect(mockCreatePipelineCache).not.toHaveBeenCalled(); + }); + + it('errors when requestAdapter resolves null', async () => { + const requestAdapter = vi.fn(async () => null); + stubGpu({ requestAdapter }); + + const { result } = renderHook(() => useGPUContext()); + + await waitFor(() => { + expect(result.current.error).not.toBeNull(); + }); + + expect(result.current.error!.message).toBe('Failed to acquire GPUAdapter'); + expect(result.current.isReady).toBe(false); + expect(result.current.adapter).toBeNull(); + expect(mockCreatePipelineCache).not.toHaveBeenCalled(); + }); + + it('cancels state updates when unmounted mid-init', async () => { + let resolveAdapter: (value: unknown) => void; + const adapterPromise = new Promise((resolve) => { + resolveAdapter = resolve; + }); + const requestDevice = vi.fn(async () => ({ id: 'device-late' })); + const requestAdapter = vi.fn(() => adapterPromise); + stubGpu({ requestAdapter }); + + const consoleError = vi.spyOn(console, 'error').mockImplementation(() => {}); + + const { result, unmount } = renderHook(() => useGPUContext()); + + // Still pending — no ready state yet. + expect(result.current.isReady).toBe(false); + expect(result.current.error).toBeNull(); + + unmount(); + + // Resolve after unmount; init continues but setState must be gated by cancelled. + await act(async () => { + resolveAdapter!({ requestDevice }); + }); + + // Flush the full async chain (requestDevice → createPipelineCache → .then). + await waitFor(() => { + expect(requestDevice).toHaveBeenCalledTimes(1); + expect(mockCreatePipelineCache).toHaveBeenCalledTimes(1); + }); + + // Allow any remaining microtasks/macrotasks from the .then handler to settle. + await act(async () => { + await Promise.resolve(); + }); + + // State must remain frozen at pre-init defaults — proves cancelled path ran. + expect(result.current.isReady).toBe(false); + expect(result.current.error).toBeNull(); + expect(result.current.adapter).toBeNull(); + expect(result.current.device).toBeNull(); + expect(result.current.pipelineCache).toBeNull(); + + // React must not warn about setState on an unmounted component. + const stateUpdateWarnings = consoleError.mock.calls.filter((args) => + args.some( + (a) => + typeof a === 'string' && + (/unmounted|Can't perform a React state update|memory leak/i.test(a) || + /not mounted/i.test(a)) + ) + ); + expect(stateUpdateWarnings).toHaveLength(0); + consoleError.mockRestore(); + }); + + it('StrictMode double effect initializes only once (shared init promise)', async () => { + const adapter = { + requestDevice: vi.fn(async () => ({ id: 'device' })), + }; + const requestAdapter = vi.fn(async () => adapter); + stubGpu({ requestAdapter }); + + const { result } = renderHook(() => useGPUContext(), { + // React 18/19 StrictMode double-invokes effects in development. + wrapper: ({ children }) => {children}, + }); + + await waitFor(() => { + expect(result.current.isReady).toBe(true); + }); + + expect(requestAdapter).toHaveBeenCalledTimes(1); + expect(mockCreatePipelineCache).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/index.ts b/src/index.ts index f940555..97bcec6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,9 +1,10 @@ /** * chartgpu-react - * React bindings for ChartGPU - WebGPU-powered charting library + * React bindings for ChartGPU — WebGPU-powered high-performance charts + * Compatible with @chartgpu/chartgpu ^0.3.6 */ -// Primary ChartGPU component (Story 6.18) +// Primary ChartGPU component export { ChartGPU } from './ChartGPU'; // Wrapper types for the ChartGPU component @@ -18,17 +19,18 @@ export type { InterleavedXYData, XYArraysData, ChartGPUDataAppendPayload, + ChartGPUAppendDataOptions, } from './types'; -// useChartGPU hook (Story 6.19) +// useChartGPU hook export { useChartGPU } from './useChartGPU'; export type { UseChartGPUResult } from './useChartGPU'; -// Shared GPU context hook (ChartGPU v0.2.7+) +// Shared GPU context hook (multi-chart dashboards) export { useGPUContext } from './useGPUContext'; export type { UseGPUContextResult } from './useGPUContext'; -// Chart sync hook (connectCharts) - ChartGPU v0.2.3+ +// Chart sync hook (connectCharts) export { useConnectCharts } from './useConnectCharts'; /** @@ -61,6 +63,7 @@ export type { ChartGPUCrosshairMovePayload, ChartGPUZoomRangeChangePayload, ChartGPUDeviceLostPayload, + ZoomChangeSourceKind, RenderMode, // Hit testing @@ -82,7 +85,16 @@ export type { PieSeriesConfig, ScatterSeriesConfig, CandlestickSeriesConfig, + OhlcSeriesConfig, + HeatmapSeriesConfig, + BandSeriesConfig, + ErrorBarSeriesConfig, + ImpulseSeriesConfig, + PointCloud3DSeriesConfig, + Surface3DSeriesConfig, SeriesConfig, + SeriesType, + SeriesSampling, // Style configurations LineStyleConfig, @@ -92,6 +104,13 @@ export type { DataPoint, OHLCDataPoint, ScatterPointTuple, + HeatmapData, + HeatmapUpdate, + BandSeriesData, + ErrorBarSeriesData, + PointCloud3DData, + Surface3DGridData, + Surface3DUpdate, // Zoom / interaction DataZoomConfig, @@ -121,4 +140,10 @@ export type { GridConfig, GridLinesConfig, GridLinesDirectionConfig, + + // 3D + CoordinateSystem, + Chart3DCameraOptions, + Interaction3DOptions, + Axes3DOptions, } from '@chartgpu/chartgpu'; diff --git a/src/types.ts b/src/types.ts index 3ae6157..aea31ac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,6 +1,6 @@ /** - * Type definitions for ChartGPU React wrapper - * Story 6.18: Wrapper types for the new ChartGPU component + * Type definitions for ChartGPU React wrapper. + * Aligned with @chartgpu/chartgpu ^0.3.6. */ import type { CSSProperties } from 'react'; @@ -19,7 +19,7 @@ import type { /** * Separate x/y/size arrays for cartesian series data. - * Mirrors the upstream shape used by ChartGPU's `appendData(...)`. + * Mirrors ChartGPU's internal `XYArraysData` (not yet re-exported from package root). */ export type XYArraysData = Readonly<{ x: ArrayLike; @@ -29,29 +29,30 @@ export type XYArraysData = Readonly<{ /** * Pre-interleaved XY cartesian data as a typed array view. - * Data must be laid out as [x0, y0, x1, y1, ...]. - * - * Note: This is a type-level convenience for `appendData(...)`. It matches - * ChartGPU's public behavior but is not currently exported as a named type - * from `@chartgpu/chartgpu` due to its package `exports` map. + * Layout: [x0, y0, x1, y1, ...]. */ export type InterleavedXYData = ArrayBufferView; /** * Union type for cartesian series data formats supported by `appendData(...)`. - * Mirrors the upstream `CartesianSeriesData` type used internally by ChartGPU. + * Matches ChartGPU 0.3.x (`DataPoint | null` gaps allowed in object arrays). */ export type CartesianSeriesData = - | ReadonlyArray + | ReadonlyArray | XYArraysData | InterleavedXYData; +/** + * Optional second argument to `appendData` (ChartGPU 0.3.x). + * `maxPoints` is opt-in fixed-capacity ring / FIFO window for that call only. + */ +export type ChartGPUAppendDataOptions = Readonly<{ + maxPoints?: number; +}>; + /** * Payload emitted by the ChartGPU `'dataAppend'` event. - * - * Note: ChartGPU emits this event in v0.2.7+ but does not currently export the - * payload type from its package root due to its package `exports` map. - * We provide this wrapper type so React consumers can strongly type `onDataAppend`. + * Not re-exported from `@chartgpu/chartgpu` package root; mirrored here for React consumers. */ export type ChartGPUDataAppendPayload = Readonly<{ readonly seriesIndex: number; @@ -64,28 +65,23 @@ export type ChartGPUDataAppendPayload = Readonly<{ /** * Bivariant callback helper (matches React's event handler variance behavior). - * This preserves backwards-compatibility for userland handlers. */ -type BivariantCallback any> = { +type BivariantCallback unknown> = { bivarianceHack(...args: Parameters): ReturnType; }['bivarianceHack']; /** * Type alias for the ChartGPU instance. - * This provides a more React-friendly name while maintaining compatibility - * with the underlying chartgpu library. */ export type ChartInstance = ChartGPUInstance; /** * Event parameters for chart click events. - * Wraps the underlying ChartGPUEventPayload with a React-friendly name. */ export type ClickParams = ChartGPUEventPayload; /** * Event parameters for chart mouseover events. - * Wraps the underlying ChartGPUEventPayload with a React-friendly name. */ export type MouseOverParams = ChartGPUEventPayload; @@ -98,9 +94,6 @@ export type ZoomRange = NonNullable /** * Props interface for the ChartGPU React component. - * - * This component provides a declarative React wrapper around the imperative - * ChartGPU library, handling initialization, updates, and cleanup. */ export interface ChartGPUProps { /** @@ -110,7 +103,7 @@ export interface ChartGPUProps { options: ChartGPUOptions; /** - * Optional shared GPU context for multi-chart dashboards (ChartGPU v0.2.7+). + * Optional shared GPU context for multi-chart dashboards. * * IMPORTANT: This prop is **init-only** (only read during `ChartGPU.create(...)`). * Changing it after mount has no effect. @@ -135,23 +128,16 @@ export interface ChartGPUProps { /** * Callback invoked when the chart instance is ready after async initialization. - * Provides access to the underlying ChartGPU instance. - * - * @param chart - The initialized ChartGPU instance */ onReady?: (chart: ChartInstance) => void; /** * Callback invoked when a chart element is clicked. - * - * @param params - Event payload containing click details */ onClick?: (params: ClickParams) => void; /** * Callback invoked when the mouse hovers over a chart element. - * - * @param params - Event payload containing mouseover details */ onMouseOver?: (params: MouseOverParams) => void; @@ -162,27 +148,22 @@ export interface ChartGPUProps { /** * Callback invoked when the crosshair moves. - * - * @param payload - Crosshair move payload containing domain-space x and optional source */ onCrosshairMove?: (payload: ChartGPUCrosshairMovePayload) => void; /** - * Callback invoked when data is appended via `appendData(...)` (ChartGPU v0.2.7+). - * Useful for coordinated streaming dashboards and cross-chart synchronization. + * Callback invoked when data is appended via `appendData(...)`. */ onDataAppend?: (payload: ChartGPUDataAppendPayload) => void; /** - * Callback invoked when a shared GPU device is lost (ChartGPU v0.2.7+). + * Callback invoked when a shared GPU device is lost. * Most useful when using `gpuContext` to share a `GPUDevice` across charts. */ onDeviceLost?: (payload: ChartGPUDeviceLostPayload) => void; /** * Callback invoked when the chart zoom range changes. - * - * @param range - The new zoom range with start and end values */ onZoomChange?: BivariantCallback<(range: ZoomRange) => void>; } @@ -190,45 +171,36 @@ export interface ChartGPUProps { /** * Imperative handle interface for the ChartGPU component. * - * Exposed via React.forwardRef to allow parent components to interact - * directly with the chart instance using imperative methods. - * - * Example usage: + * Example: * ```tsx * const chartRef = useRef(null); - * - * // Later: - * chartRef.current?.appendData(0, [{ x: 10, y: 20 }]); + * chartRef.current?.appendData(0, newPoints, { maxPoints: 50_000 }); * ``` */ export interface ChartGPUHandle { /** * Get the underlying ChartGPU instance. * Returns null if the chart hasn't been initialized yet or has been disposed. - * - * @returns The ChartGPU instance or null */ getChart(): ChartGPUInstance | null; /** * Get the container element used to mount the chart. - * Useful for wiring up helpers like `createAnnotationAuthoring(...)`. */ getContainer(): HTMLDivElement | null; /** * Append new data points to an existing series. - * This is more efficient than replacing the entire dataset. - * - * @param seriesIndex - Zero-based index of the series to update - * @param newPoints - Array of data points to append + * Prefer `{ maxPoints }` for FIFO / streaming windows over sliding-window `setOption`. */ - appendData(seriesIndex: number, newPoints: CartesianSeriesData | OHLCDataPoint[]): void; + appendData( + seriesIndex: number, + newPoints: CartesianSeriesData | OHLCDataPoint[], + options?: ChartGPUAppendDataOptions + ): void; /** * Render a single frame (external render mode only). - * - * @returns true if a frame was rendered, false if already clean */ renderFrame(): boolean; @@ -249,27 +221,18 @@ export interface ChartGPUHandle { /** * Replace the entire chart options. - * Note: This replaces the full options object, not a partial update. - * - * @param options - New complete chart configuration */ setOption(options: ChartGPUOptions): void; /** * Programmatically set the zoom range (percent-space). * No-op when zoom is disabled on the chart. - * - * @param start - Start of zoom range (0-100) - * @param end - End of zoom range (0-100) */ - setZoomRange(start: number, end: number): void; + setZoomRange(start: number, end: number, source?: unknown): void; /** * Programmatically drive the crosshair / tooltip to a domain-space x value. * Passing `null` clears the crosshair. - * - * @param x - Domain-space x value, or null to clear - * @param source - Optional source identifier (useful for sync disambiguation) */ setInteractionX(x: number | null, source?: unknown): void; @@ -280,17 +243,12 @@ export interface ChartGPUHandle { /** * Perform hit-testing on a pointer or mouse event. - * Returns coordinates and matched chart element (if any). - * - * @param e - Pointer or mouse event to test - * @returns Hit-test result with coordinates and optional match */ hitTest(e: PointerEvent | MouseEvent): ChartGPUHitTestResult; } /** - * Re-export ThemeConfig for convenience. - * This allows consumers to import all types from the wrapper package. + * Re-export common core types for convenience. */ export type { ThemeConfig, diff --git a/src/useChartGPU.ts b/src/useChartGPU.ts index 79ed485..8f377a1 100644 --- a/src/useChartGPU.ts +++ b/src/useChartGPU.ts @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from 'react'; +import { useEffect, useRef, useState, type RefObject } from 'react'; import { ChartGPU as ChartGPULib } from '@chartgpu/chartgpu'; import type { ChartGPUCreateContext, ChartGPUOptions } from '@chartgpu/chartgpu'; import type { ChartInstance } from './types'; @@ -58,7 +58,7 @@ export interface UseChartGPUResult { * ``` */ export function useChartGPU( - containerRef: React.RefObject, + containerRef: RefObject, options: ChartGPUOptions, gpuContext?: ChartGPUCreateContext ): UseChartGPUResult { diff --git a/src/useGPUContext.ts b/src/useGPUContext.ts index a2fec1c..97adc9b 100644 --- a/src/useGPUContext.ts +++ b/src/useGPUContext.ts @@ -17,9 +17,16 @@ export interface UseGPUContextResult { * single `GPUDevice` and optional `PipelineCache` to reduce shader/pipeline compilation overhead. * * Usage: - * - Call `useGPUContext()` once in a parent component. + * - Call `useGPUContext()` once in a **long-lived** parent component. * - Pass `{ adapter, device, pipelineCache }` to each `` * or to `useChartGPU(containerRef, options, gpuContext)`. + * + * StrictMode: init is deduped via a shared in-flight/completed promise (single + * `requestAdapter` / `requestDevice` / `createPipelineCache` per hook instance). + * + * Lifecycle: does **not** destroy the `GPUDevice` or pipeline cache on unmount. + * Auto-destroy would race with StrictMode remount (same promise is re-subscribed). + * Keep this hook mounted for the shared charts’ process lifetime. */ interface GPUContextState { adapter: ChartGPUCreateContext['adapter'] | null; @@ -36,43 +43,54 @@ export function useGPUContext(): UseGPUContextResult { error: null, }); - // StrictMode safety: avoid double-initializing in dev (effect is invoked twice). - const startedRef = useRef(false); + // StrictMode safety: start GPU init at most once per hook instance. + // The promise is shared so a remount (StrictMode: effect → cleanup → effect) + // reuses the same in-flight/completed init instead of requesting a second device. + const initPromiseRef = useRef | null>(null); useEffect(() => { - if (startedRef.current) return; - startedRef.current = true; - let cancelled = false; - const init = async () => { - try { - const gpu = (navigator as unknown as { gpu?: any }).gpu; - if (!gpu) { - throw new Error('WebGPU not supported in this browser'); - } - - const nextAdapter = await gpu.requestAdapter({ - powerPreference: 'high-performance', - }); - if (!nextAdapter) { - throw new Error('Failed to acquire GPUAdapter'); - } + if (!initPromiseRef.current) { + initPromiseRef.current = (async (): Promise => { + try { + const gpu = (navigator as unknown as { gpu?: any }).gpu; + if (!gpu) { + throw new Error('WebGPU not supported in this browser'); + } - const nextDevice = await nextAdapter.requestDevice(); - const nextCache = createPipelineCache(nextDevice); + const nextAdapter = await gpu.requestAdapter({ + powerPreference: 'high-performance', + }); + if (!nextAdapter) { + throw new Error('Failed to acquire GPUAdapter'); + } - if (cancelled) return; + const nextDevice = await nextAdapter.requestDevice(); + const nextCache = createPipelineCache(nextDevice); - setState({ adapter: nextAdapter, device: nextDevice, pipelineCache: nextCache, error: null }); - } catch (err) { - if (cancelled) return; - const normalized = err instanceof Error ? err : new Error(String(err)); - setState({ adapter: null, device: null, pipelineCache: null, error: normalized }); - } - }; + return { + adapter: nextAdapter, + device: nextDevice, + pipelineCache: nextCache, + error: null, + }; + } catch (err) { + const normalized = err instanceof Error ? err : new Error(String(err)); + return { + adapter: null, + device: null, + pipelineCache: null, + error: normalized, + }; + } + })(); + } - init(); + initPromiseRef.current.then((next) => { + if (cancelled) return; + setState(next); + }); return () => { cancelled = true; diff --git a/src/utils.ts b/src/utils.ts index b0ced66..7032432 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -5,12 +5,12 @@ /** * Debounce utility for throttling frequent calls. */ -export function debounce void>( - fn: T, +export function debounce( + fn: (...args: TArgs) => void, delayMs: number -): (...args: Parameters) => void { +): (...args: TArgs) => void { let timeoutId: ReturnType | null = null; - return (...args: Parameters) => { + return (...args: TArgs) => { if (timeoutId !== null) { clearTimeout(timeoutId); } diff --git a/tsconfig.build.json b/tsconfig.build.json index fe657e4..a0e9a11 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -5,8 +5,10 @@ "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, - "outDir": "dist" + "outDir": "dist", + "rootDir": "src", + "allowImportingTsExtensions": false }, "include": ["src"], - "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "examples"] + "exclude": ["src/**/*.test.ts", "src/**/*.test.tsx", "src/__tests__", "examples"] } diff --git a/tsconfig.json b/tsconfig.json index 90a26cb..3f9f6f1 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2020", + "target": "ES2022", "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], + "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", "skipLibCheck": true, @@ -19,12 +19,13 @@ "noUnusedLocals": true, "noUnusedParameters": true, "noFallthroughCasesInSwitch": true, + "noUncheckedIndexedAccess": false, - /* React */ + /* React / interop */ "allowSyntheticDefaultImports": true, "esModuleInterop": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "verbatimModuleSyntax": false }, - "include": ["src"], - "references": [{ "path": "./tsconfig.node.json" }] + "include": ["src"] } diff --git a/tsconfig.node.json b/tsconfig.node.json index 97ede7e..cc71fdf 100644 --- a/tsconfig.node.json +++ b/tsconfig.node.json @@ -1,11 +1,16 @@ { "compilerOptions": { - "composite": true, - "skipLibCheck": true, + "target": "ES2022", + "lib": ["ES2022"], "module": "ESNext", "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, - "strict": true + "esModuleInterop": true, + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "resolveJsonModule": true, + "isolatedModules": true }, - "include": ["vite.config.ts"] + "include": ["vite.config.ts", "vitest.config.ts"] } diff --git a/vite.config.ts b/vite.config.ts index c1d090a..1161ba1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,6 +1,5 @@ import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; -import dts from 'vite-plugin-dts'; import { resolve } from 'path'; export default defineConfig(({ command }) => { @@ -17,16 +16,10 @@ export default defineConfig(({ command }) => { }; } - // Build mode: library output + // Build mode: library JS only (declarations via `tsc -p tsconfig.build.json`) + // Note: vite-plugin-dts is incompatible with TypeScript 7's slim package API. return { - plugins: [ - react(), - dts({ - insertTypesEntry: true, - rollupTypes: true, - tsconfigPath: './tsconfig.build.json', - }), - ], + plugins: [react()], build: { lib: { entry: resolve(__dirname, 'src/index.ts'), @@ -41,6 +34,7 @@ export default defineConfig(({ command }) => { }, outDir: 'dist', emptyOutDir: true, + sourcemap: true, }, }; });