From 8d6b606caf8e670cad84f7acbee021343de1c2ae Mon Sep 17 00:00:00 2001 From: brsbl <57682038+brsbl@users.noreply.github.com> Date: Sun, 4 Oct 2026 02:58:13 -0700 Subject: [PATCH 1/4] Revive Loop Machine as the LM-919 Rewrite the app in TypeScript on React 19 and Vite, with pnpm only. - One session document drives everything: UI dispatches pure commands, the store keeps undo history, and the share link (v2) is rewritten on every change. - New Web Audio engine: a worker-ticked clock that keeps time in background tabs, synthesized 808 kick, 909 snare, and disco open hat with per-drum delay and decay, a stereo unison arp synth, a kick-triggered pump, a ping-pong delay, and a glue bus with headroom. - New LM-919 panel: TR-909 identity pieces (cream LED step keys, chrome knobs, red 7-segment tempo, Michroma nameplate) on modern surfaces, a piano keyboard with key LEDs, octave and chord selectors, six house patterns, and undo. - Replace Jest, Babel, Tailwind, and the old JSX components with Vitest, ESLint, and CSS Modules; CI runs lint, typecheck, test, and build. Co-Authored-By: Claude Opus 5.5 --- .claude/CLAUDE.md | 91 +- .github/workflows/ci.yml | 7 +- CONTRIBUTING.md | 11 +- README.md | 97 +- babel.config.js | 6 - components.json | 22 - eslint.config.js | 66 +- index.html | 4 +- jest.config.js | 12 - jsconfig.json | 9 - package-lock.json | 8774 ---------------------- package.json | 30 +- pnpm-lock.yaml | 4638 ++++-------- public/README.md | 1 - src/App.jsx | 14 - src/App.module.css | 3 + src/App.tsx | 80 + src/README.md | 10 - src/__tests__/Key.test.jsx | 65 - src/__tests__/Pad.test.jsx | 42 - src/__tests__/TransportControls.test.jsx | 131 - src/__tests__/instruments.test.js | 153 - src/__tests__/keyboard.test.js | 91 - src/__tests__/urlState.test.js | 183 - src/__tests__/useAudioEngine.test.js | 159 - src/components/ArpTrack.jsx | 38 - src/components/AudioVisualizer.jsx | 103 - src/components/DrumMachine.jsx | 102 - src/components/Header.jsx | 9 - src/components/Key.jsx | 39 - src/components/Keyboard.jsx | 29 - src/components/KeyboardControls.jsx | 168 - src/components/LoadingOverlay.jsx | 12 - src/components/Pad.jsx | 19 - src/components/README.md | 12 - src/components/Sequencer.jsx | 246 - src/components/Track.jsx | 45 - src/components/TrackControls.jsx | 42 - src/components/TransportControls.jsx | 83 - src/components/ui/Button.jsx | 10 - src/components/ui/Fader.jsx | 137 - src/components/ui/Knob.jsx | 158 - src/components/ui/README.md | 8 - src/components/ui/card.jsx | 101 - src/config/README.md | 6 - src/config/instruments.js | 68 - src/config/keyboard.js | 80 - src/engine/arpeggiator.test.ts | 24 + src/engine/arpeggiator.ts | 22 + src/engine/channel.ts | 31 + src/engine/clock.ts | 69 + src/engine/delay.ts | 52 + src/engine/drive.ts | 58 + src/engine/drums.ts | 163 + src/engine/engine.ts | 161 + src/engine/mixer.ts | 40 + src/engine/params.ts | 6 + src/engine/pump.ts | 24 + src/engine/reverb.ts | 27 + src/engine/synth.ts | 147 + src/hooks/README.md | 8 - src/hooks/useArpeggiator.js | 171 - src/hooks/useAudioEngine.js | 266 - src/hooks/useSequencer.js | 239 - src/hooks/useSynthEngine.js | 222 - src/index.css | 1282 ---- src/instruments.ts | 87 + src/lib/utils.js | 6 - src/main.jsx | 10 - src/main.tsx | 18 + src/session/commands.test.ts | 67 + src/session/commands.ts | 92 + src/session/library.test.ts | 16 + src/session/library.ts | 40 + src/session/schema.ts | 75 + src/session/store.test.ts | 32 + src/session/store.ts | 71 + src/session/url.test.ts | 61 + src/session/url.ts | 117 + src/setupTests.js | 1 - src/test/setup.js | 1 - src/test/setup.ts | 1 + src/ui/Keyboard.module.css | 153 + src/ui/Keyboard.tsx | 65 + src/ui/LoopMachine.module.css | 206 + src/ui/LoopMachine.tsx | 269 + src/ui/TempoControl.tsx | 57 + src/ui/Transport.module.css | 102 + src/ui/controls/Fader.module.css | 65 + src/ui/controls/Fader.tsx | 51 + src/ui/controls/Knob.module.css | 72 + src/ui/controls/Knob.tsx | 67 + src/ui/controls/LedButton.module.css | 83 + src/ui/controls/LedButton.tsx | 70 + src/ui/controls/StepKey.module.css | 109 + src/ui/controls/StepKey.tsx | 26 + src/ui/controls/notch.test.ts | 32 + src/ui/controls/notch.ts | 43 + src/ui/controls/useNotchedControl.ts | 46 + src/ui/fonts/Archivo.woff2 | Bin 0 -> 90096 bytes src/ui/fonts/DSEG7Classic-Bold.woff2 | Bin 0 -> 5132 bytes src/ui/fonts/Michroma.woff2 | Bin 0 -> 11620 bytes src/ui/fonts/OFL-Archivo.txt | 93 + src/ui/fonts/OFL-DSEG.txt | 95 + src/ui/fonts/OFL-Michroma.txt | 93 + src/ui/tokens.css | 101 + src/utils/README.md | 5 - src/utils/urlState.js | 128 - tsconfig.json | 18 + vite.config.js | 18 - vite.config.ts | 10 + 111 files changed, 5237 insertions(+), 16761 deletions(-) delete mode 100644 babel.config.js delete mode 100644 components.json delete mode 100644 jest.config.js delete mode 100644 jsconfig.json delete mode 100644 package-lock.json delete mode 100644 src/App.jsx create mode 100644 src/App.module.css create mode 100644 src/App.tsx delete mode 100644 src/README.md delete mode 100644 src/__tests__/Key.test.jsx delete mode 100644 src/__tests__/Pad.test.jsx delete mode 100644 src/__tests__/TransportControls.test.jsx delete mode 100644 src/__tests__/instruments.test.js delete mode 100644 src/__tests__/keyboard.test.js delete mode 100644 src/__tests__/urlState.test.js delete mode 100644 src/__tests__/useAudioEngine.test.js delete mode 100644 src/components/ArpTrack.jsx delete mode 100644 src/components/AudioVisualizer.jsx delete mode 100644 src/components/DrumMachine.jsx delete mode 100644 src/components/Header.jsx delete mode 100644 src/components/Key.jsx delete mode 100644 src/components/Keyboard.jsx delete mode 100644 src/components/KeyboardControls.jsx delete mode 100644 src/components/LoadingOverlay.jsx delete mode 100644 src/components/Pad.jsx delete mode 100644 src/components/README.md delete mode 100644 src/components/Sequencer.jsx delete mode 100644 src/components/Track.jsx delete mode 100644 src/components/TrackControls.jsx delete mode 100644 src/components/TransportControls.jsx delete mode 100644 src/components/ui/Button.jsx delete mode 100644 src/components/ui/Fader.jsx delete mode 100644 src/components/ui/Knob.jsx delete mode 100644 src/components/ui/README.md delete mode 100644 src/components/ui/card.jsx delete mode 100644 src/config/README.md delete mode 100644 src/config/instruments.js delete mode 100644 src/config/keyboard.js create mode 100644 src/engine/arpeggiator.test.ts create mode 100644 src/engine/arpeggiator.ts create mode 100644 src/engine/channel.ts create mode 100644 src/engine/clock.ts create mode 100644 src/engine/delay.ts create mode 100644 src/engine/drive.ts create mode 100644 src/engine/drums.ts create mode 100644 src/engine/engine.ts create mode 100644 src/engine/mixer.ts create mode 100644 src/engine/params.ts create mode 100644 src/engine/pump.ts create mode 100644 src/engine/reverb.ts create mode 100644 src/engine/synth.ts delete mode 100644 src/hooks/README.md delete mode 100644 src/hooks/useArpeggiator.js delete mode 100644 src/hooks/useAudioEngine.js delete mode 100644 src/hooks/useSequencer.js delete mode 100644 src/hooks/useSynthEngine.js delete mode 100644 src/index.css create mode 100644 src/instruments.ts delete mode 100644 src/lib/utils.js delete mode 100644 src/main.jsx create mode 100644 src/main.tsx create mode 100644 src/session/commands.test.ts create mode 100644 src/session/commands.ts create mode 100644 src/session/library.test.ts create mode 100644 src/session/library.ts create mode 100644 src/session/schema.ts create mode 100644 src/session/store.test.ts create mode 100644 src/session/store.ts create mode 100644 src/session/url.test.ts create mode 100644 src/session/url.ts delete mode 100644 src/setupTests.js delete mode 100644 src/test/setup.js create mode 100644 src/test/setup.ts create mode 100644 src/ui/Keyboard.module.css create mode 100644 src/ui/Keyboard.tsx create mode 100644 src/ui/LoopMachine.module.css create mode 100644 src/ui/LoopMachine.tsx create mode 100644 src/ui/TempoControl.tsx create mode 100644 src/ui/Transport.module.css create mode 100644 src/ui/controls/Fader.module.css create mode 100644 src/ui/controls/Fader.tsx create mode 100644 src/ui/controls/Knob.module.css create mode 100644 src/ui/controls/Knob.tsx create mode 100644 src/ui/controls/LedButton.module.css create mode 100644 src/ui/controls/LedButton.tsx create mode 100644 src/ui/controls/StepKey.module.css create mode 100644 src/ui/controls/StepKey.tsx create mode 100644 src/ui/controls/notch.test.ts create mode 100644 src/ui/controls/notch.ts create mode 100644 src/ui/controls/useNotchedControl.ts create mode 100644 src/ui/fonts/Archivo.woff2 create mode 100644 src/ui/fonts/DSEG7Classic-Bold.woff2 create mode 100644 src/ui/fonts/Michroma.woff2 create mode 100644 src/ui/fonts/OFL-Archivo.txt create mode 100644 src/ui/fonts/OFL-DSEG.txt create mode 100644 src/ui/fonts/OFL-Michroma.txt create mode 100644 src/ui/tokens.css delete mode 100644 src/utils/README.md delete mode 100644 src/utils/urlState.js create mode 100644 tsconfig.json delete mode 100644 vite.config.js create mode 100644 vite.config.ts diff --git a/.claude/CLAUDE.md b/.claude/CLAUDE.md index 133db29..4bd7140 100644 --- a/.claude/CLAUDE.md +++ b/.claude/CLAUDE.md @@ -1,88 +1,41 @@ # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +Guidance for Claude Code working in this repository. -## Project Overview +## Project -Loop Machine is a browser-based drum sequencer built with vanilla JavaScript and the Web Audio API. It features a 16-step sequencer with 3 instrument tracks (hi-hat, snare, kick), per-instrument reverb/delay effects, URL state persistence, and a JSON editor sidebar. +Loop Machine (LM-919) is a browser drum machine + synth: a 16-step drum sequencer (hi-hat, snare, kick) and an arpeggiated synth on a two-octave keyboard. React 19, TypeScript, Vite, Web Audio API. pnpm only. ## Architecture -### Core Files - -- `index.html` - Main HTML structure with sequencer grid, sidebar, and modal -- `script.js` - All application logic (audio, UI, state management) -- `style.css` - CSS Grid-based layout and styling - -### Audio System - -The application uses the Web Audio API with this signal flow per instrument: ``` -BufferSource -> mainGain -> [dry path to output] - -> reverbNode -> output - -> delayNode -> feedbackNode -> delayNode (feedback loop) - -> delayWetGain -> output +src/instruments.ts drum registry (id, label, synthesized voice, firing color) and keyboard notes +src/session/ Session types, pure commands (applyCommand), store, share-link format +src/engine/ audio engine; must not import React (ESLint enforces this) +src/ui/ React components, CSS Modules, tokens.css, vendored fonts ``` -Key audio variables: -- `audioContext` - Main Web Audio context -- `audioBuffers` - Decoded audio samples per instrument -- `effectNodes` - Gain/effect nodes per instrument -- `sequenceState` - Boolean arrays (16 steps) per instrument - -### State Management +- **One session document** is the source of truth. UI dispatches `Command`s; `applyCommand` is pure and tested. The store keeps undo history (knob drags coalesce into one step), notifies the engine (`engine.apply`), and rewrites the share link. +- **Exploring:** `src/session/library.ts` holds the ready-made patterns (the app opens on the first) and the chords. Holding the first key with no synth steps fills in a default rhythm. +- **Engine:** `Clock` schedules 100 ms ahead, ticked from a Worker so background tabs keep time. The sound is aimed at dirty French electro (Justice, Daft Punk, a little disco). `mixer.ts` builds the whole signal chain once, shared by the live engine and offline renders. Drums are synthesized per hit in `drums.ts` (808 kick with a 909-style snap, driven 909 snare, clean disco open hat; no samples), each with a DECAY tail multiplier, and run through a `ChannelStrip` (volume → mix bus, with a send to the stereo ping-pong delay in `delay.ts`). The `Synth` is a seven-voice detuned stereo unison plus a sub, through a plucked low-pass, light drive, and a 7 kHz high cut; it starts voices at scheduled times and releases the previous arp note at the next note's start. The synth, delay, and reverb run through the `Pump`, which ducks on every kick like a sidechain; drums bypass it. Everything meets in the mix bus (gentle glue compressor with headroom) before a safety limiter. The playhead (`step`, fired `note`) is published when each step actually sounds. +- **Share link (v2):** `?s=2~~~…~syn.<…>`, keyed by drum id. See `src/session/url.ts`. Malformed parts fall back to defaults. -State is persisted in the URL using a compact encoding: -- Notes: 4-char hex per instrument (16 boolean steps as binary) -- Effects: 2 chars per instrument (reverb/delay values 0-10) -- Sidebar: `1` if visible +## Adding a drum -Functions: -- `updateUrlState()` - Writes current state to URL -- `loadUrlState()` - Restores state from URL on load -- `getCurrentStateAsJson()` - Returns state for JSON editor +Write the voice in `src/engine/drums.ts`, then add an entry to `DRUMS` in `src/instruments.ts`. The step row, knobs, firing color, and link field follow. -### Timing System +## Design -Uses a scheduler pattern for accurate audio timing: -- `scheduler()` - Schedules notes ahead of playback time -- `updatePlayheadVisuals()` - RAF loop for visual step highlighting -- `scheduleAheadTime` - How far ahead to schedule (100ms) -- `stepTime` - Duration of one 16th note at current BPM +The look is documented in the "Loop Machine Revival" proposal: TR-909 identity pieces (cream step keys with LEDs, chrome knobs, red 7-segment tempo, Michroma nameplate, navy Archivo labels) on modern glass surfaces. Tokens live in `src/ui/tokens.css`. Knobs snap to 11 notches and the fader to 9; both accept drag, click, wheel, and arrow keys. -## Development Commands +## Commands -Serve locally: ```bash -npx serve . +pnpm dev # http://localhost:3000 +pnpm build +pnpm lint +pnpm typecheck +pnpm test ``` -No build step required - vanilla JS served directly. - -## Common Tasks - -### Adding a New Instrument - -1. Add entry to `instrumentsData` array with `name`, `id`, and `path` -2. Place audio file in `808 Samples/` directory -3. UI is generated automatically from `instrumentsData` - -### Modifying Effects - -Effect parameters are in `updateEffect()`: -- Reverb: Simple gain control (0-1) -- Delay: Time (0-0.5s), feedback (0-0.7), wet gain (0-0.5) - -### Changing BPM - -Modify the `bpm` constant (line 14). `stepTime` is calculated from it. - -## Testing - -No automated tests currently. Manual testing: -1. Toggle notes and verify visual feedback -2. Start/stop playback -3. Adjust effect sliders -4. Reload page and verify URL state restoration -5. Edit JSON and apply changes -6. Test reset functionality +CI runs lint, typecheck, test, and build on every PR. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ca1c637..4cdf25c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,15 +22,18 @@ jobs: - name: Setup Node.js uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' cache: 'pnpm' - name: Install dependencies - run: pnpm install + run: pnpm install --frozen-lockfile - name: Lint run: pnpm lint + - name: Typecheck + run: pnpm typecheck + - name: Test run: pnpm test diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9101675..81aadda 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,16 +12,17 @@ Thanks for your interest in contributing to Loop Machine! ```bash git clone https://github.com/brsbl/loop-machine.git cd loop-machine -npm install -npm run dev +pnpm install +pnpm dev ``` ## Before Submitting a PR ```bash -npm run lint -npm test -npm run build +pnpm lint +pnpm typecheck +pnpm test +pnpm build ``` All checks must pass before merging. diff --git a/README.md b/README.md index db6e02b..e687fc0 100644 --- a/README.md +++ b/README.md @@ -1,79 +1,58 @@ -# Loop Machine +# Loop Machine · LM-919 -A browser-based drum sequencer/loop machine built with vanilla JavaScript and the Web Audio API. - -Screenshot 2026-02-03 at 12 01 15 AM +A drum machine + synth in your browser, styled after the Roland TR-909. Program a beat, hold a chord, and share the whole loop as a link. ## Features -- **16-step sequencer** with 3 instrument tracks (hi-hat, snare, kick) -- **Real-time playback** with visual step indicator -- **Per-instrument effects**: Reverb and Delay with adjustable levels (0-10) -- **URL state persistence**: Share patterns via URL -- **JSON editor sidebar**: View and edit sequencer state directly as JSON -- **Reset functionality**: Clear all patterns and effects with confirmation modal - -## Getting Started - -### Prerequisites - -- A modern web browser with Web Audio API support -- A local web server (for loading audio samples) - -### Running Locally - -1. Clone the repository -2. Serve the directory with any static file server: - ```bash - npx serve . - ``` -3. Open `http://localhost:3000` in your browser +- **Drums:** 16-step sequencer for hi-hat, snare, and kick, synthesized 909-style in the browser (no samples), each with volume, reverb, and tone knobs +- **Synth:** arpeggiator over a two-octave keyboard, with a detuned two-oscillator voice, a sub, and a plucked filter. Keys choose which notes play; the synth's step row chooses when. Direction (up, down, up-down), speed (1/4, 1/8, 1/16), and four waveforms +- **Playback:** on steps carry a soft tint of their instrument's color and light up fully when they fire; a beat band marks the four beats; the synth's key flashes with its step +- **Controls:** knobs click to 11 notches and the fader to 9. Drag, click a notch, scroll, or use the arrow keys +- **Computer keyboard:** A–C and W–\ toggle notes, like a piano layout +- **Share links:** the URL holds the whole loop, drums and synth included -### Audio Samples +## Run it -The project uses 808 drum samples located in the `808 Samples/` directory: -- `hi hat (30).wav` -- `snare.wav` -- `kick.wav` +```bash +pnpm install +pnpm dev +``` -## Usage +Then open http://localhost:3000. -1. Click **START/STOP** to begin/stop playback -2. Click on sequencer pads to toggle notes on/off -3. Adjust **REVERB** and **DELAY** sliders for each instrument -4. Use the sidebar toggle to open the JSON editor for direct state manipulation -5. Click **RESET** to clear all patterns (requires confirmation) +## Project layout -## URL State Format +``` +src/ + instruments.ts registry: drums (id, label, voice, color) and keyboard notes + engine/ audio engine, no React: clock, channel strips, reverb, drum voices, synth, arpeggiator + session/ session types, commands, store, and share-link format + ui/ React components, design tokens, and fonts +``` -The sequencer state is encoded in the URL using a compact format: -- `s` parameter: `{notes_hex}_{sliders_chars}` - - Notes: 4-character hex per instrument (16 steps as binary) - - Sliders: 2 characters per instrument (reverb + delay, 0-9 or 'a' for 10) -- `sidebar` parameter: `1` if sidebar is visible +The UI only renders the session and dispatches commands. The engine follows the session and reports the playhead back. -## Project Structure +Adding a drum: write its voice in `src/engine/drums.ts`, then add one entry in `src/instruments.ts`: +```ts +{ id: 'clap', label: 'Clap', voice: 'clap', fire: { top: '…', bottom: '…', glow: '…' } } ``` -loop-machine/ -├── index.html # Main HTML structure -├── script.js # Core application logic -├── style.css # Styling -├── 808 Samples/ # Drum audio samples -└── src/ - └── utils/ # Utility functions -``` -## Tech Stack +Its step row, knobs, firing color, and share-link field follow automatically. + +## Scripts -- Vanilla JavaScript (ES6+) -- Web Audio API for audio playback and effects -- CSS Grid for layout -- No external dependencies +| Command | What it does | +| --- | --- | +| `pnpm dev` | Dev server on port 3000 | +| `pnpm build` | Production build | +| `pnpm lint` | ESLint | +| `pnpm typecheck` | TypeScript | +| `pnpm test` | Vitest | -## Contributing +## Credits -See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines. For bugs or feature requests, please [open an issue](https://github.com/brsbl/loop-machine/issues/new). +- Fonts: Michroma, Archivo, and DSEG7 Classic, under the SIL Open Font License (see `src/ui/fonts/`) ## License diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 6a350e5..0000000 --- a/babel.config.js +++ /dev/null @@ -1,6 +0,0 @@ -export default { - presets: [ - ['@babel/preset-env', { targets: { node: 'current' } }], - ['@babel/preset-react', { runtime: 'automatic' }], - ], -} diff --git a/components.json b/components.json deleted file mode 100644 index 22b8552..0000000 --- a/components.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": false, - "tailwind": { - "config": "", - "css": "src/index.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "iconLibrary": "lucide", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": {} -} diff --git a/eslint.config.js b/eslint.config.js index fab6f78..ec3ef7a 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,67 +1,29 @@ import js from '@eslint/js' +import tseslint from 'typescript-eslint' import react from 'eslint-plugin-react' import reactHooks from 'eslint-plugin-react-hooks' -export default [ +export default tseslint.config( + { ignores: ['dist/**', 'node_modules/**'] }, js.configs.recommended, + ...tseslint.configs.recommended, { - files: ['**/*.{js,jsx}'], - plugins: { - react, - 'react-hooks': reactHooks, - }, - languageOptions: { - parserOptions: { - ecmaFeatures: { - jsx: true, - }, - }, - globals: { - window: 'readonly', - document: 'readonly', - console: 'readonly', - AudioContext: 'readonly', - fetch: 'readonly', - requestAnimationFrame: 'readonly', - cancelAnimationFrame: 'readonly', - setTimeout: 'readonly', - clearTimeout: 'readonly', - setInterval: 'readonly', - clearInterval: 'readonly', - URL: 'readonly', - URLSearchParams: 'readonly', - }, - }, + files: ['src/**/*.{ts,tsx}'], + plugins: { react, 'react-hooks': reactHooks }, + languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } }, + settings: { react: { version: 'detect' } }, rules: { - 'react/jsx-uses-react': 'error', 'react/jsx-uses-vars': 'error', 'react-hooks/rules-of-hooks': 'error', 'react-hooks/exhaustive-deps': 'warn', - 'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], - }, - settings: { - react: { - version: 'detect', - }, + '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }], }, }, { - files: ['**/__tests__/**/*.{js,jsx}', '**/*.test.{js,jsx}', '**/*.spec.{js,jsx}'], - languageOptions: { - globals: { - describe: 'readonly', - it: 'readonly', - expect: 'readonly', - jest: 'readonly', - beforeEach: 'readonly', - afterEach: 'readonly', - beforeAll: 'readonly', - afterAll: 'readonly', - global: 'readonly', - }, + // The engine stays framework-free so the web app, Mixtape, and tests can share it. + files: ['src/engine/**/*.ts'], + rules: { + 'no-restricted-imports': ['error', { patterns: [{ group: ['react', 'react-dom', 'react/*'], message: 'The engine must not depend on React.' }] }], }, }, - { - ignores: ['dist/**', 'node_modules/**'], - }, -] +) diff --git a/index.html b/index.html index e2d0ef6..05a8d70 100644 --- a/index.html +++ b/index.html @@ -3,10 +3,10 @@ - Drum Machine + LM-919 · Loop Machine
- + diff --git a/jest.config.js b/jest.config.js deleted file mode 100644 index fe77993..0000000 --- a/jest.config.js +++ /dev/null @@ -1,12 +0,0 @@ -export default { - testEnvironment: 'jsdom', - setupFilesAfterEnv: ['/src/setupTests.js'], - moduleNameMapper: { - '^@/(.*)$': '/src/$1', - '\\.(css|less|scss|sass)$': 'identity-obj-proxy', - }, - transform: { - '^.+\\.(js|jsx)$': 'babel-jest', - }, - testMatch: ['**/__tests__/**/*.[jt]s?(x)', '**/?(*.)+(spec|test).[jt]s?(x)'], -} diff --git a/jsconfig.json b/jsconfig.json deleted file mode 100644 index f1a3469..0000000 --- a/jsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "compilerOptions": { - "baseUrl": ".", - "paths": { - "@/*": ["./src/*"] - } - }, - "include": ["src"] -} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 5511ab9..0000000 --- a/package-lock.json +++ /dev/null @@ -1,8774 +0,0 @@ -{ - "name": "drum-machine", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "drum-machine", - "version": "1.0.0", - "dependencies": { - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-slot": "^1.2.4", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^0.556.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "tailwind-merge": "^3.4.0" - }, - "devDependencies": { - "@babel/preset-env": "^7.28.5", - "@babel/preset-react": "^7.28.5", - "@eslint/js": "^9.39.1", - "@tailwindcss/vite": "^4.1.17", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.0", - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@vitejs/plugin-react": "^4.2.0", - "agentation": "^1.3.2", - "eslint": "^9.39.1", - "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^7.0.1", - "jsdom": "^27.3.0", - "tailwindcss": "^4.1.17", - "tw-animate-css": "^1.4.0", - "vite": "^5.0.0", - "vitest": "^4.0.15" - } - }, - "node_modules/@acemir/cssom": { - "version": "0.9.29", - "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.29.tgz", - "integrity": "sha512-G90x0VW+9nW4dFajtjCoT+NM0scAfH9Mb08IcjgFHYbfiL/lU04dTF9JuVOi3/OH+DJCQdcIseSXkdCB9Ky6JA==", - "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==", - "dev": true, - "license": "MIT" - }, - "node_modules/@asamuzakjp/css-color": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.0.tgz", - "integrity": "sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@csstools/css-calc": "^2.1.4", - "@csstools/css-color-parser": "^3.1.0", - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4", - "lru-cache": "^11.2.2" - } - }, - "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@asamuzakjp/dom-selector": { - "version": "6.7.6", - "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.7.6.tgz", - "integrity": "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/nwsapi": "^2.3.9", - "bidi-js": "^1.0.3", - "css-tree": "^3.1.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.2.4" - } - }, - "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { - "version": "11.2.4", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.4.tgz", - "integrity": "sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@asamuzakjp/nwsapi": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", - "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz", - "integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz", - "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", - "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.28.5", - "@babel/types": "^7.28.5", - "@jridgewell/gen-mapping": "^0.3.12", - "@jridgewell/trace-mapping": "^0.3.28", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.27.3", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", - "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.3" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.2", - "@babel/helper-validator-option": "^7.27.1", - "browserslist": "^4.24.0", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.5.tgz", - "integrity": "sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-member-expression-to-functions": "^7.28.5", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/traverse": "^7.28.5", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.28.5.tgz", - "integrity": "sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "regexpu-core": "^6.3.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.5.tgz", - "integrity": "sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "debug": "^4.4.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.22.10" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", - "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.28.5", - "@babel/types": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", - "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", - "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.27.1.tgz", - "integrity": "sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-wrap-function": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.27.1.tgz", - "integrity": "sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.27.1", - "@babel/helper-optimise-call-expression": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", - "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.28.3.tgz", - "integrity": "sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.3", - "@babel/types": "^7.28.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", - "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.5" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-firefox-class-in-computed-class-key": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz", - "integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-class-field-initializer-scope": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz", - "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz", - "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz", - "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz", - "integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.21.0-placeholder-for-preset-env.2", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", - "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-assertions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz", - "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-import-attributes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz", - "integrity": "sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz", - "integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-unicode-sets-regex": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", - "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.18.6", - "@babel/helper-plugin-utils": "^7.18.6" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.27.1.tgz", - "integrity": "sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-generator-functions": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.28.0.tgz", - "integrity": "sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1", - "@babel/traverse": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.27.1.tgz", - "integrity": "sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-remap-async-to-generator": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz", - "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.28.5.tgz", - "integrity": "sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.27.1.tgz", - "integrity": "sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-class-static-block": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz", - "integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.28.4.tgz", - "integrity": "sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-globals": "^7.28.0", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.27.1.tgz", - "integrity": "sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/template": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.28.5.tgz", - "integrity": "sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz", - "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz", - "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-dynamic-import": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz", - "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-explicit-resource-management": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz", - "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz", - "integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-export-namespace-from": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.27.1.tgz", - "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.27.1.tgz", - "integrity": "sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.27.1.tgz", - "integrity": "sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/traverse": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-json-strings": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz", - "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.27.1.tgz", - "integrity": "sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-logical-assignment-operators": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.28.5.tgz", - "integrity": "sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz", - "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz", - "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.27.1.tgz", - "integrity": "sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz", - "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-module-transforms": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.27.1.tgz", - "integrity": "sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz", - "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.27.1.tgz", - "integrity": "sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-numeric-separator": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.27.1.tgz", - "integrity": "sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-rest-spread": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.28.4.tgz", - "integrity": "sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.0", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/traverse": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz", - "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-replace-supers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-catch-binding": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.27.1.tgz", - "integrity": "sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-optional-chaining": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.28.5.tgz", - "integrity": "sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.27.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.27.7.tgz", - "integrity": "sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-methods": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.27.1.tgz", - "integrity": "sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-private-property-in-object": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.27.1.tgz", - "integrity": "sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-create-class-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz", - "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-display-name": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.28.0.tgz", - "integrity": "sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.27.1.tgz", - "integrity": "sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/plugin-syntax-jsx": "^7.27.1", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-development": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.27.1.tgz", - "integrity": "sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/plugin-transform-react-jsx": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-self": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", - "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-jsx-source": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", - "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-react-pure-annotations": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.27.1.tgz", - "integrity": "sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.28.4.tgz", - "integrity": "sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regexp-modifiers": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz", - "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz", - "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.27.1.tgz", - "integrity": "sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.27.1.tgz", - "integrity": "sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.27.1.tgz", - "integrity": "sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.27.1.tgz", - "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz", - "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz", - "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-property-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz", - "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.27.1.tgz", - "integrity": "sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-sets-regex": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz", - "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.27.1", - "@babel/helper-plugin-utils": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.28.5.tgz", - "integrity": "sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.28.5", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-bugfix-firefox-class-in-computed-class-key": "^7.28.5", - "@babel/plugin-bugfix-safari-class-field-initializer-scope": "^7.27.1", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.27.1", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.27.1", - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.28.3", - "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", - "@babel/plugin-syntax-import-assertions": "^7.27.1", - "@babel/plugin-syntax-import-attributes": "^7.27.1", - "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", - "@babel/plugin-transform-arrow-functions": "^7.27.1", - "@babel/plugin-transform-async-generator-functions": "^7.28.0", - "@babel/plugin-transform-async-to-generator": "^7.27.1", - "@babel/plugin-transform-block-scoped-functions": "^7.27.1", - "@babel/plugin-transform-block-scoping": "^7.28.5", - "@babel/plugin-transform-class-properties": "^7.27.1", - "@babel/plugin-transform-class-static-block": "^7.28.3", - "@babel/plugin-transform-classes": "^7.28.4", - "@babel/plugin-transform-computed-properties": "^7.27.1", - "@babel/plugin-transform-destructuring": "^7.28.5", - "@babel/plugin-transform-dotall-regex": "^7.27.1", - "@babel/plugin-transform-duplicate-keys": "^7.27.1", - "@babel/plugin-transform-duplicate-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-dynamic-import": "^7.27.1", - "@babel/plugin-transform-explicit-resource-management": "^7.28.0", - "@babel/plugin-transform-exponentiation-operator": "^7.28.5", - "@babel/plugin-transform-export-namespace-from": "^7.27.1", - "@babel/plugin-transform-for-of": "^7.27.1", - "@babel/plugin-transform-function-name": "^7.27.1", - "@babel/plugin-transform-json-strings": "^7.27.1", - "@babel/plugin-transform-literals": "^7.27.1", - "@babel/plugin-transform-logical-assignment-operators": "^7.28.5", - "@babel/plugin-transform-member-expression-literals": "^7.27.1", - "@babel/plugin-transform-modules-amd": "^7.27.1", - "@babel/plugin-transform-modules-commonjs": "^7.27.1", - "@babel/plugin-transform-modules-systemjs": "^7.28.5", - "@babel/plugin-transform-modules-umd": "^7.27.1", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.27.1", - "@babel/plugin-transform-new-target": "^7.27.1", - "@babel/plugin-transform-nullish-coalescing-operator": "^7.27.1", - "@babel/plugin-transform-numeric-separator": "^7.27.1", - "@babel/plugin-transform-object-rest-spread": "^7.28.4", - "@babel/plugin-transform-object-super": "^7.27.1", - "@babel/plugin-transform-optional-catch-binding": "^7.27.1", - "@babel/plugin-transform-optional-chaining": "^7.28.5", - "@babel/plugin-transform-parameters": "^7.27.7", - "@babel/plugin-transform-private-methods": "^7.27.1", - "@babel/plugin-transform-private-property-in-object": "^7.27.1", - "@babel/plugin-transform-property-literals": "^7.27.1", - "@babel/plugin-transform-regenerator": "^7.28.4", - "@babel/plugin-transform-regexp-modifiers": "^7.27.1", - "@babel/plugin-transform-reserved-words": "^7.27.1", - "@babel/plugin-transform-shorthand-properties": "^7.27.1", - "@babel/plugin-transform-spread": "^7.27.1", - "@babel/plugin-transform-sticky-regex": "^7.27.1", - "@babel/plugin-transform-template-literals": "^7.27.1", - "@babel/plugin-transform-typeof-symbol": "^7.27.1", - "@babel/plugin-transform-unicode-escapes": "^7.27.1", - "@babel/plugin-transform-unicode-property-regex": "^7.27.1", - "@babel/plugin-transform-unicode-regex": "^7.27.1", - "@babel/plugin-transform-unicode-sets-regex": "^7.27.1", - "@babel/preset-modules": "0.1.6-no-external-plugins", - "babel-plugin-polyfill-corejs2": "^0.4.14", - "babel-plugin-polyfill-corejs3": "^0.13.0", - "babel-plugin-polyfill-regenerator": "^0.6.5", - "core-js-compat": "^3.43.0", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.6-no-external-plugins", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", - "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/@babel/preset-react": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.28.5.tgz", - "integrity": "sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-plugin-utils": "^7.27.1", - "@babel/helper-validator-option": "^7.27.1", - "@babel/plugin-transform-react-display-name": "^7.28.0", - "@babel/plugin-transform-react-jsx": "^7.27.1", - "@babel/plugin-transform-react-jsx-development": "^7.27.1", - "@babel/plugin-transform-react-pure-annotations": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.4.tgz", - "integrity": "sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", - "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.5", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.5", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.5", - "debug": "^4.3.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", - "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@csstools/color-helpers": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.1.0.tgz", - "integrity": "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - } - }, - "node_modules/@csstools/css-calc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.4.tgz", - "integrity": "sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-color-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.1.0.tgz", - "integrity": "sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "dependencies": { - "@csstools/color-helpers": "^5.1.0", - "@csstools/css-calc": "^2.1.4" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^3.0.5", - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.5.tgz", - "integrity": "sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@csstools/css-tokenizer": "^3.0.4" - } - }, - "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.0.14", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.0.14.tgz", - "integrity": "sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "postcss": "^8.4" - } - }, - "node_modules/@csstools/css-tokenizer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.4.tgz", - "integrity": "sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "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==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", - "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", - "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", - "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "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==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", - "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz", - "integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.1.tgz", - "integrity": "sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - } - }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/node": { - "version": "0.16.7", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.7.tgz", - "integrity": "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "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": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "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": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "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": { - "node": ">=6.0.0" - } - }, - "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": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", - "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.8.tgz", - "integrity": "sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.4.tgz", - "integrity": "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.4" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz", - "integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.3.tgz", - "integrity": "sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.3.tgz", - "integrity": "sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.3.tgz", - "integrity": "sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.3.tgz", - "integrity": "sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.3.tgz", - "integrity": "sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.3.tgz", - "integrity": "sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.3.tgz", - "integrity": "sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.3.tgz", - "integrity": "sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.3.tgz", - "integrity": "sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.3.tgz", - "integrity": "sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.3.tgz", - "integrity": "sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.3.tgz", - "integrity": "sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.3.tgz", - "integrity": "sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.3.tgz", - "integrity": "sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.3.tgz", - "integrity": "sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.3.tgz", - "integrity": "sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.3.tgz", - "integrity": "sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.3.tgz", - "integrity": "sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.3.tgz", - "integrity": "sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.3.tgz", - "integrity": "sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.3.tgz", - "integrity": "sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.3.tgz", - "integrity": "sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@standard-schema/spec": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz", - "integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tailwindcss/node": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.17.tgz", - "integrity": "sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/remapping": "^2.3.4", - "enhanced-resolve": "^5.18.3", - "jiti": "^2.6.1", - "lightningcss": "1.30.2", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.17" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.17.tgz", - "integrity": "sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-arm64": "4.1.17", - "@tailwindcss/oxide-darwin-x64": "4.1.17", - "@tailwindcss/oxide-freebsd-x64": "4.1.17", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.17", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.17", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.17", - "@tailwindcss/oxide-linux-x64-musl": "4.1.17", - "@tailwindcss/oxide-wasm32-wasi": "4.1.17", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.17", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.17" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.17.tgz", - "integrity": "sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.17.tgz", - "integrity": "sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.17.tgz", - "integrity": "sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.17.tgz", - "integrity": "sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.17.tgz", - "integrity": "sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.17.tgz", - "integrity": "sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.17.tgz", - "integrity": "sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.17.tgz", - "integrity": "sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.17.tgz", - "integrity": "sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.17.tgz", - "integrity": "sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.6.0", - "@emnapi/runtime": "^1.6.0", - "@emnapi/wasi-threads": "^1.1.0", - "@napi-rs/wasm-runtime": "^1.0.7", - "@tybys/wasm-util": "^0.10.1", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.17.tgz", - "integrity": "sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.17.tgz", - "integrity": "sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.17.tgz", - "integrity": "sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.1.17", - "@tailwindcss/oxide": "4.1.17", - "tailwindcss": "4.1.17" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" - } - }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@testing-library/jest-dom": { - "version": "6.9.1", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.9.1.tgz", - "integrity": "sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@adobe/css-tools": "^4.4.0", - "aria-query": "^5.0.0", - "css.escape": "^1.5.1", - "dom-accessibility-api": "^0.6.3", - "picocolors": "^1.1.1", - "redent": "^3.0.0" - }, - "engines": { - "node": ">=14", - "npm": ">=6", - "yarn": ">=1" - } - }, - "node_modules/@testing-library/jest-dom/node_modules/dom-accessibility-api": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", - "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@testing-library/react": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.0.tgz", - "integrity": "sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.12.5" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@testing-library/dom": "^10.0.0", - "@types/react": "^18.0.0 || ^19.0.0", - "@types/react-dom": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } - }, - "node_modules/@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", - "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": { - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "node_modules/@types/babel__generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", - "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__template": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", - "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "node_modules/@types/babel__traverse": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", - "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.28.2" - } - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" - } - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/prop-types": { - "version": "15.7.15", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.15.tgz", - "integrity": "sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/@types/react": { - "version": "18.3.27", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", - "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@types/prop-types": "*", - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "18.3.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.7.tgz", - "integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==", - "devOptional": true, - "license": "MIT", - "peerDependencies": { - "@types/react": "^18.0.0" - } - }, - "node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "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/expect": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.15.tgz", - "integrity": "sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.0.15", - "@vitest/utils": "4.0.15", - "chai": "^6.2.1", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.15.tgz", - "integrity": "sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.15.tgz", - "integrity": "sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.0.15", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.15.tgz", - "integrity": "sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.15", - "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.15.tgz", - "integrity": "sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.15.tgz", - "integrity": "sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.0.15", - "tinyrainbow": "^3.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/acorn": { - "version": "8.15.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", - "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "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/agentation": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/agentation/-/agentation-1.3.2.tgz", - "integrity": "sha512-9yZ/3hTcNePr1asnMyipxAZU8nFdBibNfw7wTdLUd3ULTTQCp9QZX7Y5PTMzkYWX4fhqEI2LOjMCb3vkmZga9w==", - "dev": true, - "license": "PolyForm-Shield-1.0.0", - "peerDependencies": { - "react": ">=18.0.0", - "react-dom": ">=18.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "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", - "peer": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/aria-query": { - "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/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.9", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz", - "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.0", - "es-object-atoms": "^1.1.1", - "get-intrinsic": "^1.3.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.14", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.14.tgz", - "integrity": "sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/compat-data": "^7.27.7", - "@babel/helper-define-polyfill-provider": "^0.6.5", - "semver": "^6.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.13.0.tgz", - "integrity": "sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5", - "core-js-compat": "^3.43.0" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.5.tgz", - "integrity": "sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.5" - }, - "peerDependencies": { - "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.9.6", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.6.tgz", - "integrity": "sha512-v9BVVpOTLB59C9E7aSnmIF8h7qRsFpx+A2nugVMTszEOMcfjlZMsXRm4LF23I3Z9AJxc8ANpIvzbzONoX9VJlg==", - "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", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.28.1", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", - "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", - "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": { - "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/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001760", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001760.tgz", - "integrity": "sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==", - "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.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.1.tgz", - "integrity": "sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/class-variance-authority": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", - "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==", - "license": "Apache-2.0", - "dependencies": { - "clsx": "^2.1.1" - }, - "funding": { - "url": "https://polar.sh/cva" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "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/core-js-compat": { - "version": "3.47.0", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.47.0.tgz", - "integrity": "sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "browserslist": "^4.28.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "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": "5.3.4", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.4.tgz", - "integrity": "sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^4.1.0", - "@csstools/css-syntax-patches-for-csstree": "1.0.14", - "css-tree": "^3.1.0" - }, - "engines": { - "node": ">=20" - } - }, - "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==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/data-urls": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.0.tgz", - "integrity": "sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": { - "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/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": ">=6" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.5.267", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz", - "integrity": "sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==", - "dev": true, - "license": "ISC" - }, - "node_modules/enhanced-resolve": { - "version": "5.18.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.3.tgz", - "integrity": "sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-abstract": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", - "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-iterator-helpers": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz", - "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.0.3", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.6", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.4", - "safe-array-concat": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-module-lexer": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", - "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", - "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7", - "is-date-object": "^1.0.5", - "is-symbol": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "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_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": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "9.39.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.1.tgz", - "integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.1", - "@eslint/plugin-kit": "^0.4.1", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react-hooks": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz", - "integrity": "sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.24.4", - "@babel/parser": "^7.24.4", - "hermes-parser": "^0.25.1", - "zod": "^3.25.0 || ^4.0.0", - "zod-validation-error": "^3.5.0 || ^4.0.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" - } - }, - "node_modules/eslint-plugin-react/node_modules/resolve": { - "version": "2.0.0-next.5", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", - "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", - "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/espree": { - "version": "10.4.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", - "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.15.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.2.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/expect-type": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", - "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", - "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "functions-have-names": "^1.2.3", - "hasown": "^2.0.2", - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hermes-estree": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", - "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "dev": true, - "license": "MIT" - }, - "node_modules/hermes-parser": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", - "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hermes-estree": "0.25.1" - } - }, - "node_modules/html-encoding-sniffer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", - "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "whatwg-encoding": "^3.1.1" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", - "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "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": ">=8" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", - "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", - "integrity": "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsdom": { - "version": "27.3.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.3.0.tgz", - "integrity": "sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@acemir/cssom": "^0.9.28", - "@asamuzakjp/dom-selector": "^6.7.6", - "cssstyle": "^5.3.4", - "data-urls": "^6.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^4.0.0", - "http-proxy-agent": "^7.0.2", - "https-proxy-agent": "^7.0.6", - "is-potential-custom-element-name": "^1.0.1", - "parse5": "^8.0.0", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.0", - "whatwg-encoding": "^3.1.1", - "whatwg-mimetype": "^4.0.0", - "whatwg-url": "^15.1.0", - "ws": "^8.18.3", - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "canvas": "^3.0.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "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", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "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": ">=6" - } - }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lightningcss": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.2.tgz", - "integrity": "sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==", - "dev": true, - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "lightningcss-android-arm64": "1.30.2", - "lightningcss-darwin-arm64": "1.30.2", - "lightningcss-darwin-x64": "1.30.2", - "lightningcss-freebsd-x64": "1.30.2", - "lightningcss-linux-arm-gnueabihf": "1.30.2", - "lightningcss-linux-arm64-gnu": "1.30.2", - "lightningcss-linux-arm64-musl": "1.30.2", - "lightningcss-linux-x64-gnu": "1.30.2", - "lightningcss-linux-x64-musl": "1.30.2", - "lightningcss-win32-arm64-msvc": "1.30.2", - "lightningcss-win32-x64-msvc": "1.30.2" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.30.2.tgz", - "integrity": "sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.2.tgz", - "integrity": "sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.2.tgz", - "integrity": "sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.2.tgz", - "integrity": "sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.2.tgz", - "integrity": "sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.2.tgz", - "integrity": "sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.2.tgz", - "integrity": "sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.2.tgz", - "integrity": "sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.2.tgz", - "integrity": "sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.2.tgz", - "integrity": "sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.30.2", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.2.tgz", - "integrity": "sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "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": "ISC", - "dependencies": { - "yallist": "^3.0.2" - } - }, - "node_modules/lucide-react": { - "version": "0.556.0", - "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.556.0.tgz", - "integrity": "sha512-iOb8dRk7kLaYBZhR2VlV1CeJGxChBgUthpSP8wom9jfj79qovgG6qcSdiy6vkoREKPnbUYzJsCn4o4PtG3Iy+A==", - "license": "ISC", - "peerDependencies": { - "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", - "dev": true, - "license": "MIT", - "peer": true, - "bin": { - "lz-string": "bin/bin.js" - } - }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "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.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", - "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/own-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", - "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-intrinsic": "^1.2.6", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse5": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.0.tgz", - "integrity": "sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==", - "dev": true, - "license": "MIT", - "dependencies": { - "entities": "^6.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, - "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" - }, - "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": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", - "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", - "dev": true, - "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.11", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-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", - "peer": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, - "node_modules/prop-types/node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0", - "scheduler": "^0.23.2" - }, - "peerDependencies": { - "react": "^18.3.1" - } - }, - "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", - "peer": true - }, - "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true, - "license": "MIT" - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.2.tgz", - "integrity": "sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-6.4.0.tgz", - "integrity": "sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.2.2", - "regjsgen": "^0.8.0", - "regjsparser": "^0.13.0", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.2.1" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.8.0.tgz", - "integrity": "sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/regjsparser": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.13.0.tgz", - "integrity": "sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "jsesc": "~3.1.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "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", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.11", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.11.tgz", - "integrity": "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==", - "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" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/rollup": { - "version": "4.53.3", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.3.tgz", - "integrity": "sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.8" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.53.3", - "@rollup/rollup-android-arm64": "4.53.3", - "@rollup/rollup-darwin-arm64": "4.53.3", - "@rollup/rollup-darwin-x64": "4.53.3", - "@rollup/rollup-freebsd-arm64": "4.53.3", - "@rollup/rollup-freebsd-x64": "4.53.3", - "@rollup/rollup-linux-arm-gnueabihf": "4.53.3", - "@rollup/rollup-linux-arm-musleabihf": "4.53.3", - "@rollup/rollup-linux-arm64-gnu": "4.53.3", - "@rollup/rollup-linux-arm64-musl": "4.53.3", - "@rollup/rollup-linux-loong64-gnu": "4.53.3", - "@rollup/rollup-linux-ppc64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-gnu": "4.53.3", - "@rollup/rollup-linux-riscv64-musl": "4.53.3", - "@rollup/rollup-linux-s390x-gnu": "4.53.3", - "@rollup/rollup-linux-x64-gnu": "4.53.3", - "@rollup/rollup-linux-x64-musl": "4.53.3", - "@rollup/rollup-openharmony-arm64": "4.53.3", - "@rollup/rollup-win32-arm64-msvc": "4.53.3", - "@rollup/rollup-win32-ia32-msvc": "4.53.3", - "@rollup/rollup-win32-x64-gnu": "4.53.3", - "@rollup/rollup-win32-x64-msvc": "4.53.3", - "fsevents": "~2.3.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", - "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", - "dev": true, - "license": "ISC", - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=v12.22.7" - } - }, - "node_modules/scheduler": { - "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", - "license": "MIT", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, - "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": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/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": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "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": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "dev": true, - "license": "MIT" - }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/string.prototype.matchall": { - "version": "4.0.12", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz", - "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.6", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.3", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", - "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-object-atoms": "^1.0.0", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", - "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.2", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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", - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tailwind-merge": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz", - "integrity": "sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/dcastil" - } - }, - "node_modules/tailwindcss": { - "version": "4.1.17", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.17.tgz", - "integrity": "sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", - "integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.2.tgz", - "integrity": "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyrainbow": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.0.3.tgz", - "integrity": "sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tldts": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.0.19.tgz", - "integrity": "sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==", - "dev": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.0.19" - }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.0.19", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.0.19.tgz", - "integrity": "sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==", - "dev": true, - "license": "MIT" - }, - "node_modules/tough-cookie": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.0.tgz", - "integrity": "sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, - "engines": { - "node": ">=16" - } - }, - "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": { - "punycode": "^2.3.1" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/tw-animate-css": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/tw-animate-css/-/tw-animate-css-1.4.0.tgz", - "integrity": "sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Wombosvideo" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", - "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.9" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", - "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0", - "reflect.getprototypeof": "^1.0.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz", - "integrity": "sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.1.tgz", - "integrity": "sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.2.0.tgz", - "integrity": "sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/update-browserslist-db": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.2.tgz", - "integrity": "sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==", - "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" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/vite": { - "version": "5.4.21", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.21.tgz", - "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==", - "dev": true, - "license": "MIT", - "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" - }, - "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 - } - } - }, - "node_modules/vitest": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.15.tgz", - "integrity": "sha512-n1RxDp8UJm6N0IbJLQo+yzLZ2sQCDyl1o0LeugbPWf8+8Fttp29GghsQBjYJVmWq3gBFfe9Hs1spR44vovn2wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "4.0.15", - "@vitest/mocker": "4.0.15", - "@vitest/pretty-format": "4.0.15", - "@vitest/runner": "4.0.15", - "@vitest/snapshot": "4.0.15", - "@vitest/spy": "4.0.15", - "@vitest/utils": "4.0.15", - "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.15", - "@vitest/browser-preview": "4.0.15", - "@vitest/browser-webdriverio": "4.0.15", - "@vitest/ui": "4.0.15", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@opentelemetry/api": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser-playwright": { - "optional": true - }, - "@vitest/browser-preview": { - "optional": true - }, - "@vitest/browser-webdriverio": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", - "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", - "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", - "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/android-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", - "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", - "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/darwin-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", - "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", - "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", - "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", - "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", - "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", - "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-loong64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", - "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", - "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", - "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", - "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-s390x": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", - "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/linux-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", - "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", - "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", - "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/sunos-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", - "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-arm64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", - "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-ia32": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", - "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@esbuild/win32-x64": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", - "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/vitest/node_modules/@vitest/mocker": { - "version": "4.0.15", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.15.tgz", - "integrity": "sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "4.0.15", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0-0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/vitest/node_modules/esbuild": { - "version": "0.25.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", - "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.12", - "@esbuild/android-arm": "0.25.12", - "@esbuild/android-arm64": "0.25.12", - "@esbuild/android-x64": "0.25.12", - "@esbuild/darwin-arm64": "0.25.12", - "@esbuild/darwin-x64": "0.25.12", - "@esbuild/freebsd-arm64": "0.25.12", - "@esbuild/freebsd-x64": "0.25.12", - "@esbuild/linux-arm": "0.25.12", - "@esbuild/linux-arm64": "0.25.12", - "@esbuild/linux-ia32": "0.25.12", - "@esbuild/linux-loong64": "0.25.12", - "@esbuild/linux-mips64el": "0.25.12", - "@esbuild/linux-ppc64": "0.25.12", - "@esbuild/linux-riscv64": "0.25.12", - "@esbuild/linux-s390x": "0.25.12", - "@esbuild/linux-x64": "0.25.12", - "@esbuild/netbsd-arm64": "0.25.12", - "@esbuild/netbsd-x64": "0.25.12", - "@esbuild/openbsd-arm64": "0.25.12", - "@esbuild/openbsd-x64": "0.25.12", - "@esbuild/openharmony-arm64": "0.25.12", - "@esbuild/sunos-x64": "0.25.12", - "@esbuild/win32-arm64": "0.25.12", - "@esbuild/win32-ia32": "0.25.12", - "@esbuild/win32-x64": "0.25.12" - } - }, - "node_modules/vitest/node_modules/vite": { - "version": "7.2.7", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.2.7.tgz", - "integrity": "sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.5.0", - "picomatch": "^4.0.3", - "postcss": "^8.5.6", - "rollup": "^4.43.0", - "tinyglobby": "^0.2.15" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^20.19.0 || >=22.12.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "lightningcss": "^1.21.0", - "sass": "^1.70.0", - "sass-embedded": "^1.70.0", - "stylus": ">=0.54.8", - "sugarss": "^5.0.0", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "xml-name-validator": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/webidl-conversions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.0.tgz", - "integrity": "sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" - } - }, - "node_modules/whatwg-encoding": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", - "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "iconv-lite": "0.6.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-mimetype": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", - "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/whatwg-url": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", - "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.19", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", - "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true, - "license": "MIT" - }, - "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/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.1.13.tgz", - "integrity": "sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-validation-error": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/zod-validation-error/-/zod-validation-error-4.0.2.tgz", - "integrity": "sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - } - } - } -} diff --git a/package.json b/package.json index 6debd44..8e00092 100644 --- a/package.json +++ b/package.json @@ -1,43 +1,35 @@ { - "name": "drum-machine", + "name": "loop-machine", "version": "1.0.0", "type": "module", "scripts": { "dev": "vite --port 3000", "build": "vite build", "preview": "vite preview", + "typecheck": "tsc --noEmit", "lint": "eslint src", "test": "vitest run", "test:watch": "vitest" }, "dependencies": { - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-slot": "^1.2.4", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "lucide-react": "^0.556.0", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "tailwind-merge": "^3.4.0" + "react": "^19.3.0", + "react-dom": "^19.3.0" }, "devDependencies": { - "@babel/preset-env": "^7.28.5", - "@babel/preset-react": "^7.28.5", "@eslint/js": "^9.39.1", - "@tailwindcss/vite": "^4.1.17", "@testing-library/jest-dom": "^6.9.1", "@testing-library/react": "^16.3.0", - "@types/react": "^18.2.0", - "@types/react-dom": "^18.2.0", - "@vitejs/plugin-react": "^4.2.0", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@vitejs/plugin-react": "^5.2.0", "agentation": "^1.3.2", "eslint": "^9.39.1", "eslint-plugin-react": "^7.37.5", - "eslint-plugin-react-hooks": "^7.0.1", + "eslint-plugin-react-hooks": "^7.1.1", "jsdom": "^27.3.0", - "tailwindcss": "^4.1.17", - "tw-animate-css": "^1.4.0", - "vite": "^5.0.0", + "typescript": "^6.0.3", + "typescript-eslint": "^8.71.0", + "vite": "^7.2.7", "vitest": "^4.0.15" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 81aedde..751b23e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,61 +8,34 @@ importers: .: dependencies: - '@radix-ui/react-label': - specifier: ^2.1.8 - version: 2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': - specifier: ^1.2.4 - version: 1.2.4(@types/react@18.3.27)(react@18.3.1) - class-variance-authority: - specifier: ^0.7.1 - version: 0.7.1 - clsx: - specifier: ^2.1.1 - version: 2.1.1 - lucide-react: - specifier: ^0.556.0 - version: 0.556.0(react@18.3.1) react: - specifier: ^18.2.0 - version: 18.3.1 + specifier: ^19.3.0 + version: 19.3.0 react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - tailwind-merge: - specifier: ^3.4.0 - version: 3.4.0 + specifier: ^19.3.0 + version: 19.3.0(react@19.3.0) devDependencies: - '@babel/preset-env': - specifier: ^7.28.5 - version: 7.28.5(@babel/core@7.28.5) - '@babel/preset-react': - specifier: ^7.28.5 - version: 7.28.5(@babel/core@7.28.5) '@eslint/js': specifier: ^9.39.1 version: 9.39.1 - '@tailwindcss/vite': - specifier: ^4.1.17 - version: 4.1.17(vite@5.4.21(@types/node@24.10.2)(lightningcss@1.30.2)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 '@testing-library/react': specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@types/react': - specifier: ^18.2.0 - version: 18.3.27 + specifier: ^19.3.0 + version: 19.3.0 '@types/react-dom': - specifier: ^18.2.0 - version: 18.3.7(@types/react@18.3.27) + specifier: ^19.3.0 + version: 19.3.0(@types/react@19.3.0) '@vitejs/plugin-react': - specifier: ^4.2.0 - version: 4.7.0(vite@5.4.21(@types/node@24.10.2)(lightningcss@1.30.2)) + specifier: ^5.2.0 + version: 5.2.0(vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2)) agentation: specifier: ^1.3.2 - version: 1.3.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 1.3.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0) eslint: specifier: ^9.39.1 version: 9.39.1(jiti@2.6.1) @@ -70,20 +43,20 @@ importers: specifier: ^7.37.5 version: 7.37.5(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@9.39.1(jiti@2.6.1)) + specifier: ^7.1.1 + version: 7.1.1(eslint@9.39.1(jiti@2.6.1)) jsdom: specifier: ^27.3.0 version: 27.3.0(postcss@8.5.6) - tailwindcss: - specifier: ^4.1.17 - version: 4.1.17 - tw-animate-css: - specifier: ^1.4.0 - version: 1.4.0 + typescript: + specifier: ^6.0.3 + version: 6.0.3 + typescript-eslint: + specifier: ^8.71.0 + version: 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) vite: - specifier: ^5.0.0 - version: 5.4.21(@types/node@24.10.2)(lightningcss@1.30.2) + specifier: ^7.2.7 + version: 7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2) vitest: specifier: ^4.0.15 version: 4.0.15(@types/node@24.10.2)(jiti@2.6.1)(jsdom@27.3.0(postcss@8.5.6))(lightningcss@1.30.2) @@ -109,2526 +82,1842 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.5': resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + '@babel/core@7.28.5': resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.28.5': - resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + '@babel/parser@7.28.5': resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': - resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} + engines: {node: '>=6.0.0'} + hasBin: true - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': - resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} + '@babel/plugin-transform-react-jsx-self@7.27.1': + resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + '@babel/plugin-transform-react-jsx-source@7.27.1': + resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/runtime@7.28.4': + resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.5': - resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@csstools/color-helpers@5.1.0': + resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} + engines: {node: '>=18'} - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} - engines: {node: '>=6.9.0'} + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} - engines: {node: '>=6.9.0'} + '@csstools/css-color-parser@3.1.0': + resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} + engines: {node: '>=18'} peerDependencies: - '@babel/core': ^7.12.0 + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 - '@babel/plugin-transform-classes@7.28.4': - resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} - engines: {node: '>=6.9.0'} + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} peerDependencies: - '@babel/core': ^7.0.0-0 + '@csstools/css-tokenizer': ^3.0.4 - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} - engines: {node: '>=6.9.0'} + '@csstools/css-syntax-patches-for-csstree@1.0.14': + resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} + engines: {node: '>=18'} peerDependencies: - '@babel/core': ^7.0.0-0 + postcss: ^8.4 - '@babel/plugin-transform-destructuring@7.28.5': - resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] - '@babel/plugin-transform-exponentiation-operator@7.28.5': - resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] - '@babel/plugin-transform-logical-assignment-operators@7.28.5': - resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] - '@babel/plugin-transform-modules-systemjs@7.28.5': - resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] - '@babel/plugin-transform-object-rest-spread@7.28.4': - resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] - '@babel/plugin-transform-optional-chaining@7.28.5': - resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} - engines: {node: '>=6.9.0'} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} - engines: {node: '>=6.9.0'} + '@eslint-community/eslint-utils@4.9.0': + resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - '@babel/core': ^7.0.0-0 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/config-array@0.21.1': + resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-react-jsx-development@7.27.1': - resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/eslintrc@3.3.3': + resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/js@9.39.1': + resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-react-pure-annotations@7.27.1': - resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-regenerator@7.28.4': - resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@humanfs/node@0.16.7': + resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + engines: {node: '>=18.18.0'} - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@rollup/rollup-android-arm-eabi@4.53.3': + resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + cpu: [arm] + os: [android] - '@babel/preset-env@7.28.5': - resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@rollup/rollup-android-arm64@4.53.3': + resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + cpu: [arm64] + os: [android] - '@babel/preset-modules@0.1.6-no-external-plugins': - resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 + '@rollup/rollup-darwin-arm64@4.53.3': + resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + cpu: [arm64] + os: [darwin] - '@babel/preset-react@7.28.5': - resolution: {integrity: sha512-Z3J8vhRq7CeLjdC58jLv4lnZ5RKFUJWqH5emvxmv9Hv3BD1T9R/Im713R4MTKwvFaV74ejZ3sM01LyEKk4ugNQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@rollup/rollup-darwin-x64@4.53.3': + resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + cpu: [x64] + os: [darwin] - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} - engines: {node: '>=6.9.0'} + '@rollup/rollup-freebsd-arm64@4.53.3': + resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + cpu: [arm64] + os: [freebsd] - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} + '@rollup/rollup-freebsd-x64@4.53.3': + resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + cpu: [x64] + os: [freebsd] - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} - engines: {node: '>=6.9.0'} + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + cpu: [arm] + os: [linux] - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} - engines: {node: '>=6.9.0'} + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + cpu: [arm] + os: [linux] - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} + '@rollup/rollup-linux-arm64-gnu@4.53.3': + resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + cpu: [arm64] + os: [linux] - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 + '@rollup/rollup-linux-arm64-musl@4.53.3': + resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + cpu: [arm64] + os: [linux] - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-syntax-patches-for-csstree@1.0.14': - resolution: {integrity: sha512-zSlIxa20WvMojjpCSy8WrNpcZ61RqfTfX3XTaOeVlGJrt/8HF3YbzgFZa01yTbT4GWQLwfTcC3EB8i3XnB647Q==} - engines: {node: '>=18'} - peerDependencies: - postcss: ^8.4 - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.21.5': - resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] + '@rollup/rollup-linux-loong64-gnu@4.53.3': + resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + cpu: [loong64] + os: [linux] - '@esbuild/aix-ppc64@0.25.12': - resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} - engines: {node: '>=18'} + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.21.5': - resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] + os: [linux] - '@esbuild/android-arm64@0.25.12': - resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + cpu: [riscv64] + os: [linux] - '@esbuild/android-arm@0.21.5': - resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] + '@rollup/rollup-linux-riscv64-musl@4.53.3': + resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + cpu: [riscv64] + os: [linux] - '@esbuild/android-arm@0.25.12': - resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] + '@rollup/rollup-linux-s390x-gnu@4.53.3': + resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + cpu: [s390x] + os: [linux] - '@esbuild/android-x64@0.21.5': - resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} - engines: {node: '>=12'} + '@rollup/rollup-linux-x64-gnu@4.53.3': + resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] - os: [android] + os: [linux] - '@esbuild/android-x64@0.25.12': - resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} - engines: {node: '>=18'} + '@rollup/rollup-linux-x64-musl@4.53.3': + resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] - os: [android] + os: [linux] - '@esbuild/darwin-arm64@0.21.5': - resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} - engines: {node: '>=12'} + '@rollup/rollup-openharmony-arm64@4.53.3': + resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} cpu: [arm64] - os: [darwin] + os: [openharmony] - '@esbuild/darwin-arm64@0.25.12': - resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} - engines: {node: '>=18'} + '@rollup/rollup-win32-arm64-msvc@4.53.3': + resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} cpu: [arm64] - os: [darwin] + os: [win32] - '@esbuild/darwin-x64@0.21.5': - resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} - engines: {node: '>=12'} + '@rollup/rollup-win32-ia32-msvc@4.53.3': + resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.53.3': + resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} cpu: [x64] - os: [darwin] + os: [win32] - '@esbuild/darwin-x64@0.25.12': - resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} - engines: {node: '>=18'} + '@rollup/rollup-win32-x64-msvc@4.53.3': + resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} cpu: [x64] - os: [darwin] + os: [win32] - '@esbuild/freebsd-arm64@0.21.5': - resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] + '@standard-schema/spec@1.0.0': + resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@esbuild/freebsd-arm64@0.25.12': - resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - '@esbuild/freebsd-x64@0.21.5': - resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - '@esbuild/freebsd-x64@0.25.12': - resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + '@testing-library/react@16.3.0': + resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@esbuild/linux-arm64@0.21.5': - resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@esbuild/linux-arm64@0.25.12': - resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - '@esbuild/linux-arm@0.21.5': - resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - '@esbuild/linux-arm@0.25.12': - resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - '@esbuild/linux-ia32@0.21.5': - resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - '@esbuild/linux-ia32@0.25.12': - resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@esbuild/linux-loong64@0.21.5': - resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@esbuild/linux-loong64@0.25.12': - resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - '@esbuild/linux-mips64el@0.21.5': - resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@esbuild/linux-mips64el@0.25.12': - resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] + '@types/node@24.10.2': + resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==} - '@esbuild/linux-ppc64@0.21.5': - resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} + peerDependencies: + '@types/react': ^19.3.0 - '@esbuild/linux-ppc64@0.25.12': - resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} - '@esbuild/linux-riscv64@0.21.5': - resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] + '@typescript-eslint/eslint-plugin@8.71.0': + resolution: {integrity: sha512-pqcS9c1HxZTHt7End4nXqd0s5lJrrFzrgCkKFJrsbUnaL6M3+6oBFZaslg6Gjsl3argl2DDRFROnXARaZ2e4Nw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.71.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@esbuild/linux-riscv64@0.25.12': - resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] + '@typescript-eslint/parser@8.71.0': + resolution: {integrity: sha512-CG4nPk1f2zc8yw4pALqHsFYH2hdo+h1T9daSp21+Hnxi9LOE3GT9hAfTKJCBXVNM2GmYs1eMEP615wPoeOgk3A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@esbuild/linux-s390x@0.21.5': - resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] + '@typescript-eslint/project-service@8.71.0': + resolution: {integrity: sha512-aABjw5rjBacYONVPaPiWOCjJu0vEF4a25iQuodlmQYL1trtLZ0X/y+2Vzl3BKI1odM4LnwLE1oUDXYp1wzx1TQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@esbuild/linux-s390x@0.25.12': - resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] + '@typescript-eslint/scope-manager@8.71.0': + resolution: {integrity: sha512-gWF0BhUcnjZxSpLE8ngS/59n2SB0J3YqRxvX1+2aoRJk9hNtHSLOV+TcarFiOr5ipXm3yc1QrI4c9YZc8zyCxw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@esbuild/linux-x64@0.21.5': - resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] + '@typescript-eslint/tsconfig-utils@8.71.0': + resolution: {integrity: sha512-Z1UlWHADEK2Mlb9NpWfDeSjqoZ5EyrOv4R3eQpbkzqn/EwaIdOpXXupEA1+0ZIOSJSZZDBHG0BrQyN8zUG6Pwg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@esbuild/linux-x64@0.25.12': - resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] + '@typescript-eslint/type-utils@8.71.0': + resolution: {integrity: sha512-i8uO1qbdxeKgRnS5sCRt6On3/nfo2d2DwQe3Yvjx543zLy7r8ySqRuPPiIIXAhS03U0v5NfAFx+rUgxFzKKwNw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@esbuild/netbsd-arm64@0.25.12': - resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] + '@typescript-eslint/types@8.71.0': + resolution: {integrity: sha512-cJ4OoxPGWvFnBTnSZyaU+qJzGTqPTGJY+gDchj6cRyLRdmIdt4rcsE4twj+zPfrNiWuVi38wijHzShL++Z9atQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@esbuild/netbsd-x64@0.21.5': - resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] + '@typescript-eslint/typescript-estree@8.71.0': + resolution: {integrity: sha512-PEEF4G5sLLWAS5BpPrUvms4ySZkiBQQZM4z+3ReI46axK5Vqr/vXBQatJQIZZOYdGyPUAKTtsrWzpqKuU+3DEw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@esbuild/netbsd-x64@0.25.12': - resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] + '@typescript-eslint/utils@8.71.0': + resolution: {integrity: sha512-pKR/tEMVrXZG23UFKUn5BQf3zfmfk7KQceI2cGzywZ5nxM5Eu3hEJU1utjWzydtzBbcJAQhHN8iPCxobHpPcZQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@esbuild/openbsd-arm64@0.25.12': - resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] + '@typescript-eslint/visitor-keys@8.71.0': + resolution: {integrity: sha512-8eQ9R218XORK+KLosnf4bu/QsUXvUyVwTbArg7/0NMB1Pu87OJKvj4nhFblkYE8gQV73mW1dx1ptlPCkwRGa7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@esbuild/openbsd-x64@0.21.5': - resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - '@esbuild/openbsd-x64@0.25.12': - resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] + '@vitest/expect@4.0.15': + resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} - '@esbuild/openharmony-arm64@0.25.12': - resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] + '@vitest/mocker@4.0.15': + resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true - '@esbuild/sunos-x64@0.21.5': - resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] + '@vitest/pretty-format@4.0.15': + resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} - '@esbuild/sunos-x64@0.25.12': - resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] + '@vitest/runner@4.0.15': + resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} - '@esbuild/win32-arm64@0.21.5': - resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] + '@vitest/snapshot@4.0.15': + resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} - '@esbuild/win32-arm64@0.25.12': - resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] + '@vitest/spy@4.0.15': + resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} - '@esbuild/win32-ia32@0.21.5': - resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] + '@vitest/utils@4.0.15': + resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} - '@esbuild/win32-ia32@0.25.12': - resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - '@esbuild/win32-x64@0.21.5': - resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true - '@esbuild/win32-x64@0.25.12': - resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + agentation@1.3.2: + resolution: {integrity: sha512-9yZ/3hTcNePr1asnMyipxAZU8nFdBibNfw7wTdLUd3ULTTQCp9QZX7Y5PTMzkYWX4fhqEI2LOjMCb3vkmZga9w==} peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + react: '>=18.0.0' + react-dom: '>=18.0.0' - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} - '@eslint/js@9.39.1': - resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + engines: {node: '>= 0.4'} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} - '@radix-ui/react-label@2.1.8': - resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - '@radix-ui/react-primitive@2.1.4': - resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + baseline-browser-mapping@2.9.5: + resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} + hasBin: true - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} - cpu: [arm] - os: [android] + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} - cpu: [arm64] - os: [android] + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 20 || >=22} - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} - cpu: [arm64] - os: [darwin] + browserslist@4.28.1: + resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} - cpu: [x64] - os: [darwin] + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} - cpu: [arm64] - os: [freebsd] + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + engines: {node: '>= 0.4'} - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} - cpu: [arm] - os: [linux] + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} - cpu: [arm] - os: [linux] + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} - cpu: [arm64] - os: [linux] + caniuse-lite@1.0.30001760: + resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} - cpu: [arm64] - os: [linux] + chai@6.2.1: + resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + engines: {node: '>=18'} - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} - cpu: [loong64] - os: [linux] + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} - cpu: [ppc64] - os: [linux] + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} - cpu: [riscv64] - os: [linux] + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} - cpu: [riscv64] - os: [linux] + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} - cpu: [s390x] - os: [linux] + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} - cpu: [x64] - os: [linux] + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} - cpu: [x64] - os: [linux] + css-tree@3.1.0: + resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} - cpu: [arm64] - os: [openharmony] + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} - cpu: [arm64] - os: [win32] + cssstyle@5.3.4: + resolution: {integrity: sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==} + engines: {node: '>=20'} - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} - cpu: [ia32] - os: [win32] + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} - cpu: [x64] - os: [win32] + data-urls@6.0.0: + resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} + engines: {node: '>=20'} - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} - cpu: [x64] - os: [win32] + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + engines: {node: '>= 0.4'} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} - '@tailwindcss/node@4.1.17': - resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + engines: {node: '>= 0.4'} - '@tailwindcss/oxide-android-arm64@4.1.17': - resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.17': - resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - '@tailwindcss/oxide-darwin-x64@4.1.17': - resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - '@tailwindcss/oxide-freebsd-x64@4.1.17': - resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': - resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + engines: {node: '>= 0.4'} - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': - resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': - resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': - resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} - '@tailwindcss/oxide-linux-x64-musl@4.1.17': - resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - '@tailwindcss/oxide-wasm32-wasi@4.1.17': - resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': - resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': - resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} - '@tailwindcss/oxide@4.1.17': - resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} - engines: {node: '>= 10'} + electron-to-chromium@1.5.267: + resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} - '@tailwindcss/vite@4.1.17': - resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} - '@testing-library/jest-dom@6.9.1': - resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} - '@testing-library/react@16.3.0': - resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} - engines: {node: '>=18'} - peerDependencies: - '@testing-library/dom': ^10.0.0 - '@types/react': ^18.0.0 || ^19.0.0 - '@types/react-dom': ^18.0.0 || ^19.0.0 - react: ^18.0.0 || ^19.0.0 - react-dom: ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} - '@types/node@24.10.2': - resolution: {integrity: sha512-WOhQTZ4G8xZ1tjJTvKOpyEVSGgOTvJAfDK3FNFgELyaTpzhdgHVHeqW8V+UJvzF5BT+/B54T/1S2K6gd9c7bbA==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} peerDependencies: - '@types/react': ^18.0.0 + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - '@types/react@18.3.27': - resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - '@vitest/expect@4.0.15': - resolution: {integrity: sha512-Gfyva9/GxPAWXIWjyGDli9O+waHDC0Q0jaLdFP1qPAUUfo1FEXPXUfUkp3eZA0sSq340vPycSyOlYUeM15Ft1w==} + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/mocker@4.0.15': - resolution: {integrity: sha512-CZ28GLfOEIFkvCFngN8Sfx5h+Se0zN+h4B7yOsPVCcgtiO7t5jt9xQh2E1UkFep+eb9fjyMfuC5gBypwb07fvQ==} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.1: + resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true peerDependencies: - msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + jiti: '*' peerDependenciesMeta: - msw: - optional: true - vite: + jiti: optional: true - '@vitest/pretty-format@4.0.15': - resolution: {integrity: sha512-SWdqR8vEv83WtZcrfLNqlqeQXlQLh2iilO1Wk1gv4eiHKjEzvgHb2OVc3mIPyhZE6F+CtfYjNlDJwP5MN6Km7A==} + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vitest/runner@4.0.15': - resolution: {integrity: sha512-+A+yMY8dGixUhHmNdPUxOh0la6uVzun86vAbuMT3hIDxMrAOmn5ILBHm8ajrqHE0t8R9T1dGnde1A5DTnmi3qw==} + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} - '@vitest/snapshot@4.0.15': - resolution: {integrity: sha512-A7Ob8EdFZJIBjLjeO0DZF4lqR6U7Ydi5/5LIZ0xcI+23lYlsYJAfGn8PrIWTYdZQRNnSRlzhg0zyGu37mVdy5g==} + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} - '@vitest/spy@4.0.15': - resolution: {integrity: sha512-+EIjOJmnY6mIfdXtE/bnozKEvTC4Uczg19yeZ2vtCz5Yyb0QQ31QWVQ8hswJ3Ysx/K2EqaNsVanjr//2+P3FHw==} + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} - '@vitest/utils@4.0.15': - resolution: {integrity: sha512-HXjPW2w5dxhTD0dLwtYHDnelK3j8sR8cWIaLxr22evTyY6q8pRCjZSmhRWVjBaOVXChQd6AwMzi9pucorXCPZA==} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true + expect-type@1.3.0: + resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} + engines: {node: '>=12.0.0'} - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - agentation@1.3.2: - resolution: {integrity: sha512-9yZ/3hTcNePr1asnMyipxAZU8nFdBibNfw7wTdLUd3ULTTQCp9QZX7Y5PTMzkYWX4fhqEI2LOjMCb3vkmZga9w==} - peerDependencies: - react: '>=18.0.0' - react-dom: '>=18.0.0' + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} engines: {node: '>= 0.4'} - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} engines: {node: '>= 0.4'} - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + generator-function@2.0.1: + resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} - baseline-browser-mapping@2.9.5: - resolution: {integrity: sha512-D5vIoztZOq1XM54LUdttJVc96ggEsIfju2JBvht06pSzpckp3C7HReun67Bghzrtdsq9XdMGbSSB3v3GhMNmAA==} - hasBin: true + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - caniuse-lite@1.0.30001760: - resolution: {integrity: sha512-7AAMPcueWELt1p3mi13HR/LHH0TJLT11cnwDJEs3xA4+CK/PLKeO9Kl1oru24htkyUKtkGCvAx4ohB0Ttry8Dw==} + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} - class-variance-authority@0.7.1: - resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + ignore@7.0.12: + resolution: {integrity: sha512-/8UvqAPU9DGTI9k4mxtf49U37Isfwr8Uts96+SBHIkFxPJnHS0Ew4f00sM4Scd8V8EjM0jUNtVDdv1kPdt35lg==} + engines: {node: '>= 4'} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} - cssstyle@5.3.4: - resolution: {integrity: sha512-KyOS/kJMEq5O9GdPnaf82noigg5X5DYn0kZPJTaAsCUaBizp6Xa1y9D4Qoqf/JazEXWuruErHgVXwjN5391ZJw==} - engines: {node: '>=20'} + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} - data-urls@6.0.0: - resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} - engines: {node: '>=20'} + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} engines: {node: '>= 0.4'} - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} + is-generator-function@1.1.2: + resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} engines: {node: '>= 0.4'} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dom-accessibility-api@0.6.3: - resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} engines: {node: '>= 0.4'} - electron-to-chromium@1.5.267: - resolution: {integrity: sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw==} + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} - engines: {node: '>=10.13.0'} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} engines: {node: '>= 0.4'} - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} engines: {node: '>= 0.4'} - esbuild@0.21.5: - resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} - engines: {node: '>=12'} - hasBin: true - - esbuild@0.25.12: - resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + hasBin: true - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - eslint@9.39.1: - resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + + jsdom@27.3.0: + resolution: {integrity: sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} peerDependencies: - jiti: '*' + canvas: ^3.0.0 peerDependenciesMeta: - jiti: + canvas: optional: true - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] os: [darwin] - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} - engines: {node: '>= 0.4'} + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] - generator-function@2.0.1: - resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} - engines: {node: '>= 0.4'} + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + lru-cache@11.2.4: + resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} + engines: {node: 20 || >=22} - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} + mdn-data@2.12.2: + resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} engines: {node: '>= 0.4'} - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} engines: {node: '>= 0.4'} - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} engines: {node: '>= 0.4'} - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} + obug@2.1.1: + resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} - engines: {node: '>= 0.4'} + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} - is-generator-function@1.1.2: - resolution: {integrity: sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==} - engines: {node: '>= 0.4'} + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + parse5@8.0.0: + resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.3.0: + resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} + peerDependencies: + react: ^19.3.0 + + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.3.0: + resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==} + engines: {node: '>=0.10.0'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} + hasBin: true - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} - jsdom@27.3.0: - resolution: {integrity: sha512-GtldT42B8+jefDUC4yUKAvsaOrH7PDHmZxZXNgF2xMmymjUbRYJvpAybZAKEmXDGTM0mCsz8duOa4vTm5AY2Kg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} hasBin: true - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} + engines: {node: '>= 0.4'} - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} + engines: {node: '>= 0.4'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lru-cache@11.2.4: - resolution: {integrity: sha512-B5Y16Jr9LB9dHVkh6ZevG+vAbOsNOYCX+sXvFWFu7B3Iz5mijW3zdbMyhsh8ANd2mSWBYdJgnqi+mL7/LrOPYg==} - engines: {node: 20 || >=22} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lucide-react@0.556.0: - resolution: {integrity: sha512-iOb8dRk7kLaYBZhR2VlV1CeJGxChBgUthpSP8wom9jfj79qovgG6qcSdiy6vkoREKPnbUYzJsCn4o4PtG3Iy+A==} - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} - - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} engines: {node: '>= 0.4'} - object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} engines: {node: '>= 0.4'} - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} engines: {node: '>= 0.4'} - obug@2.1.1: - resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + tinyexec@1.0.2: + resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + engines: {node: '>=18'} - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + engines: {node: '>=14.0.0'} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 + tldts-core@7.0.19: + resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + tldts@7.0.19: + resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} + hasBin: true - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + tough-cookie@6.0.0: + resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + engines: {node: '>=16'} - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} - regenerate-unicode-properties@10.2.2: - resolution: {integrity: sha512-m03P+zhBeQd1RGnYxrGyDAPpWX/epKirLrp8e3qevZdVkKtnCrjjWczIbYc8+xd6vcTStVlqfycTx1KR4LOr0g==} - engines: {node: '>=4'} - - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} engines: {node: '>= 0.4'} - regexpu-core@6.4.0: - resolution: {integrity: sha512-0ghuzq67LI9bLXpOX/ISfve/Mq33a4aFRzoQYhnnok1JOFpmE/A2TBGkNVenOGEeSBCjIiWcc6MVOG5HEQv0sA==} - engines: {node: '>=4'} + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + typescript-eslint@8.71.0: + resolution: {integrity: sha512-fBdHYiqQ14RW6mOMXD14Svn82ZsCYAoQSzGRzyEjR59S5A2Krh/l7fGTOQ7iCr8gGy/mHVXtEF7s5fgjEdV0Pw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - regjsparser@0.13.0: - resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} hasBin: true - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} + update-browserslist-db@1.2.2: + resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} hasBin: true - - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} - - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} - - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} - engines: {node: '>= 0.4'} - - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} - - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} - - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - - tailwindcss@4.1.17: - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} - engines: {node: '>=18'} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} - engines: {node: '>=14.0.0'} - - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - - tldts@7.0.19: - resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} - hasBin: true - - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} - engines: {node: '>=16'} - - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - - tw-animate-css@1.4.0: - resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} - engines: {node: '>= 0.4'} - - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} - engines: {node: '>= 0.4'} - - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} - - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} - engines: {node: '>= 0.4'} - - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} - - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} - - unicode-match-property-value-ecmascript@2.2.1: - resolution: {integrity: sha512-JQ84qTuMg4nVkx8ga4A16a1epI9H6uTXAknqxkGF/aFfRLw1xC/Bp24HNLaZhHSkWd3+84t8iXnp1J0kYcZHhg==} - engines: {node: '>=4'} - - unicode-property-aliases-ecmascript@2.2.0: - resolution: {integrity: sha512-hpbDzxUY9BFwX+UeBnxv3Sh1q7HFxj48DTmXchNgRa46lO8uj3/1iEn3MiNUYTg1g9ctIqXCCERn8gYZhHC5lQ==} - engines: {node: '>=4'} - - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + peerDependencies: + browserslist: '>= 4.21.0' uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite@5.4.21: - resolution: {integrity: sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - 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 - vite@7.2.7: resolution: {integrity: sha512-ITcnkFeR3+fI8P1wMgItjGrR10170d8auB4EpMLPqmx6uxElH3a/hHGQabSHKdqd4FXWO1nFIp9rRn7JQ34ACQ==} engines: {node: ^20.19.0 || >=22.12.0} @@ -2762,740 +2051,221 @@ packages: peerDependenciesMeta: bufferutil: optional: true - utf-8-validate: - optional: true - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - -snapshots: - - '@acemir/cssom@0.9.29': {} - - '@adobe/css-tools@4.4.4': {} - - '@asamuzakjp/css-color@4.1.0': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 11.2.4 - - '@asamuzakjp/dom-selector@6.7.6': - dependencies: - '@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.4 - - '@asamuzakjp/nwsapi@2.3.9': {} - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.5': {} - - '@babel/core@7.28.5': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.4.0 - semver: 6.3.1 - - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.3 - lodash.debounce: 4.0.8 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-member-expression-to-functions@7.28.5': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.5 - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helper-wrap-function@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/helpers@7.28.4': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - - '@babel/parser@7.28.5': - dependencies: - '@babel/types': 7.28.5 - - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 - - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color + utf-8-validate: + optional: true - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 - '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 +snapshots: - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + '@acemir/cssom@0.9.29': {} - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color + '@adobe/css-tools@4.4.4': {} - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': + '@asamuzakjp/css-color@4.1.0': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 11.2.4 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': + '@asamuzakjp/dom-selector@6.7.6': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.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.4 - '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@asamuzakjp/nwsapi@2.3.9': {} - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + '@babel/code-frame@7.27.1': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + '@babel/code-frame@7.29.7': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/compat-data@7.28.5': {} + + '@babel/compat-data@7.29.7': {} - '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + '@babel/core@7.28.5': dependencies: - '@babel/core': 7.28.5 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': + '@babel/generator@7.28.5': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + '@babel/generator@7.29.8': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.1 + lru-cache: 5.1.1 + semver: 6.3.1 - '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-globals@7.28.0': {} - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-globals@7.29.7': {} - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-imports@7.29.7': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': dependencies: '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/types': 7.28.5 + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-plugin-utils@7.27.1': {} - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-string-parser@7.27.1': {} - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-string-parser@7.29.7': {} - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option@7.27.1': {} - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option@7.29.7': {} - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': + '@babel/helpers@7.28.4': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': + '@babel/parser@7.28.5': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.5 - '@babel/preset-env@7.28.5(@babel/core@7.28.5)': + '@babel/parser@7.29.9': dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@babel/types': 7.29.8 - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.5 - esutils: 2.0.3 - '@babel/preset-react@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.29.7)': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.7 '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color '@babel/runtime@7.28.4': {} @@ -3505,6 +2275,12 @@ snapshots: '@babel/parser': 7.28.5 '@babel/types': 7.28.5 + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + '@babel/traverse@7.28.5': dependencies: '@babel/code-frame': 7.27.1 @@ -3517,11 +2293,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.5': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@csstools/color-helpers@5.1.0': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -3546,153 +2339,89 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@esbuild/aix-ppc64@0.21.5': - optional: true - '@esbuild/aix-ppc64@0.25.12': optional: true - '@esbuild/android-arm64@0.21.5': - optional: true - '@esbuild/android-arm64@0.25.12': optional: true - '@esbuild/android-arm@0.21.5': - optional: true - '@esbuild/android-arm@0.25.12': optional: true - '@esbuild/android-x64@0.21.5': - optional: true - '@esbuild/android-x64@0.25.12': optional: true - '@esbuild/darwin-arm64@0.21.5': - optional: true - '@esbuild/darwin-arm64@0.25.12': optional: true - '@esbuild/darwin-x64@0.21.5': - optional: true - '@esbuild/darwin-x64@0.25.12': optional: true - '@esbuild/freebsd-arm64@0.21.5': - optional: true - '@esbuild/freebsd-arm64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.21.5': - optional: true - '@esbuild/freebsd-x64@0.25.12': optional: true - '@esbuild/linux-arm64@0.21.5': - optional: true - '@esbuild/linux-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.21.5': - optional: true - '@esbuild/linux-arm@0.25.12': optional: true - '@esbuild/linux-ia32@0.21.5': - optional: true - '@esbuild/linux-ia32@0.25.12': optional: true - '@esbuild/linux-loong64@0.21.5': - optional: true - '@esbuild/linux-loong64@0.25.12': optional: true - '@esbuild/linux-mips64el@0.21.5': - optional: true - '@esbuild/linux-mips64el@0.25.12': optional: true - '@esbuild/linux-ppc64@0.21.5': - optional: true - '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/linux-riscv64@0.21.5': - optional: true - '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/linux-s390x@0.21.5': - optional: true - '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/linux-x64@0.21.5': - optional: true - '@esbuild/linux-x64@0.25.12': optional: true '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/netbsd-x64@0.21.5': - optional: true - '@esbuild/netbsd-x64@0.25.12': optional: true '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/openbsd-x64@0.21.5': - optional: true - '@esbuild/openbsd-x64@0.25.12': optional: true '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/sunos-x64@0.21.5': - optional: true - '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/win32-arm64@0.21.5': - optional: true - '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/win32-ia32@0.21.5': - optional: true - '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-x64@0.21.5': - optional: true - '@esbuild/win32-x64@0.25.12': optional: true + '@eslint-community/eslint-utils@4.10.1(eslint@9.39.1(jiti@2.6.1))': + dependencies: + eslint: 9.39.1(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': dependencies: eslint: 9.39.1(jiti@2.6.1) @@ -3769,38 +2498,7 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.27)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.27 - - '@radix-ui/react-label@2.1.8(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-primitive@2.1.4(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@18.3.27)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) - - '@radix-ui/react-slot@1.2.4(@types/react@18.3.27)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.27)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 18.3.27 - - '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.0-rc.3': {} '@rollup/rollup-android-arm-eabi@4.53.3': optional: true @@ -3870,77 +2568,9 @@ snapshots: '@standard-schema/spec@1.0.0': {} - '@tailwindcss/node@4.1.17': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.17 - - '@tailwindcss/oxide-android-arm64@4.1.17': - optional: true - - '@tailwindcss/oxide-darwin-arm64@4.1.17': - optional: true - - '@tailwindcss/oxide-darwin-x64@4.1.17': - optional: true - - '@tailwindcss/oxide-freebsd-x64@4.1.17': - optional: true - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': - optional: true - - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.17': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.17': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': - optional: true - - '@tailwindcss/oxide@4.1.17': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-x64': 4.1.17 - '@tailwindcss/oxide-freebsd-x64': 4.1.17 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-x64-musl': 4.1.17 - '@tailwindcss/oxide-wasm32-wasi': 4.1.17 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - - '@tailwindcss/vite@4.1.17(vite@5.4.21(@types/node@24.10.2)(lightningcss@1.30.2))': - dependencies: - '@tailwindcss/node': 4.1.17 - '@tailwindcss/oxide': 4.1.17 - tailwindcss: 4.1.17 - vite: 5.4.21(@types/node@24.10.2)(lightningcss@1.30.2) - '@testing-library/dom@10.4.1': dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.7 '@babel/runtime': 7.28.4 '@types/aria-query': 5.0.4 aria-query: 5.3.0 @@ -3958,15 +2588,15 @@ snapshots: picocolors: 1.1.1 redent: 3.0.0 - '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@18.3.7(@types/react@18.3.27))(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: '@babel/runtime': 7.28.4 '@testing-library/dom': 10.4.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 18.3.27 - '@types/react-dom': 18.3.7(@types/react@18.3.27) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) '@types/aria-query@5.0.4': {} @@ -4007,26 +2637,114 @@ snapshots: undici-types: 7.16.0 optional: true - '@types/prop-types@15.7.15': {} - - '@types/react-dom@18.3.7(@types/react@18.3.27)': + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: - '@types/react': 18.3.27 + '@types/react': 19.3.0 - '@types/react@18.3.27': + '@types/react@19.3.0': dependencies: - '@types/prop-types': 15.7.15 csstype: 3.2.3 - '@vitejs/plugin-react@4.7.0(vite@5.4.21(@types/node@24.10.2)(lightningcss@1.30.2))': + '@typescript-eslint/eslint-plugin@8.71.0(@typescript-eslint/parser@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.27 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/type-utils': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.0 + eslint: 9.39.1(jiti@2.6.1) + ignore: 7.0.12 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.71.0 + debug: 4.4.3 + eslint: 9.39.1(jiti@2.6.1) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.71.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.71.0(typescript@6.0.3) + '@typescript-eslint/types': 8.71.0 + debug: 4.4.3 + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.71.0': + dependencies: + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/visitor-keys': 8.71.0 + + '@typescript-eslint/tsconfig-utils@8.71.0(typescript@6.0.3)': + dependencies: + typescript: 6.0.3 + + '@typescript-eslint/type-utils@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3)': + dependencies: + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + debug: 4.4.3 + eslint: 9.39.1(jiti@2.6.1) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.71.0': {} + + '@typescript-eslint/typescript-estree@8.71.0(typescript@6.0.3)': + dependencies: + '@typescript-eslint/project-service': 8.71.0(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.71.0(typescript@6.0.3) + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/visitor-keys': 8.71.0 + debug: 4.4.3 + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.15 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3)': + dependencies: + '@eslint-community/eslint-utils': 4.10.1(eslint@9.39.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.71.0 + '@typescript-eslint/types': 8.71.0 + '@typescript-eslint/typescript-estree': 8.71.0(typescript@6.0.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.71.0': + dependencies: + '@typescript-eslint/types': 8.71.0 + eslint-visitor-keys: 5.0.1 + + '@vitejs/plugin-react@5.2.0(vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 5.4.21(@types/node@24.10.2)(lightningcss@1.30.2) + react-refresh: 0.18.0 + vite: 7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - supports-color @@ -4077,10 +2795,10 @@ snapshots: agent-base@7.1.4: {} - agentation@1.3.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + agentation@1.3.2(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) ajv@6.12.6: dependencies: @@ -4170,32 +2888,10 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - transitivePeerDependencies: - - supports-color - balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + baseline-browser-mapping@2.9.5: {} bidi-js@1.0.3: @@ -4207,6 +2903,10 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 + brace-expansion@5.0.12: + dependencies: + balanced-match: 4.0.4 + browserslist@4.28.1: dependencies: baseline-browser-mapping: 2.9.5 @@ -4243,12 +2943,6 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 - class-variance-authority@0.7.1: - dependencies: - clsx: 2.1.1 - - clsx@2.1.1: {} - color-convert@2.0.1: dependencies: color-name: 1.1.4 @@ -4259,10 +2953,6 @@ snapshots: convert-source-map@2.0.0: {} - core-js-compat@3.47.0: - dependencies: - browserslist: 4.28.1 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4331,7 +3021,8 @@ snapshots: dequal@2.0.3: {} - detect-libc@2.1.2: {} + detect-libc@2.1.2: + optional: true doctrine@2.1.0: dependencies: @@ -4349,11 +3040,6 @@ snapshots: electron-to-chromium@1.5.267: {} - enhanced-resolve@5.18.3: - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - entities@6.0.1: {} es-abstract@1.24.0: @@ -4459,32 +3145,6 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.21.5: - 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 - esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -4518,7 +3178,7 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-react-hooks@7.0.1(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-react-hooks@7.1.1(eslint@9.39.1(jiti@2.6.1)): dependencies: '@babel/core': 7.28.5 '@babel/parser': 7.28.5 @@ -4560,6 +3220,8 @@ snapshots: eslint-visitor-keys@4.2.1: {} + eslint-visitor-keys@5.0.1: {} + eslint@9.39.1(jiti@2.6.1): dependencies: '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) @@ -4712,8 +3374,6 @@ snapshots: gopd@1.2.0: {} - graceful-fs@4.2.11: {} - has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -4766,6 +3426,8 @@ snapshots: ignore@5.3.2: {} + ignore@7.0.12: {} + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -4902,7 +3564,8 @@ snapshots: has-symbols: 1.1.0 set-function-name: 2.0.2 - jiti@2.6.1: {} + jiti@2.6.1: + optional: true js-tokens@4.0.0: {} @@ -5012,13 +3675,12 @@ snapshots: lightningcss-linux-x64-musl: 1.30.2 lightningcss-win32-arm64-msvc: 1.30.2 lightningcss-win32-x64-msvc: 1.30.2 + optional: true locate-path@6.0.0: dependencies: p-locate: 5.0.0 - lodash.debounce@4.0.8: {} - lodash.merge@4.6.2: {} loose-envify@1.4.0: @@ -5031,10 +3693,6 @@ snapshots: dependencies: yallist: 3.1.1 - lucide-react@0.556.0(react@18.3.1): - dependencies: - react: 18.3.1 - lz-string@1.5.0: {} magic-string@0.30.21: @@ -5047,6 +3705,10 @@ snapshots: min-indent@1.0.1: {} + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.12 + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -5164,21 +3826,18 @@ snapshots: punycode@2.3.1: {} - react-dom@18.3.1(react@18.3.1): + react-dom@19.3.0(react@19.3.0): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + react: 19.3.0 + scheduler: 0.28.0 react-is@16.13.1: {} react-is@17.0.2: {} - react-refresh@0.17.0: {} + react-refresh@0.18.0: {} - react@18.3.1: - dependencies: - loose-envify: 1.4.0 + react@19.3.0: {} redent@3.0.0: dependencies: @@ -5196,12 +3855,6 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 - regenerate-unicode-properties@10.2.2: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} - regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -5211,31 +3864,10 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - regexpu-core@6.4.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.2 - regjsgen: 0.8.0 - regjsparser: 0.13.0 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.1 - - regjsgen@0.8.0: {} - - regjsparser@0.13.0: - dependencies: - jsesc: 3.1.0 - require-from-string@2.0.2: {} resolve-from@4.0.0: {} - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - resolve@2.0.0-next.5: dependencies: is-core-module: 2.16.1 @@ -5295,12 +3927,12 @@ snapshots: dependencies: xmlchars: 2.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 + scheduler@0.28.0: {} semver@6.3.1: {} + semver@7.8.5: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5428,12 +4060,6 @@ snapshots: symbol-tree@3.2.4: {} - tailwind-merge@3.4.0: {} - - tailwindcss@4.1.17: {} - - tapable@2.3.0: {} - tinybench@2.9.0: {} tinyexec@1.0.2: {} @@ -5459,7 +4085,9 @@ snapshots: dependencies: punycode: 2.3.1 - tw-animate-css@1.4.0: {} + ts-api-utils@2.5.0(typescript@6.0.3): + dependencies: + typescript: 6.0.3 type-check@0.4.0: dependencies: @@ -5498,6 +4126,19 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typescript-eslint@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.71.0(@typescript-eslint/parser@8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3))(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.71.0(typescript@6.0.3) + '@typescript-eslint/utils': 8.71.0(eslint@9.39.1(jiti@2.6.1))(typescript@6.0.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 6.0.3 + transitivePeerDependencies: + - supports-color + + typescript@6.0.3: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -5508,17 +4149,6 @@ snapshots: undici-types@7.16.0: optional: true - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.2.0 - - unicode-match-property-value-ecmascript@2.2.1: {} - - unicode-property-aliases-ecmascript@2.2.0: {} - update-browserslist-db@1.2.2(browserslist@4.28.1): dependencies: browserslist: 4.28.1 @@ -5529,16 +4159,6 @@ snapshots: dependencies: punycode: 2.3.1 - vite@5.4.21(@types/node@24.10.2)(lightningcss@1.30.2): - dependencies: - esbuild: 0.21.5 - postcss: 8.5.6 - rollup: 4.53.3 - optionalDependencies: - '@types/node': 24.10.2 - fsevents: 2.3.3 - lightningcss: 1.30.2 - vite@7.2.7(@types/node@24.10.2)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: esbuild: 0.25.12 diff --git a/public/README.md b/public/README.md index 5368fa9..207dce2 100644 --- a/public/README.md +++ b/public/README.md @@ -3,4 +3,3 @@ Static assets served directly. - `808 Samples/` - Drum machine audio samples -- `fonts/` - Custom fonts diff --git a/src/App.jsx b/src/App.jsx deleted file mode 100644 index 14d0cdb..0000000 --- a/src/App.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import { Agentation } from 'agentation' -import DrumMachine from './components/DrumMachine' -import { DEFAULT_INSTRUMENTS } from './config/instruments' - -function App() { - return ( - <> - - - - ) -} - -export default App diff --git a/src/App.module.css b/src/App.module.css new file mode 100644 index 0000000..4928fed --- /dev/null +++ b/src/App.module.css @@ -0,0 +1,3 @@ +.app { + position: relative; +} diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..b9bdec1 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,80 @@ +import { useEffect, useLayoutEffect, useState, useSyncExternalStore } from 'react' +import { Engine } from './engine/engine' +import { DRUMS, noteForKey } from './instruments' +import { createSessionStore } from './session/store' +import { readSessionFromLocation, writeSessionToLocation } from './session/url' +import { LoopMachine } from './ui/LoopMachine' +import styles from './App.module.css' + +/** Panel width plus its glass border, and the page margin on each side. */ +const PANEL_WIDTH = 1128 +const PAGE_GUTTER = 48 + +export function App() { + const [store] = useState(() => createSessionStore(readSessionFromLocation())) + const [engine] = useState(() => new Engine(DRUMS)) + + const playhead = useSyncExternalStore(engine.subscribe, engine.getPlayhead) + const isPlaying = useSyncExternalStore(engine.subscribe, () => engine.isPlaying) + + useEffect(() => { + engine.apply(store.getState()) + engine.load() + return () => engine.dispose() + }, [engine, store]) + + // The session drives both the engine and the share link. + useEffect( + () => + store.subscribe(() => { + const session = store.getState() + engine.apply(session) + writeSessionToLocation(session) + }), + [engine, store], + ) + + // The panel has a fixed hardware layout; scale it down to fit narrower windows, like the prototype in the proposal. + const [zoom, setZoom] = useState(1) + useLayoutEffect(() => { + const fit = () => setZoom(Math.min(1, (window.innerWidth - PAGE_GUTTER) / PANEL_WIDTH)) + fit() + window.addEventListener('resize', fit) + return () => window.removeEventListener('resize', fit) + }, []) + + // Computer keys toggle notes, like clicking the keyboard; ⌘Z / Ctrl+Z undoes. + useEffect(() => { + const onKeyDown = (e: KeyboardEvent) => { + const target = e.target as HTMLElement + if (target.closest('input, textarea, [contenteditable="true"]')) return + if ((e.metaKey || e.ctrlKey) && !e.shiftKey && !e.altKey && e.key.toLowerCase() === 'z') { + e.preventDefault() + store.undo() + return + } + if (e.repeat || e.metaKey || e.ctrlKey || e.altKey) return + const note = noteForKey(e.key) + if (!note) return + e.preventDefault() + store.dispatch({ type: 'toggleNote', note }) + } + window.addEventListener('keydown', onKeyDown) + return () => window.removeEventListener('keydown', onKeyDown) + }, [store]) + + return ( +
+ (engine.isPlaying ? engine.stop() : void engine.start())} + onReset={() => { + engine.stop() + store.dispatch({ type: 'reset' }) + }} + /> +
+ ) +} diff --git a/src/README.md b/src/README.md deleted file mode 100644 index 78da0f4..0000000 --- a/src/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# src/ - -Application source code. - -- `components/` - React components -- `hooks/` - Custom React hooks for audio and sequencer logic -- `config/` - Instrument and keyboard configuration -- `utils/` - URL state persistence utilities -- `lib/` - Shared utilities (cn helper) -- `__tests__/` - Test files diff --git a/src/__tests__/Key.test.jsx b/src/__tests__/Key.test.jsx deleted file mode 100644 index 67c8aff..0000000 --- a/src/__tests__/Key.test.jsx +++ /dev/null @@ -1,65 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { render, screen, fireEvent } from '@testing-library/react' -import Key from '../components/Key' - -describe('Key', () => { - const defaultProps = { - note: 'C3', - type: 'white', - isHeld: false, - isPlaying: false, - keyHint: 'a', - onToggle: vi.fn(), - } - - beforeEach(() => { - vi.clearAllMocks() - }) - - it('renders with correct classes for white key', () => { - render() - const key = screen.getByText('a').closest('.key') - expect(key).toHaveClass('key', 'white') - }) - - it('renders with correct classes for black key', () => { - render() - const key = screen.getByText('a').closest('.key') - expect(key).toHaveClass('key', 'black') - }) - - it('has held class when isHeld', () => { - render() - const key = screen.getByText('a').closest('.key') - expect(key).toHaveClass('held') - }) - - it('has playing class when isPlaying', () => { - render() - const key = screen.getByText('a').closest('.key') - expect(key).toHaveClass('playing') - }) - - it('displays key hint', () => { - render() - expect(screen.getByText('a')).toBeInTheDocument() - }) - - it('does not display hint when keyHint is null', () => { - render() - expect(screen.queryByText('a')).not.toBeInTheDocument() - }) - - it('calls onToggle on click', () => { - render() - const key = screen.getByText('a').closest('.key') - fireEvent.click(key) - expect(defaultProps.onToggle).toHaveBeenCalledWith('C3') - }) - - it('has data-note attribute', () => { - render() - const key = screen.getByText('a').closest('.key') - expect(key).toHaveAttribute('data-note', 'C3') - }) -}) diff --git a/src/__tests__/Pad.test.jsx b/src/__tests__/Pad.test.jsx deleted file mode 100644 index 8c59828..0000000 --- a/src/__tests__/Pad.test.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { render, screen, fireEvent } from '@testing-library/react' -import Pad from '../components/Pad' - -describe('Pad', () => { - const defaultProps = { - active: false, - playing: false, - isBeatStart: false, - onClick: vi.fn(), - } - - beforeEach(() => { - vi.clearAllMocks() - }) - - it('renders a button', () => { - render() - expect(screen.getByRole('button')).toBeInTheDocument() - }) - - it('calls onClick when clicked', () => { - render() - fireEvent.click(screen.getByRole('button')) - expect(defaultProps.onClick).toHaveBeenCalledTimes(1) - }) - - it('has active class when active', () => { - render() - expect(screen.getByRole('button')).toHaveClass('active') - }) - - it('has playing-step class when playing', () => { - render() - expect(screen.getByRole('button')).toHaveClass('playing-step') - }) - - it('has beat-start class when isBeatStart and not active', () => { - render() - expect(screen.getByRole('button')).toHaveClass('beat-start') - }) -}) diff --git a/src/__tests__/TransportControls.test.jsx b/src/__tests__/TransportControls.test.jsx deleted file mode 100644 index 0188c90..0000000 --- a/src/__tests__/TransportControls.test.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { render, screen, fireEvent } from '@testing-library/react' -import TransportControls from '../components/TransportControls' - -describe('TransportControls', () => { - const defaultProps = { - bpm: 120, - isPlaying: false, - isLoading: false, - onPlayStop: vi.fn(), - onReset: vi.fn(), - onBpmChange: vi.fn(), - } - - beforeEach(() => { - vi.clearAllMocks() - }) - - it('renders tempo input with correct value', () => { - render() - const input = screen.getByRole('spinbutton') - expect(input).toHaveValue(120) - }) - - it('renders TEMPO label', () => { - render() - expect(screen.getByText('TEMPO')).toBeInTheDocument() - }) - - it('shows START button when not playing', () => { - render() - expect(screen.getByText('START')).toBeInTheDocument() - }) - - it('shows STOP button when playing', () => { - render() - expect(screen.getByText('STOP')).toBeInTheDocument() - }) - - it('calls onPlayStop when Start/Stop button is clicked', () => { - render() - fireEvent.click(screen.getByText('START')) - expect(defaultProps.onPlayStop).toHaveBeenCalledTimes(1) - }) - - it('calls onReset when Reset button is clicked', () => { - render() - fireEvent.click(screen.getByText('RESET')) - expect(defaultProps.onReset).toHaveBeenCalledTimes(1) - }) - - it('disables Start/Stop button when loading', () => { - render() - expect(screen.getByText('START')).toBeDisabled() - }) - - describe('tempo input', () => { - it('allows typing new BPM value', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '90' } }) - expect(input).toHaveValue(90) - }) - - it('calls onBpmChange on blur with valid value', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '140' } }) - fireEvent.blur(input) - - expect(defaultProps.onBpmChange).toHaveBeenCalledWith(140) - }) - - it('calls onBpmChange on Enter key', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '100' } }) - fireEvent.keyDown(input, { key: 'Enter' }) - // Enter triggers blur which calls onBpmChange - fireEvent.blur(input) - - expect(defaultProps.onBpmChange).toHaveBeenCalledWith(100) - }) - - it('resets to current BPM if value is below minimum (60)', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '30' } }) - fireEvent.blur(input) - - expect(defaultProps.onBpmChange).not.toHaveBeenCalled() - expect(input).toHaveValue(120) // Reset to original - }) - - it('resets to current BPM if value is above maximum (200)', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '250' } }) - fireEvent.blur(input) - - expect(defaultProps.onBpmChange).not.toHaveBeenCalled() - expect(input).toHaveValue(120) // Reset to original - }) - - it('resets to current BPM if value is not a number', () => { - render() - const input = screen.getByRole('spinbutton') - - fireEvent.change(input, { target: { value: '' } }) - fireEvent.blur(input) - - expect(defaultProps.onBpmChange).not.toHaveBeenCalled() - expect(input).toHaveValue(120) // Reset to original - }) - - it('syncs with external BPM changes', () => { - const { rerender } = render() - const input = screen.getByRole('spinbutton') - - expect(input).toHaveValue(120) - - rerender() - expect(input).toHaveValue(85) - }) - }) -}) diff --git a/src/__tests__/instruments.test.js b/src/__tests__/instruments.test.js deleted file mode 100644 index 222c562..0000000 --- a/src/__tests__/instruments.test.js +++ /dev/null @@ -1,153 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { - DEFAULT_INSTRUMENTS, - DEFAULT_TRACK_SETTINGS, - SEQUENCER_CONFIG, - createInitialTrackSettings, - createInitialPattern, -} from '../config/instruments' - -describe('instruments config', () => { - describe('DEFAULT_INSTRUMENTS', () => { - it('contains 3 instruments', () => { - expect(DEFAULT_INSTRUMENTS).toHaveLength(3) - }) - - it('has hihat, snare, and kick', () => { - const ids = DEFAULT_INSTRUMENTS.map(i => i.id) - expect(ids).toContain('hihat') - expect(ids).toContain('snare') - expect(ids).toContain('kick') - }) - - it('each instrument has required properties', () => { - DEFAULT_INSTRUMENTS.forEach(instrument => { - expect(instrument).toHaveProperty('id') - expect(instrument).toHaveProperty('name') - expect(instrument).toHaveProperty('path') - expect(instrument).toHaveProperty('color') - }) - }) - - it('each instrument has a valid audio path', () => { - DEFAULT_INSTRUMENTS.forEach(instrument => { - expect(instrument.path).toMatch(/\.wav$/i) - }) - }) - }) - - describe('DEFAULT_TRACK_SETTINGS', () => { - it('has default volume of 0.8', () => { - expect(DEFAULT_TRACK_SETTINGS.volume).toBe(0.8) - }) - - it('has default reverb of 0', () => { - expect(DEFAULT_TRACK_SETTINGS.reverb).toBe(0) - }) - - it('has default filter of 1', () => { - expect(DEFAULT_TRACK_SETTINGS.filter).toBe(1) - }) - - it('is not muted by default', () => { - expect(DEFAULT_TRACK_SETTINGS.muted).toBe(false) - }) - - it('is not solo by default', () => { - expect(DEFAULT_TRACK_SETTINGS.solo).toBe(false) - }) - }) - - describe('SEQUENCER_CONFIG', () => { - it('has 16 steps', () => { - expect(SEQUENCER_CONFIG.steps).toBe(16) - }) - - it('has default BPM of 120', () => { - expect(SEQUENCER_CONFIG.bpm).toBe(120) - }) - - it('has scheduleAheadTime', () => { - expect(SEQUENCER_CONFIG.scheduleAheadTime).toBeDefined() - expect(typeof SEQUENCER_CONFIG.scheduleAheadTime).toBe('number') - }) - - it('has schedulerInterval', () => { - expect(SEQUENCER_CONFIG.schedulerInterval).toBeDefined() - expect(typeof SEQUENCER_CONFIG.schedulerInterval).toBe('number') - }) - }) - - describe('createInitialTrackSettings', () => { - it('creates settings for each instrument', () => { - const instruments = [{ id: 'test1' }, { id: 'test2' }] - const settings = createInitialTrackSettings(instruments) - - expect(settings).toHaveProperty('test1') - expect(settings).toHaveProperty('test2') - }) - - it('applies default settings to each instrument', () => { - const instruments = [{ id: 'test' }] - const settings = createInitialTrackSettings(instruments) - - expect(settings.test.volume).toBe(DEFAULT_TRACK_SETTINGS.volume) - expect(settings.test.reverb).toBe(DEFAULT_TRACK_SETTINGS.reverb) - expect(settings.test.filter).toBe(DEFAULT_TRACK_SETTINGS.filter) - expect(settings.test.muted).toBe(DEFAULT_TRACK_SETTINGS.muted) - expect(settings.test.solo).toBe(DEFAULT_TRACK_SETTINGS.solo) - }) - - it('creates independent settings objects', () => { - const instruments = [{ id: 'a' }, { id: 'b' }] - const settings = createInitialTrackSettings(instruments) - - settings.a.volume = 0.5 - expect(settings.b.volume).toBe(0.8) - }) - - it('returns empty object for empty instruments array', () => { - const settings = createInitialTrackSettings([]) - expect(settings).toEqual({}) - }) - }) - - describe('createInitialPattern', () => { - it('creates pattern for each instrument', () => { - const instruments = [{ id: 'test1' }, { id: 'test2' }] - const pattern = createInitialPattern(instruments, 16) - - expect(pattern).toHaveProperty('test1') - expect(pattern).toHaveProperty('test2') - }) - - it('creates arrays with correct number of steps', () => { - const instruments = [{ id: 'test' }] - const pattern = createInitialPattern(instruments, 16) - - expect(pattern.test).toHaveLength(16) - }) - - it('initializes all steps to false', () => { - const instruments = [{ id: 'test' }] - const pattern = createInitialPattern(instruments, 8) - - pattern.test.forEach(step => { - expect(step).toBe(false) - }) - }) - - it('creates independent pattern arrays', () => { - const instruments = [{ id: 'a' }, { id: 'b' }] - const pattern = createInitialPattern(instruments, 4) - - pattern.a[0] = true - expect(pattern.b[0]).toBe(false) - }) - - it('returns empty object for empty instruments array', () => { - const pattern = createInitialPattern([], 16) - expect(pattern).toEqual({}) - }) - }) -}) diff --git a/src/__tests__/keyboard.test.js b/src/__tests__/keyboard.test.js deleted file mode 100644 index 7d1e209..0000000 --- a/src/__tests__/keyboard.test.js +++ /dev/null @@ -1,91 +0,0 @@ -import { describe, it, expect } from 'vitest' -import { NOTES, QWERTY_MAP, NOTE_TO_KEY, getNoteByName, WAVEFORMS } from '../config/keyboard' - -describe('keyboard config', () => { - describe('NOTES', () => { - it('has 24 notes (2 octaves)', () => { - expect(NOTES).toHaveLength(24) - }) - - it('starts with C3 and ends with B4', () => { - expect(NOTES[0].note).toBe('C3') - expect(NOTES[23].note).toBe('B4') - }) - - it('has correct frequency for A4 (440Hz)', () => { - const a4 = NOTES.find((n) => n.note === 'A4') - expect(a4.freq).toBe(440.0) - }) - - it('has 14 white keys and 10 black keys', () => { - const whiteKeys = NOTES.filter((n) => n.type === 'white') - const blackKeys = NOTES.filter((n) => n.type === 'black') - expect(whiteKeys).toHaveLength(14) - expect(blackKeys).toHaveLength(10) - }) - - it('all notes have required properties', () => { - NOTES.forEach((note) => { - expect(note).toHaveProperty('note') - expect(note).toHaveProperty('freq') - expect(note).toHaveProperty('type') - expect(typeof note.note).toBe('string') - expect(typeof note.freq).toBe('number') - expect(['white', 'black']).toContain(note.type) - }) - }) - - it('frequencies increase with each note', () => { - for (let i = 1; i < NOTES.length; i++) { - expect(NOTES[i].freq).toBeGreaterThan(NOTES[i - 1].freq) - } - }) - }) - - describe('QWERTY_MAP', () => { - it('maps lowercase keys to note names', () => { - expect(QWERTY_MAP['a']).toBe('C3') - expect(QWERTY_MAP['w']).toBe('C#3') - expect(QWERTY_MAP['k']).toBe('C4') - }) - - it('all mapped notes exist in NOTES', () => { - const noteNames = NOTES.map((n) => n.note) - Object.values(QWERTY_MAP).forEach((noteName) => { - expect(noteNames).toContain(noteName) - }) - }) - }) - - describe('NOTE_TO_KEY', () => { - it('is reverse of QWERTY_MAP', () => { - Object.entries(QWERTY_MAP).forEach(([key, note]) => { - expect(NOTE_TO_KEY[note]).toBe(key) - }) - }) - }) - - describe('getNoteByName', () => { - it('returns note data for valid note', () => { - const c3 = getNoteByName('C3') - expect(c3).toEqual({ note: 'C3', freq: 130.81, type: 'white' }) - }) - - it('returns undefined for invalid note', () => { - expect(getNoteByName('X9')).toBeUndefined() - }) - }) - - describe('WAVEFORMS', () => { - it('contains all four waveform types', () => { - expect(WAVEFORMS).toContain('sine') - expect(WAVEFORMS).toContain('square') - expect(WAVEFORMS).toContain('sawtooth') - expect(WAVEFORMS).toContain('triangle') - }) - - it('has sawtooth as default (first)', () => { - expect(WAVEFORMS[0]).toBe('sawtooth') - }) - }) -}) diff --git a/src/__tests__/urlState.test.js b/src/__tests__/urlState.test.js deleted file mode 100644 index 0ff2250..0000000 --- a/src/__tests__/urlState.test.js +++ /dev/null @@ -1,183 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { encodeStateToUrl, decodeStateFromUrl } from '../utils/urlState' - -const mockInstruments = [ - { id: 'hihat', name: 'HI-HAT' }, - { id: 'snare', name: 'SNARE' }, - { id: 'kick', name: 'KICK' }, -] - -describe('urlState', () => { - beforeEach(() => { - // Reset URL before each test - window.history.replaceState(null, '', '/') - }) - - describe('encodeStateToUrl', () => { - it('encodes empty pattern correctly', () => { - const pattern = { - hihat: Array(16).fill(false), - snare: Array(16).fill(false), - kick: Array(16).fill(false), - } - const trackSettings = { - hihat: { volume: 0.8, reverb: 0, filter: 1 }, - snare: { volume: 0.8, reverb: 0, filter: 1 }, - kick: { volume: 0.8, reverb: 0, filter: 1 }, - } - - encodeStateToUrl(pattern, trackSettings, mockInstruments, 120) - - // Each instrument: 4 hex for notes + 6 hex for settings (volume cc, reverb 00, filter ff) - // Notes: 0000 0000 0000 (all off) - // Settings per instrument: cc (0.8 volume) + 00 (0 reverb) + ff (1.0 filter) = cc00ff - expect(window.location.search).toBe('?s=000000000000_cc00ffcc00ffcc00ff_120') - }) - - it('encodes pattern with active steps correctly', () => { - const pattern = { - hihat: [true, false, false, false, true, false, false, false, true, false, false, false, true, false, false, false], - snare: Array(16).fill(false), - kick: Array(16).fill(false), - } - const trackSettings = { - hihat: { volume: 0.8, reverb: 0, filter: 1 }, - snare: { volume: 0.8, reverb: 0, filter: 1 }, - kick: { volume: 0.8, reverb: 0, filter: 1 }, - } - - encodeStateToUrl(pattern, trackSettings, mockInstruments, 120) - - // 1000100010001000 in binary = 0x8888 - expect(window.location.search).toContain('8888') - }) - - it('encodes BPM correctly', () => { - const pattern = { - hihat: Array(16).fill(false), - snare: Array(16).fill(false), - kick: Array(16).fill(false), - } - const trackSettings = { - hihat: { volume: 0.8, reverb: 0, filter: 1 }, - snare: { volume: 0.8, reverb: 0, filter: 1 }, - kick: { volume: 0.8, reverb: 0, filter: 1 }, - } - - encodeStateToUrl(pattern, trackSettings, mockInstruments, 85) - - expect(window.location.search).toContain('_085') - }) - - it('encodes effects correctly', () => { - const pattern = { - hihat: Array(16).fill(false), - snare: Array(16).fill(false), - kick: Array(16).fill(false), - } - const trackSettings = { - hihat: { volume: 0.5, reverb: 0.3, filter: 0.8 }, - snare: { volume: 0.8, reverb: 0, filter: 1 }, - kick: { volume: 1.0, reverb: 0.5, filter: 0.5 }, - } - - encodeStateToUrl(pattern, trackSettings, mockInstruments, 120) - - // Check the URL was set (exact values depend on floatToHex conversion) - expect(window.location.search).toContain('?s=') - expect(window.location.search).toContain('_120') - }) - }) - - describe('decodeStateFromUrl', () => { - it('returns null values for empty URL', () => { - const result = decodeStateFromUrl(mockInstruments, 16) - - expect(result.pattern).toBeNull() - expect(result.trackSettings).toBeNull() - expect(result.bpm).toBeNull() - }) - - it('decodes pattern correctly', () => { - // Set URL with encoded state (6 chars per instrument for settings) - window.history.replaceState(null, '', '/?s=888800000000_cc00ffcc00ffcc00ff_120') - - const result = decodeStateFromUrl(mockInstruments, 16) - - expect(result.pattern.hihat[0]).toBe(true) - expect(result.pattern.hihat[4]).toBe(true) - expect(result.pattern.hihat[8]).toBe(true) - expect(result.pattern.hihat[12]).toBe(true) - expect(result.pattern.hihat[1]).toBe(false) - }) - - it('decodes BPM correctly', () => { - window.history.replaceState(null, '', '/?s=000000000000_cc00ffcc00ffcc00ff_085') - - const result = decodeStateFromUrl(mockInstruments, 16) - - expect(result.bpm).toBe(85) - }) - - it('handles old URL format without BPM (backwards compatibility)', () => { - window.history.replaceState(null, '', '/?s=000000000000_cc00ffcc00ffcc00ff') - - const result = decodeStateFromUrl(mockInstruments, 16) - - expect(result.pattern).not.toBeNull() - expect(result.bpm).toBeNull() - }) - - it('rejects BPM outside valid range', () => { - window.history.replaceState(null, '', '/?s=000000000000_cc00ffcc00ffcc00ff_300') - - const result = decodeStateFromUrl(mockInstruments, 16) - - expect(result.bpm).toBeNull() - }) - - it('decodes effects correctly', () => { - // volume=0.8 (cc), reverb=0.5 (80), filter=1.0 (ff) for hihat - // volume=0.8 (cc), reverb=0 (00), filter=1.0 (ff) for snare - // volume=1.0 (ff), reverb=0.3 (4d), filter=0.5 (80) for kick - window.history.replaceState(null, '', '/?s=000000000000_cc80ffcc00ffff4d80_120') - - const result = decodeStateFromUrl(mockInstruments, 16) - - // Check that settings are decoded (values will be approximate due to hex encoding) - expect(result.trackSettings.hihat.volume).toBeCloseTo(0.8, 1) - expect(result.trackSettings.hihat.reverb).toBeCloseTo(0.5, 1) - expect(result.trackSettings.hihat.filter).toBeCloseTo(1.0, 1) - expect(result.trackSettings.snare.reverb).toBe(0) - expect(result.trackSettings.kick.volume).toBeCloseTo(1.0, 1) - }) - }) - - describe('round-trip encoding/decoding', () => { - it('preserves state through encode/decode cycle', () => { - const originalPattern = { - hihat: [true, true, false, false, true, true, false, false, true, true, false, false, true, true, false, false], - snare: [false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false], - kick: [true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false], - } - const originalSettings = { - hihat: { volume: 0.8, reverb: 0.3, filter: 1.0 }, - snare: { volume: 0.8, reverb: 0, filter: 0.5 }, - kick: { volume: 1.0, reverb: 0.5, filter: 0.8 }, - } - const originalBpm = 140 - - encodeStateToUrl(originalPattern, originalSettings, mockInstruments, originalBpm) - const decoded = decodeStateFromUrl(mockInstruments, 16) - - expect(decoded.pattern.hihat).toEqual(originalPattern.hihat) - expect(decoded.pattern.snare).toEqual(originalPattern.snare) - expect(decoded.pattern.kick).toEqual(originalPattern.kick) - // Float values may have small rounding differences due to hex encoding - expect(decoded.trackSettings.hihat.volume).toBeCloseTo(originalSettings.hihat.volume, 1) - expect(decoded.trackSettings.hihat.reverb).toBeCloseTo(originalSettings.hihat.reverb, 1) - expect(decoded.trackSettings.hihat.filter).toBeCloseTo(originalSettings.hihat.filter, 1) - expect(decoded.bpm).toBe(originalBpm) - }) - }) -}) diff --git a/src/__tests__/useAudioEngine.test.js b/src/__tests__/useAudioEngine.test.js deleted file mode 100644 index ebd2df7..0000000 --- a/src/__tests__/useAudioEngine.test.js +++ /dev/null @@ -1,159 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { renderHook, act, waitFor } from '@testing-library/react' -import { useAudioEngine } from '../hooks/useAudioEngine' - -// Mock AudioContext with a class -class MockAudioContext { - constructor() { - this.state = 'running' - this.currentTime = 0 - this.destination = {} - } - - createGain() { - return { - gain: { value: 1, setValueAtTime: vi.fn() }, - connect: vi.fn(), - } - } - - createDelay() { - return { - delayTime: { value: 0 }, - connect: vi.fn(), - } - } - - createBiquadFilter() { - return { - type: 'lowpass', - frequency: { value: 20000, setValueAtTime: vi.fn() }, - Q: { value: 1 }, - connect: vi.fn(), - } - } - - createBufferSource() { - return { - buffer: null, - connect: vi.fn(), - start: vi.fn(), - } - } - - decodeAudioData() { - return Promise.resolve({}) - } - - resume() { - return Promise.resolve() - } - - close() { - return Promise.resolve() - } -} - -vi.stubGlobal('AudioContext', MockAudioContext) -vi.stubGlobal('webkitAudioContext', MockAudioContext) - -// Mock fetch -vi.stubGlobal('fetch', vi.fn(() => { - return Promise.resolve({ - ok: true, - arrayBuffer: () => Promise.resolve(new ArrayBuffer(8)), - }) -})) - -describe('useAudioEngine', () => { - const mockInstruments = [ - { id: 'kick', name: 'Kick', path: '/samples/kick.wav' }, - { id: 'snare', name: 'Snare', path: '/samples/snare.wav' }, - ] - - beforeEach(() => { - vi.clearAllMocks() - }) - - describe('initialization', () => { - it('initializes and loads audio', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - }) - - it('sets isLoading to false after loading', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - }) - }) - - describe('playSound', () => { - it('exposes playSound function', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - - expect(typeof result.current.playSound).toBe('function') - }) - - it('does not throw when playing muted sound', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - - expect(() => { - act(() => { - result.current.playSound('kick', 0, { muted: true }) - }) - }).not.toThrow() - }) - }) - - describe('resumeContext', () => { - it('exposes resumeContext function', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - - expect(typeof result.current.resumeContext).toBe('function') - }) - - it('can be called without throwing', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - - await expect(act(async () => { - await result.current.resumeContext() - })).resolves.not.toThrow() - }) - }) - - describe('getCurrentTime', () => { - it('returns audio context current time', async () => { - const { result } = renderHook(() => useAudioEngine(mockInstruments)) - - await waitFor(() => { - expect(result.current.isLoading).toBe(false) - }) - - // Default currentTime is 0 - expect(result.current.getCurrentTime()).toBe(0) - }) - }) - -}) diff --git a/src/components/ArpTrack.jsx b/src/components/ArpTrack.jsx deleted file mode 100644 index 825f2de..0000000 --- a/src/components/ArpTrack.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import { memo } from 'react' -import Pad from './Pad' - -/** - * Arpeggiator track - 16-step gate pattern - */ -function ArpTrack({ - pattern, - currentStep, - onToggleStep, - showLabel = true, -}) { - // Group pads into groups of 4 - const padGroups = [] - for (let g = 0; g < 16; g += 4) { - padGroups.push(Array.from({ length: 4 }, (_, i) => g + i)) - } - - return ( -
- {padGroups.map((group, groupIndex) => ( -
- {group.map((i) => ( - onToggleStep(i)} - /> - ))} -
- ))} -
- ) -} - -export default memo(ArpTrack) diff --git a/src/components/AudioVisualizer.jsx b/src/components/AudioVisualizer.jsx deleted file mode 100644 index 4f74bb3..0000000 --- a/src/components/AudioVisualizer.jsx +++ /dev/null @@ -1,103 +0,0 @@ -/* global ResizeObserver */ -import { useRef, useEffect, memo } from 'react' - -const AudioVisualizer = memo(function AudioVisualizer({ analyser, barCount = 16 }) { - const containerRef = useRef(null) - const canvasRef = useRef(null) - const animationRef = useRef(null) - const dataArrayRef = useRef(null) - - useEffect(() => { - const canvas = canvasRef.current - const container = containerRef.current - if (!canvas || !container) return - - const ctx = canvas.getContext('2d') - - // Create data array for frequency data - if (analyser) { - dataArrayRef.current = new Uint8Array(analyser.frequencyBinCount) - } - - const updateCanvasSize = () => { - const rect = container.getBoundingClientRect() - canvas.width = rect.width * window.devicePixelRatio - canvas.height = rect.height * window.devicePixelRatio - ctx.scale(window.devicePixelRatio, window.devicePixelRatio) - } - - updateCanvasSize() - - // Watch for container resize - const resizeObserver = new ResizeObserver(updateCanvasSize) - resizeObserver.observe(container) - - const draw = () => { - animationRef.current = requestAnimationFrame(draw) - - const rect = container.getBoundingClientRect() - const width = rect.width - const height = rect.height - - // Clear canvas - ctx.fillStyle = '#1a1a1a' - ctx.fillRect(0, 0, width, height) - - const barSpacing = 3 - const barWidth = Math.max(3, (width - (barCount - 1) * barSpacing) / barCount) - - if (analyser && dataArrayRef.current) { - analyser.getByteFrequencyData(dataArrayRef.current) - - for (let i = 0; i < barCount; i++) { - // Sample from different parts of the frequency spectrum - const dataIndex = Math.floor((i / barCount) * (dataArrayRef.current.length / 2)) - const value = dataArrayRef.current[dataIndex] || 0 - const barHeight = Math.max(2, (value / 255) * (height - 8)) - - const x = i * (barWidth + barSpacing) - const y = height - barHeight - 4 - - // Orange gradient - const gradient = ctx.createLinearGradient(0, y, 0, height) - gradient.addColorStop(0, '#f5a623') - gradient.addColorStop(1, '#e08a00') - - ctx.fillStyle = gradient - ctx.beginPath() - ctx.roundRect(x, y, barWidth, barHeight, 2) - ctx.fill() - } - } else { - // Draw idle bars when no analyser - for (let i = 0; i < barCount; i++) { - const barHeight = 4 - const x = i * (barWidth + barSpacing) - const y = height - barHeight - 4 - - ctx.fillStyle = '#3a3a3a' - ctx.beginPath() - ctx.roundRect(x, y, barWidth, barHeight, 2) - ctx.fill() - } - } - } - - draw() - - return () => { - resizeObserver.disconnect() - if (animationRef.current) { - cancelAnimationFrame(animationRef.current) - } - } - }, [analyser, barCount]) - - return ( -
- -
- ) -}) - -export default AudioVisualizer diff --git a/src/components/DrumMachine.jsx b/src/components/DrumMachine.jsx deleted file mode 100644 index 4d0081c..0000000 --- a/src/components/DrumMachine.jsx +++ /dev/null @@ -1,102 +0,0 @@ -import { useState, useEffect, useCallback } from 'react' -import { useAudioEngine } from '../hooks/useAudioEngine' -import { useSequencer } from '../hooks/useSequencer' -import { useSynthEngine } from '../hooks/useSynthEngine' -import { useArpeggiator } from '../hooks/useArpeggiator' -import LoadingOverlay from './LoadingOverlay' -import Header from './Header' -import Sequencer from './Sequencer' -import Keyboard from './Keyboard' -import { QWERTY_MAP } from '../config/keyboard' - -function DrumMachine({ instruments }) { - const audioEngine = useAudioEngine(instruments) - const synth = useSynthEngine(audioEngine.audioContext, audioEngine.masterGain) - const arpeggiator = useArpeggiator(synth) - const sequencer = useSequencer(instruments, audioEngine, arpeggiator) - - // Track which note the arpeggiator is currently playing (for keyboard highlight) - const [currentArpNote, setCurrentArpNote] = useState(null) - - // Update current arp note for keyboard highlighting - useEffect(() => { - arpeggiator.setOnNoteChange(setCurrentArpNote) - }, [arpeggiator]) - - const handlePlayStop = () => { - if (sequencer.isPlaying) { - sequencer.stopPlayback() - setCurrentArpNote(null) - } else { - sequencer.startPlayback() - } - } - - // Toggle note on/off (click to toggle, like drum pads) - const handleNoteToggle = useCallback( - (noteName) => { - arpeggiator.toggleNote(noteName) - }, - [arpeggiator] - ) - - // QWERTY keyboard toggles notes - useEffect(() => { - const handleKeyDown = (e) => { - // Ignore if typing in an input - if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return - // Ignore repeat events (key held down) - if (e.repeat) return - - const noteName = QWERTY_MAP[e.key.toLowerCase()] - if (noteName) { - e.preventDefault() - handleNoteToggle(noteName) - } - } - - window.addEventListener('keydown', handleKeyDown) - - return () => { - window.removeEventListener('keydown', handleKeyDown) - } - }, [handleNoteToggle]) - - return ( -
-
- - -
- - - - -
-
- ) -} - -export default DrumMachine diff --git a/src/components/Header.jsx b/src/components/Header.jsx deleted file mode 100644 index abbed3a..0000000 --- a/src/components/Header.jsx +++ /dev/null @@ -1,9 +0,0 @@ -function Header({ title }) { - return ( -
-

{title}

-
- ) -} - -export default Header diff --git a/src/components/Key.jsx b/src/components/Key.jsx deleted file mode 100644 index 376ff49..0000000 --- a/src/components/Key.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import { memo } from 'react' - -/** - * Individual piano key component - * Click to toggle note on/off (like drum pads) - */ -function Key({ note, type, isHeld, isPlaying, keyHint, onToggle }) { - const handleClick = (e) => { - e.preventDefault() - onToggle(note) - } - - const classNames = [ - 'key', - type, - isHeld ? 'held' : '', - isPlaying ? 'playing' : '', - ].filter(Boolean).join(' ') - - // Format note name (e.g., "C#3" -> "C#") - const noteName = note.replace(/\d+$/, '') - - return ( -
- {noteName} - {keyHint && ( - - {keyHint} - - )} -
- ) -} - -export default memo(Key) diff --git a/src/components/Keyboard.jsx b/src/components/Keyboard.jsx deleted file mode 100644 index 7dd316e..0000000 --- a/src/components/Keyboard.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import { memo } from 'react' -import Key from './Key' -import { NOTES, NOTE_TO_KEY } from '../config/keyboard' - -/** - * 2-octave piano keyboard component (C3-B4) - * Click keys to toggle them on/off for arpeggiator - */ -function Keyboard({ heldNotes, playingNote, onToggle, showKeyHints = true }) { - return ( -
-
- {NOTES.map((noteData) => ( - - ))} -
-
- ) -} - -export default memo(Keyboard) diff --git a/src/components/KeyboardControls.jsx b/src/components/KeyboardControls.jsx deleted file mode 100644 index d5e6b05..0000000 --- a/src/components/KeyboardControls.jsx +++ /dev/null @@ -1,168 +0,0 @@ -import { memo } from 'react' -import { WAVEFORMS } from '../config/keyboard' - -const DIRECTIONS = [ - { id: 'up', label: '↑' }, - { id: 'down', label: '↓' }, - { id: 'up-down', label: '↕' }, -] - -const SPEEDS = [ - { id: '1/4', label: '1/4' }, - { id: '1/8', label: '1/8' }, - { id: '1/16', label: '1/16' }, -] - -/** - * Combined keyboard controls - dir, speed, vol, wave - * Layout: [DIR/SPEED stacked] [VOL] [WAVE] [Keyboard] - */ -function KeyboardControls({ - mode, - rate, - onModeChange, - onRateChange, - waveform, - volume, - onWaveformChange, - onVolumeChange, - children, -}) { - return ( -
- {/* All synth controls in a container */} -
- {/* DIR and SPEED stacked vertically */} -
- {/* DIRECTION control */} -
- DIRECTION -
- {DIRECTIONS.map((d) => ( - - ))} -
-
- - {/* SPEED control */} -
- SPEED -
- {SPEEDS.map((s) => ( - - ))} -
-
-
- - {/* VOL control - vertical slider */} -
- VOL -
- onVolumeChange(parseFloat(e.target.value))} - /> -
-
- - {/* WAVE control - vertical buttons */} -
- WAVE -
- {WAVEFORMS.map((type) => ( - - ))} -
-
-
- - {/* Keyboard */} - {children} -
- ) -} - -/** - * SVG icons for waveform types - */ -function WaveformIcon({ type }) { - const width = 20 - const height = 14 - - switch (type) { - case 'sine': - return ( - - - - ) - case 'square': - return ( - - - - ) - case 'sawtooth': - return ( - - - - ) - case 'triangle': - return ( - - - - ) - default: - return null - } -} - -export default memo(KeyboardControls) diff --git a/src/components/LoadingOverlay.jsx b/src/components/LoadingOverlay.jsx deleted file mode 100644 index e284f0b..0000000 --- a/src/components/LoadingOverlay.jsx +++ /dev/null @@ -1,12 +0,0 @@ -function LoadingOverlay({ isLoading }) { - if (!isLoading) return null - - return ( -
-
-
Loading sounds...
-
- ) -} - -export default LoadingOverlay diff --git a/src/components/Pad.jsx b/src/components/Pad.jsx deleted file mode 100644 index 52db94b..0000000 --- a/src/components/Pad.jsx +++ /dev/null @@ -1,19 +0,0 @@ -import { memo } from 'react' - -const Pad = memo(function Pad({ active, playing, isBeatStart, onClick }) { - const classNames = [ - 'note-button', - active ? 'active' : '', - playing ? 'playing-step' : '', - isBeatStart ? 'beat-start' : '', - ].filter(Boolean).join(' ') - - return ( - - - - - - - {/* Speed control */} -
- SPEED -
- - - -
-
- - {/* Wave control */} -
- WAVE -
- - - - -
-
- - - - )} - - ) -} - -export default Sequencer diff --git a/src/components/Track.jsx b/src/components/Track.jsx deleted file mode 100644 index 046adc0..0000000 --- a/src/components/Track.jsx +++ /dev/null @@ -1,45 +0,0 @@ -import { memo } from 'react' -import Pad from './Pad' - -const Track = memo(function Track({ - instrument, - steps, - pattern, - currentStep, - onToggle, - showLabel = true, -}) { - // Group pads into groups of 4 - const padGroups = [] - for (let g = 0; g < steps; g += 4) { - padGroups.push( - Array.from({ length: 4 }, (_, i) => g + i) - ) - } - - return ( -
- {showLabel && {instrument.name}} -
- {padGroups.map((group, groupIndex) => ( -
- {group.map(i => ( - onToggle(instrument.id, i)} - /> - ))} -
- ))} -
-
- ) -}) - -export default Track diff --git a/src/components/TrackControls.jsx b/src/components/TrackControls.jsx deleted file mode 100644 index 1a8f0bd..0000000 --- a/src/components/TrackControls.jsx +++ /dev/null @@ -1,42 +0,0 @@ -import { memo } from 'react' -import Knob from './ui/Knob' - -const TrackControls = memo(function TrackControls({ - volume, - reverb, - filter, - onVolumeChange, - onReverbChange, - onFilterChange, -}) { - return ( -
- - - -
- ) -}) - -export default TrackControls diff --git a/src/components/TransportControls.jsx b/src/components/TransportControls.jsx deleted file mode 100644 index a832b7a..0000000 --- a/src/components/TransportControls.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import { useState, useEffect } from 'react' -import Button from './ui/Button' - -function TransportControls({ bpm, isPlaying, isLoading, onPlayStop, onReset, onBpmChange }) { - const [inputValue, setInputValue] = useState(String(bpm)) - - // Sync input when bpm prop changes externally - useEffect(() => { - setInputValue(String(bpm)) - }, [bpm]) - - const handleChange = (e) => { - setInputValue(e.target.value) - } - - const handleBlur = () => { - const parsed = parseInt(inputValue, 10) - if (!isNaN(parsed) && parsed >= 60 && parsed <= 200) { - onBpmChange(parsed) - } else { - // Reset to current bpm if invalid - setInputValue(String(bpm)) - } - } - - const handleKeyDown = (e) => { - if (e.key === 'Enter') { - e.target.blur() - } - } - - const increment = () => { - const newValue = Math.min(200, bpm + 1) - onBpmChange(newValue) - } - - const decrement = () => { - const newValue = Math.max(60, bpm - 1) - onBpmChange(newValue) - } - - return ( -
-
- TEMPO -
-
- -
-
- - -
-
-
-
- - -
-
- ) -} - -export default TransportControls diff --git a/src/components/ui/Button.jsx b/src/components/ui/Button.jsx deleted file mode 100644 index aa71534..0000000 --- a/src/components/ui/Button.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import { memo } from 'react' - -function Button({ variant = '', active = false, disabled = false, onClick, children }) { - const classes = ['btn'] - if (variant) classes.push(...variant.split(' ').map(v => 'btn-' + v)) - if (active) classes.push('active') - return -} - -export default memo(Button) diff --git a/src/components/ui/Fader.jsx b/src/components/ui/Fader.jsx deleted file mode 100644 index 5ecdf3c..0000000 --- a/src/components/ui/Fader.jsx +++ /dev/null @@ -1,137 +0,0 @@ -import { memo, useCallback, useRef } from 'react' - -/** - * Horizontal fader component with tick marks and draggable thumb - * Matches hardware mixer/synth fader aesthetic - */ -const Fader = memo(function Fader({ - value, - onChange, - min = 0, - max = 1, - step = 0.01, -}) { - const trackRef = useRef(null) - const dragStartRef = useRef(null) - - const range = max - min - const normalized = (value - min) / range - - const handleMouseDown = useCallback((e) => { - e.preventDefault() - const track = trackRef.current - if (!track) return - - const rect = track.getBoundingClientRect() - - dragStartRef.current = { - trackLeft: rect.left, - trackWidth: rect.width, - } - - // Set initial value based on click position - const clickX = e.clientX - rect.left - const newNormalized = Math.max(0, Math.min(1, clickX / rect.width)) - const newValue = min + newNormalized * range - const snapped = Math.round(newValue / step) * step - onChange(Math.max(min, Math.min(max, snapped))) - - const handleMouseMove = (e) => { - if (!dragStartRef.current) return - - const { trackLeft, trackWidth } = dragStartRef.current - const currentX = e.clientX - trackLeft - const newNormalized = Math.max(0, Math.min(1, currentX / trackWidth)) - const newValue = min + newNormalized * range - const snapped = Math.round(newValue / step) * step - onChange(Math.max(min, Math.min(max, snapped))) - } - - const handleMouseUp = () => { - dragStartRef.current = null - document.removeEventListener('mousemove', handleMouseMove) - document.removeEventListener('mouseup', handleMouseUp) - } - - document.addEventListener('mousemove', handleMouseMove) - document.addEventListener('mouseup', handleMouseUp) - }, [min, max, range, step, onChange]) - - const handleTouchStart = useCallback((e) => { - e.preventDefault() - const track = trackRef.current - if (!track) return - - const rect = track.getBoundingClientRect() - const touch = e.touches[0] - - dragStartRef.current = { - trackLeft: rect.left, - trackWidth: rect.width, - } - - const touchX = touch.clientX - rect.left - const newNormalized = Math.max(0, Math.min(1, touchX / rect.width)) - const newValue = min + newNormalized * range - const snapped = Math.round(newValue / step) * step - onChange(Math.max(min, Math.min(max, snapped))) - - const handleTouchMove = (e) => { - if (!dragStartRef.current) return - const touch = e.touches[0] - - const { trackLeft, trackWidth } = dragStartRef.current - const currentX = touch.clientX - trackLeft - const newNormalized = Math.max(0, Math.min(1, currentX / trackWidth)) - const newValue = min + newNormalized * range - const snapped = Math.round(newValue / step) * step - onChange(Math.max(min, Math.min(max, snapped))) - } - - const handleTouchEnd = () => { - dragStartRef.current = null - document.removeEventListener('touchmove', handleTouchMove) - document.removeEventListener('touchend', handleTouchEnd) - } - - document.addEventListener('touchmove', handleTouchMove, { passive: false }) - document.addEventListener('touchend', handleTouchEnd) - }, [min, max, range, step, onChange]) - - return ( -
-
- {/* Single tick line above */} -
- - {/* Track */} -
- {/* Thumb */} -
-
-
-
-
-
- - {/* Single tick line below */} -
-
-
- ) -}) - -export default Fader diff --git a/src/components/ui/Knob.jsx b/src/components/ui/Knob.jsx deleted file mode 100644 index 57551b0..0000000 --- a/src/components/ui/Knob.jsx +++ /dev/null @@ -1,158 +0,0 @@ -import { memo, useCallback, useRef, useEffect } from 'react' -import * as Label from '@radix-ui/react-label' - -const Knob = memo(function Knob({ - value, - onChange, - min = 0, - max = 1, - step = 0.01, - label, - size = 48, -}) { - const knobRef = useRef(null) - const dragStartRef = useRef(null) - - // Convert value to angle (0-270 degrees, starting from bottom-left) - const range = max - min - const normalized = (value - min) / range - - // Arc path calculation for the value indicator - const radius = (size - 8) / 2 - const centerX = size / 2 - const centerY = size / 2 - - // Calculate arc angles to match background track rotation (135 degrees) - // Background track starts at 135° (bottom-left) and spans 270° to 45° (bottom-right) - const startAngle = 135 * (Math.PI / 180) - const endAngle = (135 + normalized * 270) * (Math.PI / 180) - - const startX = centerX + radius * Math.cos(startAngle) - const startY = centerY + radius * Math.sin(startAngle) - const endX = centerX + radius * Math.cos(endAngle) - const endY = centerY + radius * Math.sin(endAngle) - - // largeArc flag should be 1 when arc exceeds 180 degrees - // For a 270 degree span, 180/270 = 0.6667 (2/3) - const largeArc = normalized > 2 / 3 ? 1 : 0 - - const handleMouseDown = useCallback((e) => { - e.preventDefault() - dragStartRef.current = { - y: e.clientY, - value: value, - } - - const handleMouseMove = (e) => { - if (!dragStartRef.current) return - - const deltaY = dragStartRef.current.y - e.clientY - const sensitivity = range / 150 // 150px drag = full range - const newValue = Math.min(max, Math.max(min, - dragStartRef.current.value + deltaY * sensitivity - )) - - // Snap to step - const snapped = Math.round(newValue / step) * step - onChange(snapped) - } - - const handleMouseUp = () => { - dragStartRef.current = null - document.removeEventListener('mousemove', handleMouseMove) - document.removeEventListener('mouseup', handleMouseUp) - } - - document.addEventListener('mousemove', handleMouseMove) - document.addEventListener('mouseup', handleMouseUp) - }, [value, min, max, range, step, onChange]) - - // Use useEffect to attach wheel listener with { passive: false } - // React 18 uses passive listeners by default, making e.preventDefault() ineffective - useEffect(() => { - const knob = knobRef.current - if (!knob) return - - const handleWheel = (e) => { - e.preventDefault() - const delta = e.deltaY > 0 ? -step : step - const newValue = Math.min(max, Math.max(min, value + delta * 5)) - onChange(Math.round(newValue / step) * step) - } - - knob.addEventListener('wheel', handleWheel, { passive: false }) - - return () => { - knob.removeEventListener('wheel', handleWheel) - } - }, [value, min, max, step, onChange]) - - return ( -
-
- - {/* Background track */} - - - {/* Value arc */} - {normalized > 0 && ( - - )} - - {/* Center dot / indicator */} - - - {/* Indicator line */} - - -
- {label && ( - - {label} - - )} -
- ) -}) - -export default Knob diff --git a/src/components/ui/README.md b/src/components/ui/README.md deleted file mode 100644 index 834a17a..0000000 --- a/src/components/ui/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# ui/ - -Reusable UI components. - -- `Button.jsx` - Button with variants -- `Knob.jsx` - Rotary knob control -- `Fader.jsx` - Vertical/horizontal slider -- `card.jsx` - Card container diff --git a/src/components/ui/card.jsx b/src/components/ui/card.jsx deleted file mode 100644 index 397151e..0000000 --- a/src/components/ui/card.jsx +++ /dev/null @@ -1,101 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -function Card({ - className, - ...props -}) { - return ( -
- ); -} - -function CardHeader({ - className, - ...props -}) { - return ( -
- ); -} - -function CardTitle({ - className, - ...props -}) { - return ( -
- ); -} - -function CardDescription({ - className, - ...props -}) { - return ( -
- ); -} - -function CardAction({ - className, - ...props -}) { - return ( -
- ); -} - -function CardContent({ - className, - ...props -}) { - return (
); -} - -function CardFooter({ - className, - ...props -}) { - return ( -
- ); -} - -export { - Card, - CardHeader, - CardFooter, - CardTitle, - CardAction, - CardDescription, - CardContent, -} diff --git a/src/config/README.md b/src/config/README.md deleted file mode 100644 index 614f21d..0000000 --- a/src/config/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# config/ - -Configuration files. - -- `instruments.js` - Drum kit definitions and sample paths -- `keyboard.js` - Keyboard layout and note mappings diff --git a/src/config/instruments.js b/src/config/instruments.js deleted file mode 100644 index 4c7e713..0000000 --- a/src/config/instruments.js +++ /dev/null @@ -1,68 +0,0 @@ -/** - * Instrument configuration for the drum machine. - * Add new instruments by adding entries to this array. - */ - -export const DEFAULT_INSTRUMENTS = [ - { - id: 'hihat', - name: 'HI-HAT', - path: '/808 Samples/hi hat (30).wav', - color: '#f5a623', - }, - { - id: 'snare', - name: 'SNARE', - path: '/808 Samples/snare.WAV', - color: '#f5a623', - }, - { - id: 'kick', - name: 'KICK', - path: '/808 Samples/kick.WAV', - color: '#f5a623', - }, -] - -/** - * Default track settings for each instrument - */ -export const DEFAULT_TRACK_SETTINGS = { - volume: 0.8, - reverb: 0, - filter: 1, - muted: false, - solo: false, -} - -/** - * Sequencer configuration - */ -export const SEQUENCER_CONFIG = { - steps: 16, - bpm: 120, - scheduleAheadTime: 0.1, // seconds - schedulerInterval: 25, // milliseconds -} - -/** - * Helper to create initial track settings for all instruments - */ -export function createInitialTrackSettings(instruments) { - const settings = {} - instruments.forEach(inst => { - settings[inst.id] = { ...DEFAULT_TRACK_SETTINGS } - }) - return settings -} - -/** - * Helper to create initial pattern state for all instruments - */ -export function createInitialPattern(instruments, steps) { - const pattern = {} - instruments.forEach(inst => { - pattern[inst.id] = Array(steps).fill(false) - }) - return pattern -} diff --git a/src/config/keyboard.js b/src/config/keyboard.js deleted file mode 100644 index 0989b27..0000000 --- a/src/config/keyboard.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Keyboard configuration for 2-octave synth (C3-B4) - * A4 = 440Hz standard tuning - */ - -export const NOTES = [ - // Octave 3 - { note: 'C3', freq: 130.81, type: 'white' }, - { note: 'C#3', freq: 138.59, type: 'black' }, - { note: 'D3', freq: 146.83, type: 'white' }, - { note: 'D#3', freq: 155.56, type: 'black' }, - { note: 'E3', freq: 164.81, type: 'white' }, - { note: 'F3', freq: 174.61, type: 'white' }, - { note: 'F#3', freq: 185.0, type: 'black' }, - { note: 'G3', freq: 196.0, type: 'white' }, - { note: 'G#3', freq: 207.65, type: 'black' }, - { note: 'A3', freq: 220.0, type: 'white' }, - { note: 'A#3', freq: 233.08, type: 'black' }, - { note: 'B3', freq: 246.94, type: 'white' }, - // Octave 4 - { note: 'C4', freq: 261.63, type: 'white' }, - { note: 'C#4', freq: 277.18, type: 'black' }, - { note: 'D4', freq: 293.66, type: 'white' }, - { note: 'D#4', freq: 311.13, type: 'black' }, - { note: 'E4', freq: 329.63, type: 'white' }, - { note: 'F4', freq: 349.23, type: 'white' }, - { note: 'F#4', freq: 369.99, type: 'black' }, - { note: 'G4', freq: 392.0, type: 'white' }, - { note: 'G#4', freq: 415.3, type: 'black' }, - { note: 'A4', freq: 440.0, type: 'white' }, - { note: 'A#4', freq: 466.16, type: 'black' }, - { note: 'B4', freq: 493.88, type: 'white' }, -] - -// Map QWERTY keys to notes -// Layout: -// W E T Y U O P -// A S D F G H J K L ; -export const QWERTY_MAP = { - // Bottom row - white keys (octave 3) - a: 'C3', - s: 'D3', - d: 'E3', - f: 'F3', - g: 'G3', - h: 'A3', - j: 'B3', - // Bottom row - white keys (octave 4) - k: 'C4', - l: 'D4', - ';': 'E4', - "'": 'F4', - // Top row - black keys (octave 3) - w: 'C#3', - e: 'D#3', - t: 'F#3', - y: 'G#3', - u: 'A#3', - // Top row - black keys (octave 4) - o: 'C#4', - p: 'D#4', - ']': 'F#4', - // Additional keys for remaining notes - z: 'G4', - x: 'A4', - c: 'B4', - '[': 'G#4', - '\\': 'A#4', -} - -// Reverse lookup: note -> QWERTY key (for displaying hints) -export const NOTE_TO_KEY = Object.fromEntries( - Object.entries(QWERTY_MAP).map(([key, note]) => [note, key]) -) - -// Get note data by note name -export const getNoteByName = (noteName) => NOTES.find((n) => n.note === noteName) - -// Available waveforms -export const WAVEFORMS = ['sawtooth', 'square', 'sine', 'triangle'] diff --git a/src/engine/arpeggiator.test.ts b/src/engine/arpeggiator.test.ts new file mode 100644 index 0000000..79d2f7c --- /dev/null +++ b/src/engine/arpeggiator.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest' +import { arpIndex, arpPlaysOnStep } from './arpeggiator' + +const sequence = (mode: Parameters[0], length: number, count: number) => + Array.from({ length: count }, (_, i) => arpIndex(mode, i, length)) + +describe('arpeggiator', () => { + it('walks held notes up, down, and up-down', () => { + expect(sequence('up', 3, 6)).toEqual([0, 1, 2, 0, 1, 2]) + expect(sequence('down', 3, 6)).toEqual([2, 1, 0, 2, 1, 0]) + expect(sequence('up-down', 3, 8)).toEqual([0, 1, 2, 1, 0, 1, 2, 1]) + expect(sequence('up-down', 1, 3)).toEqual([0, 0, 0]) + expect(arpIndex('up', 0, 0)).toBe(-1) + }) + + it('plays only on gated steps that land on the rate grid', () => { + expect(arpPlaysOnStep(4, true, '1/4')).toBe(true) + expect(arpPlaysOnStep(5, true, '1/4')).toBe(false) + expect(arpPlaysOnStep(2, true, '1/8')).toBe(true) + expect(arpPlaysOnStep(3, true, '1/8')).toBe(false) + expect(arpPlaysOnStep(3, true, '1/16')).toBe(true) + expect(arpPlaysOnStep(3, false, '1/16')).toBe(false) + }) +}) diff --git a/src/engine/arpeggiator.ts b/src/engine/arpeggiator.ts new file mode 100644 index 0000000..71fdb5b --- /dev/null +++ b/src/engine/arpeggiator.ts @@ -0,0 +1,22 @@ +import type { ArpMode, ArpRate } from '../session/schema' + +/** How many 16th-note steps each arp note lasts. */ +export const STEPS_PER_NOTE: Record = { '1/4': 4, '1/8': 2, '1/16': 1 } + +/** The arp plays on a step when its gate pad is on and the step lands on the rate's grid. */ +export const arpPlaysOnStep = (step: number, gateOn: boolean, rate: ArpRate): boolean => + gateOn && step % STEPS_PER_NOTE[rate] === 0 + +/** + * Which held note (in pitch order) plays for the `count`-th arp note. + * up: 0 1 2 0 1 2 · down: 2 1 0 2 1 0 · up-down: 0 1 2 1 0 1 2 1 + */ +export function arpIndex(mode: ArpMode, count: number, length: number): number { + if (length <= 0) return -1 + if (mode === 'up') return count % length + if (mode === 'down') return length - 1 - (count % length) + if (length === 1) return 0 + const cycle = length * 2 - 2 + const pos = count % cycle + return pos < length ? pos : cycle - pos +} diff --git a/src/engine/channel.ts b/src/engine/channel.ts new file mode 100644 index 0000000..70ab15e --- /dev/null +++ b/src/engine/channel.ts @@ -0,0 +1,31 @@ +import { glide } from './params' + +/** The DELAY knob at full sends this much to the echo, so repeats sit under the dry hit. */ +const MAX_SEND = 0.8 + +/** + * The same strip on every drum: volume → output, with a post-fader send to + * the shared delay. + */ +export class ChannelStrip { + readonly input: GainNode + private readonly send: GainNode + + constructor( + private readonly ctx: BaseAudioContext, + output: AudioNode, + delayInput: AudioNode, + ) { + this.input = ctx.createGain() + this.send = ctx.createGain() + this.send.gain.value = 0 + this.input.connect(output) + this.input.connect(this.send) + this.send.connect(delayInput) + } + + set(volume: number, delay: number): void { + glide(this.input.gain, volume, this.ctx) + glide(this.send.gain, delay * MAX_SEND, this.ctx) + } +} diff --git a/src/engine/clock.ts b/src/engine/clock.ts new file mode 100644 index 0000000..65083f6 --- /dev/null +++ b/src/engine/clock.ts @@ -0,0 +1,69 @@ +import { STEPS } from '../session/schema' + +/** How far ahead notes are scheduled, and how often the scheduler wakes up. */ +export const LOOKAHEAD = 0.1 +export const TICK_MS = 25 + +export const stepSeconds = (bpm: number): number => 60 / bpm / 4 + +/** + * Lookahead scheduler. A Worker drives the tick so playback stays steady when + * the tab is in the background, where main-thread timers are throttled. + */ +export class Clock { + private step = 0 + private nextTime = 0 + private ticker: { stop(): void } | null = null + + constructor( + private readonly ctx: BaseAudioContext, + private readonly secondsPerStep: () => number, + private readonly onStep: (step: number, time: number) => void, + ) {} + + get running(): boolean { + return this.ticker !== null + } + + start(): void { + if (this.ticker) return + this.step = 0 + this.nextTime = this.ctx.currentTime + 0.05 + this.tick() + this.ticker = startTicker(this.tick) + } + + stop(): void { + this.ticker?.stop() + this.ticker = null + } + + private readonly tick = (): void => { + const horizon = this.ctx.currentTime + LOOKAHEAD + while (this.nextTime < horizon) { + this.onStep(this.step, this.nextTime) + this.nextTime += this.secondsPerStep() + this.step = (this.step + 1) % STEPS + } + } +} + +function startTicker(tick: () => void): { stop(): void } { + if (typeof Worker !== 'undefined' && typeof Blob !== 'undefined') { + try { + const url = URL.createObjectURL(new Blob([`setInterval(() => postMessage(0), ${TICK_MS})`], { type: 'text/javascript' })) + const worker = new Worker(url) + worker.onmessage = tick + return { + stop() { + worker.terminate() + URL.revokeObjectURL(url) + }, + } + } catch { + // Fall through to a main-thread timer. + } + } + const id = setInterval(tick, TICK_MS) + return { stop: () => clearInterval(id) } +} diff --git a/src/engine/delay.ts b/src/engine/delay.ts new file mode 100644 index 0000000..d8050e9 --- /dev/null +++ b/src/engine/delay.ts @@ -0,0 +1,52 @@ +import { glide } from './params' + +/** Echo time in sixteenth steps: three is a dotted eighth, the classic disco and French house delay. */ +const ECHO_STEPS = 3 + +/** Each echo is this share of the one before, and the band the repeats are squeezed into so they darken as they fade. */ +const FEEDBACK = 0.5 +const BAND = { low: 250, high: 3200 } + +/** + * One shared tempo-synced ping-pong echo. Each drum's DELAY knob sets how much + * it sends here; repeats bounce left, right, left… into `destination`. + */ +export class DelayBus { + readonly input: GainNode + private readonly left: DelayNode + private readonly right: DelayNode + + constructor( + private readonly ctx: BaseAudioContext, + destination: AudioNode, + ) { + this.input = ctx.createGain() + this.left = ctx.createDelay(2) + this.right = ctx.createDelay(2) + const highpass = ctx.createBiquadFilter() + highpass.type = 'highpass' + highpass.frequency.value = BAND.low + const lowpass = ctx.createBiquadFilter() + lowpass.type = 'lowpass' + lowpass.frequency.value = BAND.high + const bounce = ctx.createGain() + bounce.gain.value = FEEDBACK + const feedback = ctx.createGain() + feedback.gain.value = FEEDBACK + const stereo = ctx.createChannelMerger(2) + + this.input.connect(this.left) + this.left.connect(highpass).connect(lowpass) + lowpass.connect(stereo, 0, 0) + lowpass.connect(bounce).connect(this.right) + this.right.connect(stereo, 0, 1) + this.right.connect(feedback).connect(this.left) + stereo.connect(destination) + } + + /** Keeps the echo on the beat when the tempo changes. */ + setStepSeconds(seconds: number): void { + glide(this.left.delayTime, seconds * ECHO_STEPS, this.ctx) + glide(this.right.delayTime, seconds * ECHO_STEPS, this.ctx) + } +} diff --git a/src/engine/drive.ts b/src/engine/drive.ts new file mode 100644 index 0000000..98e11db --- /dev/null +++ b/src/engine/drive.ts @@ -0,0 +1,58 @@ +/** + * Saturation for the kick, snare, and synth, and the mix bus they share. The + * grit is aimed at dirty French electro, but placed: highs (the hi-hat) and the + * full mix stay clean, so it reads as drive rather than a crushed lo-fi file. + */ + +const curves = new Map>() + +/** A tanh curve normalized to ±1; higher `amount` drives harder. Cached per amount. */ +export function saturationCurve(amount: number): Float32Array { + let curve = curves.get(amount) + if (!curve) { + const n = 2048 + curve = new Float32Array(new ArrayBuffer(n * 4)) + for (let i = 0; i < n; i++) { + const x = (i / (n - 1)) * 2 - 1 + curve[i] = Math.tanh(amount * x) / Math.tanh(amount) + } + curves.set(amount, curve) + } + return curve +} + +/** A saturator feeding `out`: connect sources to the returned node. */ +export function drive(ctx: BaseAudioContext, out: AudioNode, amount: number, level = 1): WaveShaperNode { + const shaper = ctx.createWaveShaper() + shaper.curve = saturationCurve(amount) + shaper.oversample = '4x' + if (level === 1) { + shaper.connect(out) + } else { + const trim = ctx.createGain() + trim.gain.value = level + shaper.connect(trim).connect(out) + } + return shaper +} + +/** Mix level into the limiter, leaving headroom so the limiter only catches stray peaks instead of squashing every kick. */ +const HEADROOM = 0.6 + +/** + * Mix bus: a gentle glue compressor into `destination`. Its slow attack lets + * each drum hit punch through before it clamps. Returns the bus input. + */ +export function createMixBus(ctx: BaseAudioContext, destination: AudioNode): GainNode { + const input = ctx.createGain() + const trim = ctx.createGain() + trim.gain.value = HEADROOM + const glue = ctx.createDynamicsCompressor() + glue.threshold.value = -14 + glue.knee.value = 8 + glue.ratio.value = 2.5 + glue.attack.value = 0.015 + glue.release.value = 0.2 + input.connect(glue).connect(trim).connect(destination) + return input +} diff --git a/src/engine/drums.ts b/src/engine/drums.ts new file mode 100644 index 0000000..46a618e --- /dev/null +++ b/src/engine/drums.ts @@ -0,0 +1,163 @@ +import { drive } from './drive' + +/** + * Synthesized drum voices in the dirty French electro style: an 808 kick, + * a 909 snare, and a disco open hat; the kick and snare are driven. No samples: + * every hit is built from oscillators and noise at its scheduled time, then + * sent through the drum's channel strip (volume, delay send). Each voice + * takes a `length` multiplier from its DECAY knob that stretches its tail. Levels peak around kick 0.95, snare 0.85, and + * hi-hat 0.4 before the channel volume. + */ + +export type DrumVoice = 'kick' | 'snare' | 'hihat' + +const noiseBuffers = new WeakMap() + +/** One second of white noise per context, reused by every hit. */ +function noise(ctx: BaseAudioContext): AudioBuffer { + let buffer = noiseBuffers.get(ctx) + if (!buffer) { + buffer = ctx.createBuffer(1, ctx.sampleRate, ctx.sampleRate) + const data = buffer.getChannelData(0) + for (let i = 0; i < data.length; i++) data[i] = Math.random() * 2 - 1 + noiseBuffers.set(ctx, buffer) + } + return buffer +} + +function noiseSource(ctx: BaseAudioContext, time: number, duration: number): AudioBufferSourceNode { + const src = ctx.createBufferSource() + src.buffer = noise(ctx) + src.loop = true + src.start(time, Math.random() * 0.5) + src.stop(time + duration) + return src +} + +/** Exponential decay envelope from `peak` to silence over `decay` seconds. */ +function envelope(ctx: BaseAudioContext, time: number, peak: number, decay: number, attack = 0.001): GainNode { + const g = ctx.createGain() + g.gain.setValueAtTime(0.0001, time) + g.gain.exponentialRampToValueAtTime(peak, time + attack) + g.gain.exponentialRampToValueAtTime(0.0001, time + attack + decay) + return g +} + +/** + * A gain into `out` that the next hit in the same group cuts off at its start + * time, like the 808's kick or a hi-hat pedal closing an open hat. + */ +function choked(ctx: BaseAudioContext, out: AudioNode, time: number, group: WeakMap): GainNode { + group.get(out)?.gain.setTargetAtTime(0, time, 0.008) + const gain = ctx.createGain() + gain.connect(out) + group.set(out, gain) + return gain +} + +const lastKick = new WeakMap() +const lastHat = new WeakMap() + +/** + * 808 kick: a sine that drops 110 → 52 Hz in 50 ms, then sags toward 45 Hz + * over a long boom. On top, a 909-style snap (a sine sweeping 3.5 kHz → 160 Hz + * in 25 ms) and a noise tick give the attack its punch. Light saturation adds + * harmonics so the low end carries on small speakers without losing its roundness. + */ +function kick(ctx: BaseAudioContext, out: AudioNode, time: number, length: number): void { + const dirt = drive(ctx, choked(ctx, out, time, lastKick), 2.5, 0.95) + + const body = ctx.createOscillator() + body.frequency.setValueAtTime(110, time) + body.frequency.exponentialRampToValueAtTime(52, time + 0.05) + body.frequency.exponentialRampToValueAtTime(45, time + 1.2 * length) + body.connect(envelope(ctx, time, 0.95, 1.5 * length, 0.002)).connect(dirt) + body.start(time) + body.stop(time + 1.5 * length + 0.1) + + const snap = ctx.createOscillator() + snap.frequency.setValueAtTime(3500, time) + snap.frequency.exponentialRampToValueAtTime(160, time + 0.025) + snap.connect(envelope(ctx, time, 0.5, 0.03, 0.0005)).connect(dirt) + snap.start(time) + snap.stop(time + 0.06) + + const click = noiseSource(ctx, time, 0.01) + const bp = ctx.createBiquadFilter() + bp.type = 'bandpass' + bp.frequency.value = 2500 + click.connect(bp).connect(envelope(ctx, time, 0.25, 0.006)).connect(dirt) +} + +/** Two low pitched shells under a thick noise snap, driven for a crunchy hit. */ +function snare(ctx: BaseAudioContext, out: AudioNode, time: number, length: number): void { + const dirt = drive(ctx, out, 2.2, 0.75) + + for (const [start, end, level] of [ + [200, 160, 0.35], + [330, 280, 0.18], + ]) { + const shell = ctx.createOscillator() + shell.type = 'triangle' + shell.frequency.setValueAtTime(start, time) + shell.frequency.exponentialRampToValueAtTime(end, time + 0.05) + shell.connect(envelope(ctx, time, level, 0.15 * length)).connect(dirt) + shell.start(time) + shell.stop(time + 0.15 * length + 0.1) + } + + const snap = noiseSource(ctx, time, 0.28 * length + 0.07) + const hp = ctx.createBiquadFilter() + hp.type = 'highpass' + hp.frequency.value = 900 + const peak = ctx.createBiquadFilter() + peak.type = 'peaking' + peak.frequency.value = 3500 + peak.gain.value = 5 + snap.connect(hp).connect(peak).connect(envelope(ctx, time, 0.45, 0.28 * length)).connect(dirt) +} + +/** + * Disco open hat: six detuned square waves at inharmonic ratios for the metal, + * plus noise for sizzle, band-passed high with a long "tsss" tail. The next + * hat closes it, so it opens fully on the off-beats and stays crisp in busy patterns. + */ +const HAT_RATIOS = [2, 3, 4.16, 5.43, 6.79, 8.21] + +function hihat(ctx: BaseAudioContext, out: AudioNode, time: number, length: number): void { + const mix = ctx.createGain() + mix.gain.value = 0.45 + for (const ratio of HAT_RATIOS) { + const osc = ctx.createOscillator() + osc.type = 'square' + osc.frequency.value = 40 * ratio + osc.connect(mix) + osc.start(time) + osc.stop(time + 0.6 * length + 0.1) + } + const air = noiseSource(ctx, time, 0.6 * length + 0.1) + const airLevel = ctx.createGain() + airLevel.gain.value = 0.7 + air.connect(airLevel).connect(mix) + + const bp = ctx.createBiquadFilter() + bp.type = 'bandpass' + bp.frequency.value = 9500 + bp.Q.value = 0.7 + const hp = ctx.createBiquadFilter() + hp.type = 'highpass' + hp.frequency.value = 7000 + // Left clean: driving the hat's highs only adds grain. + mix.connect(bp).connect(hp).connect(envelope(ctx, time, 0.75, 0.6 * length, 0.002)).connect(choked(ctx, out, time, lastHat)) +} + +type Voice = (ctx: BaseAudioContext, out: AudioNode, time: number, length: number) => void + +const VOICES: Record = { kick, snare, hihat } + +/** DECAY 0–1 to a tail multiplier: ¼× (tight, a closed hat) through 1× at center to 4× (long, a washy open hat). */ +export const decayLength = (decay: number): number => 2 ** (4 * decay - 2) + +export function playDrum(voice: DrumVoice, ctx: BaseAudioContext, out: AudioNode, time: number, decay = 0.5): void { + VOICES[voice](ctx, out, time, decayLength(decay)) +} diff --git a/src/engine/engine.ts b/src/engine/engine.ts new file mode 100644 index 0000000..5898062 --- /dev/null +++ b/src/engine/engine.ts @@ -0,0 +1,161 @@ +import { noteByName, type DrumDefinition } from '../instruments' +import type { Session } from '../session/schema' +import { arpIndex, arpPlaysOnStep } from './arpeggiator' +import { playDrum } from './drums' +import { Clock, stepSeconds } from './clock' +import { buildMixer, type Mixer } from './mixer' +import type { Voice } from './synth' + +/** What the UI shows while playing: the step under the playhead and the synth note fired on it. */ +export interface Playhead { + step: number + note: string | null +} + +export const STOPPED: Playhead = { step: -1, note: null } + +interface Graph extends Mixer { + ctx: AudioContext + clock: Clock +} + +type Listener = () => void + +/** + * The audio engine. It has no UI dependencies: callers hand it a session and + * read the playhead back. Scheduling runs ahead on the audio clock; the + * playhead is published when each step actually sounds. + */ +export class Engine { + private graph: Graph | null = null + private session: Session | null = null + private playhead: Playhead = STOPPED + private pending: Array<{ time: number } & Playhead> = [] + private frame = 0 + private arpCount = 0 + private lastVoice: Voice | null = null + private readonly listeners = new Set() + + constructor(private readonly drums: readonly DrumDefinition[]) {} + + /** Creates the audio graph. Safe to call again after `dispose`. */ + load(): void { + if (this.graph) return + const ctx = new AudioContext() + const graph: Graph = { + ctx, + ...buildMixer(ctx, this.drums), + clock: new Clock(ctx, () => stepSeconds(this.session?.bpm ?? 120), this.scheduleStep), + } + this.graph = graph + if (this.session) this.applyParams(this.session) + } + + dispose(): void { + this.stop() + void this.graph?.ctx.close() + this.graph = null + } + + /** Called on every session change; knob values glide to their new settings. */ + apply(session: Session): void { + this.session = session + if (this.graph) this.applyParams(session) + } + + get isPlaying(): boolean { + return this.graph?.clock.running ?? false + } + + getPlayhead = (): Playhead => this.playhead + + subscribe = (listener: Listener): (() => void) => { + this.listeners.add(listener) + return () => this.listeners.delete(listener) + } + + async start(): Promise { + const g = this.graph + if (!g || g.clock.running) return + if (g.ctx.state === 'suspended') await g.ctx.resume() + this.arpCount = 0 + g.clock.start() + this.frame = requestAnimationFrame(this.publish) + this.emit() + } + + stop(): void { + const g = this.graph + if (!g) return + g.clock.stop() + g.synth.releaseAll() + this.lastVoice = null + this.pending = [] + cancelAnimationFrame(this.frame) + this.playhead = STOPPED + this.emit() + } + + private applyParams(session: Session): void { + const g = this.graph! + for (const [id, strip] of g.channels) { + const t = session.drums[id] + if (t) strip.set(t.volume, t.delay) + } + g.echo.setStepSeconds(stepSeconds(session.bpm)) + g.synth.setVolume(session.synth.volume) + g.synth.setWaveform(session.synth.waveform) + } + + private readonly scheduleStep = (step: number, time: number): void => { + const g = this.graph + const s = this.session + if (!g || !s) return + + for (const drum of this.drums) { + const strip = g.channels.get(drum.id) + const track = s.drums[drum.id] + if (!track?.steps[step] || !strip) continue + playDrum(drum.voice, g.ctx, strip.input, time, track.decay) + if (drum.voice === 'kick') g.pump.duck(time) + } + + let note: string | null = null + const { synth } = s + // With every key let go, the last note ends on this step instead of droning on. + if (synth.notes.length === 0 && this.lastVoice) { + g.synth.release(this.lastVoice, time) + this.lastVoice = null + } + if (arpPlaysOnStep(step, synth.steps[step], synth.rate) && synth.notes.length > 0) { + note = synth.notes[arpIndex(synth.mode, this.arpCount, synth.notes.length)] + const def = noteByName(note) + if (def) { + if (this.lastVoice) g.synth.release(this.lastVoice, time) + this.lastVoice = g.synth.noteOn(def.freq * 2 ** synth.octave, time) + this.arpCount++ + } + } + this.pending.push({ time, step, note }) + } + + private readonly publish = (): void => { + const g = this.graph + if (!g) return + const now = g.ctx.currentTime + let next: Playhead | null = null + while (this.pending.length && this.pending[0].time <= now) { + const { step, note } = this.pending.shift()! + next = { step, note } + } + if (next) { + this.playhead = next + this.emit() + } + this.frame = requestAnimationFrame(this.publish) + } + + private emit(): void { + this.listeners.forEach((l) => l()) + } +} diff --git a/src/engine/mixer.ts b/src/engine/mixer.ts new file mode 100644 index 0000000..a5c13a6 --- /dev/null +++ b/src/engine/mixer.ts @@ -0,0 +1,40 @@ +import type { DrumDefinition } from '../instruments' +import { ChannelStrip } from './channel' +import { DelayBus } from './delay' +import { createMixBus } from './drive' +import { Pump } from './pump' +import { createReverbBus } from './reverb' +import { Synth } from './synth' + +export interface Mixer { + channels: Map + echo: DelayBus + synth: Synth + pump: Pump +} + +/** + * The whole signal chain, from voices to speakers: + * + * drums → channel strips ─────────────────────┐ + * └ delay send → echo ───┐ │ + * synth ────────────────────────────┼→ pump ──┴→ mix bus → limiter → out + * └ reverb send → reverb ─────────┘ + * + * Shared by the live engine and offline renders, so both hear the same thing. + */ +export function buildMixer(ctx: BaseAudioContext, drums: readonly DrumDefinition[]): Mixer { + const limiter = ctx.createDynamicsCompressor() + limiter.threshold.value = -3 + limiter.knee.value = 0 + limiter.ratio.value = 20 + limiter.attack.value = 0.001 + limiter.release.value = 0.1 + limiter.connect(ctx.destination) + const bus = createMixBus(ctx, limiter) + const pump = new Pump(ctx, bus) + const reverb = createReverbBus(ctx, pump.input) + const echo = new DelayBus(ctx, pump.input) + const channels = new Map(drums.map((d) => [d.id, new ChannelStrip(ctx, bus, echo.input)])) + return { channels, echo, synth: new Synth(ctx, pump.input, reverb), pump } +} diff --git a/src/engine/params.ts b/src/engine/params.ts new file mode 100644 index 0000000..e0ad543 --- /dev/null +++ b/src/engine/params.ts @@ -0,0 +1,6 @@ +/** Seconds a parameter takes to settle, so knob moves glide instead of clicking. */ +export const SMOOTHING = 0.015 + +export function glide(param: AudioParam, value: number, ctx: BaseAudioContext): void { + param.setTargetAtTime(value, ctx.currentTime, SMOOTHING) +} diff --git a/src/engine/pump.ts b/src/engine/pump.ts new file mode 100644 index 0000000..3e2814f --- /dev/null +++ b/src/engine/pump.ts @@ -0,0 +1,24 @@ +/** How far the pumped parts dip on each kick (-16 dB), how fast, and how they swell back. */ +const DUCK = { depth: 0.16, attack: 0.004, hold: 0.02, recover: 0.1 } + +/** + * Sidechain pump: everything sustained (the synth, the delay, and the reverb) + * runs through here and ducks on every kick, the French house breathing. + * The drums bypass it so their hits stay intact. + */ +export class Pump { + readonly input: GainNode + + constructor(ctx: BaseAudioContext, destination: AudioNode) { + this.input = ctx.createGain() + this.input.connect(destination) + } + + /** Dips at `time`, when a kick lands, then swells back. */ + duck(time: number): void { + const gain = this.input.gain + gain.cancelScheduledValues(time) + gain.setTargetAtTime(DUCK.depth, time, DUCK.attack) + gain.setTargetAtTime(1, time + DUCK.hold, DUCK.recover) + } +} diff --git a/src/engine/reverb.ts b/src/engine/reverb.ts new file mode 100644 index 0000000..ff51e42 --- /dev/null +++ b/src/engine/reverb.ts @@ -0,0 +1,27 @@ +/** + * One shared reverb return bus, used by the synth for a little space. The + * impulse response is generated, so no file is needed. + */ +export function createReverbBus(ctx: BaseAudioContext, destination: AudioNode, seconds = 2.2): GainNode { + const input = ctx.createGain() + const convolver = ctx.createConvolver() + convolver.buffer = makeImpulse(ctx, seconds) + const ret = ctx.createGain() + ret.gain.value = 0.9 + input.connect(convolver) + convolver.connect(ret) + ret.connect(destination) + return input +} + +function makeImpulse(ctx: BaseAudioContext, seconds: number): AudioBuffer { + const length = Math.floor(ctx.sampleRate * seconds) + const impulse = ctx.createBuffer(2, length, ctx.sampleRate) + for (let ch = 0; ch < 2; ch++) { + const data = impulse.getChannelData(ch) + for (let i = 0; i < length; i++) { + data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / length, 3) + } + } + return impulse +} diff --git a/src/engine/synth.ts b/src/engine/synth.ts new file mode 100644 index 0000000..db4b963 --- /dev/null +++ b/src/engine/synth.ts @@ -0,0 +1,147 @@ +import type { Waveform } from '../session/schema' +import { drive } from './drive' +import { glide } from './params' + +const ENVELOPE = { attack: 0.008, decay: 0.18, sustain: 0.6, release: 0.25 } + +/** + * Supersaw-style unison: seven oscillators detuned up to ±22 cents and spread + * across the stereo field give the dense, wide tone; a centered sub an octave + * down gives it weight. Positions run -1 (left) to 1 (right). + */ +const UNISON = [-1, -0.62, -0.3, 0, 0.3, 0.62, 1] +const DETUNE_CENTS = 22 +const STEREO_SPREAD = 0.85 +const SUB_LEVEL = 0.25 + +/** A small share of the synth goes to the shared reverb so the arp has some space. */ +const REVERB_SEND = 0.18 + +/** Each note's filter opens to `peak` × the base cutoff and settles back, so notes pluck instead of drone. */ +const FILTER = { peak: 3.5, settle: 0.2, resonance: 2.5 } + +/** Bright waves get a lower base cutoff so they stay warm under the drive. */ +const cutoffFor = (waveform: Waveform): number => (waveform === 'sawtooth' || waveform === 'square' ? 3600 : 6000) + +/** The filtered voices are driven after the filter, the gritty French electro way. */ +const DRIVE = { amount: 1.8, level: 0.8 } + +/** A steep low-pass after the drive shaves off the fizz the saturation adds on top, above the 2–6 kHz presence range. */ +const HIGH_CUT = 7000 + +export interface Voice { + /** The unison oscillators, which follow the waveform. */ + unison: OscillatorNode[] + oscs: OscillatorNode[] + filter: BiquadFilterNode + env: GainNode +} + +/** Arp synth voice: stereo unison + sub → plucked low-pass → ADSR → drive → high cut. Voices start and release at scheduled times. */ +export class Synth { + readonly output: GainNode + private readonly input: AudioNode + private waveform: Waveform = 'sawtooth' + private readonly voices = new Set() + + constructor( + private readonly ctx: BaseAudioContext, + destination: AudioNode, + reverbInput: AudioNode, + ) { + this.output = ctx.createGain() + // Two 12 dB/octave stages make a 24 dB/octave cut. Web Audio's low-pass Q is in dB; -3 is flat (Butterworth), with no bump before the cut. + const [cutA, cutB] = [0, 1].map(() => { + const f = ctx.createBiquadFilter() + f.type = 'lowpass' + f.frequency.value = HIGH_CUT + f.Q.value = -3 + return f + }) + cutA.connect(cutB).connect(this.output) + this.input = drive(ctx, cutA, DRIVE.amount, DRIVE.level) + this.output.connect(destination) + const send = ctx.createGain() + send.gain.value = REVERB_SEND + this.output.connect(send) + send.connect(reverbInput) + } + + setVolume(volume: number): void { + glide(this.output.gain, volume, this.ctx) + } + + setWaveform(waveform: Waveform): void { + if (waveform === this.waveform) return + this.waveform = waveform + for (const v of this.voices) { + for (const osc of v.unison) osc.type = waveform + glide(v.filter.frequency, cutoffFor(waveform), this.ctx) + } + } + + noteOn(frequency: number, time: number): Voice { + const { ctx } = this + const mix = ctx.createGain() + mix.gain.value = 1 / Math.sqrt(UNISON.length) + + const unison = UNISON.map((position) => { + const osc = ctx.createOscillator() + osc.type = this.waveform + osc.frequency.setValueAtTime(frequency, time) + osc.detune.setValueAtTime(position * DETUNE_CENTS, time) + const pan = ctx.createStereoPanner() + pan.pan.value = position * STEREO_SPREAD + osc.connect(pan).connect(mix) + return osc + }) + const sub = ctx.createOscillator() + sub.type = 'sine' + sub.frequency.setValueAtTime(frequency / 2, time) + const subLevel = ctx.createGain() + subLevel.gain.value = SUB_LEVEL + const oscs = [...unison, sub] + + const base = cutoffFor(this.waveform) + const filter = ctx.createBiquadFilter() + filter.type = 'lowpass' + filter.Q.value = FILTER.resonance + filter.frequency.setValueAtTime(base * FILTER.peak, time) + filter.frequency.exponentialRampToValueAtTime(base, time + FILTER.settle) + + const env = ctx.createGain() + env.gain.setValueAtTime(0, time) + env.gain.linearRampToValueAtTime(1, time + ENVELOPE.attack) + env.gain.linearRampToValueAtTime(ENVELOPE.sustain, time + ENVELOPE.attack + ENVELOPE.decay) + + mix.connect(filter) + sub.connect(subLevel).connect(filter) + filter.connect(env) + env.connect(this.input) + // Each unison oscillator starts a random fraction of a cycle late, so they begin out of phase instead of flanging. + unison.forEach((o) => o.start(time + Math.random() / frequency)) + sub.start(time) + + const voice = { unison, oscs, filter, env } + this.voices.add(voice) + oscs[0].onended = () => { + this.voices.delete(voice) + env.disconnect() + } + return voice + } + + /** Releases at `time`, the moment the next note starts, not when it was scheduled. */ + release(voice: Voice, time: number): void { + const gain = voice.env.gain + if (typeof gain.cancelAndHoldAtTime === 'function') gain.cancelAndHoldAtTime(time) + else gain.cancelScheduledValues(time) + gain.setTargetAtTime(0, time, ENVELOPE.release / 4) + voice.oscs.forEach((o) => o.stop(time + ENVELOPE.release + 0.05)) + } + + releaseAll(): void { + const now = this.ctx.currentTime + for (const v of this.voices) this.release(v, now) + } +} diff --git a/src/hooks/README.md b/src/hooks/README.md deleted file mode 100644 index 9eb67c6..0000000 --- a/src/hooks/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# hooks/ - -Custom React hooks for audio functionality. - -- `useAudioEngine.js` - Web Audio API setup, sample loading, playback -- `useSequencer.js` - Step sequencer state and scheduling -- `useSynthEngine.js` - Synthesizer with oscillators, filter, effects -- `useArpeggiator.js` - Arpeggiator patterns and timing diff --git a/src/hooks/useArpeggiator.js b/src/hooks/useArpeggiator.js deleted file mode 100644 index 5eeb4c5..0000000 --- a/src/hooks/useArpeggiator.js +++ /dev/null @@ -1,171 +0,0 @@ -import { useState, useCallback, useRef } from 'react' -import { getNoteByName } from '../config/keyboard' - -/** - * Arpeggiator hook - cycles through held notes in a pattern - */ -export function useArpeggiator(synth) { - // 16-step gate pattern - const [pattern, setPattern] = useState(() => Array(16).fill(false)) - // Notes currently held (toggled on) - const [heldNotes, setHeldNotes] = useState(() => new Set()) - // Arpeggiator mode: 'up', 'down', 'up-down' - const [mode, setMode] = useState('up') - // Rate: '1/4', '1/8', '1/16' - const [rate, setRate] = useState('1/16') - - // Refs for scheduling (don't trigger re-renders) - const arpStepRef = useRef(0) - const lastPlayedNoteRef = useRef(null) - const directionRef = useRef(1) // 1 = up, -1 = down (for up-down mode) - const onNoteChangeRef = useRef(null) - - // Toggle a step in the gate pattern - const toggleStep = useCallback((index) => { - setPattern((prev) => - prev.map((val, i) => (i === index ? !val : val)) - ) - }, []) - - // Toggle a note on/off - const toggleNote = useCallback((noteName) => { - setHeldNotes((prev) => { - const next = new Set(prev) - if (next.has(noteName)) { - next.delete(noteName) - } else { - next.add(noteName) - } - return next - }) - }, []) - - // Clear all held notes - const clearNotes = useCallback(() => { - setHeldNotes(new Set()) - }, []) - - // Set callback for note change (for keyboard highlighting) - const setOnNoteChange = useCallback((callback) => { - onNoteChangeRef.current = callback - }, []) - - // Get sorted notes by frequency (low to high) - const getSortedNotes = useCallback(() => { - return [...heldNotes].sort((a, b) => { - const freqA = getNoteByName(a)?.freq || 0 - const freqB = getNoteByName(b)?.freq || 0 - return freqA - freqB - }) - }, [heldNotes]) - - // Calculate which note to play based on mode - const getNextNoteIndex = useCallback((sortedNotes) => { - const len = sortedNotes.length - if (len === 0) return -1 - - const step = arpStepRef.current - - if (mode === 'up') { - return step % len - } else if (mode === 'down') { - return (len - 1) - (step % len) - } else if (mode === 'up-down') { - if (len === 1) return 0 - // Ping-pong: 0,1,2,1,0,1,2,1... - const cycle = len * 2 - 2 - const pos = step % cycle - if (pos < len) { - return pos - } else { - return cycle - pos - } - } - return 0 - }, [mode]) - - // Schedule arp notes - called by sequencer - const scheduleArpNote = useCallback((currentStep, noteTime, stepTime) => { - // Check if gate is open for this step - if (!pattern[currentStep]) { - return - } - - // Rate determines how often we advance the arp - const stepsPerArpNote = { '1/4': 4, '1/8': 2, '1/16': 1 } - const skipSteps = stepsPerArpNote[rate] || 1 - - // Only play on matching steps - if (currentStep % skipSteps !== 0) { - return - } - - const sortedNotes = getSortedNotes() - if (sortedNotes.length === 0) return - - const noteIndex = getNextNoteIndex(sortedNotes) - if (noteIndex < 0) return - - const noteName = sortedNotes[noteIndex] - const noteData = getNoteByName(noteName) - if (!noteData) return - - // Stop previous note - if (lastPlayedNoteRef.current) { - synth.stopNote('arp-' + lastPlayedNoteRef.current) - } - - // Play new note - synth.playNote('arp-' + noteName, noteData.freq, noteTime) - lastPlayedNoteRef.current = noteName - - // Notify keyboard of current note - if (onNoteChangeRef.current) { - onNoteChangeRef.current(noteName) - } - - // Advance arp step - arpStepRef.current++ - }, [pattern, rate, getSortedNotes, getNextNoteIndex, synth]) - - // Stop current arp note (called when playback stops) - const stopArp = useCallback(() => { - if (lastPlayedNoteRef.current) { - synth.stopNote('arp-' + lastPlayedNoteRef.current) - lastPlayedNoteRef.current = null - } - arpStepRef.current = 0 - directionRef.current = 1 - if (onNoteChangeRef.current) { - onNoteChangeRef.current(null) - } - }, [synth]) - - // Reset pattern - const resetPattern = useCallback(() => { - setPattern(Array(16).fill(false)) - }, []) - - return { - // State - pattern, - heldNotes, - mode, - rate, - - // Actions - toggleStep, - toggleNote, - clearNotes, - setMode, - setRate, - resetPattern, - setOnNoteChange, - - // Scheduling - scheduleArpNote, - stopArp, - } -} - -export default useArpeggiator diff --git a/src/hooks/useAudioEngine.js b/src/hooks/useAudioEngine.js deleted file mode 100644 index 4f70dfb..0000000 --- a/src/hooks/useAudioEngine.js +++ /dev/null @@ -1,266 +0,0 @@ -import { useState, useRef, useCallback, useEffect } from 'react' - -/** - * Custom hook for managing Web Audio API - * Handles loading sounds, playback, and per-track volume/effects - */ -export function useAudioEngine(instruments) { - const [isLoading, setIsLoading] = useState(true) - const [analyser, setAnalyser] = useState(null) - const audioContextRef = useRef(null) - const audioBuffersRef = useRef({}) - const effectNodesRef = useRef({}) - const masterGainRef = useRef(null) - const analyserRef = useRef(null) - const initCountRef = useRef(0) - - // Initialize audio context and load all instrument samples - useEffect(() => { - const currentInit = ++initCountRef.current - - const initAudio = async () => { - try { - // Close any existing context first - if (audioContextRef.current && audioContextRef.current.state !== 'closed') { - audioContextRef.current.close() - } - - const ctx = new (window.AudioContext || window.webkitAudioContext)() - audioContextRef.current = ctx - - // Create master gain and analyser for visualization - const masterGain = ctx.createGain() - const analyserNode = ctx.createAnalyser() - analyserNode.fftSize = 256 - analyserNode.smoothingTimeConstant = 0.8 - - masterGain.connect(analyserNode) - analyserNode.connect(ctx.destination) - - masterGainRef.current = masterGain - analyserRef.current = analyserNode - setAnalyser(analyserNode) - - // Create effect nodes for each instrument - instruments.forEach(instrument => { - const mainGain = ctx.createGain() - const lowpassFilter = ctx.createBiquadFilter() - const reverbGain = ctx.createGain() - const delayNode = ctx.createDelay(1.0) - const delayFeedback = ctx.createGain() - const delayWetGain = ctx.createGain() - const outputGain = ctx.createGain() - - // Initial settings - lowpassFilter.type = 'lowpass' - lowpassFilter.frequency.value = 20000 // Start fully open - lowpassFilter.Q.value = 1 - delayNode.delayTime.value = 0 - delayFeedback.gain.value = 0 - delayWetGain.gain.value = 0 - reverbGain.gain.value = 0 - - // Signal routing: - // mainGain -> lowpassFilter -> outputGain (dry) - // mainGain -> reverbGain -> outputGain - // mainGain -> delayNode -> delayFeedback -> delayNode (feedback loop) - // -> delayWetGain -> outputGain - mainGain.connect(lowpassFilter) - lowpassFilter.connect(outputGain) // Dry signal with filter - mainGain.connect(reverbGain) - reverbGain.connect(outputGain) - mainGain.connect(delayNode) - delayNode.connect(delayFeedback) - delayFeedback.connect(delayNode) - delayNode.connect(delayWetGain) - delayWetGain.connect(outputGain) - outputGain.connect(masterGain) // Route through master for visualization - - effectNodesRef.current[instrument.id] = { - mainGain, - lowpassFilter, - reverbGain, - delayNode, - delayFeedback, - delayWetGain, - outputGain, - } - }) - - // Load all samples - for (const instrument of instruments) { - // Check if this init is still current - if (currentInit !== initCountRef.current) return - - try { - const response = await fetch(instrument.path) - if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${response.statusText}`) - } - const arrayBuffer = await response.arrayBuffer() - - // Check again before decode - if (currentInit !== initCountRef.current || ctx.state === 'closed') return - - audioBuffersRef.current[instrument.id] = await ctx.decodeAudioData(arrayBuffer) - } catch (error) { - // Swallow load errors to allow remaining samples to continue - } - } - - // Only set loading false if this init is still current - if (currentInit === initCountRef.current) { - setIsLoading(false) - } - } catch (error) { - if (currentInit === initCountRef.current) { - setIsLoading(false) - } - } - } - - initAudio() - - return () => { - if (audioContextRef.current && audioContextRef.current.state !== 'closed') { - audioContextRef.current.close() - } - } - }, []) - - // Play a sound at a specific time - const playSound = useCallback((instrumentId, time, trackSettings) => { - if (!audioBuffersRef.current[instrumentId] || !audioContextRef.current) return - - // Check mute/solo - if (trackSettings?.muted) return - - const source = audioContextRef.current.createBufferSource() - source.buffer = audioBuffersRef.current[instrumentId] - - // Connect through effect chain - const nodes = effectNodesRef.current[instrumentId] - if (nodes) { - nodes.mainGain.gain.value = trackSettings?.volume ?? 0.8 - source.connect(nodes.mainGain) - } else { - source.connect(audioContextRef.current.destination) - } - - source.start(time) - }, []) - - // Set volume for a specific track - const setTrackVolume = useCallback((instrumentId, volume) => { - const nodes = effectNodesRef.current[instrumentId] - if (nodes && audioContextRef.current) { - nodes.mainGain.gain.setValueAtTime(volume, audioContextRef.current.currentTime) - } - }, []) - - // Set effect parameters for a track - const setEffect = useCallback((instrumentId, effectType, value) => { - const nodes = effectNodesRef.current[instrumentId] - if (!nodes || !audioContextRef.current) return - - const sliderValue = parseFloat(value) - const currentTime = audioContextRef.current.currentTime - - if (effectType === 'reverb') { - const reverbAmount = sliderValue - nodes.reverbGain.gain.setValueAtTime(reverbAmount, currentTime) - } - - if (effectType === 'delay') { - const delayTime = sliderValue * 0.5 - const feedbackAmount = sliderValue * 0.7 - const wetAmount = sliderValue * 0.5 - nodes.delayNode.delayTime.setValueAtTime(delayTime, currentTime) - nodes.delayFeedback.gain.setValueAtTime(feedbackAmount, currentTime) - nodes.delayWetGain.gain.setValueAtTime(wetAmount, currentTime) - } - - if (effectType === 'filter') { - const minFreq = 200 - const maxFreq = 20000 - const cutoff = minFreq * Math.pow(maxFreq / minFreq, sliderValue) - nodes.lowpassFilter.frequency.setValueAtTime(cutoff, currentTime) - } - }, []) - - // Resume audio context (needed for browser autoplay policies) - const resumeContext = useCallback(async () => { - if (audioContextRef.current?.state === 'suspended') { - await audioContextRef.current.resume() - } - }, []) - - // Get current audio context time - const getCurrentTime = useCallback(() => { - return audioContextRef.current?.currentTime ?? 0 - }, []) - - // Load a new instrument dynamically - const loadInstrument = useCallback(async (instrument) => { - if (!audioContextRef.current) return false - const ctx = audioContextRef.current - - try { - // Create effect nodes - const mainGain = ctx.createGain() - const lowpassFilter = ctx.createBiquadFilter() - const reverbGain = ctx.createGain() - const delayNode = ctx.createDelay(1.0) - const delayFeedback = ctx.createGain() - const delayWetGain = ctx.createGain() - const outputGain = ctx.createGain() - - lowpassFilter.type = 'lowpass' - lowpassFilter.frequency.value = 20000 // Start fully open - lowpassFilter.Q.value = 1 - delayNode.delayTime.value = 0 - delayFeedback.gain.value = 0 - delayWetGain.gain.value = 0 - reverbGain.gain.value = 0 - - mainGain.connect(lowpassFilter) - lowpassFilter.connect(outputGain) - mainGain.connect(reverbGain) - reverbGain.connect(outputGain) - mainGain.connect(delayNode) - delayNode.connect(delayFeedback) - delayFeedback.connect(delayNode) - delayNode.connect(delayWetGain) - delayWetGain.connect(outputGain) - outputGain.connect(masterGainRef.current || ctx.destination) - - effectNodesRef.current[instrument.id] = { - mainGain, lowpassFilter, reverbGain, delayNode, delayFeedback, delayWetGain, outputGain, - } - - // Load sample - const response = await fetch(instrument.path) - const arrayBuffer = await response.arrayBuffer() - audioBuffersRef.current[instrument.id] = await ctx.decodeAudioData(arrayBuffer) - - return true - } catch (error) { - return false - } - }, []) - - return { - isLoading, - analyser, - audioContext: audioContextRef.current, - masterGain: masterGainRef.current, - playSound, - setTrackVolume, - setEffect, - resumeContext, - getCurrentTime, - loadInstrument, - } -} - -export default useAudioEngine diff --git a/src/hooks/useSequencer.js b/src/hooks/useSequencer.js deleted file mode 100644 index b08cfb6..0000000 --- a/src/hooks/useSequencer.js +++ /dev/null @@ -1,239 +0,0 @@ -import { useState, useRef, useCallback, useEffect } from 'react' -import { createInitialPattern, createInitialTrackSettings, SEQUENCER_CONFIG } from '../config/instruments' -import { decodeStateFromUrl, encodeStateToUrl } from '../utils/urlState' - -/** - * Custom hook for managing sequencer state and playback timing - */ -export function useSequencer(instruments, audioEngine, arpeggiator = null) { - const { steps, bpm: defaultBpm, scheduleAheadTime, schedulerInterval } = SEQUENCER_CONFIG - - // Initialize state from URL if available - const [pattern, setPattern] = useState(() => { - const urlState = decodeStateFromUrl(instruments, steps) - return urlState.pattern || createInitialPattern(instruments, steps) - }) - const [trackSettings, setTrackSettings] = useState(() => { - const urlState = decodeStateFromUrl(instruments, steps) - return urlState.trackSettings || createInitialTrackSettings(instruments) - }) - const [bpm, setBpmState] = useState(() => { - const urlState = decodeStateFromUrl(instruments, steps) - return urlState.bpm || defaultBpm - }) - const [isPlaying, setIsPlaying] = useState(false) - const [currentStep, setCurrentStep] = useState(-1) - - // Compute stepTime dynamically from bpm - const stepTime = 60 / bpm / 4 // Time per 16th note - - // Refs for playback timing (don't trigger re-renders) - const nextNoteTimeRef = useRef(0) - const currentStepRef = useRef(0) - const timerIdRef = useRef(null) - const startTimeRef = useRef(0) - const animationFrameRef = useRef(null) - const isPlayingRef = useRef(false) - const patternRef = useRef(pattern) - const trackSettingsRef = useRef(trackSettings) - const bpmRef = useRef(bpm) - const stepTimeRef = useRef(stepTime) - const arpeggiatorRef = useRef(arpeggiator) - - // Keep refs in sync with state - useEffect(() => { - isPlayingRef.current = isPlaying - }, [isPlaying]) - - useEffect(() => { - patternRef.current = pattern - }, [pattern]) - - useEffect(() => { - trackSettingsRef.current = trackSettings - }, [trackSettings]) - - useEffect(() => { - bpmRef.current = bpm - stepTimeRef.current = 60 / bpm / 4 - }, [bpm]) - - useEffect(() => { - arpeggiatorRef.current = arpeggiator - }, [arpeggiator]) - - // Check if any track is soloed - const hasSoloedTrack = useCallback(() => { - return Object.values(trackSettingsRef.current).some(s => s.solo) - }, []) - - // Check if a track should play (considering solo/mute) - const shouldTrackPlay = useCallback((instrumentId) => { - const settings = trackSettingsRef.current[instrumentId] - if (!settings) return true - - if (settings.muted) return false - if (hasSoloedTrack()) { - return settings.solo - } - return true - }, [hasSoloedTrack]) - - // Scheduler function - schedules notes ahead of time - const scheduler = useCallback(() => { - const currentTime = audioEngine.getCurrentTime() - - while (nextNoteTimeRef.current < currentTime + scheduleAheadTime) { - const step = currentStepRef.current - - // Schedule drum sounds - instruments.forEach(instrument => { - if (patternRef.current[instrument.id][step] && shouldTrackPlay(instrument.id)) { - const settings = trackSettingsRef.current[instrument.id] - audioEngine.playSound(instrument.id, nextNoteTimeRef.current, settings) - } - }) - - // Schedule arpeggiator notes - if (arpeggiatorRef.current) { - arpeggiatorRef.current.scheduleArpNote(step, nextNoteTimeRef.current, stepTimeRef.current) - } - - nextNoteTimeRef.current += stepTimeRef.current - currentStepRef.current = (currentStepRef.current + 1) % steps - } - - timerIdRef.current = setTimeout(scheduler, schedulerInterval) - }, [instruments, audioEngine, steps, scheduleAheadTime, schedulerInterval, shouldTrackPlay]) - - // Visual update loop - syncs UI with audio - const updateVisuals = useCallback(() => { - if (!isPlayingRef.current) return - - const currentTime = audioEngine.getCurrentTime() - const currentStepTime = stepTimeRef.current - const loopDuration = steps * currentStepTime - const timeWithinLoop = (currentTime - startTimeRef.current) % loopDuration - const visualStep = Math.floor(timeWithinLoop / currentStepTime) - - setCurrentStep(visualStep) - animationFrameRef.current = requestAnimationFrame(updateVisuals) - }, [audioEngine, steps]) - - // Start playback - const startPlayback = useCallback(async () => { - await audioEngine.resumeContext() - - setIsPlaying(true) - isPlayingRef.current = true - currentStepRef.current = 0 - - const currentTime = audioEngine.getCurrentTime() - startTimeRef.current = currentTime - nextNoteTimeRef.current = currentTime - - scheduler() - requestAnimationFrame(updateVisuals) - }, [audioEngine, scheduler, updateVisuals]) - - // Stop playback - const stopPlayback = useCallback(() => { - setIsPlaying(false) - isPlayingRef.current = false - setCurrentStep(-1) - - if (timerIdRef.current) { - clearTimeout(timerIdRef.current) - timerIdRef.current = null - } - if (animationFrameRef.current) { - cancelAnimationFrame(animationFrameRef.current) - animationFrameRef.current = null - } - - // Stop arpeggiator - if (arpeggiatorRef.current) { - arpeggiatorRef.current.stopArp() - } - }, []) - - // Toggle a step in the pattern - const toggleStep = useCallback((instrumentId, stepIndex) => { - setPattern(prev => ({ - ...prev, - [instrumentId]: prev[instrumentId].map((val, i) => - i === stepIndex ? !val : val - ) - })) - }, []) - - // Reset pattern to empty - const resetPattern = useCallback(() => { - stopPlayback() - setPattern(createInitialPattern(instruments, steps)) - // Also reset arpeggiator pattern - if (arpeggiatorRef.current) { - arpeggiatorRef.current.resetPattern() - } - }, [stopPlayback, instruments, steps]) - - // Update track settings (volume, mute, solo) - const updateTrackSettings = useCallback((instrumentId, updates) => { - setTrackSettings(prev => ({ - ...prev, - [instrumentId]: { - ...prev[instrumentId], - ...updates - } - })) - }, []) - - // Add a new track - const addTrack = useCallback((instrument) => { - setPattern(prev => ({ - ...prev, - [instrument.id]: Array(steps).fill(false) - })) - setTrackSettings(prev => ({ - ...prev, - [instrument.id]: { volume: 0.8, muted: false, solo: false, reverb: 0, delay: 0 } - })) - }, [steps]) - - // Update BPM with clamping - const setBpm = useCallback((newBpm) => { - const clampedBpm = Math.max(60, Math.min(200, Number(newBpm) || 120)) - setBpmState(clampedBpm) - }, []) - - // Persist state to URL when pattern, trackSettings, or bpm changes - useEffect(() => { - encodeStateToUrl(pattern, trackSettings, instruments, bpm) - }, [pattern, trackSettings, instruments, bpm]) - - // Cleanup on unmount - useEffect(() => { - return () => { - if (timerIdRef.current) clearTimeout(timerIdRef.current) - if (animationFrameRef.current) cancelAnimationFrame(animationFrameRef.current) - } - }, []) - - return { - pattern, - trackSettings, - isPlaying, - currentStep, - steps, - bpm, - setBpm, - toggleStep, - startPlayback, - stopPlayback, - resetPattern, - updateTrackSettings, - addTrack, - } -} - -export default useSequencer diff --git a/src/hooks/useSynthEngine.js b/src/hooks/useSynthEngine.js deleted file mode 100644 index 68c3360..0000000 --- a/src/hooks/useSynthEngine.js +++ /dev/null @@ -1,222 +0,0 @@ -import { useState, useRef, useCallback, useEffect } from 'react' - -/** - * Custom hook for oscillator-based synthesis - * Manages note playback with ADSR envelope and waveform selection - * @param {AudioContext} sharedContext - Optional shared AudioContext from drum engine - * @param {GainNode} sharedMasterGain - Optional shared master gain node for routing audio - */ -export function useSynthEngine(sharedContext = null, sharedMasterGain = null) { - const [waveform, setWaveformState] = useState('sawtooth') - const [volume, setVolumeState] = useState(0.5) - - const audioContextRef = useRef(null) - const masterGainRef = useRef(null) - const limiterRef = useRef(null) - const activeNotesRef = useRef(new Map()) // noteId -> { oscillator, gainNode } - const waveformRef = useRef('sawtooth') - const volumeRef = useRef(0.5) - const isUsingSharedContext = useRef(false) - - // Keep refs in sync with state - useEffect(() => { - waveformRef.current = waveform - }, [waveform]) - - useEffect(() => { - volumeRef.current = volume - if (masterGainRef.current && audioContextRef.current) { - masterGainRef.current.gain.setValueAtTime( - volume, - audioContextRef.current.currentTime - ) - } - }, [volume]) - - // Initialize audio context lazily (on first user interaction) - const ensureContext = useCallback(() => { - if (audioContextRef.current) return audioContextRef.current - - // Use shared context if provided, otherwise create our own - const ctx = sharedContext || new (window.AudioContext || window.webkitAudioContext)() - audioContextRef.current = ctx - isUsingSharedContext.current = !!sharedContext - - // Create master gain - const masterGain = ctx.createGain() - masterGain.gain.value = volumeRef.current - masterGainRef.current = masterGain - - if (sharedContext && sharedMasterGain) { - // If using shared context, connect our master gain to the shared master gain - // This routes synth audio through the same analyser as drums - masterGain.connect(sharedMasterGain) - } else { - // Create limiter to prevent clipping (only for standalone mode) - const limiter = ctx.createDynamicsCompressor() - limiter.threshold.value = -3 - limiter.knee.value = 0 - limiter.ratio.value = 20 - limiter.attack.value = 0.001 - limiter.release.value = 0.1 - limiterRef.current = limiter - - // Connect: masterGain -> limiter -> destination - masterGain.connect(limiter) - limiter.connect(ctx.destination) - } - - return ctx - }, [sharedContext, sharedMasterGain]) - - // Resume context if suspended (browser autoplay policy) - const resumeContext = useCallback(async () => { - const ctx = ensureContext() - if (ctx.state === 'suspended') { - await ctx.resume() - } - }, [ensureContext]) - - // ADSR envelope parameters - const envelope = { - attack: 0.01, // 10ms - decay: 0.1, // 100ms - sustain: 0.7, // 70% of max - release: 0.2, // 200ms - } - - // Get filter cutoff based on waveform type - const getFilterCutoff = (waveformType) => { - switch (waveformType) { - case 'sawtooth': - case 'square': - return 2500 - case 'triangle': - case 'sine': - default: - return 8000 - } - } - - // Play a note by frequency - const playNote = useCallback( - (noteId, frequency, time) => { - const ctx = ensureContext() - if (ctx.state === 'suspended') { - ctx.resume() - } - - // Don't play if already playing - if (activeNotesRef.current.has(noteId)) return - - const now = time ?? ctx.currentTime - - // Create oscillator - const oscillator = ctx.createOscillator() - oscillator.type = waveformRef.current - oscillator.frequency.setValueAtTime(frequency, now) - - // Create low-pass filter to tame harsh high frequencies - const filter = ctx.createBiquadFilter() - filter.type = 'lowpass' - filter.frequency.setValueAtTime(getFilterCutoff(waveformRef.current), now) - filter.Q.setValueAtTime(0.7, now) - - // Create gain for envelope - const gainNode = ctx.createGain() - gainNode.gain.setValueAtTime(0, now) - - // Attack - gainNode.gain.linearRampToValueAtTime(1, now + envelope.attack) - // Decay to sustain level - gainNode.gain.linearRampToValueAtTime( - envelope.sustain, - now + envelope.attack + envelope.decay - ) - - // Connect: oscillator -> filter -> gainNode -> masterGain - oscillator.connect(filter) - filter.connect(gainNode) - gainNode.connect(masterGainRef.current) - - // Start oscillator - oscillator.start(now) - - // Store reference for stopping later - activeNotesRef.current.set(noteId, { oscillator, gainNode, filter }) - }, - [ensureContext] - ) - - // Stop a note - const stopNote = useCallback((noteId) => { - const noteData = activeNotesRef.current.get(noteId) - if (!noteData) return - - const { oscillator, gainNode } = noteData - const ctx = audioContextRef.current - if (!ctx) return - - const now = ctx.currentTime - - // Release envelope - gainNode.gain.cancelScheduledValues(now) - gainNode.gain.setValueAtTime(gainNode.gain.value, now) - gainNode.gain.linearRampToValueAtTime(0, now + envelope.release) - - // Stop oscillator after release - oscillator.stop(now + envelope.release + 0.01) - - // Remove from active notes - activeNotesRef.current.delete(noteId) - }, []) - - // Stop all notes - const stopAllNotes = useCallback(() => { - for (const noteId of activeNotesRef.current.keys()) { - stopNote(noteId) - } - }, [stopNote]) - - // Set waveform type - const setWaveform = useCallback((type) => { - setWaveformState(type) - // Update any currently playing oscillators and their filters - const ctx = audioContextRef.current - for (const { oscillator, filter } of activeNotesRef.current.values()) { - oscillator.type = type - if (filter && ctx) { - filter.frequency.setValueAtTime(getFilterCutoff(type), ctx.currentTime) - } - } - }, []) - - // Set master volume - const setVolume = useCallback((value) => { - setVolumeState(value) - }, []) - - // Cleanup on unmount - useEffect(() => { - return () => { - stopAllNotes() - // Only close context if we created it ourselves (not shared) - if (!isUsingSharedContext.current && audioContextRef.current && audioContextRef.current.state !== 'closed') { - audioContextRef.current.close() - } - } - }, [stopAllNotes]) - - return { - playNote, - stopNote, - stopAllNotes, - setWaveform, - setVolume, - waveform, - volume, - resumeContext, - } -} - -export default useSynthEngine diff --git a/src/index.css b/src/index.css deleted file mode 100644 index 97d55a9..0000000 --- a/src/index.css +++ /dev/null @@ -1,1282 +0,0 @@ -@import "tailwindcss"; -@import "tw-animate-css"; - -/* 7-segment LED display font */ -@font-face { - font-family: 'DSEG7'; - src: url('/fonts/DSEG7Classic-Regular.woff2') format('woff2'); - font-weight: normal; - font-style: normal; -} - -@custom-variant dark (&:is(.dark *)); - -/* Reset default styles for consistency */ -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - font-family: "Helvetica Neue", Arial, sans-serif; - background-color: #d4d0c8; - display: flex; - justify-content: center; - align-items: flex-start; - padding-top: 60px; - min-height: 100vh; - margin: 0; - overflow-x: hidden; -} - -#root { - width: 100%; - display: flex; - justify-content: center; -} - -/* --- MAIN DRUM MACHINE CONTAINER --- */ -.container, -.drum-machine { - display: flex; - flex-direction: column; - background: linear-gradient(145deg, #e8e4dc 0%, #d4d0c8 50%, #c8c4bc 100%); - border-radius: 18px; - padding: 38px 45px 30px 45px; - box-shadow: - 0 12px 48px rgba(0, 0, 0, 0.3), - 0 3px 12px rgba(0, 0, 0, 0.2), - inset 0 1px 0 rgba(255, 255, 255, 0.5), - inset 0 -1px 0 rgba(0, 0, 0, 0.1); - position: relative; - width: fit-content; -} - -/* Subtle texture overlay */ -.container::before, -.drum-machine::before { - content: ""; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: 18px; - background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E"); - opacity: 0.03; - pointer-events: none; -} - -/* --- HEADER SECTION --- */ -.header { - display: flex; - align-items: center; - margin-bottom: 30px; - padding: 0 8px; -} - -.title { - font-size: 2.7em; - font-weight: 900; - color: #1a1a1a; - letter-spacing: 3px; - text-shadow: 1px 1px 0 rgba(255, 255, 255, 0.3); - margin: 0; -} - -.tempo-section { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 6px; - flex: 1; -} - -.tempo-label { - font-size: 0.9em; - font-weight: 600; - color: #d0d0d0; - letter-spacing: 1.5px; -} - -.tempo-input-group { - display: flex; - align-items: stretch; - gap: 4px; -} - -.tempo-btn-stack { - display: flex; - flex-direction: column; - background: linear-gradient(180deg, #4a4a4a 0%, #2a2a2a 100%); - border-radius: 4px; - border: 1px solid #1a1a1a; - overflow: hidden; - box-shadow: - inset 0 1px 0 rgba(255, 255, 255, 0.1), - 0 2px 4px rgba(0, 0, 0, 0.3); -} - -.tempo-btn { - flex: 1; - width: 28px; - font-size: 12px; - font-weight: 700; - border: none; - border-radius: 0; - cursor: pointer; - background: transparent; - color: #999; - display: flex; - align-items: center; - justify-content: center; - transition: all 0.1s ease; - padding: 0; - line-height: 1; -} - -.tempo-btn:first-child { - border-bottom: 1px solid rgba(0, 0, 0, 0.3); -} - -.tempo-btn:hover { - background: rgba(255, 255, 255, 0.1); - color: #fff; -} - -.tempo-btn:active { - background: rgba(0, 0, 0, 0.2); - color: #f5a623; -} - -.tempo-display { - background: linear-gradient(180deg, #1a1a1a 0%, #0a0a0a 100%); - padding: 12px 16px; - border-radius: 4px; - border: 2px solid #0a0a0a; - box-shadow: - inset 0 2px 8px rgba(0, 0, 0, 0.8), - inset 0 0 20px rgba(0, 0, 0, 0.5), - 0 1px 0 rgba(255, 255, 255, 0.05); - display: flex; - align-items: center; - justify-content: center; -} - -#tempo-value { - font-family: 'DSEG7', "Courier New", monospace; - font-size: 2em; - color: #e63939; - text-shadow: 0 0 4px rgba(230, 57, 57, 0.5); - letter-spacing: 2px; - font-weight: normal; - background: transparent; - border: none; - width: 3.5ch; - text-align: center; - outline: none; - -moz-appearance: textfield; -} - -#tempo-value::-webkit-outer-spin-button, -#tempo-value::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -#tempo-value:focus { - color: #ff4d4d; - text-shadow: 0 0 6px rgba(255, 77, 77, 0.6); -} - -/* --- SEQUENCER SECTION --- */ -.sequencer-section { - display: flex; - flex-direction: column; - gap: 6px; -} - -/* --- DRUMS SECTION --- */ -.drums-row { - display: flex; - align-items: stretch; - justify-content: center; - gap: 12px; -} - -.drums-grid-container { - display: flex; - flex-direction: column; - gap: 10px; - background: linear-gradient(180deg, #d8d4cc 0%, #c8c4bc 100%); - border-radius: 8px; - padding: 12px; - border: 1px solid rgba(0, 0, 0, 0.15); - width: fit-content; -} - -.track-controls-column { - display: flex; - flex-direction: column; - gap: 10px; - padding: 14px 16px; - /* top padding: match drums container border (1px) + padding (12px) */ - padding-top: 13px; - background: linear-gradient(180deg, #d8d4cc 0%, #c8c4bc 100%); - border-radius: 8px; - border: 1px solid rgba(0, 0, 0, 0.15); - flex-shrink: 0; - align-self: stretch; - width: 203px; /* match transport controls width */ - box-sizing: border-box; -} - -/* Knob labels row - single row above all track knobs */ -.knob-labels-row { - display: flex; - justify-content: space-around; - align-items: center; - height: 20px; /* match step numbers row height */ - font-size: 10px; - font-weight: 600; - color: #666; - text-transform: uppercase; - letter-spacing: 0.5px; - width: 100%; -} - -/* Step numbers row */ -.step-numbers-row { - display: flex; - align-items: center; -} - -/* Instrument labels column - separate from pads */ -.instrument-labels-column { - display: flex; - flex-direction: column; - gap: 10px; -} - -.instrument-label-spacer, -.label-spacer { - height: 20px; /* match step number row height */ - flex-shrink: 0; -} - - -.controls-spacer { - width: 240px; - flex-shrink: 0; -} - -.step-numbers { - display: flex; - gap: 6px; -} - -/* Step number groups to match pad groups */ -.step-number-group { - display: flex; - gap: 6px; -} - -.step-number-group.bordered { - padding: 3px; - margin: -3px; -} - -.step-numbers span { - width: 36px; - height: 20px; - text-align: center; - font-size: 1.05em; - font-weight: 600; - color: #444; - margin: 2px; /* match note-button margin for alignment */ -} - -/* --- ARPEGGIATOR TRACK --- */ -.arp-notes { - /* Left aligned */ -} - -/* Arp pads - different color scheme */ -.arp-notes .note-button.active { - background: linear-gradient(180deg, #27ae60 0%, #1e8449 100%); - box-shadow: - 0 3px 6px rgba(0, 0, 0, 0.3), - inset 0 1px 0 rgba(255, 255, 255, 0.4), - inset 0 -1px 0 rgba(0, 0, 0, 0.2), - 0 0 12px rgba(39, 174, 96, 0.4); -} - -.arp-notes .note-button.active:hover { - background: linear-gradient(180deg, #2ecc71 0%, #27ae60 100%); -} - -/* Instrument labels */ -.instrument-label { - width: 90px; - height: 52px; /* match track controls height */ - display: flex; - align-items: center; - justify-content: flex-end; /* right-align to sit next to pads */ - font-size: 1.125em; - font-weight: 700; - color: #222; - text-transform: uppercase; - letter-spacing: 0.75px; -} - -/* Track row with label */ -.track-row { - display: flex; - align-items: center; - gap: 8px; -} - -.track-label { - width: 60px; - font-size: 0.7em; - font-weight: 700; - color: #555; - text-transform: uppercase; - letter-spacing: 0.5px; - text-align: right; - flex-shrink: 0; -} - -/* Notes container */ -.notes-container { - display: flex; - gap: 6px; -} - -/* Pad groups (4 pads each) */ -.pad-group { - display: flex; - gap: 6px; -} - -.pad-group.bordered { - border: 1px solid rgba(0, 0, 0, 0.25); - border-radius: 4px; - padding: 3px; - margin: -3px; -} - -/* --- TRACK CONTROLS --- */ -.track-controls { - display: flex; - align-items: center; - justify-content: space-around; - gap: 8px; - height: 52px; /* match larger knob size */ -} - -/* --- KNOB CONTROLS --- */ -.knob-container { - display: flex; - flex-direction: column; - align-items: center; - position: relative; -} - -.knob { - cursor: grab; - user-select: none; - touch-action: none; -} - -.knob svg { - display: block; - overflow: visible; -} - -.knob:active { - cursor: grabbing; -} - -.knob:focus { - outline: none; -} - -.knob:focus-visible { - outline: 2px solid #f5a623; - outline-offset: 2px; - border-radius: 50%; -} - -.knob-label { - position: absolute; - bottom: -14px; - font-size: 0.65em; - font-weight: 600; - color: #555; - text-transform: uppercase; - letter-spacing: 0.5px; -} - -/* --- FADER CONTROLS --- */ -.fader-container { - display: flex; - flex-direction: column; - align-items: center; -} - -.fader-wrapper { - position: relative; - width: 60px; - display: flex; - flex-direction: column; - align-items: center; - gap: 3px; -} - -/* Single horizontal tick lines above and below track */ -.fader-tick-line { - width: 100%; - height: 2px; - background: #998b7a; - border-radius: 1px; -} - -/* Fader track - horizontal bar */ -.fader-track { - position: relative; - width: 100%; - height: 10px; - background: linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 100%); - border-radius: 5px; - cursor: pointer; - box-shadow: - inset 0 1px 3px rgba(0, 0, 0, 0.5), - 0 1px 0 rgba(255, 255, 255, 0.05); -} - -/* Fader thumb - the draggable handle */ -.fader-thumb { - position: absolute; - top: 50%; - transform: translate(-50%, -50%); - width: 24px; - height: 24px; - cursor: grab; - z-index: 2; -} - -.fader-thumb:active { - cursor: grabbing; -} - -/* The round grip part of the thumb */ -.fader-thumb-grip { - width: 100%; - height: 100%; - background: linear-gradient(180deg, #5a5a5a 0%, #3a3a3a 50%, #2a2a2a 100%); - border-radius: 50%; - box-shadow: - 0 2px 6px rgba(0, 0, 0, 0.4), - inset 0 1px 0 rgba(255, 255, 255, 0.15), - inset 0 -1px 0 rgba(0, 0, 0, 0.3); - display: flex; - align-items: center; - justify-content: center; - overflow: hidden; -} - -/* Orange indicator stripe on the thumb */ -.fader-thumb-indicator { - width: 4px; - height: 14px; - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - border-radius: 2px; - box-shadow: 0 0 4px rgba(245, 166, 35, 0.4); -} - -.track-button { - width: 36px; - height: 30px; - font-size: 0.825em; - font-weight: 700; - border-radius: 4px; - cursor: pointer; - transition: all 0.1s ease; - text-transform: uppercase; -} - -.mute-button { - background: linear-gradient(180deg, #888 0%, #666 100%); - border: 1px solid #555; - color: #ddd; -} - -.mute-button:hover { - background: linear-gradient(180deg, #999 0%, #777 100%); -} - -.mute-button.active { - background: linear-gradient(180deg, #e74c3c 0%, #c0392b 100%); - border-color: #a93226; - color: #fff; - box-shadow: 0 0 9px rgba(231, 76, 60, 0.4); -} - -.solo-button { - background: linear-gradient(180deg, #888 0%, #666 100%); - border: 1px solid #555; - color: #ddd; -} - -.solo-button:hover { - background: linear-gradient(180deg, #999 0%, #777 100%); -} - -.solo-button.active { - background: linear-gradient(180deg, #f39c12 0%, #d68910 100%); - border-color: #b7950b; - color: #fff; - box-shadow: 0 0 9px rgba(243, 156, 18, 0.4); -} - -/* --- NOTE BUTTONS (PADS) --- */ -.note-button { - width: 36px; - height: 52px; - margin: 2px; - border: none; - border-radius: 4px; - cursor: pointer; - transition: all 0.08s ease; - - /* Default inactive state - dark gray */ - background: linear-gradient(180deg, #6a6a6a 0%, #525252 100%); - box-shadow: - 0 3px 6px rgba(0, 0, 0, 0.3), - inset 0 1px 0 rgba(255, 255, 255, 0.15), - inset 0 -1px 0 rgba(0, 0, 0, 0.2); -} - -.note-button:hover:not(.active) { - background: linear-gradient(180deg, #7a7a7a 0%, #5a5a5a 100%); -} - -/* Light gray pads for certain positions (beat markers) */ -.note-button.beat-start { - background: linear-gradient(180deg, #a8a8a8 0%, #8a8a8a 100%); - box-shadow: - 0 3px 6px rgba(0, 0, 0, 0.25), - inset 0 1px 0 rgba(255, 255, 255, 0.3), - inset 0 -1px 0 rgba(0, 0, 0, 0.15); -} - -.note-button.beat-start:hover:not(.active) { - background: linear-gradient(180deg, #b8b8b8 0%, #9a9a9a 100%); -} - -/* Active state - orange */ -.note-button.active { - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - box-shadow: - 0 3px 6px rgba(0, 0, 0, 0.3), - inset 0 1px 0 rgba(255, 255, 255, 0.4), - inset 0 -1px 0 rgba(0, 0, 0, 0.2), - 0 0 12px rgba(245, 166, 35, 0.4); -} - -.note-button.active:hover { - background: linear-gradient(180deg, #ffb633 0%, #f09a10 100%); -} - -/* Playing step indicator */ -.note-button.playing-step { - filter: brightness(1.3); - box-shadow: - 0 3px 6px rgba(0, 0, 0, 0.3), - 0 0 18px rgba(255, 255, 255, 0.5); -} - -/* Hi-hat row - shorter pads */ -.instrument-track-row:first-child .note-button { - height: 24px; -} - -/* --- SYNTH SECTION (vol + steps + keyboard + transport) --- */ -.synth-section { - display: flex; - flex-direction: column; - gap: 16px; - margin-top: 24px; -} - -.synth-row { - display: flex; - align-items: stretch; - justify-content: center; - gap: 12px; -} - -.synth-vol-container { - display: flex; - align-items: stretch; - flex-shrink: 0; - width: 90px; /* match instrument-labels-column width to align synth grid with drums grid */ - justify-content: flex-end; -} - -.synth-grid-container { - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 12px; - background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%); - border-radius: 8px; - padding: 12px; - width: fit-content; -} - -/* Transport section */ -.transport-section { - display: flex; - align-items: stretch; - flex-shrink: 0; - width: 203px; /* match track controls width */ -} - -/* Synth controls row (direction, speed, wave) */ -.synth-controls-row { - display: flex; - align-items: center; - justify-content: center; - gap: 12px; - /* Offset to align with synth-grid: 90px (vol container) + 12px (gap) on left, 203px (transport) + 12px (gap) on right */ - padding-left: 102px; - padding-right: 215px; -} - -.synth-controls-center { - flex: 1; - display: flex; - justify-content: center; -} - -.synth-controls-container { - display: flex; - gap: 16px; -} - -/* Visualizer container - takes remaining space */ -.visualizer-container { - flex: 1; - display: flex; - align-items: center; -} - -/* Right visualizer - match transport/knobs width */ -.visualizer-container:last-child { - flex: none; - width: 203px; -} - -/* Audio visualizer canvas wrapper */ -.audio-visualizer { - width: 100%; - height: 60px; - background: linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 100%); - border-radius: 6px; - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.4); - overflow: hidden; -} - -.audio-visualizer canvas { - width: 100%; - height: 100%; -} - -.transport-controls { - display: flex; - flex-direction: column; - gap: 10px; - background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%); - padding: 14px 16px; - border-radius: 8px; - box-shadow: - inset 0 2px 6px rgba(0, 0, 0, 0.4), - 0 1px 0 rgba(255, 255, 255, 0.1); - width: 100%; - box-sizing: border-box; -} - -.transport-buttons { - display: flex; - gap: 6px; -} - -/* --- BUTTON BASE --- */ -.btn { - font-weight: 700; - text-transform: uppercase; - letter-spacing: 1px; - border-radius: 4px; - cursor: pointer; - transition: all 0.1s ease; - background: linear-gradient(180deg, #4a4a4a 0%, #2a2a2a 100%); - border: 1px solid #1a1a1a; - color: #e0e0e0; - box-shadow: - 0 2px 4px rgba(0, 0, 0, 0.4), - inset 0 1px 0 rgba(255, 255, 255, 0.1); -} - -.btn:hover { - background: linear-gradient(180deg, #5a5a5a 0%, #3a3a3a 100%); -} - -.btn:active, -.btn.active { - background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%); - box-shadow: - inset 0 2px 4px rgba(0, 0, 0, 0.4), - 0 1px 2px rgba(0, 0, 0, 0.3); -} - -.btn:disabled { - background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%); - border-color: #1a1a1a; - color: #555; - cursor: not-allowed; -} - -/* --- BUTTON VARIANTS --- */ -.btn-transport { - flex: 1; - padding: 8px 6px; - font-size: 0.85em; -} - -.btn-reset { - background: linear-gradient(180deg, #fafafa 0%, #e0e0e0 100%); - border: 1px solid #bbb; - color: #333; -} - -.btn-reset:hover { - background: linear-gradient(180deg, #ffffff 0%, #f0f0f0 100%); -} - -.btn-reset:active { - background: linear-gradient(180deg, #e0e0e0 0%, #d0d0d0 100%); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15); -} - -.btn-play { - background: linear-gradient(180deg, #e74c3c 0%, #c0392b 100%); - border: 1px solid #a93226; - color: #fff; - width: 62px; /* fixed width so START/STOP don't change button size */ -} - -.btn-play:hover { - background: linear-gradient(180deg, #ec7063 0%, #e74c3c 100%); -} - -.btn-play:active, -.btn-play.active { - background: linear-gradient(180deg, #c0392b 0%, #a93226 100%); - box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.3); -} - -/* --- KEYBOARD CONTROLS (dir, speed, vol, wave + keyboard) --- */ -.keyboard-controls { - display: flex; - align-items: stretch; - gap: 12px; -} - -/* Container for all synth controls */ -.synth-controls-container { - display: flex; - align-items: stretch; - gap: 8px; - padding: 10px; - background: linear-gradient(180deg, #5a5a5a 0%, #3a3a3a 100%); - border-radius: 8px; - box-shadow: - inset 0 2px 6px rgba(0, 0, 0, 0.3), - 0 1px 0 rgba(255, 255, 255, 0.1); -} - -/* Stack for DIR over SPEED */ -.control-stack { - display: flex; - flex-direction: column; - gap: 8px; -} - -/* Half-height control boxes (for stacked DIR/SPEED) */ -.control-box-half { - flex: 1; - justify-content: center; -} - -/* --- CONTROL BOX (container for each control group) --- */ -.control-box { - display: flex; - flex-direction: column; - align-items: center; - gap: 6px; - padding: 8px 10px; - background: linear-gradient(180deg, #d8d4cc 0%, #c8c4bc 100%); - border-radius: 6px; - border: 1px solid rgba(0, 0, 0, 0.15); -} - -/* Vertical control boxes (VOL, WAVE) */ -.control-box-vertical { - padding: 8px 8px; - justify-content: space-between; -} - -.control-box-label { - font-size: 9px; - font-weight: 700; - color: #555; - letter-spacing: 1px; - text-transform: uppercase; -} - -.control-box-buttons { - display: flex; - gap: 3px; -} - -/* Vertical buttons layout */ -.control-box-buttons-vertical { - display: flex; - flex-direction: column; - gap: 3px; - flex: 1; - justify-content: space-between; -} - -.control-btn { - width: 32px; - height: 26px; - font-size: 11px; - font-weight: 700; - border: 1px solid #444; - border-radius: 4px; - cursor: pointer; - transition: all 0.1s ease; - background: linear-gradient(180deg, #5a5a5a 0%, #3a3a3a 100%); - color: #aaa; - display: flex; - align-items: center; - justify-content: center; -} - -.control-btn:hover { - background: linear-gradient(180deg, #6a6a6a 0%, #4a4a4a 100%); - color: #ccc; -} - -.control-btn.active { - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - border-color: #f5a623; - color: #fff; - box-shadow: 0 0 8px rgba(245, 166, 35, 0.4); -} - -/* Wave buttons for icons */ -.control-btn.wave-btn { - width: 32px; - height: 26px; -} - -/* Vertical volume slider */ -.control-box-slider-vertical { - display: flex; - align-items: center; - justify-content: center; - flex: 1; - width: 24px; -} - -.vol-slider-vertical { - width: 100px; - height: 6px; - -webkit-appearance: none; - appearance: none; - background: linear-gradient(180deg, #2a2a2a 0%, #1a1a1a 100%); - border-radius: 3px; - cursor: pointer; - transform: rotate(-90deg); - transform-origin: center center; -} - -.vol-slider-vertical::-webkit-slider-thumb { - -webkit-appearance: none; - width: 16px; - height: 16px; - border-radius: 50%; - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - cursor: pointer; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); -} - -.vol-slider-vertical::-moz-range-thumb { - width: 16px; - height: 16px; - border: none; - border-radius: 50%; - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - cursor: pointer; - box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3); -} - -/* --- KEYBOARD SECTION --- */ -.keyboard-section { - display: flex; - justify-content: center; - align-self: stretch; -} - -.keyboard { - display: flex; - position: relative; - height: 150px; -} - -.key { - cursor: pointer; - transition: all 0.05s ease; -} - -.key.white { - width: 48px; - height: 150px; - background: linear-gradient(180deg, #fafafa 0%, #e8e8e8 100%); - border: 1px solid #ccc; - border-radius: 0 0 6px 6px; - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.2), - inset 0 -6px 12px rgba(0, 0, 0, 0.05); - margin-right: -1px; - z-index: 1; -} - -.key.white:hover { - background: linear-gradient(180deg, #ffffff 0%, #f0f0f0 100%); -} - -.key.white:active { - background: linear-gradient(180deg, #e0e0e0 0%, #d0d0d0 100%); - box-shadow: inset 0 3px 6px rgba(0, 0, 0, 0.1); -} - -.key.black { - width: 36px; - height: 90px; - background: linear-gradient(180deg, #3a3a3a 0%, #1a1a1a 100%); - border: 1px solid #000; - border-radius: 0 0 4px 4px; - margin-left: -18px; - margin-right: -18px; - z-index: 2; - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.4), - inset 0 -3px 6px rgba(255, 255, 255, 0.05); -} - -.key.black:hover { - background: linear-gradient(180deg, #4a4a4a 0%, #2a2a2a 100%); -} - -.key.black:active, -.key.black.active, -.key.black.held { - background: linear-gradient(180deg, #2a2a2a 0%, #0a0a0a 100%); - height: 87px; - margin-top: 3px; -} - -/* Held state for white keys (toggled on for arpeggiator) */ -.key.white.held { - background: linear-gradient(180deg, #f5a623 0%, #e08a00 100%); - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.2), - inset 0 -6px 12px rgba(0, 0, 0, 0.1), - 0 0 12px rgba(245, 166, 35, 0.4); -} - -/* Held state for black keys */ -.key.black.held { - background: linear-gradient(180deg, #f5a623 0%, #c07000 100%); - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.4), - inset 0 -3px 6px rgba(0, 0, 0, 0.2), - 0 0 8px rgba(245, 166, 35, 0.5); - height: 90px; - margin-top: 0; -} - -/* Playing state - currently playing arp note */ -.key.white.playing { - background: linear-gradient(180deg, #fff 0%, #f5a623 100%); - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.2), - 0 0 20px rgba(245, 166, 35, 0.6); -} - -.key.black.playing { - background: linear-gradient(180deg, #f5a623 0%, #ff8c00 100%); - box-shadow: - 0 6px 12px rgba(0, 0, 0, 0.4), - 0 0 16px rgba(245, 166, 35, 0.7); -} - -/* Note name on piano keys */ -.note-name { - position: absolute; - top: 8px; - left: 50%; - transform: translateX(-50%); - font-size: 12px; - font-weight: 700; - pointer-events: none; - user-select: none; -} - -.key.white .note-name { - color: #444; -} - -.key.black .note-name { - color: #aaa; -} - -.key.white.held .note-name, -.key.white.playing .note-name { - color: #fff; -} - -/* Key hints container (QWERTY letters) */ -.key-hint-container { - position: absolute; - bottom: 6px; - left: 50%; - transform: translateX(-50%); - background: rgba(0, 0, 0, 0.15); - border-radius: 3px; - padding: 2px 5px; - pointer-events: none; - user-select: none; -} - -.key-hint { - font-size: 10px; - font-weight: 600; - text-transform: uppercase; -} - -.key.white .key-hint-container { - background: rgba(0, 0, 0, 0.1); -} - -.key.white .key-hint { - color: #555; -} - -.key.black .key-hint-container { - background: rgba(255, 255, 255, 0.15); - bottom: 4px; -} - -.key.black .key-hint { - color: #999; -} - -.key.white.held .key-hint-container, -.key.white.playing .key-hint-container { - background: rgba(0, 0, 0, 0.2); -} - -.key.white.held .key-hint, -.key.white.playing .key-hint { - color: #fff; -} - -/* Position keys relatively for hint positioning */ -.key { - position: relative; -} - - -/* --- LOADING OVERLAY --- */ -.loading-overlay { - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: linear-gradient(145deg, #e8e4dc 0%, #d4d0c8 50%, #c8c4bc 100%); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - gap: 22px; - z-index: 100; - border-radius: 18px; - transition: opacity 0.3s ease-out, visibility 0.3s ease-out; -} - -.loading-spinner { - width: 60px; - height: 60px; - border: 6px solid #c8c4bc; - border-top: 6px solid #f5a623; - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.loading-text { - font-size: 1.35em; - font-weight: 600; - color: #444; - text-transform: uppercase; - letter-spacing: 1.5px; - animation: pulse 1.5s ease-in-out infinite; -} - -@keyframes pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.5; } -} - -/* --- APP CONTAINER --- */ -.app-container { - display: flex; - justify-content: center; - width: fit-content; -} - -@theme inline { - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); - --radius-lg: var(--radius); - --radius-xl: calc(var(--radius) + 4px); - --color-background: var(--background); - --color-foreground: var(--foreground); - --color-card: var(--card); - --color-card-foreground: var(--card-foreground); - --color-popover: var(--popover); - --color-popover-foreground: var(--popover-foreground); - --color-primary: var(--primary); - --color-primary-foreground: var(--primary-foreground); - --color-secondary: var(--secondary); - --color-secondary-foreground: var(--secondary-foreground); - --color-muted: var(--muted); - --color-muted-foreground: var(--muted-foreground); - --color-accent: var(--accent); - --color-accent-foreground: var(--accent-foreground); - --color-destructive: var(--destructive); - --color-border: var(--border); - --color-input: var(--input); - --color-ring: var(--ring); - --color-chart-1: var(--chart-1); - --color-chart-2: var(--chart-2); - --color-chart-3: var(--chart-3); - --color-chart-4: var(--chart-4); - --color-chart-5: var(--chart-5); - --color-sidebar: var(--sidebar); - --color-sidebar-foreground: var(--sidebar-foreground); - --color-sidebar-primary: var(--sidebar-primary); - --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); - --color-sidebar-accent: var(--sidebar-accent); - --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); - --color-sidebar-border: var(--sidebar-border); - --color-sidebar-ring: var(--sidebar-ring); -} - -:root { - --radius: 0.625rem; - --background: oklch(1 0 0); - --foreground: oklch(0.145 0 0); - --card: oklch(1 0 0); - --card-foreground: oklch(0.145 0 0); - --popover: oklch(1 0 0); - --popover-foreground: oklch(0.145 0 0); - --primary: oklch(0.205 0 0); - --primary-foreground: oklch(0.985 0 0); - --secondary: oklch(0.97 0 0); - --secondary-foreground: oklch(0.205 0 0); - --muted: oklch(0.97 0 0); - --muted-foreground: oklch(0.556 0 0); - --accent: oklch(0.97 0 0); - --accent-foreground: oklch(0.205 0 0); - --destructive: oklch(0.577 0.245 27.325); - --border: oklch(0.922 0 0); - --input: oklch(0.922 0 0); - --ring: oklch(0.708 0 0); - --chart-1: oklch(0.646 0.222 41.116); - --chart-2: oklch(0.6 0.118 184.704); - --chart-3: oklch(0.398 0.07 227.392); - --chart-4: oklch(0.828 0.189 84.429); - --chart-5: oklch(0.769 0.188 70.08); - --sidebar: oklch(0.985 0 0); - --sidebar-foreground: oklch(0.145 0 0); - --sidebar-primary: oklch(0.205 0 0); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.97 0 0); - --sidebar-accent-foreground: oklch(0.205 0 0); - --sidebar-border: oklch(0.922 0 0); - --sidebar-ring: oklch(0.708 0 0); -} - -.dark { - --background: oklch(0.145 0 0); - --foreground: oklch(0.985 0 0); - --card: oklch(0.205 0 0); - --card-foreground: oklch(0.985 0 0); - --popover: oklch(0.205 0 0); - --popover-foreground: oklch(0.985 0 0); - --primary: oklch(0.922 0 0); - --primary-foreground: oklch(0.205 0 0); - --secondary: oklch(0.269 0 0); - --secondary-foreground: oklch(0.985 0 0); - --muted: oklch(0.269 0 0); - --muted-foreground: oklch(0.708 0 0); - --accent: oklch(0.269 0 0); - --accent-foreground: oklch(0.985 0 0); - --destructive: oklch(0.704 0.191 22.216); - --border: oklch(1 0 0 / 10%); - --input: oklch(1 0 0 / 15%); - --ring: oklch(0.556 0 0); - --chart-1: oklch(0.488 0.243 264.376); - --chart-2: oklch(0.696 0.17 162.48); - --chart-3: oklch(0.769 0.188 70.08); - --chart-4: oklch(0.627 0.265 303.9); - --chart-5: oklch(0.645 0.246 16.439); - --sidebar: oklch(0.205 0 0); - --sidebar-foreground: oklch(0.985 0 0); - --sidebar-primary: oklch(0.488 0.243 264.376); - --sidebar-primary-foreground: oklch(0.985 0 0); - --sidebar-accent: oklch(0.269 0 0); - --sidebar-accent-foreground: oklch(0.985 0 0); - --sidebar-border: oklch(1 0 0 / 10%); - --sidebar-ring: oklch(0.556 0 0); -} - -@layer base { - * { - @apply border-border outline-ring/50; - } -} diff --git a/src/instruments.ts b/src/instruments.ts new file mode 100644 index 0000000..ab614b4 --- /dev/null +++ b/src/instruments.ts @@ -0,0 +1,87 @@ +import type { DrumVoice } from './engine/drums' + +/** + * The instrument registry. Adding a drum is one entry here: the step row, + * mixer knobs, playback color, and share link follow. + */ + +export interface FireColor { + /** Gradient top and bottom of a pad that fires, and its glow as `r,g,b`. */ + top: string + bottom: string + glow: string +} + +export interface DrumDefinition { + id: string + label: string + /** Which synthesized voice plays it. */ + voice: DrumVoice + fire: FireColor +} + +export const DRUMS: readonly DrumDefinition[] = [ + { + id: 'hihat', + label: 'Hi-hat', + voice: 'hihat', + fire: { top: '#d2ad70', bottom: '#a07733', glow: '160,119,51' }, + }, + { + id: 'snare', + label: 'Snare', + voice: 'snare', + fire: { top: '#e39c82', bottom: '#b4664a', glow: '180,102,74' }, + }, + { + id: 'kick', + label: 'Kick', + voice: 'kick', + fire: { top: '#91a7d0', bottom: '#58719f', glow: '88,113,159' }, + }, +] + +/** The synth's pads and keys share one color so a step and the note it plays read together. */ +export const SYNTH_FIRE: FireColor = { top: '#9fba88', bottom: '#68864e', glow: '104,134,78' } + +export interface NoteDefinition { + note: string + freq: number + black: boolean + /** Computer key that toggles the note. */ + key: string +} + +/** Two octaves, C3 to B4, A4 = 440 Hz. */ +export const NOTES: readonly NoteDefinition[] = [ + { note: 'C3', freq: 130.81, black: false, key: 'a' }, + { note: 'C#3', freq: 138.59, black: true, key: 'w' }, + { note: 'D3', freq: 146.83, black: false, key: 's' }, + { note: 'D#3', freq: 155.56, black: true, key: 'e' }, + { note: 'E3', freq: 164.81, black: false, key: 'd' }, + { note: 'F3', freq: 174.61, black: false, key: 'f' }, + { note: 'F#3', freq: 185.0, black: true, key: 't' }, + { note: 'G3', freq: 196.0, black: false, key: 'g' }, + { note: 'G#3', freq: 207.65, black: true, key: 'y' }, + { note: 'A3', freq: 220.0, black: false, key: 'h' }, + { note: 'A#3', freq: 233.08, black: true, key: 'u' }, + { note: 'B3', freq: 246.94, black: false, key: 'j' }, + { note: 'C4', freq: 261.63, black: false, key: 'k' }, + { note: 'C#4', freq: 277.18, black: true, key: 'o' }, + { note: 'D4', freq: 293.66, black: false, key: 'l' }, + { note: 'D#4', freq: 311.13, black: true, key: 'p' }, + { note: 'E4', freq: 329.63, black: false, key: ';' }, + { note: 'F4', freq: 349.23, black: false, key: "'" }, + { note: 'F#4', freq: 369.99, black: true, key: ']' }, + { note: 'G4', freq: 392.0, black: false, key: 'z' }, + { note: 'G#4', freq: 415.3, black: true, key: '[' }, + { note: 'A4', freq: 440.0, black: false, key: 'x' }, + { note: 'A#4', freq: 466.16, black: true, key: '\\' }, + { note: 'B4', freq: 493.88, black: false, key: 'c' }, +] + +const NOTE_BY_NAME = new Map(NOTES.map((n) => [n.note, n])) +const NOTE_BY_KEY = new Map(NOTES.map((n) => [n.key, n.note])) + +export const noteByName = (note: string): NoteDefinition | undefined => NOTE_BY_NAME.get(note) +export const noteForKey = (key: string): string | undefined => NOTE_BY_KEY.get(key.toLowerCase()) diff --git a/src/lib/utils.js b/src/lib/utils.js deleted file mode 100644 index b20bf01..0000000 --- a/src/lib/utils.js +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx } from "clsx"; -import { twMerge } from "tailwind-merge" - -export function cn(...inputs) { - return twMerge(clsx(inputs)); -} diff --git a/src/main.jsx b/src/main.jsx deleted file mode 100644 index 5cc5991..0000000 --- a/src/main.jsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App' -import './index.css' - -ReactDOM.createRoot(document.getElementById('root')).render( - - - , -) diff --git a/src/main.tsx b/src/main.tsx new file mode 100644 index 0000000..53b978c --- /dev/null +++ b/src/main.tsx @@ -0,0 +1,18 @@ +import { StrictMode, Suspense, lazy } from 'react' +import { createRoot } from 'react-dom/client' +import { App } from './App' +import './ui/tokens.css' + +// The Agentation annotation toolbar is a development aid; it never ships to visitors. +const DevToolbar = import.meta.env.DEV ? lazy(() => import('agentation').then((m) => ({ default: m.Agentation }))) : null + +createRoot(document.getElementById('root')!).render( + + + {DevToolbar && ( + + + + )} + , +) diff --git a/src/session/commands.test.ts b/src/session/commands.test.ts new file mode 100644 index 0000000..fc26c1e --- /dev/null +++ b/src/session/commands.test.ts @@ -0,0 +1,67 @@ +import { describe, expect, it } from 'vitest' +import { applyCommand } from './commands' +import { DEFAULT_GATE } from './library' +import { defaultSession } from './schema' + +describe('session commands', () => { + it('reset clears steps but keeps held notes, knobs, and tempo', () => { + let s = defaultSession() + s = applyCommand(s, { type: 'toggleDrumStep', drum: 'snare', step: 4 }) + s = applyCommand(s, { type: 'toggleSynthStep', step: 0 }) + s = applyCommand(s, { type: 'toggleNote', note: 'E4' }) + s = applyCommand(s, { type: 'setDrumParam', drum: 'snare', param: 'volume', value: 0.3 }) + s = applyCommand(s, { type: 'setBpm', bpm: 90 }) + + const r = applyCommand(s, { type: 'reset' }) + + expect(r.drums.snare.steps.some(Boolean)).toBe(false) + expect(r.synth.steps.some(Boolean)).toBe(false) + expect(r.synth.notes).toEqual(['E4']) + expect(r.drums.snare.volume).toBe(0.3) + expect(r.bpm).toBe(90) + }) + + it('keeps held notes in pitch order and toggles them off', () => { + let s = defaultSession() + for (const note of ['G4', 'C4', 'E4']) s = applyCommand(s, { type: 'toggleNote', note }) + expect(s.synth.notes).toEqual(['C4', 'E4', 'G4']) + s = applyCommand(s, { type: 'toggleNote', note: 'C4' }) + expect(s.synth.notes).toEqual(['E4', 'G4']) + }) + + it('clamps tempo and knob values', () => { + let s = defaultSession() + s = applyCommand(s, { type: 'setBpm', bpm: 10 }) + expect(s.bpm).toBe(60) + s = applyCommand(s, { type: 'setBpm', bpm: 500 }) + expect(s.bpm).toBe(200) + s = applyCommand(s, { type: 'setDrumParam', drum: 'kick', param: 'decay', value: 3 }) + expect(s.drums.kick.decay).toBe(1) + }) + + it('fills in a synth rhythm when the first key is held with no steps set', () => { + let s = applyCommand(defaultSession(), { type: 'toggleNote', note: 'C4' }) + expect(s.synth.steps).toEqual([...DEFAULT_GATE]) + s = applyCommand(s, { type: 'toggleSynthStep', step: 0 }) + s = applyCommand(s, { type: 'setNotes', notes: ['A3', 'C4'] }) + expect(s.synth.steps[0]).toBe(!DEFAULT_GATE[0]) + }) + + it('leaves your synth steps alone when you already set some', () => { + let s = applyCommand(defaultSession(), { type: 'toggleSynthStep', step: 3 }) + s = applyCommand(s, { type: 'setNotes', notes: ['G4', 'E4'] }) + expect(s.synth.notes).toEqual(['E4', 'G4']) + expect(s.synth.steps.filter(Boolean)).toHaveLength(1) + }) + + it('loads a whole session', () => { + const s = defaultSession() + const other = { ...defaultSession(), bpm: 140 } + expect(applyCommand(s, { type: 'loadSession', session: other })).toBe(other) + }) + + it('ignores drums that are not in the session', () => { + const s = defaultSession() + expect(applyCommand(s, { type: 'toggleDrumStep', drum: 'cowbell', step: 0 })).toBe(s) + }) +}) diff --git a/src/session/commands.ts b/src/session/commands.ts new file mode 100644 index 0000000..93974db --- /dev/null +++ b/src/session/commands.ts @@ -0,0 +1,92 @@ +import { + clamp01, + clampBpm, + emptySteps, + normalizeNotes, + OCTAVES, + type ArpMode, + type ArpRate, + type Octave, + type Session, + type Waveform, +} from './schema' +import { DEFAULT_GATE } from './library' + +export type DrumParam = 'volume' | 'delay' | 'decay' + +export type Command = + | { type: 'toggleDrumStep'; drum: string; step: number } + | { type: 'setDrumParam'; drum: string; param: DrumParam; value: number } + | { type: 'toggleSynthStep'; step: number } + | { type: 'toggleNote'; note: string } + /** Holds exactly these notes, e.g. a chord. */ + | { type: 'setNotes'; notes: string[] } + /** Replaces the whole session, e.g. with a ready-made pattern. */ + | { type: 'loadSession'; session: Session } + | { type: 'setArpMode'; mode: ArpMode } + | { type: 'setArpRate'; rate: ArpRate } + | { type: 'setWaveform'; waveform: Waveform } + | { type: 'setOctave'; octave: Octave } + | { type: 'setSynthVolume'; value: number } + | { type: 'setBpm'; bpm: number } + /** Clears the drum and synth steps. Held notes and knob settings stay. */ + | { type: 'reset' } + +const toggleAt = (steps: boolean[], i: number): boolean[] => steps.map((on, j) => (j === i ? !on : on)) + +/** + * New held notes. Holding the first key while no synth steps are set also + * fills in a default rhythm, so the keyboard always makes a sound. + */ +function withNotes(session: Session, notes: Iterable): Session { + const synth = { ...session.synth, notes: normalizeNotes(notes) } + if (session.synth.notes.length === 0 && synth.notes.length > 0 && !synth.steps.some(Boolean)) synth.steps = [...DEFAULT_GATE] + return { ...session, synth } +} + +/** Pure state transition: every change to a session goes through here. */ +export function applyCommand(session: Session, command: Command): Session { + switch (command.type) { + case 'toggleDrumStep': { + const track = session.drums[command.drum] + if (!track) return session + return { ...session, drums: { ...session.drums, [command.drum]: { ...track, steps: toggleAt(track.steps, command.step) } } } + } + case 'setDrumParam': { + const track = session.drums[command.drum] + if (!track) return session + return { ...session, drums: { ...session.drums, [command.drum]: { ...track, [command.param]: clamp01(command.value) } } } + } + case 'toggleSynthStep': + return { ...session, synth: { ...session.synth, steps: toggleAt(session.synth.steps, command.step) } } + case 'toggleNote': { + const held = new Set(session.synth.notes) + if (held.has(command.note)) held.delete(command.note) + else held.add(command.note) + return withNotes(session, held) + } + case 'setNotes': + return withNotes(session, command.notes) + case 'loadSession': + return command.session + case 'setArpMode': + return { ...session, synth: { ...session.synth, mode: command.mode } } + case 'setArpRate': + return { ...session, synth: { ...session.synth, rate: command.rate } } + case 'setWaveform': + return { ...session, synth: { ...session.synth, waveform: command.waveform } } + case 'setOctave': + if (!OCTAVES.includes(command.octave)) return session + return { ...session, synth: { ...session.synth, octave: command.octave } } + case 'setSynthVolume': + return { ...session, synth: { ...session.synth, volume: clamp01(command.value) } } + case 'setBpm': + return { ...session, bpm: clampBpm(command.bpm) } + case 'reset': + return { + ...session, + drums: Object.fromEntries(Object.entries(session.drums).map(([id, t]) => [id, { ...t, steps: emptySteps() }])), + synth: { ...session.synth, steps: emptySteps() }, + } + } +} diff --git a/src/session/library.test.ts b/src/session/library.test.ts new file mode 100644 index 0000000..21d297a --- /dev/null +++ b/src/session/library.test.ts @@ -0,0 +1,16 @@ +import { describe, expect, it } from 'vitest' +import { NOTES } from '../instruments' +import { CHORDS, chordFor, PRESETS } from './library' +import { decodeSession, encodeSession } from './url' + +describe('library', () => { + it('stores every pattern as a valid, canonical share link', () => { + for (const p of PRESETS) expect(encodeSession(decodeSession(p.link))).toBe(p.link) + }) + + it('builds chords only from keys on the keyboard', () => { + const keys = new Set(NOTES.map((n) => n.note)) + for (const c of CHORDS) expect(c.notes.every((n) => keys.has(n))).toBe(true) + expect(chordFor(['A3', 'C4', 'E4', 'G4'])?.name).toBe('Am7') + }) +}) diff --git a/src/session/library.ts b/src/session/library.ts new file mode 100644 index 0000000..f680b5c --- /dev/null +++ b/src/session/library.ts @@ -0,0 +1,40 @@ +/** + * Starting material for exploring: ready-made loops and chords that work + * together. Everything here sits in house music (four-on-the-floor, claps on + * 2 and 4, off-beat hats) with a French touch, so trying things never lands + * on noise. + */ + +/** + * Ready-made house loops, stored as share-link payloads, one per CHORD key: + * deep, jackin', French, piano, tech, and garage house. The first one plays + * when the app opens without a link. + */ +export const PRESETS: ReadonlyArray<{ name: string; link: string }> = [ + { name: 'Deep Night', link: '2~122~hihat.2222.990066~snare.0808.b33380~kick.8888.e60066~syn.2222.244800.u.16.t.9f.0' }, + { name: 'Jack Box', link: '2~124~hihat.ffff.80001a~snare.0809.b30066~kick.8888.e6004d~syn.9249.004890.u.16.q.9f.-1' }, + { name: 'French Filter', link: '2~124~hihat.2222.990099~snare.0808.cc3380~kick.8888.e60066~syn.db6d.044880.b.16.s.9f.0' }, + { name: 'Piano Hands', link: '2~123~hihat.2223.990066~snare.0808.cc4d80~kick.8888.e60066~syn.a2a2.891000.b.8.t.80.1' }, + { name: 'Warehouse', link: '2~125~hihat.3333.800033~snare.0808.99004d~kick.8888.ff004d~syn.7777.091200.d.16.i.bf.-1' }, + { name: 'Sunday Garage', link: '2~122~hihat.2222.9900b3~snare.080a.b34d80~kick.8888.e60066~syn.aaaa.011240.u.8.s.80.0' }, +] + +/** Seven-chords from one key (A minor / C major), so switching between any of them always works. */ +export const CHORDS: ReadonlyArray<{ name: string; notes: readonly string[] }> = [ + { name: 'Am7', notes: ['A3', 'C4', 'E4', 'G4'] }, + { name: 'Cmaj7', notes: ['C3', 'E3', 'G3', 'B3'] }, + { name: 'Dm7', notes: ['D3', 'F3', 'A3', 'C4'] }, + { name: 'Em7', notes: ['E3', 'G3', 'B3', 'D4'] }, + { name: 'Fmaj7', notes: ['F3', 'A3', 'C4', 'E4'] }, + { name: 'G7', notes: ['G3', 'B3', 'D4', 'F4'] }, +] + +const toSteps = (on: readonly number[]): boolean[] => Array.from({ length: 16 }, (_, i) => on.includes(i + 1)) + +/** The synth's steps when you first hold a key with none set: off-beat stabs, so the keyboard always answers. */ +export const DEFAULT_GATE: readonly boolean[] = toSteps([3, 7, 11, 15]) + +const sameNotes = (a: readonly string[], b: readonly string[]) => a.length === b.length && a.every((n, i) => n === b[i]) + +/** The chord exactly matching the held notes, if any. */ +export const chordFor = (notes: readonly string[]) => CHORDS.find((c) => sameNotes(c.notes, notes)) diff --git a/src/session/schema.ts b/src/session/schema.ts new file mode 100644 index 0000000..abc918c --- /dev/null +++ b/src/session/schema.ts @@ -0,0 +1,75 @@ +import { DRUMS, NOTES } from '../instruments' + +export const STEPS = 16 +export const BPM_MIN = 60 +export const BPM_MAX = 200 +export const DEFAULT_BPM = 120 + +export const WAVEFORMS = ['sawtooth', 'square', 'sine', 'triangle'] as const +export const ARP_MODES = ['up', 'down', 'up-down'] as const +export const ARP_RATES = ['1/4', '1/8', '1/16'] as const +/** Octave shift for the synth, applied on top of the keyboard's C3–B4. */ +export const OCTAVES = [-1, 0, 1] as const + +export type Waveform = (typeof WAVEFORMS)[number] +export type ArpMode = (typeof ARP_MODES)[number] +export type ArpRate = (typeof ARP_RATES)[number] +export type Octave = (typeof OCTAVES)[number] + +/** Knob values are 0–1. Delay is the echo send; decay scales how long each hit rings, 0.5 being the voice's own length. */ +export interface DrumTrack { + steps: boolean[] + volume: number + delay: number + decay: number +} + +export interface SynthTrack { + steps: boolean[] + /** Held notes by name, e.g. "C4". */ + notes: string[] + mode: ArpMode + rate: ArpRate + waveform: Waveform + octave: Octave + volume: number +} + +export interface Session { + version: 2 + bpm: number + drums: Record + synth: SynthTrack +} + +export const emptySteps = (): boolean[] => Array(STEPS).fill(false) + +export const defaultDrumTrack = (): DrumTrack => ({ steps: emptySteps(), volume: 0.8, delay: 0, decay: 0.5 }) + +export const defaultSynthTrack = (): SynthTrack => ({ + steps: emptySteps(), + notes: [], + mode: 'up', + rate: '1/16', + waveform: 'sawtooth', + octave: 0, + volume: 0.5, +}) + +export const defaultSession = (): Session => ({ + version: 2, + bpm: DEFAULT_BPM, + drums: Object.fromEntries(DRUMS.map((d) => [d.id, defaultDrumTrack()])), + synth: defaultSynthTrack(), +}) + +export const clamp01 = (v: number): number => (Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : 0) + +export const clampBpm = (bpm: number): number => + Number.isFinite(bpm) ? Math.round(Math.min(BPM_MAX, Math.max(BPM_MIN, bpm))) : DEFAULT_BPM + +const NOTE_ORDER = new Map(NOTES.map((n, i) => [n.note, i])) + +/** Held notes in pitch order, dropping unknown names and duplicates. */ +export const normalizeNotes = (notes: Iterable): string[] => + [...new Set(notes)].filter((n) => NOTE_ORDER.has(n)).sort((a, b) => NOTE_ORDER.get(a)! - NOTE_ORDER.get(b)!) diff --git a/src/session/store.test.ts b/src/session/store.test.ts new file mode 100644 index 0000000..cf209d5 --- /dev/null +++ b/src/session/store.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest' +import { defaultSession } from './schema' +import { createSessionStore } from './store' + +describe('session store undo', () => { + it('steps back one change at a time', () => { + const store = createSessionStore(defaultSession()) + expect(store.canUndo()).toBe(false) + store.dispatch({ type: 'toggleDrumStep', drum: 'kick', step: 0 }) + store.dispatch({ type: 'toggleDrumStep', drum: 'kick', step: 4 }) + store.undo() + expect(store.getState().drums.kick.steps.filter(Boolean)).toHaveLength(1) + store.undo() + expect(store.getState()).toEqual(defaultSession()) + expect(store.canUndo()).toBe(false) + }) + + it('undoes a knob drag in one step, but separate turns separately', () => { + let t = 0 + const store = createSessionStore(defaultSession(), () => t) + for (const value of [0.5, 0.4, 0.3]) { + store.dispatch({ type: 'setDrumParam', drum: 'snare', param: 'volume', value }) + t += 100 + } + t += 2000 + store.dispatch({ type: 'setDrumParam', drum: 'snare', param: 'volume', value: 0.1 }) + store.undo() + expect(store.getState().drums.snare.volume).toBe(0.3) + store.undo() + expect(store.getState().drums.snare.volume).toBe(defaultSession().drums.snare.volume) + }) +}) diff --git a/src/session/store.ts b/src/session/store.ts new file mode 100644 index 0000000..96ef350 --- /dev/null +++ b/src/session/store.ts @@ -0,0 +1,71 @@ +import { useSyncExternalStore } from 'react' +import { applyCommand, type Command } from './commands' +import type { Session } from './schema' + +export interface SessionStore { + getState(): Session + dispatch(command: Command): void + /** Steps back one change. */ + undo(): void + canUndo(): boolean + subscribe(listener: () => void): () => void +} + +/** How many changes undo remembers. */ +const HISTORY_LIMIT = 100 + +/** Repeats of the same continuous control within this window count as one change, so a knob drag undoes in one step. */ +const COALESCE_MS = 800 + +/** Commands that come in streams while a control is dragged, keyed by the control they move. */ +function continuousKey(command: Command): string | null { + switch (command.type) { + case 'setDrumParam': + return `${command.type}:${command.drum}:${command.param}` + case 'setSynthVolume': + case 'setBpm': + return command.type + default: + return null + } +} + +export function createSessionStore(initial: Session, now: () => number = Date.now): SessionStore { + let state = initial + let past: Session[] = [] + let last: { key: string; at: number } | null = null + const listeners = new Set<() => void>() + const notify = () => listeners.forEach((l) => l()) + + return { + getState: () => state, + dispatch(command) { + const next = applyCommand(state, command) + if (next === state) return + const key = continuousKey(command) + const at = now() + const continuing = key !== null && last?.key === key && at - last.at < COALESCE_MS + if (!continuing) past = [...past, state].slice(-HISTORY_LIMIT) + last = key === null ? null : { key, at } + state = next + notify() + }, + undo() { + const previous = past.at(-1) + if (!previous) return + past = past.slice(0, -1) + last = null + state = previous + notify() + }, + canUndo: () => past.length > 0, + subscribe(listener) { + listeners.add(listener) + return () => listeners.delete(listener) + }, + } +} + +export function useSession(store: SessionStore, select: (s: Session) => T): T { + return useSyncExternalStore(store.subscribe, () => select(store.getState())) +} diff --git a/src/session/url.test.ts b/src/session/url.test.ts new file mode 100644 index 0000000..6218d06 --- /dev/null +++ b/src/session/url.test.ts @@ -0,0 +1,61 @@ +import { describe, expect, it } from 'vitest' +import { applyCommand } from './commands' +import { defaultSession } from './schema' +import { decodeSession, encodeSession } from './url' + +describe('share link', () => { + it('round-trips drums, tempo, and the full synth', () => { + let s = defaultSession() + s = applyCommand(s, { type: 'setBpm', bpm: 98 }) + s = applyCommand(s, { type: 'toggleDrumStep', drum: 'kick', step: 0 }) + s = applyCommand(s, { type: 'toggleDrumStep', drum: 'kick', step: 10 }) + s = applyCommand(s, { type: 'setDrumParam', drum: 'snare', param: 'delay', value: 0.4 }) + s = applyCommand(s, { type: 'toggleSynthStep', step: 3 }) + s = applyCommand(s, { type: 'toggleNote', note: 'G4' }) + s = applyCommand(s, { type: 'toggleNote', note: 'C3' }) + s = applyCommand(s, { type: 'setArpMode', mode: 'up-down' }) + s = applyCommand(s, { type: 'setArpRate', rate: '1/8' }) + s = applyCommand(s, { type: 'setWaveform', waveform: 'triangle' }) + s = applyCommand(s, { type: 'setOctave', octave: -1 }) + s = applyCommand(s, { type: 'setSynthVolume', value: 0.25 }) + + const back = decodeSession(encodeSession(s)) + + expect(back.bpm).toBe(98) + expect(back.drums.kick.steps[0]).toBe(true) + expect(back.drums.kick.steps[10]).toBe(true) + expect(back.drums.kick.steps.filter(Boolean)).toHaveLength(2) + expect(back.drums.snare.delay).toBeCloseTo(0.4, 2) + expect(back.synth.steps[3]).toBe(true) + expect(back.synth.notes).toEqual(['C3', 'G4']) + expect(back.synth.mode).toBe('up-down') + expect(back.synth.rate).toBe('1/8') + expect(back.synth.waveform).toBe('triangle') + expect(back.synth.octave).toBe(-1) + expect(back.synth.volume).toBeCloseTo(0.25, 2) + }) + + it('keys drums by id, so their order in the link does not matter', () => { + const link = '2~120~kick.8000.ff00ff~hihat.0001.8000ff~syn.0000.000000.u.16.s.80' + const s = decodeSession(link) + expect(s.drums.kick.steps[0]).toBe(true) + expect(s.drums.hihat.steps[15]).toBe(true) + }) + + it('reads links made before the octave field as octave 0', () => { + const s = decodeSession('2~120~syn.8000.000800.u.16.s.80') + expect(s.synth.steps[0]).toBe(true) + expect(s.synth.octave).toBe(0) + }) + + it('falls back to defaults for missing, unknown, or malformed parts', () => { + expect(decodeSession(null)).toEqual(defaultSession()) + expect(decodeSession('8888080880a2_cc0000cc3300cc00ff_098')).toEqual(defaultSession()) + const s = decodeSession('2~999~cowbell.ffff.ffffff~snare.zz.qq~syn.ffff.zz.x.3.w.zz') + expect(s.bpm).toBe(200) + expect(s.drums.snare).toEqual(defaultSession().drums.snare) + expect(s.synth.steps.every(Boolean)).toBe(true) + expect(s.synth.notes).toEqual([]) + expect(s.synth.mode).toBe('up') + }) +}) diff --git a/src/session/url.ts b/src/session/url.ts new file mode 100644 index 0000000..2764a39 --- /dev/null +++ b/src/session/url.ts @@ -0,0 +1,117 @@ +import { DRUMS, NOTES } from '../instruments' +import { PRESETS } from './library' +import { + ARP_MODES, + ARP_RATES, + OCTAVES, + STEPS, + WAVEFORMS, + clamp01, + clampBpm, + defaultSession, + normalizeNotes, + type ArpMode, + type ArpRate, + type Session, + type Waveform, +} from './schema' + +/** + * Share-link format, version 2. Every part is keyed, so adding a drum never + * changes how existing parts read: + * + * ?s=2~~~…~syn....... + * drum = .. + * + * steps: 16 bits as 4 hex · notes: 24 bits as 6 hex · knob values: 0–255 as 2 hex. + * octave: -1, 0, or 1; links from before it existed omit it and play at 0. + */ +export const LINK_VERSION = '2' + +const MODE_CODES: Record = { up: 'u', down: 'd', 'up-down': 'b' } +const RATE_CODES: Record = { '1/4': '4', '1/8': '8', '1/16': '16' } +const WAVE_CODES: Record = { sawtooth: 's', square: 'q', sine: 'i', triangle: 't' } + +const invert = (m: Record) => + Object.fromEntries(Object.entries(m).map(([k, v]) => [v, k])) as Record +const MODE_BY_CODE = invert(MODE_CODES) +const RATE_BY_CODE = invert(RATE_CODES) +const WAVE_BY_CODE = invert(WAVE_CODES) + +const bitsToHex = (bits: boolean[], width: number) => + bits.reduce((n, on, i) => (on ? n | (1 << (bits.length - 1 - i)) : n), 0).toString(16).padStart(width, '0') + +function hexToBits(hex: string | undefined, length: number): boolean[] | null { + if (!hex || !/^[0-9a-f]+$/i.test(hex) || hex.length * 4 < length) return null + const n = parseInt(hex, 16) + return Array.from({ length }, (_, i) => (n & (1 << (length - 1 - i))) !== 0) +} + +const byteHex = (v: number) => Math.round(clamp01(v) * 255).toString(16).padStart(2, '0') + +function hexByte(hex: string | undefined): number | null { + if (!hex || !/^[0-9a-f]{2}$/i.test(hex)) return null + return parseInt(hex, 16) / 255 +} + +export function encodeSession(session: Session): string { + const drums = DRUMS.map(({ id }) => { + const t = session.drums[id] + return `${id}.${bitsToHex(t.steps, 4)}.${byteHex(t.volume)}${byteHex(t.delay)}${byteHex(t.decay)}` + }) + const s = session.synth + const held = new Set(s.notes) + const synth = [ + 'syn', + bitsToHex(s.steps, 4), + bitsToHex(NOTES.map((n) => held.has(n.note)), 6), + MODE_CODES[s.mode], + RATE_CODES[s.rate], + WAVE_CODES[s.waveform], + byteHex(s.volume), + String(s.octave), + ].join('.') + return [LINK_VERSION, String(session.bpm), ...drums, synth].join('~') +} + +/** Reads a share-link payload. Anything missing or malformed falls back to the default for that part. */ +export function decodeSession(payload: string | null): Session { + const session = defaultSession() + if (!payload) return session + const [version, bpm, ...parts] = payload.split('~') + if (version !== LINK_VERSION) return session + + session.bpm = clampBpm(Number(bpm)) + for (const part of parts) { + const [id, ...fields] = part.split('.') + if (id === 'syn') { + const [steps, notes, mode, rate, wave, volume, octave] = fields + const s = session.synth + s.steps = hexToBits(steps, STEPS) ?? s.steps + const noteBits = hexToBits(notes, NOTES.length) + if (noteBits) s.notes = normalizeNotes(NOTES.filter((_, i) => noteBits[i]).map((n) => n.note)) + s.mode = ARP_MODES.includes(MODE_BY_CODE[mode]) ? MODE_BY_CODE[mode] : s.mode + s.rate = ARP_RATES.includes(RATE_BY_CODE[rate]) ? RATE_BY_CODE[rate] : s.rate + s.waveform = WAVEFORMS.includes(WAVE_BY_CODE[wave]) ? WAVE_BY_CODE[wave] : s.waveform + s.volume = hexByte(volume) ?? s.volume + s.octave = OCTAVES.find((o) => String(o) === octave) ?? s.octave + continue + } + const track = session.drums[id] + if (!track) continue + const [steps, knobs = ''] = fields + track.steps = hexToBits(steps, STEPS) ?? track.steps + track.volume = hexByte(knobs.slice(0, 2)) ?? track.volume + track.delay = hexByte(knobs.slice(2, 4)) ?? track.delay + track.decay = hexByte(knobs.slice(4, 6)) ?? track.decay + } + return session +} + +/** The session in the address bar, or the first ready-made pattern when there is no link, so the machine opens on a groove. */ +export const readSessionFromLocation = (): Session => + decodeSession(new URLSearchParams(window.location.search).get('s') ?? PRESETS[0].link) + +export function writeSessionToLocation(session: Session): void { + window.history.replaceState(null, '', `${window.location.pathname}?s=${encodeSession(session)}`) +} diff --git a/src/setupTests.js b/src/setupTests.js deleted file mode 100644 index c44951a..0000000 --- a/src/setupTests.js +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom' diff --git a/src/test/setup.js b/src/test/setup.js deleted file mode 100644 index c44951a..0000000 --- a/src/test/setup.js +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom' diff --git a/src/test/setup.ts b/src/test/setup.ts new file mode 100644 index 0000000..a9d0dd3 --- /dev/null +++ b/src/test/setup.ts @@ -0,0 +1 @@ +import '@testing-library/jest-dom/vitest' diff --git a/src/ui/Keyboard.module.css b/src/ui/Keyboard.module.css new file mode 100644 index 0000000..54cc34d --- /dev/null +++ b/src/ui/Keyboard.module.css @@ -0,0 +1,153 @@ +/* Dark keybed the keys sit in, with a felt strip under the fallboard. */ +.bed { + padding: 9px 7px 7px; + border-radius: 10px; + background: linear-gradient(#26272b, #141517); + box-shadow: + inset 0 2px 5px rgba(0, 0, 0, 0.6), + inset 0 -1px 0 rgba(255, 255, 255, 0.06), + 0 1px 0 rgba(255, 255, 255, 0.9); +} + +.keys { + --gap: 1px; + --white-w: calc((100% - 13 * var(--gap)) / 14); + position: relative; + display: grid; + grid-template-columns: repeat(14, 1fr); + gap: var(--gap); + height: 140px; +} + +.keys::before { + content: ''; + position: absolute; + inset: -4px 0 auto; + z-index: 2; + height: 4px; + border-radius: 2px 2px 0 0; + background: var(--grain), linear-gradient(#7d2a26, #561a18); + box-shadow: 0 2px 3px rgba(0, 0, 0, 0.45); + pointer-events: none; +} + +.white, +.black { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-end; + gap: 4px; + border: 0; +} + +/* Ivory key: shaded where it slides under the felt, with a front lip at the bottom. */ +.white { + padding: 0 0 14px; + border-radius: 0 0 5px 5px; + background: + var(--grain), + linear-gradient(rgba(0, 0, 0, 0.16), transparent 14px), + linear-gradient(#f8f4ea 70%, #e9e2d1); + box-shadow: + inset 0 -7px 0 #d6ccb6, + inset 0 -8px 0 rgba(255, 255, 255, 0.85), + inset 1px 0 0 rgba(255, 255, 255, 0.9), + inset -1px 0 0 rgba(0, 0, 0, 0.1), + 0 2px 2px rgba(0, 0, 0, 0.5); +} + +/* Ebony key: a raised top face with sloped sides and a longer slope at the front. */ +.black { + position: absolute; + top: 0; + z-index: 1; + width: calc(var(--white-w) * 0.6); + height: 62%; + left: calc(var(--x) * (var(--white-w) + var(--gap)) - var(--gap) / 2 - var(--white-w) * 0.3); + padding: 0 0 15px; + border-radius: 0 0 4px 4px; + background: linear-gradient(90deg, #08090a, #2a2b2f 18%, #1a1b1e 50%, #2a2b2f 82%, #08090a); + box-shadow: + inset 0 -9px 6px -4px rgba(255, 255, 255, 0.12), + 1px 4px 5px rgba(0, 0, 0, 0.55), + 0 0 0 1px #050506; +} + +.black::before { + content: ''; + position: absolute; + inset: 0 3px 9px; + border-radius: 0 0 3px 3px; + background: + linear-gradient(90deg, transparent 20%, rgba(255, 255, 255, 0.1) 45%, transparent 70%), + linear-gradient(#141518, #2f3035 82%, #232428); + box-shadow: + inset 0 -1px 0 rgba(255, 255, 255, 0.14), + 0 1px 2px rgba(0, 0, 0, 0.6); +} + +.name, +.hint, +.led { + position: relative; +} + +.name { + height: 10px; + font: 700 9.5px/1 var(--font-label); + color: var(--navy); +} + +.hint { + font: 600 9.5px/1 var(--font-label); + color: var(--muted); +} + +.black .hint { + color: #8a8d95; +} + +/* Key LED: unlit and recessed into the key, red when held, amber while the note plays. */ +.led { + width: 7px; + height: 7px; + margin-bottom: 3px; + border-radius: 50%; + background: #d3c9b3; + box-shadow: + inset 0 1px 1px rgba(0, 0, 0, 0.25), + 0 1px 0 rgba(255, 255, 255, 0.8); + transition: + background var(--fade), + box-shadow var(--fade); +} + +.black .led { + background: #0b0c0e; + box-shadow: + inset 0 1px 1px rgba(0, 0, 0, 0.8), + 0 1px 0 rgba(255, 255, 255, 0.1); +} + +.held .led { + background: var(--led-red); + box-shadow: + 0 0 6px var(--led-red), + inset 0 1px 0 #fff6; +} + +.playing .led { + background: var(--led-amber); + box-shadow: + 0 0 8px var(--led-amber), + inset 0 1px 0 #fff6; + transition-duration: var(--flash); +} + +.white:focus-visible, +.black:focus-visible { + outline: 2px solid var(--navy); + outline-offset: -2px; +} diff --git a/src/ui/Keyboard.tsx b/src/ui/Keyboard.tsx new file mode 100644 index 0000000..25fe9c3 --- /dev/null +++ b/src/ui/Keyboard.tsx @@ -0,0 +1,65 @@ +import { memo, type CSSProperties } from 'react' +import { NOTES } from '../instruments' +import styles from './Keyboard.module.css' + +interface KeyboardProps { + held: readonly string[] + /** The note the synth fired on the current step, if any. */ + playing: string | null + /** The synth's octave shift; the C labels follow it. */ + octave: number + onToggle: (note: string) => void +} + +const WHITE = NOTES.filter((n) => !n.black) + +/** Position of each black key, counted in white-key widths from the left edge. */ +const BLACK = NOTES.flatMap((n, i) => (n.black ? [{ ...n, x: NOTES.slice(0, i).filter((m) => !m.black).length }] : [])) + +/** + * Two-octave piano keyboard set in a keybed. Each key carries an LED: red for held + * notes (the chord the arp plays), amber for the note the synth plays on this step. + */ +/** "C3" shifted by `octave`, e.g. "C2" at -1. */ +const shifted = (note: string, octave: number) => note.replace(/\d+$/, (n) => String(Number(n) + octave)) + +export const Keyboard = memo(function Keyboard({ held, playing, octave, onToggle }: KeyboardProps) { + const heldSet = new Set(held) + const cls = (base: string, note: string) => + [base, heldSet.has(note) && styles.held, playing === note && styles.playing].filter(Boolean).join(' ') + + return ( +
+
+ {WHITE.map((n) => ( + + ))} + {BLACK.map((n) => ( + + ))} +
+
+ ) +}) diff --git a/src/ui/LoopMachine.module.css b/src/ui/LoopMachine.module.css new file mode 100644 index 0000000..f9c3599 --- /dev/null +++ b/src/ui/LoopMachine.module.css @@ -0,0 +1,206 @@ +/* Glass housing over the wallpaper; the panel inside carries the 909 layout. */ +/* Polished-chrome housing frame, as on the original direction A, around the matte panel. */ +.device { + width: 1128px; + padding: 8px; + border-radius: 20px; + background: + linear-gradient(180deg, rgba(255, 255, 255, 0.55), transparent 18%, transparent 82%, rgba(0, 0, 0, 0.12)), + linear-gradient(90deg, #b9bcbf, #eef0f1 12%, #c9ccce 30%, #f6f7f8 50%, #c3c6c9 70%, #eceeef 88%, #b3b6b9); + box-shadow: + 0 30px 60px -28px rgba(32, 38, 56, 0.45), + 0 2px 6px rgba(32, 38, 56, 0.12), + 0 0 0 1px rgba(32, 38, 56, 0.18), + inset 0 1px 0 rgba(255, 255, 255, 0.9), + inset 0 -1px 0 rgba(0, 0, 0, 0.15); +} + +.face { + padding: 22px 28px 26px; + border-radius: 13px; + background: #f7f4ee; + box-shadow: + inset 0 1px 0 rgba(255, 255, 255, 0.9), + 0 0 0 1px rgba(0, 0, 0, 0.12); +} + +/* Nameplate on the left; the global pattern and undo keys on the right, like the 909's pattern section. */ +.top { + display: flex; + justify-content: space-between; + align-items: flex-start; + margin-bottom: 32px; +} + +/* "DRUM MACHINE + SYNTH" is sized to run exactly as wide as "LM-919". */ +.nameplate { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 6px; +} + +.globals { + display: flex; + align-items: flex-start; + gap: 22px; +} + +.pattern { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; +} + +/* The loaded pattern's name, or "Your loop" once you change it. */ +.patternName { + font: 600 10px/1 var(--font-label); + letter-spacing: 0.06em; + color: var(--muted); + text-transform: uppercase; +} + +/* Undo has no LED, so its key sits level with the pattern keys below their LEDs. */ +.undo { + display: flex; + flex-direction: column; + align-items: center; + gap: 16px; +} + +.descriptor { + font: 400 9.5px/1 var(--font-nameplate); + letter-spacing: 0.16em; + color: var(--navy); + white-space: nowrap; +} + +/* Carved into the panel and paint-filled; see the "carved" filter in LoopMachine.tsx. */ +.model { + margin: 0; + font: 400 34.53px/1 var(--font-nameplate); + letter-spacing: 0.05em; + color: var(--navy); + white-space: nowrap; + filter: url(#carved); +} + +.defs { + position: absolute; + width: 0; + height: 0; +} + +.cols { + display: grid; + grid-template-columns: 84px minmax(0, 1fr) 190px; + column-gap: 30px; + row-gap: 8px; + align-items: center; +} + +.seq { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + column-gap: 14px; +} + +.group { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + column-gap: 6px; +} + +/* 909-style beat band: one segment per beat, aligned with each group of four steps. */ +.beats { + display: grid; + grid-template-columns: repeat(4, minmax(0, 1fr)); + column-gap: 14px; +} + +.beat { + height: 10px; + border-radius: 5px; + background: rgba(44, 58, 94, 0.14); + transition: background var(--fade); +} + +.beatNow { + background: var(--orange); + transition-duration: var(--flash); +} + +.num { + font: 700 11px/1 var(--font-label); + color: var(--navy); + text-align: center; +} + +.numNow { + color: var(--orange); +} + +/* Labels and knobs sit level with the pads, not with the LED strip above them. */ +.rowLabel { + display: flex; + align-items: center; + justify-content: center; + height: 24px; + margin-top: 9px; +} + +.mix { + display: grid; + grid-template-columns: repeat(3, 1fr); + justify-items: center; + transform: translateY(4.5px); +} + +.lower { + margin-top: 22px; + align-items: stretch; +} + +.faderColumn { + grid-column: 1; + grid-row: 1; + display: flex; + flex-direction: column; + align-items: center; + gap: 10px; + padding-top: 4px; +} + +/* The synth's inset panel; negative margins keep its steps the same width as the drums'. */ +.synth { + grid-column: 2; + grid-row: 1; + display: flex; + flex-direction: column; + gap: 12px; + margin: 0 -13px; + padding: 12px; + border: 1px solid var(--well-line); + border-radius: 16px; + background: var(--well); +} + +.controls { + grid-column: 2; + grid-row: 2; + display: flex; + justify-content: center; + gap: 22px; + margin-top: 14px; +} + +.chordRow { + grid-column: 2; + grid-row: 3; + display: flex; + justify-content: center; + align-items: flex-end; + gap: 10px; + margin-top: 6px; +} diff --git a/src/ui/LoopMachine.tsx b/src/ui/LoopMachine.tsx new file mode 100644 index 0000000..7e6c4d9 --- /dev/null +++ b/src/ui/LoopMachine.tsx @@ -0,0 +1,269 @@ +import { useCallback, useSyncExternalStore, type CSSProperties, type ReactNode } from 'react' +import { DRUMS, SYNTH_FIRE, type FireColor } from '../instruments' +import type { Playhead } from '../engine/engine' +import { CHORDS, chordFor, PRESETS } from '../session/library' +import { OCTAVES, type ArpMode, type ArpRate, type Waveform } from '../session/schema' +import { useSession, type SessionStore } from '../session/store' +import { decodeSession, encodeSession } from '../session/url' +import { Fader } from './controls/Fader' +import { Knob } from './controls/Knob' +import { LedChoice, PlainKey } from './controls/LedButton' +import { StepKey } from './controls/StepKey' +import { Keyboard } from './Keyboard' +import { TempoControl } from './TempoControl' +import styles from './LoopMachine.module.css' +import transport from './Transport.module.css' + +interface LoopMachineProps { + store: SessionStore + playhead: Playhead + isPlaying: boolean + onStartStop: () => void + onReset: () => void +} + +const fireVars = (c: FireColor) => ({ '--fire-top': c.top, '--fire-bottom': c.bottom, '--fire-glow': c.glow }) as CSSProperties + +/** Four groups of four steps, like the 909's beat groups. */ +function StepGroups({ render }: { render: (step: number) => ReactNode }) { + return ( +
+ {[0, 4, 8, 12].map((start) => ( +
+ {Array.from({ length: 4 }, (_, i) => render(start + i))} +
+ ))} +
+ ) +} + +const MODES: ReadonlyArray<{ value: ArpMode; content: string; name: string }> = [ + { value: 'up', content: '↑', name: 'Up' }, + { value: 'down', content: '↓', name: 'Down' }, + { value: 'up-down', content: '↕', name: 'Up and down' }, +] + +const RATES: ReadonlyArray<{ value: ArpRate; content: string; name: string }> = [ + { value: '1/4', content: '1/4', name: 'Quarter notes' }, + { value: '1/8', content: '1/8', name: 'Eighth notes' }, + { value: '1/16', content: '1/16', name: 'Sixteenth notes' }, +] + +const OCTAVE_OPTIONS = OCTAVES.map((o) => ({ + value: String(o), + content: o > 0 ? `+${o}` : o < 0 ? `−${-o}` : '0', + name: o > 0 ? 'Octave up' : o < 0 ? 'Octave down' : 'Normal octave', +})) + +const PATTERN_OPTIONS = PRESETS.map((p, i) => ({ value: p.link, content: String(i + 1), name: p.name })) + +const CHORD_OPTIONS = CHORDS.map((c) => ({ value: c.name, content: c.name, name: c.name })) + +const undoIcon = ( + + + +) + +/** + * Makes the wordmark look cut into the panel: a shadow inside each stroke + * along its upper wall, and light catching the lower lip just outside it. + */ +const carvedFilter = ( + + + + + + + + + + + + + + + + + + +) + +const wave = (d: string) => ( + + + +) + +const WAVES: ReadonlyArray<{ value: Waveform; content: ReactNode; name: string }> = [ + { value: 'sawtooth', content: wave('M2 12 L12 2 L12 12 L22 2'), name: 'Sawtooth' }, + { value: 'square', content: wave('M2 12 V2 H12 V12 H22 V2'), name: 'Square' }, + { value: 'sine', content: wave('M2 7 C6 -1 8 -1 12 7 S18 15 22 7'), name: 'Sine' }, + { value: 'triangle', content: wave('M2 12 L7 2 L17 12 L22 2'), name: 'Triangle' }, +] + +/** The LM-919 panel. Every control dispatches a session command; the engine follows the session. */ +export function LoopMachine({ store, playhead, isPlaying, onStartStop, onReset }: LoopMachineProps) { + const session = useSession(store, (s) => s) + const canUndo = useSyncExternalStore(store.subscribe, store.canUndo) + const { dispatch } = store + const now = playhead.step + // A pattern's LED stays lit until you change something. + const link = encodeSession(session) + const preset = PRESETS.find((p) => p.link === link) + + const toggleSynthStep = useCallback((step: number) => dispatch({ type: 'toggleSynthStep', step }), [dispatch]) + const toggleNote = useCallback((note: string) => dispatch({ type: 'toggleNote', note }), [dispatch]) + + return ( +
+
+
+
+ {carvedFilter} + DRUM MACHINE + SYNTH +

LM-919

+
+
+
+ dispatch({ type: 'loadSession', session: decodeSession(value) })} + /> + {preset?.name ?? 'Your loop'} +
+
+ UNDO + + {undoIcon} + +
+
+
+ +
+ +
+ {[0, 1, 2, 3].map((beat) => ( + = 0 && Math.floor(now / 4) === beat ? `${styles.beat} ${styles.beatNow}` : styles.beat} /> + ))} +
+ + + + ( + + {step + 1} + + )} + /> +
+ VOL + DELAY + DECAY +
+ + {DRUMS.map((drum) => { + const track = session.drums[drum.id] + const label = drum.label.toUpperCase() + return ( + + dispatch({ type: 'setDrumParam', drum: drum.id, param: 'volume', value })} /> + dispatch({ type: 'setDrumParam', drum: drum.id, param: 'delay', value })} /> + dispatch({ type: 'setDrumParam', drum: drum.id, param: 'decay', value })} /> + + ) + })} +
+ +
+
+ VOL + dispatch({ type: 'setSynthVolume', value })} /> +
+ +
+ ( + + )} + /> + +
+ +
+ TEMPO + dispatch({ type: 'setBpm', bpm })} /> +
+
+ RESET +
+
+ {isPlaying ? 'STOP' : 'START'} +
+
+
+ +
+ dispatch({ type: 'setArpMode', mode })} /> + dispatch({ type: 'setArpRate', rate })} /> + dispatch({ type: 'setWaveform', waveform })} /> + { + const octave = OCTAVES.find((o) => String(o) === value) + if (octave !== undefined) dispatch({ type: 'setOctave', octave }) + }} + /> +
+ +
+ { + const chord = CHORDS.find((c) => c.name === name) + if (chord) dispatch({ type: 'setNotes', notes: [...chord.notes] }) + }} + /> +
+
+
+
+ ) +} + +interface DrumRowProps { + id: string + label: string + fire: FireColor + steps: boolean[] + now: number + store: SessionStore + children: ReactNode +} + +function DrumRow({ id, label, fire, steps, now, store, children }: DrumRowProps) { + const toggle = useCallback((step: number) => store.dispatch({ type: 'toggleDrumStep', drum: id, step }), [store, id]) + return ( + <> + {label} +
+ } + /> +
+
{children}
+ + ) +} + diff --git a/src/ui/TempoControl.tsx b/src/ui/TempoControl.tsx new file mode 100644 index 0000000..9424ca4 --- /dev/null +++ b/src/ui/TempoControl.tsx @@ -0,0 +1,57 @@ +import { useState } from 'react' +import { ArrowKey } from './controls/LedButton' +import styles from './Transport.module.css' + +interface TempoControlProps { + bpm: number + onChange: (bpm: number) => void +} + +/** Red 7-segment tempo window. Type a value, or step it with ▲▼. */ +export function TempoControl({ bpm, onChange }: TempoControlProps) { + const [draft, setDraft] = useState(null) + const shown = draft ?? String(bpm).padStart(3, '0') + + const commit = () => { + if (draft !== null) { + const parsed = parseInt(draft, 10) + if (!Number.isNaN(parsed)) onChange(parsed) + } + setDraft(null) + } + + return ( +
+ +
+ onChange(bpm + 1)}> + ▲ + + onChange(bpm - 1)}> + ▼ + +
+
+ ) +} diff --git a/src/ui/Transport.module.css b/src/ui/Transport.module.css new file mode 100644 index 0000000..b0dd029 --- /dev/null +++ b/src/ui/Transport.module.css @@ -0,0 +1,102 @@ +.panel { + grid-column: 3; + grid-row: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 12px; + padding: 16px 12px; + border: 1px solid rgba(44, 58, 94, 0.07); + border-radius: 16px; + background: rgba(44, 58, 94, 0.025); +} + +.tempo { + display: flex; + align-items: center; + gap: 6px; +} + +.window { + position: relative; + display: flex; + align-items: center; + height: 44px; + padding: 8px 10px; + border-radius: 3px; + background: #2a0b0a; + box-shadow: + inset 0 2px 8px #000, + 0 0 0 2px var(--ink); + cursor: text; +} + +.ghost, +.digits { + font: 700 26px/1 var(--font-led); +} + +.ghost { + color: #3d1513; +} + +.digits { + position: absolute; + right: 10px; + width: 3.2em; + padding: 0; + border: 0; + background: transparent; + color: var(--led-red); + text-align: right; + text-shadow: 0 0 8px #ff3b2a99; + caret-color: var(--led-red); + outline: none; +} + +.digits::selection { + background: #ff3b2a40; +} + +.arrows { + display: flex; + flex-direction: column; + gap: 4px; +} + +.keys { + display: flex; + gap: 14px; +} + +.control { + display: flex; + flex-direction: column; + align-items: center; + gap: 6px; +} + +.big { + width: 52px; + height: 44px; + border: 1px solid var(--hair); + border-radius: 10px; + background: var(--key-face); + box-shadow: + 0 1px 2px rgba(31, 33, 36, 0.1), + inset 0 -1px 0 rgba(31, 33, 36, 0.05); +} + +.big:active { + box-shadow: inset 0 1px 2px rgba(31, 33, 36, 0.15); +} + +.big:focus-visible { + outline: 2px solid var(--navy); + outline-offset: 2px; +} + +.big[aria-pressed='true'] { + background: linear-gradient(#f2a587, #d9744f); +} diff --git a/src/ui/controls/Fader.module.css b/src/ui/controls/Fader.module.css new file mode 100644 index 0000000..e3bfa12 --- /dev/null +++ b/src/ui/controls/Fader.module.css @@ -0,0 +1,65 @@ +/* Black slot, printed marks either side, chrome cap with an orange index line. */ +.fader { + --v: 0.5; + position: relative; + flex: 1; + width: 34px; + min-height: 150px; + cursor: ns-resize; + outline: none; + touch-action: none; +} + +.fader::before { + content: ''; + position: absolute; + left: 50%; + top: 6px; + bottom: 6px; + width: 6px; + margin-left: -3px; + border-radius: 3px; + background: var(--ink); + box-shadow: inset 0 1px 2px #000; +} + +/* Nine marks spanning exactly the cap's travel, so every notch lands on one. */ +.fader::after { + content: ''; + position: absolute; + left: 4px; + right: 4px; + top: 8px; + bottom: 7px; + opacity: 0.45; + background: repeating-linear-gradient(180deg, var(--navy) 0 1px, transparent 1px 12.5%); + -webkit-mask: linear-gradient(90deg, #000 0 6px, transparent 6px calc(100% - 6px), #000 calc(100% - 6px)); + mask: linear-gradient(90deg, #000 0 6px, transparent 6px calc(100% - 6px), #000 calc(100% - 6px)); +} + +.cap { + position: absolute; + z-index: 1; + left: 2px; + right: 2px; + top: calc((1 - var(--v)) * (100% - 16px)); + height: 16px; + border-radius: 3px; + background: linear-gradient(180deg, #f6f7f8, #b4b7ba 45%, #8e9196 50%, #d9dbdd); + box-shadow: 0 2px 3px #0006; + transition: top 0.06s ease-out; +} + +.cap::after { + content: ''; + position: absolute; + left: 3px; + right: 3px; + top: 7px; + height: 2px; + background: var(--orange); +} + +.fader:focus-visible .cap { + box-shadow: 0 0 0 3px #2c3a5e66; +} diff --git a/src/ui/controls/Fader.tsx b/src/ui/controls/Fader.tsx new file mode 100644 index 0000000..4171f40 --- /dev/null +++ b/src/ui/controls/Fader.tsx @@ -0,0 +1,51 @@ +import { useRef, type CSSProperties, type PointerEvent } from 'react' +import { FADER_NOTCHES, faderValueAt } from './notch' +import { useNotchedControl } from './useNotchedControl' +import styles from './Fader.module.css' + +interface FaderProps { + value: number + onChange: (value: number) => void + label: string +} + +const CAP_HEIGHT = 16 + +/** Vertical fader that clicks to its marks. Click or drag along the track, scroll, or use the arrow keys. */ +export function Fader({ value, onChange, label }: FaderProps) { + const ref = useRef(null) + const dragging = useRef(false) + const { commit, onKeyDown } = useNotchedControl(ref, value, FADER_NOTCHES, onChange) + + const follow = (e: PointerEvent) => { + const r = e.currentTarget.getBoundingClientRect() + commit(faderValueAt(e.clientY, r.top, r.height, CAP_HEIGHT)) + } + + return ( +
{ + if (e.button !== 0) return + e.currentTarget.setPointerCapture(e.pointerId) + dragging.current = true + follow(e) + }} + onPointerMove={(e) => dragging.current && follow(e)} + onPointerUp={() => (dragging.current = false)} + onPointerCancel={() => (dragging.current = false)} + onKeyDown={onKeyDown} + > + +
+ ) +} diff --git a/src/ui/controls/Knob.module.css b/src/ui/controls/Knob.module.css new file mode 100644 index 0000000..17fd28e --- /dev/null +++ b/src/ui/controls/Knob.module.css @@ -0,0 +1,72 @@ +/* Knurled black skirt, spun-chrome cap, orange pointer, 11 printed ticks. */ +.knob { + --v: 0.5; + --s: 40px; + position: relative; + display: grid; + place-items: center; + width: calc(var(--s) + 14px); + height: calc(var(--s) + 14px); + border-radius: 50%; + cursor: pointer; + outline: none; + touch-action: none; +} + +.knob::before { + content: ''; + position: absolute; + inset: 0; + border-radius: 50%; + opacity: 0.45; + background: repeating-conic-gradient(from -136deg, var(--navy) 0 2deg, transparent 2deg 27deg); + -webkit-mask: + radial-gradient(circle, transparent calc(var(--s) / 2 + 2px), #000 calc(var(--s) / 2 + 3px)), + conic-gradient(from -137deg, #000 0 274deg, transparent 0); + -webkit-mask-composite: source-in; + mask: + radial-gradient(circle, transparent calc(var(--s) / 2 + 2px), #000 calc(var(--s) / 2 + 3px)), + conic-gradient(from -137deg, #000 0 274deg, transparent 0); + mask-composite: intersect; +} + +.cap { + position: relative; + width: var(--s); + height: var(--s); + border-radius: 50%; + background: repeating-conic-gradient(#1b1c1f 0 6deg, #3a3c40 6deg 12deg); + box-shadow: 0 3px 4px #0005; +} + +.cap::after { + content: ''; + position: absolute; + inset: 18%; + border-radius: 50%; + background: + radial-gradient(circle at 50% 50%, #fdfdfd 0 8%, transparent 9%), + conic-gradient(from 20deg, #f4f5f6, #a9acaf, #eef0f1, #9a9da0, #f6f7f8, #b2b5b8, #f4f5f6); + box-shadow: + inset 0 0 0 1px #ffffff90, + 0 0 0 1px #00000040; +} + +.pointer { + position: absolute; + left: 50%; + top: 50%; + z-index: 2; + width: 2px; + height: 48%; + margin-left: -1px; + border-radius: 1px; + background: var(--orange); + transform-origin: 50% 0; + transform: rotate(calc(45deg + var(--v) * 270deg)); + transition: transform 0.06s ease-out; +} + +.knob:focus-visible .cap { + box-shadow: 0 0 0 3px #2c3a5e66; +} diff --git a/src/ui/controls/Knob.tsx b/src/ui/controls/Knob.tsx new file mode 100644 index 0000000..db66d54 --- /dev/null +++ b/src/ui/controls/Knob.tsx @@ -0,0 +1,67 @@ +import { useRef, type CSSProperties, type PointerEvent } from 'react' +import { KNOB_NOTCHES, knobValueAt } from './notch' +import { useNotchedControl } from './useNotchedControl' +import styles from './Knob.module.css' + +interface KnobProps { + value: number + onChange: (value: number) => void + label: string +} + +/** Pixels of vertical drag for the full sweep. */ +const DRAG_RANGE = 150 +/** Movement below this counts as a click, which jumps to the tick nearest the pointer. */ +const CLICK_SLOP = 3 + +/** Chrome knob that clicks to its tick marks. Drag up/down, click a tick, scroll, or use the arrow keys. */ +export function Knob({ value, onChange, label }: KnobProps) { + const ref = useRef(null) + const drag = useRef<{ y: number; start: number; moved: boolean } | null>(null) + const { commit, onKeyDown } = useNotchedControl(ref, value, KNOB_NOTCHES, onChange) + + const onPointerDown = (e: PointerEvent) => { + if (e.button !== 0) return + e.currentTarget.setPointerCapture(e.pointerId) + drag.current = { y: e.clientY, start: value, moved: false } + } + + const onPointerMove = (e: PointerEvent) => { + const d = drag.current + if (!d) return + const dy = d.y - e.clientY + if (Math.abs(dy) >= CLICK_SLOP) d.moved = true + if (d.moved) commit(d.start + dy / DRAG_RANGE) + } + + const onPointerUp = (e: PointerEvent) => { + const d = drag.current + drag.current = null + if (!d || d.moved) return + const r = e.currentTarget.getBoundingClientRect() + commit(knobValueAt(e.clientX - (r.left + r.width / 2), e.clientY - (r.top + r.height / 2))) + } + + return ( +
(drag.current = null)} + onKeyDown={onKeyDown} + > +
+ +
+
+ ) +} diff --git a/src/ui/controls/LedButton.module.css b/src/ui/controls/LedButton.module.css new file mode 100644 index 0000000..5d83685 --- /dev/null +++ b/src/ui/controls/LedButton.module.css @@ -0,0 +1,83 @@ +.group { + display: flex; + flex-direction: column; + align-items: center; + gap: 8px; +} + +.row { + display: flex; + gap: 6px; +} + +.button { + display: flex; + flex-direction: column; + align-items: center; + gap: 4px; + padding: 0; + border: 0; + background: none; +} + +.led { + width: 10px; + height: 4px; + border-radius: 2px; + background: var(--led-off); +} + +.button[aria-checked='true'] .led { + background: var(--led-red); + box-shadow: 0 0 6px var(--led-red); +} + +.face { + display: grid; + place-items: center; + width: 44px; + height: 30px; + border: 1px solid var(--hair); + border-radius: 8px; + background: var(--key-face); + box-shadow: 0 1px 2px rgba(31, 33, 36, 0.08); + font: 700 11px/1 var(--font-label); + font-stretch: 110%; + color: var(--navy); +} + +.face svg { + width: 20px; + height: 12px; +} + +.button:focus-visible { + outline: none; +} + +.button:disabled { + cursor: default; +} + +.button:disabled .face { + opacity: 0.45; +} + +.button:focus-visible .face { + border-color: var(--navy); +} + +/* Tempo arrows keep the 909's dark bezel. */ +.arrow .face { + width: 26px; + height: 20px; + border: 2px solid var(--bezel); + border-radius: 4px; + background: linear-gradient(#f4efe2, #e6dfce); + box-shadow: inset 0 -2px 0 #d3cab5; + font-size: 9px; +} + +.arrow:active .face { + box-shadow: inset 0 1px 0 #d3cab5; +} diff --git a/src/ui/controls/LedButton.tsx b/src/ui/controls/LedButton.tsx new file mode 100644 index 0000000..00d6149 --- /dev/null +++ b/src/ui/controls/LedButton.tsx @@ -0,0 +1,70 @@ +import { useId, type ReactNode } from 'react' +import styles from './LedButton.module.css' + +interface LedChoiceProps { + label: string + options: ReadonlyArray<{ value: T; content: ReactNode; name: string }> + value: T + onChange: (value: T) => void +} + +/** A row of small keys with an LED over the selected one, like the 909's mode buttons. */ +export function LedChoice({ label, options, value, onChange }: LedChoiceProps) { + const labelId = useId() + return ( +
+ + {label} + +
+ {options.map((o) => ( + + ))} +
+
+ ) +} + +interface ArrowKeyProps { + label: string + children: ReactNode + onPress: () => void +} + +/** Small momentary key with a 909 bezel and no LED, used for the tempo arrows. */ +export function ArrowKey({ label, children, onPress }: ArrowKeyProps) { + return ( + + ) +} + +interface PlainKeyProps { + label: string + title: string + disabled?: boolean + children: ReactNode + onPress: () => void +} + +/** A momentary key with the mode buttons' cream face and no LED, for one-shot actions like undo. */ +export function PlainKey({ label, title, disabled, children, onPress }: PlainKeyProps) { + return ( + + ) +} diff --git a/src/ui/controls/StepKey.module.css b/src/ui/controls/StepKey.module.css new file mode 100644 index 0000000..a69c18c --- /dev/null +++ b/src/ui/controls/StepKey.module.css @@ -0,0 +1,109 @@ +.step { + display: flex; + flex-direction: column; + align-items: center; + gap: 5px; + width: 100%; + padding: 0; + border: 0; + background: none; +} + +.led { + width: 14px; + height: 4px; + border-radius: 3px; + background: var(--led-off); + box-shadow: inset 0 1px 1px #0006; +} + +.step[aria-pressed='true'] .led { + background: var(--led-red); + box-shadow: + 0 0 6px var(--led-red), + inset 0 1px 0 #fff6; +} + +.synth[aria-pressed='true'] .led { + background: var(--led-amber); + box-shadow: + 0 0 6px var(--led-amber), + inset 0 1px 0 #fff6; +} + +.key { + /* Glossy molded plastic: cream face, thin dark ring, soft backlight when on. */ + --ring: + 0 0 0 1px rgba(42, 44, 47, 0.5), + 0 1px 2px rgba(0, 0, 0, 0.18); + /* The plastic's shine: a bright reflection over the top half with a crisp lower edge, like light on a glossy molding. */ + --sheen: linear-gradient(rgba(255, 255, 255, 0.65), rgba(255, 255, 255, 0.3) 40%, rgba(255, 255, 255, 0.05) 47%, rgba(255, 255, 255, 0) 60%); + /* Molded edges: a crisp highlight along the top, a faint rim, and shade where the face curves away at the bottom. */ + --mold: + inset 0 1px 0 rgba(255, 255, 255, 0.95), + inset 0 0 0 1px rgba(255, 255, 255, 0.22), + inset 0 -3px 4px rgba(0, 0, 0, 0.12); + display: block; + width: 100%; + height: 42px; + border: 0; + border-radius: 7px; + background: var(--sheen), linear-gradient(#f2eee6, #ded9cf); + box-shadow: + var(--ring), + var(--mold); + transition: + background var(--fade), + box-shadow var(--fade), + transform var(--fade); +} + +/* On: a soft, calm version of the row's firing color, so on and firing read as one color at two strengths. The key sits a little pressed in. */ +.step[aria-pressed='true'] .key { + transform: translateY(1px); + background: + var(--sheen), + linear-gradient(color-mix(in oklab, var(--fire-top) 50%, #ece6da), color-mix(in oklab, var(--fire-bottom) 50%, #dcd4c3)); + box-shadow: + 0 0 0 1px rgba(42, 44, 47, 0.5), + 0 0 1px rgba(0, 0, 0, 0.18), + inset 0 2px 3px rgba(0, 0, 0, 0.14), + var(--mold); +} + +.step:focus-visible { + outline: none; +} + +.step:focus-visible .key { + outline: 2px solid var(--navy); + outline-offset: 3px; +} + +/* Playhead: a faint cool shade on keys that are off… */ +.now .key { + background: + var(--sheen), + linear-gradient(#efefed, #dddddb); + transition-duration: var(--flash); +} + +/* …and keys that are on fire glow evenly through the plastic, like a backlit pad: saturated, barely brighter at the center, light held close. */ +.now[aria-pressed='true'] .key { + background: + var(--sheen), + radial-gradient( + ellipse 95% 90% at 50% 45%, + color-mix(in oklab, var(--fire-top) 68%, #fff8ec) 0%, + color-mix(in oklab, var(--fire-top) 88%, #fff8ec) 40%, + var(--fire-top) 70%, + color-mix(in oklab, var(--fire-top) 55%, var(--fire-bottom)) 100% + ); + box-shadow: + var(--ring), + 0 0 4px rgba(var(--fire-glow), 0.7), + 0 0 16px 3px rgba(var(--fire-glow), 0.38), + inset 0 0 9px rgba(var(--fire-glow), 0.4), + var(--mold); + transition-duration: var(--flash); +} diff --git a/src/ui/controls/StepKey.tsx b/src/ui/controls/StepKey.tsx new file mode 100644 index 0000000..d8b7b21 --- /dev/null +++ b/src/ui/controls/StepKey.tsx @@ -0,0 +1,26 @@ +import { memo } from 'react' +import styles from './StepKey.module.css' + +interface StepKeyProps { + step: number + on: boolean + /** The playhead is on this step. */ + now: boolean + variant?: 'drum' | 'synth' + label: string + onToggle: (step: number) => void +} + +/** + * A 909 step key: cream key with an LED above it. Under the playhead it takes + * a faint grey shade; if it's on, it fires in its row's color and fades out. + */ +export const StepKey = memo(function StepKey({ step, on, now, variant = 'drum', label, onToggle }: StepKeyProps) { + const className = [styles.step, variant === 'synth' && styles.synth, now && styles.now].filter(Boolean).join(' ') + return ( + + ) +}) diff --git a/src/ui/controls/notch.test.ts b/src/ui/controls/notch.test.ts new file mode 100644 index 0000000..36d8bcd --- /dev/null +++ b/src/ui/controls/notch.test.ts @@ -0,0 +1,32 @@ +import { describe, expect, it } from 'vitest' +import { faderValueAt, knobValueAt, snapToNotch, valueForKey } from './notch' + +describe('notched controls', () => { + it('snaps to the nearest notch', () => { + expect(snapToNotch(0.62, 10)).toBe(0.6) + expect(snapToNotch(0.66, 10)).toBe(0.7) + expect(snapToNotch(0.55, 8)).toBe(0.5) + expect(snapToNotch(1.4, 10)).toBe(1) + }) + + it('maps a click around the knob to a value', () => { + expect(knobValueAt(0, -10)).toBeCloseTo(0.5) // straight up + expect(knobValueAt(-10, 10)).toBeCloseTo(0) // down-left, start of the sweep + expect(knobValueAt(10, 10)).toBeCloseTo(1) // down-right, end of the sweep + expect(knobValueAt(-1, 20)).toBe(0) // bottom dead zone goes to the nearer end + expect(knobValueAt(1, 20)).toBe(1) + }) + + it('maps a click on the fader track to a value', () => { + expect(faderValueAt(8, 0, 116, 16)).toBe(1) + expect(faderValueAt(108, 0, 116, 16)).toBe(0) + expect(faderValueAt(58, 0, 116, 16)).toBeCloseTo(0.5) + }) + + it('moves one notch per arrow key', () => { + expect(valueForKey('ArrowUp', 0.5, 10)).toBe(0.6) + expect(valueForKey('ArrowLeft', 0.5, 8)).toBe(0.375) + expect(valueForKey('End', 0.2, 8)).toBe(1) + expect(valueForKey('a', 0.2, 8)).toBeNull() + }) +}) diff --git a/src/ui/controls/notch.ts b/src/ui/controls/notch.ts new file mode 100644 index 0000000..d466f57 --- /dev/null +++ b/src/ui/controls/notch.ts @@ -0,0 +1,43 @@ +import { clamp01 } from '../../session/schema' + +/** Knobs click to 11 tick marks (0–10); the fader to 9 marks. */ +export const KNOB_NOTCHES = 10 +export const FADER_NOTCHES = 8 + +export const snapToNotch = (value: number, notches: number): number => Math.round(clamp01(value) * notches) / notches + +/** Knob sweep: 270° from 7:30 to 4:30, so 0 is down-left and 1 is down-right. */ +export const KNOB_SWEEP = 270 + +/** + * Value for a click at (dx, dy) from the knob's center. Clicks in the dead + * zone at the bottom go to the nearer end. + */ +export function knobValueAt(dx: number, dy: number): number { + const degrees = (Math.atan2(dx, -dy) * 180) / Math.PI + return clamp01((degrees + KNOB_SWEEP / 2) / KNOB_SWEEP) +} + +/** Value for a pointer at `y` on a vertical fader whose cap is `capHeight` tall. */ +export function faderValueAt(y: number, top: number, height: number, capHeight: number): number { + return clamp01(1 - (y - top - capHeight / 2) / (height - capHeight)) +} + +/** One notch per arrow key, the ends for Home and End. Returns null for other keys. */ +export function valueForKey(key: string, value: number, notches: number): number | null { + const step = 1 / notches + switch (key) { + case 'ArrowUp': + case 'ArrowRight': + return snapToNotch(value + step, notches) + case 'ArrowDown': + case 'ArrowLeft': + return snapToNotch(value - step, notches) + case 'Home': + return 0 + case 'End': + return 1 + default: + return null + } +} diff --git a/src/ui/controls/useNotchedControl.ts b/src/ui/controls/useNotchedControl.ts new file mode 100644 index 0000000..fe07090 --- /dev/null +++ b/src/ui/controls/useNotchedControl.ts @@ -0,0 +1,46 @@ +import { useEffect, useRef, type KeyboardEvent, type RefObject } from 'react' +import { snapToNotch, valueForKey } from './notch' + +/** + * Shared behavior for knobs and faders: the value snaps to notches, arrow keys + * move one notch, and the mouse wheel moves one notch per tick. + */ +export function useNotchedControl( + ref: RefObject, + value: number, + notches: number, + onChange: (value: number) => void, +) { + const latest = useRef({ value, onChange }) + useEffect(() => { + latest.current = { value, onChange } + }) + + const commit = (next: number) => { + const snapped = snapToNotch(next, notches) + if (snapped !== latest.current.value) latest.current.onChange(snapped) + } + + // React attaches wheel listeners as passive, so preventDefault needs a native listener. + useEffect(() => { + const el = ref.current + if (!el) return + const onWheel = (e: WheelEvent) => { + e.preventDefault() + const { value: v, onChange: change } = latest.current + const next = snapToNotch(v + (e.deltaY < 0 ? 1 : -1) / notches, notches) + if (next !== v) change(next) + } + el.addEventListener('wheel', onWheel, { passive: false }) + return () => el.removeEventListener('wheel', onWheel) + }, [ref, notches]) + + const onKeyDown = (e: KeyboardEvent) => { + const next = valueForKey(e.key, latest.current.value, notches) + if (next === null) return + e.preventDefault() + commit(next) + } + + return { commit, onKeyDown } +} diff --git a/src/ui/fonts/Archivo.woff2 b/src/ui/fonts/Archivo.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..7af3f7db56708079e71cc2c265b3889d7f4649a6 GIT binary patch literal 90096 zcmV(?K-a%_Pew8T0RR910blR{6951J15Stl0bhIo0RR9100000000000000000000 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 literal 0 HcmV?d00001 diff --git a/src/ui/fonts/DSEG7Classic-Bold.woff2 b/src/ui/fonts/DSEG7Classic-Bold.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..558eec408af275c2f840e012edcff769deff8902 GIT binary patch literal 5132 zcmV+n6!YtMPew8T0RR9102B-W4gdfE09pV5028qQ0RR9100000000000000000000 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 literal 0 HcmV?d00001 diff --git a/src/ui/fonts/Michroma.woff2 b/src/ui/fonts/Michroma.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..807ac77d0cee7512ff749d810c274709beeaa446 GIT binary patch literal 11620 zcmV-qEt}GJPew8T0RR9104-zy4gdfE09sH004)mu0RR9100000000000000000000 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%0Ds@`+#FxiH)E#9xY`rZk= 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 i`xRwQRFqs val ? '1' : '0').join('') - return parseInt(binaryString, 2).toString(16).padStart(4, '0') -} - -// Helper: Convert hex string back to boolean array -function hexToState(hexString, steps) { - if (!hexString || hexString.length !== 4) return Array(steps).fill(false) - const binaryString = parseInt(hexString, 16).toString(2).padStart(steps, '0') - return binaryString.split('').map(char => char === '1') -} - -// Helper: Encode float 0-1 to 2 hex chars (0-255) -function floatToHex(val) { - const clamped = Math.max(0, Math.min(1, val)) - const int = Math.round(clamped * 255) - return int.toString(16).padStart(2, '0') -} - -// Helper: Decode 2 hex chars to float 0-1 -function hexToFloat(hex, defaultValue = 0.8) { - if (!hex || hex.length !== 2) return defaultValue - // Validate hex characters before parsing - if (!/^[0-9a-fA-F]{2}$/.test(hex)) return defaultValue - const int = parseInt(hex, 16) - // Safety check for NaN (defensive programming) - if (Number.isNaN(int)) return defaultValue - return int / 255 -} - -/** - * Encode current state to URL - * Format: notes_settings_bpm - * - notes: 4 hex chars per instrument (16 steps) - * - settings: 6 hex chars per instrument (volume 2, reverb 2, filter 2) - * - bpm: 3 digit number - */ -export function encodeStateToUrl(pattern, trackSettings, instruments, bpm = 120) { - let notesHex = '' - let settingsHex = '' - - instruments.forEach(instrument => { - // Notes (16 steps -> 4 hex chars) - notesHex += stateToHex(pattern[instrument.id] || []) - // Settings (volume, reverb, filter as 2 hex chars each) - const settings = trackSettings[instrument.id] || {} - settingsHex += floatToHex(settings.volume ?? 0.8) - settingsHex += floatToHex(settings.reverb ?? 0) - settingsHex += floatToHex(settings.filter ?? 1) - }) - - // BPM as 3-digit string (zero-padded) - const bpmStr = String(bpm).padStart(3, '0') - const compactState = `${notesHex}_${settingsHex}_${bpmStr}` - const newUrl = window.location.pathname + '?s=' + compactState - window.history.replaceState(null, '', newUrl) -} - -/** - * Decode state from URL - */ -export function decodeStateFromUrl(instruments, steps) { - const params = new URLSearchParams(window.location.search) - - const result = { - pattern: null, - trackSettings: null, - bpm: null, - } - - const compactState = params.get('s') - - // Support both old format (notes_settings) and new format (notes_settings_bpm) - if (compactState && compactState.includes('_')) { - try { - const parts = compactState.split('_') - const notesPart = parts[0] - const settingsPart = parts[1] - const bpmPart = parts[2] // may be undefined for old URLs - - const pattern = {} - const trackSettings = {} - let noteOffset = 0 - let settingsOffset = 0 - - instruments.forEach(instrument => { - // Load Notes - const noteHex = notesPart.substring(noteOffset, noteOffset + 4) - pattern[instrument.id] = hexToState(noteHex, steps) - noteOffset += 4 - - // Load Settings (volume, reverb, filter) - const volumeHex = settingsPart.substring(settingsOffset, settingsOffset + 2) - const reverbHex = settingsPart.substring(settingsOffset + 2, settingsOffset + 4) - const filterHex = settingsPart.substring(settingsOffset + 4, settingsOffset + 6) - trackSettings[instrument.id] = { - volume: hexToFloat(volumeHex, 0.8), - reverb: hexToFloat(reverbHex, 0), - filter: hexToFloat(filterHex, 1), - muted: false, - solo: false, - } - settingsOffset += 6 - }) - - result.pattern = pattern - result.trackSettings = trackSettings - - // Parse BPM if present - if (bpmPart && bpmPart.length === 3) { - const parsedBpm = parseInt(bpmPart, 10) - if (parsedBpm >= 60 && parsedBpm <= 200) { - result.bpm = parsedBpm - } - } - } catch (error) { - console.error('Error parsing URL state:', error) - } - } - - return result -} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fc14e5f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "types": ["vite/client"], + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "isolatedModules": true, + "skipLibCheck": true, + "noEmit": true + }, + "include": ["src", "vite.config.ts"] +} diff --git a/vite.config.js b/vite.config.js deleted file mode 100644 index ea26c84..0000000 --- a/vite.config.js +++ /dev/null @@ -1,18 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' -import tailwindcss from '@tailwindcss/vite' -import path from 'path' - -export default defineConfig({ - plugins: [react(), tailwindcss()], - resolve: { - alias: { - '@': path.resolve(__dirname, './src'), - }, - }, - test: { - globals: true, - environment: 'jsdom', - setupFiles: './src/test/setup.js', - }, -}) diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..b7ec64f --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from 'vitest/config' +import react from '@vitejs/plugin-react' + +export default defineConfig({ + plugins: [react()], + test: { + environment: 'jsdom', + setupFiles: './src/test/setup.ts', + }, +}) From 9ba38de3d87b9b0295409cc52bbc4f83e4429dc8 Mon Sep 17 00:00:00 2001 From: brsbl <57682038+brsbl@users.noreply.github.com> Date: Sun, 4 Oct 2026 02:59:41 -0700 Subject: [PATCH 2/4] Ignore share-link drum ids that reach the object prototype A link naming __proto__ as a drum made decoding write knob values onto Object.prototype. Only accept ids the session actually has. Co-Authored-By: Claude Opus 5.5 --- src/session/url.test.ts | 7 +++++++ src/session/url.ts | 3 ++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/session/url.test.ts b/src/session/url.test.ts index 6218d06..faadbab 100644 --- a/src/session/url.test.ts +++ b/src/session/url.test.ts @@ -48,6 +48,13 @@ describe('share link', () => { expect(s.synth.octave).toBe(0) }) + it('ignores drum ids that would reach the object prototype', () => { + const s = decodeSession('2~120~__proto__.ffff.ffffff~constructor.ffff.ffffff~kick.8000.ff00ff') + expect(({} as Record).steps).toBeUndefined() + expect(Object.keys(s.drums)).toEqual(Object.keys(defaultSession().drums)) + expect(s.drums.kick.steps[0]).toBe(true) + }) + it('falls back to defaults for missing, unknown, or malformed parts', () => { expect(decodeSession(null)).toEqual(defaultSession()) expect(decodeSession('8888080880a2_cc0000cc3300cc00ff_098')).toEqual(defaultSession()) diff --git a/src/session/url.ts b/src/session/url.ts index 2764a39..32a250a 100644 --- a/src/session/url.ts +++ b/src/session/url.ts @@ -97,8 +97,9 @@ export function decodeSession(payload: string | null): Session { s.octave = OCTAVES.find((o) => String(o) === octave) ?? s.octave continue } + // Only real drum ids: a link naming "__proto__" or "constructor" must not reach Object.prototype. + if (!Object.hasOwn(session.drums, id)) continue const track = session.drums[id] - if (!track) continue const [steps, knobs = ''] = fields track.steps = hexToBits(steps, STEPS) ?? track.steps track.volume = hexByte(knobs.slice(0, 2)) ?? track.volume From 344a67a871eba1792c3b91b2f2ef4b8b11fbc6b7 Mon Sep 17 00:00:00 2001 From: brsbl <57682038+brsbl@users.noreply.github.com> Date: Sun, 4 Oct 2026 03:15:51 -0700 Subject: [PATCH 3/4] Play old share links and show keyboard focus on dark keys - Links from the previous app (__) now load their beat, volumes, and tempo instead of a blank machine. - The tempo arrows and black piano keys get a focus ring that shows on their dark surfaces. Co-Authored-By: Claude Opus 5.5 --- src/session/url.test.ts | 14 +++++++++++++- src/session/url.ts | 23 +++++++++++++++++++++++ src/ui/Keyboard.module.css | 9 +++++++-- src/ui/controls/LedButton.module.css | 8 ++++++++ 4 files changed, 51 insertions(+), 3 deletions(-) diff --git a/src/session/url.test.ts b/src/session/url.test.ts index faadbab..9d8188e 100644 --- a/src/session/url.test.ts +++ b/src/session/url.test.ts @@ -55,9 +55,21 @@ describe('share link', () => { expect(s.drums.kick.steps[0]).toBe(true) }) + it("plays links from the previous app's format", () => { + const s = decodeSession('8888080880a2_cc0000cc3300cc00ff_098') + const on = (steps: boolean[]) => steps.flatMap((v, i) => (v ? [i] : [])) + expect(on(s.drums.hihat.steps)).toEqual([0, 4, 8, 12]) + expect(on(s.drums.snare.steps)).toEqual([4, 12]) + expect(on(s.drums.kick.steps)).toEqual([0, 8, 10, 14]) + expect(s.drums.hihat.volume).toBeCloseTo(0.8, 2) + expect(s.drums.snare.volume).toBeCloseTo(0.8, 2) + expect(s.bpm).toBe(98) + expect(decodeSession('888800000000_cc00ffcc00ffcc00ff').bpm).toBe(120) + }) + it('falls back to defaults for missing, unknown, or malformed parts', () => { expect(decodeSession(null)).toEqual(defaultSession()) - expect(decodeSession('8888080880a2_cc0000cc3300cc00ff_098')).toEqual(defaultSession()) + expect(decodeSession('8888_cc00ff_098')).toEqual(defaultSession()) const s = decodeSession('2~999~cowbell.ffff.ffffff~snare.zz.qq~syn.ffff.zz.x.3.w.zz') expect(s.bpm).toBe(200) expect(s.drums.snare).toEqual(defaultSession().drums.snare) diff --git a/src/session/url.ts b/src/session/url.ts index 32a250a..9745bde 100644 --- a/src/session/url.ts +++ b/src/session/url.ts @@ -74,10 +74,33 @@ export function encodeSession(session: Session): string { return [LINK_VERSION, String(session.bpm), ...drums, synth].join('~') } +/** + * Links from the previous app: `_[_]`, 4 hex of steps and + * 6 hex of knobs (volume, reverb, filter) per drum, in this drum order. + */ +const V1_LINK = /^([0-9a-f]{12})_([0-9a-f]{18})(?:_(\d{1,3}))?$/i +const V1_DRUMS = ['hihat', 'snare', 'kick'] + +/** Keeps old shared beats playing: their steps, volumes, and tempo carry over. Reverb and filter have no equivalent and stay at defaults. */ +function decodeV1(match: RegExpExecArray): Session { + const session = defaultSession() + const [, steps, knobs, bpm] = match + V1_DRUMS.forEach((id, i) => { + if (!Object.hasOwn(session.drums, id)) return + const track = session.drums[id] + track.steps = hexToBits(steps.slice(i * 4, i * 4 + 4), STEPS) ?? track.steps + track.volume = hexByte(knobs.slice(i * 6, i * 6 + 2)) ?? track.volume + }) + if (bpm) session.bpm = clampBpm(Number(bpm)) + return session +} + /** Reads a share-link payload. Anything missing or malformed falls back to the default for that part. */ export function decodeSession(payload: string | null): Session { const session = defaultSession() if (!payload) return session + const v1 = V1_LINK.exec(payload) + if (v1) return decodeV1(v1) const [version, bpm, ...parts] = payload.split('~') if (version !== LINK_VERSION) return session diff --git a/src/ui/Keyboard.module.css b/src/ui/Keyboard.module.css index 54cc34d..6115974 100644 --- a/src/ui/Keyboard.module.css +++ b/src/ui/Keyboard.module.css @@ -146,8 +146,13 @@ transition-duration: var(--flash); } -.white:focus-visible, -.black:focus-visible { +.white:focus-visible { outline: 2px solid var(--navy); outline-offset: -2px; } + +/* Navy disappears on ebony, so black keys get a cream ring inside the edge. */ +.black:focus-visible { + outline: 2px solid #fdfbf6; + outline-offset: -4px; +} diff --git a/src/ui/controls/LedButton.module.css b/src/ui/controls/LedButton.module.css index 5d83685..e895cae 100644 --- a/src/ui/controls/LedButton.module.css +++ b/src/ui/controls/LedButton.module.css @@ -78,6 +78,14 @@ font-size: 9px; } +/* The dark bezel hides a border-color change, so focus draws a cream gap and a navy ring outside it. */ +.arrow:focus-visible .face { + box-shadow: + inset 0 -2px 0 #d3cab5, + 0 0 0 2px #f7f4ee, + 0 0 0 4px var(--navy); +} + .arrow:active .face { box-shadow: inset 0 1px 0 #d3cab5; } From b7547b5e447ba8e3b34c11eb0306ff350a8862ab Mon Sep 17 00:00:00 2001 From: brsbl <57682038+brsbl@users.noreply.github.com> Date: Sun, 4 Oct 2026 03:29:01 -0700 Subject: [PATCH 4/4] Play share links from every earlier app version Links from Jul-Dec 2025 used a shorter knob part and opened a blank machine. Like the previous app, load the steps from any _[_] link, and read volumes only from the layout that carries them. Co-Authored-By: Claude Opus 5.5 --- src/session/url.test.ts | 9 +++++++++ src/session/url.ts | 29 +++++++++++++++++------------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/src/session/url.test.ts b/src/session/url.test.ts index 9d8188e..481a282 100644 --- a/src/session/url.test.ts +++ b/src/session/url.test.ts @@ -67,6 +67,15 @@ describe('share link', () => { expect(decodeSession('888800000000_cc00ffcc00ffcc00ff').bpm).toBe(120) }) + it('plays links from the older one-digit knob format, keeping default volumes', () => { + const s = decodeSession('8888080880a2_000500') + const on = (steps: boolean[]) => steps.flatMap((v, i) => (v ? [i] : [])) + expect(on(s.drums.hihat.steps)).toEqual([0, 4, 8, 12]) + expect(on(s.drums.kick.steps)).toEqual([0, 8, 10, 14]) + expect(s.drums.hihat.volume).toBe(defaultSession().drums.hihat.volume) + expect(s.bpm).toBe(120) + }) + it('falls back to defaults for missing, unknown, or malformed parts', () => { expect(decodeSession(null)).toEqual(defaultSession()) expect(decodeSession('8888_cc00ff_098')).toEqual(defaultSession()) diff --git a/src/session/url.ts b/src/session/url.ts index 9745bde..fea7c69 100644 --- a/src/session/url.ts +++ b/src/session/url.ts @@ -75,23 +75,28 @@ export function encodeSession(session: Session): string { } /** - * Links from the previous app: `_[_]`, 4 hex of steps and - * 6 hex of knobs (volume, reverb, filter) per drum, in this drum order. + * Links from earlier versions of the app: `_[_]`, 4 hex of + * steps per drum in this drum order. The knob part changed over time; only the + * last layout (6 hex per drum: volume, reverb, filter) carries volumes we can read. */ -const V1_LINK = /^([0-9a-f]{12})_([0-9a-f]{18})(?:_(\d{1,3}))?$/i -const V1_DRUMS = ['hihat', 'snare', 'kick'] +const LEGACY_STEPS = /^[0-9a-f]{12}$/i +const LEGACY_KNOBS = /^[0-9a-f]{18}$/i +const LEGACY_DRUMS = ['hihat', 'snare', 'kick'] -/** Keeps old shared beats playing: their steps, volumes, and tempo carry over. Reverb and filter have no equivalent and stay at defaults. */ -function decodeV1(match: RegExpExecArray): Session { +/** Keeps old shared beats playing, as the previous app did: steps always, volumes and tempo when present. Other knobs stay at defaults. */ +function decodeLegacy(payload: string): Session | null { + if (payload.includes('~')) return null + const [steps, knobs = '', bpm] = payload.split('_') + if (!LEGACY_STEPS.test(steps)) return null const session = defaultSession() - const [, steps, knobs, bpm] = match - V1_DRUMS.forEach((id, i) => { + const volumes = LEGACY_KNOBS.test(knobs) + LEGACY_DRUMS.forEach((id, i) => { if (!Object.hasOwn(session.drums, id)) return const track = session.drums[id] track.steps = hexToBits(steps.slice(i * 4, i * 4 + 4), STEPS) ?? track.steps - track.volume = hexByte(knobs.slice(i * 6, i * 6 + 2)) ?? track.volume + if (volumes) track.volume = hexByte(knobs.slice(i * 6, i * 6 + 2)) ?? track.volume }) - if (bpm) session.bpm = clampBpm(Number(bpm)) + if (bpm && /^\d{3}$/.test(bpm)) session.bpm = clampBpm(Number(bpm)) return session } @@ -99,8 +104,8 @@ function decodeV1(match: RegExpExecArray): Session { export function decodeSession(payload: string | null): Session { const session = defaultSession() if (!payload) return session - const v1 = V1_LINK.exec(payload) - if (v1) return decodeV1(v1) + const legacy = decodeLegacy(payload) + if (legacy) return legacy const [version, bpm, ...parts] = payload.split('~') if (version !== LINK_VERSION) return session