From ca24dbf2e04f9cde4e67589c054c7e72990b7f11 Mon Sep 17 00:00:00 2001 From: Edgar Montano Date: Sun, 31 May 2026 14:35:01 -0400 Subject: [PATCH 1/9] chore: gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 872d5f6..49d167e 100644 --- a/.gitignore +++ b/.gitignore @@ -141,3 +141,10 @@ dist vite.config.js.timestamp-* vite.config.ts.timestamp-* .vite/ + +.DS_Store +out-tsc/ +release/ +MPC-Sample/ +public/kits/ +claudedocs/ From 74659702f933fd969299359cb89d3aa54799febf Mon Sep 17 00:00:00 2001 From: Edgar Montano Date: Sun, 31 May 2026 16:03:12 -0400 Subject: [PATCH 2/9] feat: init --- README.md | 141 +- biome.json | 62 + electron-builder.yml | 53 + electron.vite.config.ts | 56 + electron/__tests__/fsops.test.ts | 142 + electron/fsops.ts | 287 + electron/ipc.ts | 18 + electron/main.ts | 277 + electron/paths.ts | 25 + electron/preload.ts | 85 + electron/vitest.config.ts | 11 + index.html | 22 + package-lock.json | 9163 +++++++++++++++++ package.json | 74 + public/favicon/android-chrome-192x192.png | Bin 0 -> 24104 bytes public/favicon/android-chrome-512x512.png | Bin 0 -> 84068 bytes public/favicon/apple-touch-icon.png | Bin 0 -> 21557 bytes public/favicon/favicon-16x16.png | Bin 0 -> 662 bytes public/favicon/favicon-32x32.png | Bin 0 -> 1801 bytes public/favicon/favicon.ico | Bin 0 -> 15406 bytes public/favicon/site.webmanifest | 1 + scripts/build-kits.mjs | 446 + src/App.tsx | 49 + src/audio/SampleEngine.ts | 471 + src/audio/__tests__/SampleEngine.test.ts | 614 ++ src/components/BankSelector.tsx | 73 + src/components/DataEncoder.tsx | 96 + src/components/DisplayPanel.tsx | 48 + src/components/EraseButtons.tsx | 22 + src/components/ExportButton.tsx | 512 + src/components/HUD.tsx | 132 + src/components/KitEditor.tsx | 528 + src/components/Knob.tsx | 145 + src/components/Launcher.tsx | 182 + src/components/MPCDevice.tsx | 163 + src/components/ModeButtons.tsx | 109 + src/components/Pad.tsx | 252 + src/components/PadGrid.tsx | 37 + src/components/PadPlayButtons.tsx | 74 + src/components/PitchFader.tsx | 119 + src/components/Screen.tsx | 66 + src/components/StartOverlay.tsx | 79 + src/components/Transport.tsx | 41 + src/components/TweaksPanel.tsx | 312 + src/components/UtilityButtons.tsx | 89 + src/components/Waveform.tsx | 44 + src/components/ZoomControls.tsx | 85 + .../__tests__/BankSelector.test.tsx | 92 + src/components/__tests__/Buttons.test.tsx | 155 + src/components/__tests__/DataEncoder.test.tsx | 65 + .../__tests__/ExportButton.test.tsx | 648 ++ src/components/__tests__/HUD.test.tsx | 98 + src/components/__tests__/KitEditor.test.tsx | 427 + src/components/__tests__/Knob.test.tsx | 119 + src/components/__tests__/Launcher.test.tsx | 258 + src/components/__tests__/MPCDevice.test.tsx | 175 + src/components/__tests__/Pad.test.tsx | 178 + src/components/__tests__/PadDrop.test.tsx | 432 + src/components/__tests__/PadGrid.test.tsx | 112 + src/components/__tests__/PitchFader.test.tsx | 90 + .../__tests__/StartOverlay.test.tsx | 86 + src/components/__tests__/Transport.test.tsx | 70 + src/components/__tests__/TweaksPanel.test.tsx | 159 + src/components/__tests__/Waveform.test.tsx | 115 + .../__tests__/ZoomControls.test.tsx | 194 + src/data/ledColors.ts | 19 + src/data/padLayout.ts | 96 + src/desktop/__tests__/exportToDisk.test.ts | 253 + src/desktop/__tests__/loadProject.test.ts | 341 + src/desktop/bridge.ts | 27 + src/desktop/bridge.types.ts | 114 + src/desktop/exportToDisk.ts | 136 + src/desktop/loadProject.ts | 106 + src/hooks/__tests__/useAudioEngine.test.tsx | 180 + src/hooks/__tests__/useKeyboardInput.test.tsx | 230 + .../__tests__/useKitLoaderDesktop.test.tsx | 203 + src/hooks/__tests__/useMidiInput.test.tsx | 171 + src/hooks/useAudioEngine.ts | 123 + src/hooks/useKeyboardInput.ts | 61 + src/hooks/useKitLoader.ts | 116 + src/hooks/useMidiInput.ts | 50 + src/hooks/useReducedMotion.ts | 21 + src/hooks/useWaveformDraw.ts | 275 + src/index.ts | 1 + src/kits/__tests__/importWav.test.ts | 241 + src/kits/importWav.ts | 137 + src/kits/kit.types.ts | 155 + src/kits/loadManifest.ts | 123 + src/kits/registry.ts | 66 + src/main.tsx | 30 + src/midi/MidiInput.ts | 133 + src/midi/__tests__/MidiInput.test.ts | 326 + src/state/__tests__/buildExportKit.test.ts | 144 + src/state/__tests__/store.test.ts | 670 ++ src/state/__tests__/uiTransform.test.ts | 211 + src/state/store.ts | 747 ++ src/styles/chassis.css | 100 + src/styles/controls.css | 741 ++ src/styles/editor.css | 446 + src/styles/export.css | 234 + src/styles/global.css | 34 + src/styles/launcher.css | 170 + src/styles/layout.css | 568 + src/styles/tokens.css | 137 + src/styles/viewport.css | 159 + src/test/setup.ts | 89 + src/test/smoke.test.ts | 43 + src/types/mpc.types.ts | 163 + src/xpj/__tests__/buildXpj.test.ts | 594 ++ src/xpj/__tests__/codec.test.ts | 240 + src/xpj/__tests__/crosscheck.python.test.ts | 407 + src/xpj/__tests__/exportKit.test.ts | 517 + src/xpj/__tests__/jsonLossless.test.ts | 207 + src/xpj/__tests__/readXpj.test.ts | 331 + src/xpj/buildXpj.ts | 340 + src/xpj/codec.ts | 115 + src/xpj/exportKit.ts | 268 + src/xpj/jsonLossless.ts | 313 + src/xpj/readXpj.ts | 182 + src/xpj/template.skeleton.json | 1 + tsconfig.base.json | 14 + tsconfig.json | 19 + tsconfig.lib.json | 25 + tsconfig.node.json | 20 + tsconfig.spec.json | 32 + vite.config.ts | 49 + vitest.config.ts | 25 + 127 files changed, 30766 insertions(+), 1 deletion(-) create mode 100644 biome.json create mode 100644 electron-builder.yml create mode 100644 electron.vite.config.ts create mode 100644 electron/__tests__/fsops.test.ts create mode 100644 electron/fsops.ts create mode 100644 electron/ipc.ts create mode 100644 electron/main.ts create mode 100644 electron/paths.ts create mode 100644 electron/preload.ts create mode 100644 electron/vitest.config.ts create mode 100644 index.html create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 public/favicon/android-chrome-192x192.png create mode 100644 public/favicon/android-chrome-512x512.png create mode 100644 public/favicon/apple-touch-icon.png create mode 100644 public/favicon/favicon-16x16.png create mode 100644 public/favicon/favicon-32x32.png create mode 100644 public/favicon/favicon.ico create mode 100644 public/favicon/site.webmanifest create mode 100644 scripts/build-kits.mjs create mode 100644 src/App.tsx create mode 100644 src/audio/SampleEngine.ts create mode 100644 src/audio/__tests__/SampleEngine.test.ts create mode 100644 src/components/BankSelector.tsx create mode 100644 src/components/DataEncoder.tsx create mode 100644 src/components/DisplayPanel.tsx create mode 100644 src/components/EraseButtons.tsx create mode 100644 src/components/ExportButton.tsx create mode 100644 src/components/HUD.tsx create mode 100644 src/components/KitEditor.tsx create mode 100644 src/components/Knob.tsx create mode 100644 src/components/Launcher.tsx create mode 100644 src/components/MPCDevice.tsx create mode 100644 src/components/ModeButtons.tsx create mode 100644 src/components/Pad.tsx create mode 100644 src/components/PadGrid.tsx create mode 100644 src/components/PadPlayButtons.tsx create mode 100644 src/components/PitchFader.tsx create mode 100644 src/components/Screen.tsx create mode 100644 src/components/StartOverlay.tsx create mode 100644 src/components/Transport.tsx create mode 100644 src/components/TweaksPanel.tsx create mode 100644 src/components/UtilityButtons.tsx create mode 100644 src/components/Waveform.tsx create mode 100644 src/components/ZoomControls.tsx create mode 100644 src/components/__tests__/BankSelector.test.tsx create mode 100644 src/components/__tests__/Buttons.test.tsx create mode 100644 src/components/__tests__/DataEncoder.test.tsx create mode 100644 src/components/__tests__/ExportButton.test.tsx create mode 100644 src/components/__tests__/HUD.test.tsx create mode 100644 src/components/__tests__/KitEditor.test.tsx create mode 100644 src/components/__tests__/Knob.test.tsx create mode 100644 src/components/__tests__/Launcher.test.tsx create mode 100644 src/components/__tests__/MPCDevice.test.tsx create mode 100644 src/components/__tests__/Pad.test.tsx create mode 100644 src/components/__tests__/PadDrop.test.tsx create mode 100644 src/components/__tests__/PadGrid.test.tsx create mode 100644 src/components/__tests__/PitchFader.test.tsx create mode 100644 src/components/__tests__/StartOverlay.test.tsx create mode 100644 src/components/__tests__/Transport.test.tsx create mode 100644 src/components/__tests__/TweaksPanel.test.tsx create mode 100644 src/components/__tests__/Waveform.test.tsx create mode 100644 src/components/__tests__/ZoomControls.test.tsx create mode 100644 src/data/ledColors.ts create mode 100644 src/data/padLayout.ts create mode 100644 src/desktop/__tests__/exportToDisk.test.ts create mode 100644 src/desktop/__tests__/loadProject.test.ts create mode 100644 src/desktop/bridge.ts create mode 100644 src/desktop/bridge.types.ts create mode 100644 src/desktop/exportToDisk.ts create mode 100644 src/desktop/loadProject.ts create mode 100644 src/hooks/__tests__/useAudioEngine.test.tsx create mode 100644 src/hooks/__tests__/useKeyboardInput.test.tsx create mode 100644 src/hooks/__tests__/useKitLoaderDesktop.test.tsx create mode 100644 src/hooks/__tests__/useMidiInput.test.tsx create mode 100644 src/hooks/useAudioEngine.ts create mode 100644 src/hooks/useKeyboardInput.ts create mode 100644 src/hooks/useKitLoader.ts create mode 100644 src/hooks/useMidiInput.ts create mode 100644 src/hooks/useReducedMotion.ts create mode 100644 src/hooks/useWaveformDraw.ts create mode 100644 src/index.ts create mode 100644 src/kits/__tests__/importWav.test.ts create mode 100644 src/kits/importWav.ts create mode 100644 src/kits/kit.types.ts create mode 100644 src/kits/loadManifest.ts create mode 100644 src/kits/registry.ts create mode 100644 src/main.tsx create mode 100644 src/midi/MidiInput.ts create mode 100644 src/midi/__tests__/MidiInput.test.ts create mode 100644 src/state/__tests__/buildExportKit.test.ts create mode 100644 src/state/__tests__/store.test.ts create mode 100644 src/state/__tests__/uiTransform.test.ts create mode 100644 src/state/store.ts create mode 100644 src/styles/chassis.css create mode 100644 src/styles/controls.css create mode 100644 src/styles/editor.css create mode 100644 src/styles/export.css create mode 100644 src/styles/global.css create mode 100644 src/styles/launcher.css create mode 100644 src/styles/layout.css create mode 100644 src/styles/tokens.css create mode 100644 src/styles/viewport.css create mode 100644 src/test/setup.ts create mode 100644 src/test/smoke.test.ts create mode 100644 src/types/mpc.types.ts create mode 100644 src/xpj/__tests__/buildXpj.test.ts create mode 100644 src/xpj/__tests__/codec.test.ts create mode 100644 src/xpj/__tests__/crosscheck.python.test.ts create mode 100644 src/xpj/__tests__/exportKit.test.ts create mode 100644 src/xpj/__tests__/jsonLossless.test.ts create mode 100644 src/xpj/__tests__/readXpj.test.ts create mode 100644 src/xpj/buildXpj.ts create mode 100644 src/xpj/codec.ts create mode 100644 src/xpj/exportKit.ts create mode 100644 src/xpj/jsonLossless.ts create mode 100644 src/xpj/readXpj.ts create mode 100644 src/xpj/template.skeleton.json create mode 100644 tsconfig.base.json create mode 100644 tsconfig.json create mode 100644 tsconfig.lib.json create mode 100644 tsconfig.node.json create mode 100644 tsconfig.spec.json create mode 100644 vite.config.ts create mode 100644 vitest.config.ts diff --git a/README.md b/README.md index ac2cbe1..43934b2 100644 --- a/README.md +++ b/README.md @@ -1 +1,140 @@ -# mpcsample \ No newline at end of file +# MPC Sample + +Web + desktop Akai MPC sample drum machine with `.xpj` project export. + +Runs as a browser app (Vite dev server) or as a packaged desktop app (Electron). Load drum kits built from real Akai `.xpj` project files, sequence patterns, and export back to `.xpj` for playback on hardware. + +**Package:** `@worldlinkstudio/mpcsample` — License: GPL-3.0 + +--- + +## Prerequisites + +- Node.js >= 18 +- npm + +--- + +## Installation + +```bash +git clone +cd mpcsample +npm install +``` + +After cloning, regenerate the kit assets (see [Kit Generation](#kit-generation)): + +```bash +npm run build-kits +``` + +--- + +## Development + +**Browser (Vite dev server, port 4404):** + +```bash +npm run dev +``` + +**Electron (renderer on port 4406):** + +```bash +npm run electron:dev +``` + +--- + +## Scripts + +| Script | Description | +| ------------------------ | ----------------------------------------------------- | +| `npm run dev` | Start Vite dev server (browser, port 4404) | +| `npm run build` | Build React library to `dist/` | +| `npm run electron:dev` | Start Electron in dev mode (renderer port 4406) | +| `npm run electron:build` | Build Electron app to `out/` | +| `npm run electron:dist` | Package distributable via electron-builder | +| `npm run build-kits` | Regenerate `public/kits/` from `MPC-Sample/Projects/` | +| `npm test` | Run all tests (Vitest) | +| `npm run typecheck` | TypeScript type-check, no emit | +| `npm run lint` | Biome lint | +| `npm run format` | Biome format (write) | +| `npm run check` | Biome lint + format check | + +--- + +## Kit Generation + +Kit assets are not committed to the repository. They are generated from Akai project files stored locally in `MPC-Sample/` (also gitignored, ~300 MB of WAV samples). + +The `build-kits` script reads `.xpj` project files from `MPC-Sample/Projects/` and copies WAV samples into `public/kits//`, producing the kit manifests the app expects at runtime. + +```bash +npm run build-kits +``` + +Run this once after cloning, and again whenever `MPC-Sample/Projects/` changes. The `MPC-Sample/` directory is an irreplaceable build input — keep it on disk alongside the repo. + +--- + +## Project Structure + +``` +mpcsample/ +├── src/ # React components, audio engine, Zustand state, xpj codec +├── electron/ # Electron main process, preload script, fs operations +├── scripts/ # build-kits.mjs and other build utilities +├── public/kits/ # Generated kit manifests + WAVs (gitignored) +├── MPC-Sample/ # Akai project files — gitignored, kept on disk +├── index.html +├── vite.config.ts +├── electron.vite.config.ts +├── electron-builder.yml +└── biome.json +``` + +--- + +## Tech Stack + +- **React 19** + **TypeScript** +- **Vite 6** (browser build) / **electron-vite** (Electron build) +- **Electron 35** +- **Zustand** — state management +- **Web Audio API** / **Tone.js** — audio engine +- **fflate** — zip compression (`.xpj` export) +- **Tailwind CSS v4** +- **Vitest** — unit tests +- **Biome** — formatter + linter + +--- + +## macOS Note + +The packaged app is unsigned. macOS will quarantine it after download or distribution. Remove the quarantine attribute before launching: + +**On the installed app:** + +```bash +xattr -dr com.apple.quarantine "/Applications/MPC Sample.app" +``` + +**On an extracted `.app` before installing:** + +```bash +xattr -cr "MPC Sample.app" +``` + +--- + +## .xpj Format Note + +The `.xpj` file format stores sample filenames as a sequence of 4-byte IEEE 754 float tokens — not a string type. This matches the Akai firmware's internal serialization format and was confirmed by cross-referencing with a Python reference implementation (`make_xpj.py`). The codec in `src/xpj/` faithfully encodes and decodes this representation to ensure compatibility with MPC hardware. + +--- + +## License + +GPL-3.0 — see [LICENSE](LICENSE). diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..19b31a1 --- /dev/null +++ b/biome.json @@ -0,0 +1,62 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json", + "assist": { + "actions": { + "source": { + "organizeImports": "on" + } + } + }, + "linter": { + "enabled": true, + "rules": { + "recommended": true, + "a11y": { + "useSemanticElements": "off" + } + } + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2, + "lineWidth": 100 + }, + "css": { + "formatter": { "enabled": false }, + "linter": { "enabled": false } + }, + "javascript": { + "formatter": { + "quoteStyle": "double", + "semicolons": "always", + "trailingCommas": "all" + } + }, + "files": { + "includes": [ + "**", + "!dist", + "!out", + "!out-tsc", + "!release", + "!public", + "!MPC-Sample", + "!node_modules", + "!src/xpj/template.skeleton.json", + "!**/*.tsbuildinfo", + "!**/*.css" + ] + }, + "overrides": [ + { + "includes": ["**/*.test.ts", "**/*.test.tsx", "**/*.spec.ts", "**/*.spec.tsx"], + "linter": { + "rules": { + "suspicious": { "noExplicitAny": "off" }, + "style": { "noNonNullAssertion": "off" } + } + } + } + ] +} diff --git a/electron-builder.yml b/electron-builder.yml new file mode 100644 index 0000000..c0b883b --- /dev/null +++ b/electron-builder.yml @@ -0,0 +1,53 @@ +appId: com.worldlinkstudio.mpcsample +productName: MPC Sample +electronVersion: "42.3.0" + +directories: + output: release + +files: + - "out/**/*" + - "package.json" + # The renderer is fully bundled by electron-vite and main/preload inline their + # @electron-toolkit/* devDeps, so no runtime node_modules are needed. Excluding + # them keeps app.asar small (otherwise tone/tailwind/etc. balloon it to ~300MB). + - "!node_modules/**/*" + - "!public/kits" + - "!src/**/*" + - "!electron/**/*" + - "!electron.vite.config.{js,ts,mjs,cjs}" + - "!vite.config.{js,ts,mjs,cjs}" + - "!tsconfig*.json" + - "!{.eslintcache,eslint.config.mjs}" + - "!{.env,.env.*,.npmrc}" + +# Override package.json main for the packaged app +extraMetadata: + main: out/main/index.js + +asar: true +npmRebuild: false + +mac: + icon: public/favicon/android-chrome-512x512.png + target: + - dmg + - zip + category: public.app-category.music + +dmg: + artifactName: ${productName}-${version}.${ext} + +win: + icon: public/favicon/favicon.ico + target: + - nsis + - zip + +nsis: + artifactName: ${productName}-Setup-${version}.${ext} + oneClick: true + perMachine: false + createDesktopShortcut: true + createStartMenuShortcut: true + shortcutName: MPC Sample diff --git a/electron.vite.config.ts b/electron.vite.config.ts new file mode 100644 index 0000000..a00a417 --- /dev/null +++ b/electron.vite.config.ts @@ -0,0 +1,56 @@ +import { resolve } from "node:path"; +import tailwindcss from "@tailwindcss/vite"; +import react from "@vitejs/plugin-react"; +import { defineConfig, externalizeDepsPlugin } from "electron-vite"; + +export default defineConfig({ + main: { + plugins: [externalizeDepsPlugin()], + build: { + lib: { + entry: resolve(__dirname, "electron/main.ts"), + }, + rollupOptions: { + output: { + // Emit as index.js to match electron-builder extraMetadata.main = out/main/index.js + entryFileNames: "index.js", + }, + }, + }, + }, + preload: { + plugins: [externalizeDepsPlugin()], + build: { + lib: { + entry: resolve(__dirname, "electron/preload.ts"), + }, + rollupOptions: { + output: { + // Force the preload to emit as index.js so main.ts can reference + // "../preload/index.js" (standard electron-vite convention). + entryFileNames: "index.js", + format: "cjs", + }, + }, + }, + }, + renderer: { + root: ".", + plugins: [react(), tailwindcss()], + build: { + // Relative base so assets resolve correctly when loaded via file:// + base: "./", + outDir: "out/renderer", + // The desktop app is directory-driven and never fetches the preset /kits + // assets, so skip copying public/ (it holds ~296MB of preset WAVs that + // would otherwise bloat out/renderer and the packaged app.asar). + copyPublicDir: false, + rollupOptions: { + input: resolve(__dirname, "index.html"), + }, + }, + server: { + port: 4406, + }, + }, +}); diff --git a/electron/__tests__/fsops.test.ts b/electron/__tests__/fsops.test.ts new file mode 100644 index 0000000..7a7b991 --- /dev/null +++ b/electron/__tests__/fsops.test.ts @@ -0,0 +1,142 @@ +/** + * fsops.test.ts — Integration tests for electron/fsops.ts using real temp dirs. + * + * Run: pnpm exec vitest run --config electron/vitest.config.ts + */ + +import * as fs from "node:fs/promises"; +import * as os from "node:os"; +import * as path from "node:path"; +import { afterEach, beforeEach, describe, expect, it } from "vitest"; +import type { WriteProjectArgs } from "../../src/desktop/bridge.types"; +import { readProjectFromDir, writeProjectToDisk } from "../fsops"; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/** Create a fresh temp directory for each test and clean it up after. */ +let tmpDir: string; + +beforeEach(async () => { + tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), "mpcsample-fsops-")); +}); + +afterEach(async () => { + await fs.rm(tmpDir, { recursive: true, force: true }); +}); + +function makeArgs(overrides: Partial = {}): WriteProjectArgs { + const xpjBytes = new Uint8Array([0x50, 0x4b, 0x03, 0x04]); // fake .xpj bytes + const wavBytes = new Uint8Array([0x52, 0x49, 0x46, 0x46]); // "RIFF" WAV header + + return { + projectName: "Test Project", + xpjBytes, + sampleFiles: [ + { path: "kick.wav", bytes: wavBytes }, + { path: "snare.wav", bytes: wavBytes }, + ], + overwrite: false, + ...overrides, + }; +} + +// --------------------------------------------------------------------------- +// Tests +// --------------------------------------------------------------------------- + +describe("writeProjectToDisk + readProjectFromDir — round-trip", () => { + it("writes .xpj and _[ProjectData]/*.wav files then reads them back", async () => { + const args = makeArgs(); + const result = await writeProjectToDisk(args, tmpDir); + + // Verify returned paths + expect(result.written).toBe(path.join(tmpDir, "Test Project.xpj")); + expect(result.dataDir).toBe(path.join(tmpDir, "Test Project_[ProjectData]")); + expect(result.sampleCount).toBe(2); + + // Verify on-disk structure + const xpjStat = await fs.stat(result.written); + expect(xpjStat.isFile()).toBe(true); + const wavFiles = await fs.readdir(result.dataDir); + expect(wavFiles.sort()).toEqual(["kick.wav", "snare.wav"]); + + // Round-trip: read the project back + const loaded = await readProjectFromDir(tmpDir); + expect(loaded.dir).toBe(tmpDir); + expect(loaded.xpjBytes).toBeInstanceOf(Uint8Array); + expect(loaded.xpjBytes).toEqual(args.xpjBytes); + expect(loaded.samples).toHaveLength(2); + + const sampleNames = loaded.samples.map((s) => s.fileName).sort(); + expect(sampleNames).toEqual(["kick.wav", "snare.wav"]); + for (const sample of loaded.samples) { + expect(sample.bytes).toBeInstanceOf(Uint8Array); + expect(sample.bytes.length).toBeGreaterThan(0); + } + }); +}); + +describe("writeProjectToDisk — EEXIST guard", () => { + it("throws EEXIST when .xpj already exists and overwrite is false", async () => { + const args = makeArgs({ overwrite: false }); + // Write once to create the file + await writeProjectToDisk(args, tmpDir); + + // Second write should throw + await expect(writeProjectToDisk(args, tmpDir)).rejects.toMatchObject({ + code: "EEXIST", + }); + }); + + it("succeeds when .xpj already exists and overwrite is true", async () => { + const args = makeArgs({ overwrite: false }); + await writeProjectToDisk(args, tmpDir); + + // Should not throw + const result = await writeProjectToDisk({ ...args, overwrite: true }, tmpDir); + expect(result.written).toContain(".xpj"); + expect(result.sampleCount).toBe(2); + }); +}); + +describe("writeProjectToDisk — ENOENT for missing destDir", () => { + it("throws ENOENT when the destination directory does not exist", async () => { + const args = makeArgs(); + const missingDir = path.join(tmpDir, "does-not-exist"); + + await expect(writeProjectToDisk(args, missingDir)).rejects.toMatchObject({ + code: "ENOENT", + }); + }); +}); + +describe("readProjectFromDir — ENOXPJ", () => { + it("throws ENOXPJ when no .xpj file is present", async () => { + // tmpDir is empty + await expect(readProjectFromDir(tmpDir)).rejects.toMatchObject({ + code: "ENOXPJ", + }); + }); +}); + +describe("writeProjectToDisk — path traversal safety", () => { + it("writes a file with path '../evil.wav' as 'evil.wav' inside the data dir", async () => { + const wavBytes = new Uint8Array([0x52, 0x49, 0x46, 0x46]); + const args = makeArgs({ + sampleFiles: [{ path: "../evil.wav", bytes: wavBytes }], + }); + + const result = await writeProjectToDisk(args, tmpDir); + + // The traversal path should resolve inside dataDir, not outside tmpDir + const expectedPath = path.join(result.dataDir, "evil.wav"); + const stat = await fs.stat(expectedPath); + expect(stat.isFile()).toBe(true); + + // Verify the file was NOT created outside the dataDir + const outerPath = path.join(tmpDir, "evil.wav"); + await expect(fs.stat(outerPath)).rejects.toThrow(); + }); +}); diff --git a/electron/fsops.ts b/electron/fsops.ts new file mode 100644 index 0000000..4a2f293 --- /dev/null +++ b/electron/fsops.ts @@ -0,0 +1,287 @@ +/** + * fsops.ts — Pure Node fs operations for the MPC Sample desktop app. + * + * NO `electron` imports — this module is safe to load in unit tests (node env) + * and during electron-vite preload bundling without issues. + */ + +import type { Dirent } from "node:fs"; +import * as fs from "node:fs/promises"; +import * as path from "node:path"; + +import type { + DesktopErrorCode, + LoadedProject, + WriteProjectArgs, + WriteProjectResult, +} from "../src/desktop/bridge.types"; + +/** Map a Node.js errno code string to the typed DesktopErrorCode set. */ +function mapErrno(code: string | undefined): DesktopErrorCode { + switch (code) { + case "ENOENT": + return "ENOENT"; + case "EACCES": + return "EACCES"; + case "EEXIST": + return "EEXIST"; + default: + return "EUNKNOWN"; + } +} + +/** Create a typed desktop error from any caught value. */ +function toDesktopError( + err: unknown, + fallbackCode: DesktopErrorCode = "EUNKNOWN", +): Error & { code: DesktopErrorCode } { + if (err instanceof Error && "code" in err) { + const nodeErr = err as NodeJS.ErrnoException; + const code = mapErrno(nodeErr.code); + return Object.assign(new Error(nodeErr.message), { code }); + } + if (err instanceof Error && (err as Error & { code?: unknown }).code !== undefined) { + const typed = err as Error & { code: DesktopErrorCode }; + return Object.assign(new Error(typed.message), { code: typed.code }); + } + const msg = err instanceof Error ? err.message : String(err); + return Object.assign(new Error(msg), { code: fallbackCode }); +} + +/** Sanitize a project name — strip characters illegal on common filesystems. */ +function sanitizeProjectName(name: string): string { + // Strip \ / : * ? " < > | + return name.replace(/[\\/:*?"<>|]/g, "").trim(); +} + +/** + * Write a full MPC project (`.xpj` + `_[ProjectData]/` WAVs) to `destDir`. + * + * Throws a typed `Error & { code: DesktopErrorCode }` on failure so that the + * caller (main process) can wrap it into an `IpcResult`. + */ +export async function writeProjectToDisk( + args: WriteProjectArgs, + destDir: string, +): Promise { + const name = sanitizeProjectName(args.projectName); + if (!name) { + throw Object.assign(new Error("Project name is empty after sanitization."), { + code: "EUNKNOWN" as DesktopErrorCode, + }); + } + + const dataDir = path.join(destDir, `${name}_[ProjectData]`); + const xpjPath = path.join(destDir, `${name}.xpj`); + + // Verify destDir exists + try { + await fs.access(destDir); + } catch { + throw Object.assign(new Error(`Destination directory does not exist: ${destDir}`), { + code: "ENOENT" as DesktopErrorCode, + }); + } + + // Guard against overwrite when not permitted + if (!args.overwrite) { + try { + await fs.access(xpjPath); + // If we reach here, the file exists — reject + throw Object.assign( + new Error(`Project already exists at ${xpjPath}. Set overwrite to replace it.`), + { code: "EEXIST" as DesktopErrorCode }, + ); + } catch (err) { + const typedErr = err as Error & { code?: string }; + if (typedErr.code === "EEXIST") throw err; + // ENOENT from fs.access means the file does not exist — that's fine + } + } + + // Create the _[ProjectData] directory + try { + await fs.mkdir(dataDir, { recursive: true }); + } catch (err) { + throw toDesktopError(err); + } + + // Write WAV files first — use only the basename to prevent path traversal + let sampleCount = 0; + for (const sampleFile of args.sampleFiles) { + const safeName = path.basename(sampleFile.path); + const outPath = path.join(dataDir, safeName); + try { + await fs.writeFile(outPath, sampleFile.bytes); + sampleCount++; + } catch (err) { + throw toDesktopError(err); + } + } + + // Write the .xpj last (atomicity: if WAVs fail, no .xpj is created) + try { + await fs.writeFile(xpjPath, args.xpjBytes); + } catch (err) { + throw toDesktopError(err); + } + + return { written: xpjPath, dataDir, sampleCount }; +} + +/** + * Read an MPC project given the direct path to an `.xpj` file. + * + * Derives the project directory from the file path, reads the `.xpj` bytes, + * then locates the sibling `_[ProjectData]` folder and reads every + * `*.wav` inside it. + * + * Throws a typed `Error & { code: DesktopErrorCode }` on failure. + */ +export async function readProjectFromFile(xpjFilePath: string): Promise { + const dir = path.dirname(xpjFilePath); + const xpjBase = path.basename(xpjFilePath).replace(/\.xpj$/i, ""); + + let xpjBytes: Uint8Array; + try { + const buf = await fs.readFile(xpjFilePath); + xpjBytes = new Uint8Array(buf); + } catch (err) { + throw toDesktopError(err); + } + + let entries: Dirent[]; + try { + entries = await fs.readdir(dir, { withFileTypes: true }); + } catch (err) { + throw toDesktopError(err); + } + + const canonicalDataDirName = `${xpjBase}_[ProjectData]`; + const dataDirEntries = entries.filter( + (e) => e.isDirectory() && e.name.endsWith("_[ProjectData]"), + ); + + let dataDirPath: string | null = null; + const canonical = dataDirEntries.find((e) => e.name === canonicalDataDirName); + if (canonical) { + dataDirPath = path.join(dir, canonical.name); + } else if (dataDirEntries.length === 1) { + dataDirPath = path.join(dir, dataDirEntries[0].name); + } + + const samples: { fileName: string; bytes: Uint8Array }[] = []; + + if (dataDirPath !== null) { + let wavEntries: Dirent[]; + try { + wavEntries = await fs.readdir(dataDirPath, { withFileTypes: true }); + } catch (err) { + throw toDesktopError(err); + } + + const wavFiles = wavEntries + .filter((e) => e.isFile() && e.name.toLowerCase().endsWith(".wav")) + .sort((a, b) => a.name.localeCompare(b.name)); + + for (const wavEntry of wavFiles) { + const wavPath = path.join(dataDirPath, wavEntry.name); + try { + const buf = await fs.readFile(wavPath); + samples.push({ fileName: wavEntry.name, bytes: new Uint8Array(buf) }); + } catch (err) { + throw toDesktopError(err); + } + } + } + + return { dir, xpjBytes, samples }; +} + +/** + * Read an MPC project from `dir`. + * + * Locates the single `*.xpj` in the directory, reads its bytes, then locates + * the sibling `_[ProjectData]` folder and reads every `*.wav` + * inside it. + * + * Throws a typed `Error & { code: DesktopErrorCode }` on failure. + */ +export async function readProjectFromDir(dir: string): Promise { + let entries: Dirent[]; + try { + entries = await fs.readdir(dir, { withFileTypes: true }); + } catch (err) { + throw toDesktopError(err); + } + + // Find all .xpj files + const xpjEntries = entries + .filter((e) => e.isFile() && e.name.toLowerCase().endsWith(".xpj")) + .sort((a, b) => a.name.localeCompare(b.name)); + + if (xpjEntries.length === 0) { + throw Object.assign(new Error(`No .xpj file found in directory: ${dir}`), { + code: "ENOXPJ" as DesktopErrorCode, + }); + } + + // Use the first .xpj deterministically (sorted alphabetically) + const xpjEntry = xpjEntries[0]; + const xpjPath = path.join(dir, xpjEntry.name); + const xpjBase = xpjEntry.name.replace(/\.xpj$/i, ""); + + // Read .xpj bytes + let xpjBytes: Uint8Array; + try { + const buf = await fs.readFile(xpjPath); + xpjBytes = new Uint8Array(buf); + } catch (err) { + throw toDesktopError(err); + } + + // Locate the _[ProjectData] directory — prefer the canonical sibling name; + // fall back to any single *_[ProjectData] dir present. + const canonicalDataDirName = `${xpjBase}_[ProjectData]`; + const dataDirEntries = entries.filter( + (e) => e.isDirectory() && e.name.endsWith("_[ProjectData]"), + ); + + let dataDirPath: string | null = null; + + const canonical = dataDirEntries.find((e) => e.name === canonicalDataDirName); + if (canonical) { + dataDirPath = path.join(dir, canonical.name); + } else if (dataDirEntries.length === 1) { + // Accept a single non-canonical _[ProjectData] dir + dataDirPath = path.join(dir, dataDirEntries[0].name); + } + // If no data dir found, return empty samples array (some projects may have none) + + const samples: { fileName: string; bytes: Uint8Array }[] = []; + + if (dataDirPath !== null) { + let wavEntries: Dirent[]; + try { + wavEntries = await fs.readdir(dataDirPath, { withFileTypes: true }); + } catch (err) { + throw toDesktopError(err); + } + + const wavFiles = wavEntries + .filter((e) => e.isFile() && e.name.toLowerCase().endsWith(".wav")) + .sort((a, b) => a.name.localeCompare(b.name)); + + for (const wavEntry of wavFiles) { + const wavPath = path.join(dataDirPath, wavEntry.name); + try { + const buf = await fs.readFile(wavPath); + samples.push({ fileName: wavEntry.name, bytes: new Uint8Array(buf) }); + } catch (err) { + throw toDesktopError(err); + } + } + } + + return { dir, xpjBytes, samples }; +} diff --git a/electron/ipc.ts b/electron/ipc.ts new file mode 100644 index 0000000..f1f658e --- /dev/null +++ b/electron/ipc.ts @@ -0,0 +1,18 @@ +/** + * ipc.ts — IPC channel name constants and result type for the MPC Sample + * Electron main ↔ renderer bridge. + */ + +import type { DesktopError } from "../src/desktop/bridge.types"; + +export const CH = { + getDefaultExportDir: "mpc:getDefaultExportDir", + chooseExportDir: "mpc:chooseExportDir", + chooseProjectDir: "mpc:chooseProjectDir", + readProject: "mpc:readProject", + writeProject: "mpc:writeProject", + ejectVolume: "mpc:ejectVolume", + openPath: "mpc:openPath", +} as const; + +export type IpcResult = { ok: true; result: T } | { ok: false; error: DesktopError }; diff --git a/electron/main.ts b/electron/main.ts new file mode 100644 index 0000000..df14f28 --- /dev/null +++ b/electron/main.ts @@ -0,0 +1,277 @@ +/** + * main.ts — Electron main process for MPC Sample. + * + * Security model: + * - contextIsolation: true, sandbox: true, nodeIntegration: false + * - MIDI permissions granted (Web MIDI API); Web Audio requires no permission grant. + * - CSP via onHeadersReceived: allows bundled assets, inline styles (Tailwind v4), + * data/blob URLs, and Google Fonts; `unsafe-eval` only in dev for Vite HMR. + */ + +import { execFile } from "node:child_process"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import { electronApp, is, optimizer } from "@electron-toolkit/utils"; +import { app, BrowserWindow, dialog, ipcMain, nativeImage, session, shell } from "electron"; + +const execFileAsync = promisify(execFile); + +import type { + DefaultExportDir, + DesktopError, + DesktopErrorCode, + LoadedProject, + WriteProjectArgs, + WriteProjectResult, +} from "../src/desktop/bridge.types"; +import { readProjectFromFile, writeProjectToDisk } from "./fsops"; +import type { IpcResult } from "./ipc"; +import { CH } from "./ipc"; +import { DEFAULT_EXPORT_DIR, getDefaultExportDir, VOLUME_ROOT } from "./paths"; + +function normalizeError(err: unknown): DesktopError { + if (err instanceof Error) { + const typed = err as Error & { code?: unknown }; + const knownCodes = new Set([ + "CANCELLED", + "EEXIST", + "ENOENT", + "EACCES", + "ENOXPJ", + "EUNKNOWN", + ]); + const rawCode = String(typed.code ?? "EUNKNOWN"); + const code: DesktopErrorCode = knownCodes.has(rawCode as DesktopErrorCode) + ? (rawCode as DesktopErrorCode) + : "EUNKNOWN"; + return { code, message: err.message }; + } + return { code: "EUNKNOWN", message: String(err) }; +} + +function ok(result: T): IpcResult { + return { ok: true, result }; +} + +function fail(err: unknown): IpcResult { + return { ok: false, error: normalizeError(err) }; +} + +// Natural MPC dimensions at 100 % zoom (content area, no title-bar). +const BASE_W = 920; +const BASE_H = 960; + +function createWindow(): void { + const mainWindow = new BrowserWindow({ + width: BASE_W, + height: BASE_H, + show: false, + autoHideMenuBar: true, + icon: APP_ICON_PATH, + webPreferences: { + preload: join(__dirname, "../preload/index.js"), + sandbox: true, + nodeIntegration: false, + contextIsolation: true, + }, + }); + + // Grant MIDI permissions (Web MIDI API) — Web Audio needs no permission. + mainWindow.webContents.session.setPermissionRequestHandler((_wc, permission, callback) => { + callback(permission === "midi" || permission === "midiSysex"); + }); + mainWindow.webContents.session.setPermissionCheckHandler( + (_wc, permission) => permission === "midi" || permission === "midiSysex", + ); + + // CSP — applied for all navigation responses. + mainWindow.webContents.session.webRequest.onHeadersReceived((details, callback) => { + const scriptSrc = is.dev ? "'self' 'unsafe-inline' 'unsafe-eval'" : "'self' 'unsafe-inline'"; + + const csp = [ + `default-src 'self' blob: data:`, + `script-src ${scriptSrc}`, + // Tone.js creates a clock worker from a blob URL — allow it. + `worker-src blob: 'self'`, + // Tailwind v4 injects styles at runtime + `style-src 'self' 'unsafe-inline' https://fonts.googleapis.com`, + `font-src 'self' data: https://fonts.gstatic.com`, + `img-src 'self' data: blob:`, + `media-src 'self' blob: data:`, + `connect-src 'self' blob: data:`, + ].join("; "); + + callback({ + responseHeaders: { + ...details.responseHeaders, + "Content-Security-Policy": [csp], + }, + }); + }); + + // Show as soon as the first paint is ready… + mainWindow.on("ready-to-show", () => { + mainWindow.show(); + }); + // …with fallbacks so the window can never get stuck invisible: show once the + // document finishes loading, and surface any load failure instead of hanging. + mainWindow.webContents.on("did-finish-load", () => { + if (!mainWindow.isVisible()) mainWindow.show(); + }); + mainWindow.webContents.on("did-fail-load", (_e, errorCode, errorDescription, validatedURL) => { + console.error( + `[main] renderer failed to load (${errorCode} ${errorDescription}) url=${validatedURL}`, + ); + if (!mainWindow.isVisible()) mainWindow.show(); + }); + + mainWindow.webContents.setWindowOpenHandler((details) => { + shell.openExternal(details.url); + return { action: "deny" }; + }); + + const rendererUrl = process.env.ELECTRON_RENDERER_URL; + if (is.dev && rendererUrl) { + if (!app.isPackaged) console.log(`[main] dev: loading renderer URL ${rendererUrl}`); + if (is.dev) mainWindow.webContents.openDevTools({ mode: "detach" }); + mainWindow.loadURL(rendererUrl).catch((err) => console.error("[main] loadURL failed:", err)); + } else { + const indexFile = join(__dirname, "../renderer/index.html"); + if (!app.isPackaged) console.log(`[main] prod: loading file ${indexFile}`); + mainWindow.loadFile(indexFile).catch((err) => console.error("[main] loadFile failed:", err)); + } +} + +function registerIpcHandlers(): void { + ipcMain.handle(CH.getDefaultExportDir, async (): Promise> => { + try { + const result = await getDefaultExportDir(); + return ok(result); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle(CH.chooseExportDir, async (): Promise> => { + try { + const { canceled, filePaths } = await dialog.showOpenDialog({ + properties: ["openDirectory", "createDirectory"], + }); + return ok(canceled || filePaths.length === 0 ? null : filePaths[0]); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle(CH.chooseProjectDir, async (): Promise> => { + try { + const { canceled, filePaths } = await dialog.showOpenDialog({ + properties: ["openFile"], + filters: [{ name: "Akai Project", extensions: ["xpj"] }], + }); + return ok(canceled || filePaths.length === 0 ? null : filePaths[0]); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle(CH.readProject, async (_event, filePath: string): Promise> => { + try { + const result = await readProjectFromFile(filePath); + return ok(result); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle(CH.ejectVolume, async (): Promise> => { + try { + await execFileAsync("diskutil", ["eject", VOLUME_ROOT]); + return ok(undefined); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle(CH.openPath, async (_event, dir: string): Promise> => { + try { + await shell.openPath(dir); + return ok(undefined); + } catch (err) { + return fail(err); + } + }); + + ipcMain.handle( + CH.writeProject, + async (_event, args: WriteProjectArgs): Promise> => { + try { + let destDir = args.destDir; + + if (!destDir) { + // Try the default export dir first + const defaultDir = await getDefaultExportDir(); + if (defaultDir.exists) { + destDir = defaultDir.path; + } else { + // Fall back to a native directory picker + const { canceled, filePaths } = await dialog.showOpenDialog({ + properties: ["openDirectory", "createDirectory"], + defaultPath: DEFAULT_EXPORT_DIR, + }); + if (canceled || filePaths.length === 0) { + return fail( + Object.assign(new Error("Export cancelled by user."), { + code: "CANCELLED" as DesktopErrorCode, + }), + ); + } + destDir = filePaths[0]; + } + } + + const result = await writeProjectToDisk(args, destDir); + return ok(result); + } catch (err) { + return fail(err); + } + }, + ); +} + +const APP_ICON_PATH = join(app.getAppPath(), "public/favicon/android-chrome-512x512.png"); + +app.whenReady().then(() => { + electronApp.setAppUserModelId("com.worldlinkstudio.mpcsample"); + + if (process.platform === "darwin" && app.dock) { + app.dock.setIcon(nativeImage.createFromPath(APP_ICON_PATH)); + } + + app.on("browser-window-created", (_, window) => { + optimizer.watchWindowShortcuts(window); + }); + + // Ensure all windows share the MIDI permission policy set above. + session.defaultSession.setPermissionRequestHandler((_wc, permission, callback) => { + callback(permission === "midi" || permission === "midiSysex"); + }); + session.defaultSession.setPermissionCheckHandler( + (_wc, permission) => permission === "midi" || permission === "midiSysex", + ); + + registerIpcHandlers(); + createWindow(); + + app.on("activate", () => { + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } + }); +}); + +app.on("window-all-closed", () => { + if (process.platform !== "darwin") { + app.quit(); + } +}); diff --git a/electron/paths.ts b/electron/paths.ts new file mode 100644 index 0000000..94c5c7a --- /dev/null +++ b/electron/paths.ts @@ -0,0 +1,25 @@ +/** + * paths.ts — Default filesystem paths for the MPC Sample desktop app. + * No Electron imports — importable from unit tests. + */ + +import * as fs from "node:fs/promises"; + +import type { DefaultExportDir } from "../src/desktop/bridge.types"; + +export const VOLUME_ROOT = "/Volumes/MPC-SD" as const; + +export const DEFAULT_EXPORT_DIR = "/Volumes/MPC-SD/MPC-Sample/Projects" as const; + +/** + * Resolve the default export directory and check whether it is currently + * accessible (i.e. the SD card is mounted and the path exists). + */ +export async function getDefaultExportDir(): Promise { + try { + await fs.access(DEFAULT_EXPORT_DIR); + return { path: DEFAULT_EXPORT_DIR, exists: true }; + } catch { + return { path: DEFAULT_EXPORT_DIR, exists: false }; + } +} diff --git a/electron/preload.ts b/electron/preload.ts new file mode 100644 index 0000000..846706f --- /dev/null +++ b/electron/preload.ts @@ -0,0 +1,85 @@ +/** + * preload.ts — Electron preload for MPC Sample. + * + * Exposes `window.mpcDesktop` (typed as {@link MpcDesktop}) via contextBridge. + * Every method invokes the corresponding IPC channel and unwraps the + * `IpcResult` discriminated union: on `ok: false` it throws a typed Error + * with the `.code` property from the main-process error, so renderers can + * `catch (e) { if (e.code === "CANCELLED") ... }`. + * + * Binary payloads (`Uint8Array`) cross the contextBridge boundary via the + * structured-clone algorithm — no base64 encoding required. + */ + +import { contextBridge, ipcRenderer } from "electron"; + +import type { + DefaultExportDir, + DesktopError, + LoadedProject, + MpcDesktop, + WriteProjectArgs, + WriteProjectResult, +} from "../src/desktop/bridge.types"; +import type { IpcResult } from "./ipc"; +import { CH } from "./ipc"; + +/** Unwrap an IpcResult — throws a typed Error on `ok: false`. */ +async function unwrap(promise: Promise>): Promise { + const res = await promise; + if (!res.ok) { + const { code, message } = res.error as DesktopError; + throw Object.assign(new Error(message), { code }); + } + return res.result; +} + +const mpcDesktop: MpcDesktop = { + isElectron: true, + + versions: { + app: (process.env.npm_package_version as string | undefined) ?? "", + electron: process.versions.electron, + chrome: process.versions.chrome, + }, + + getDefaultExportDir(): Promise { + return unwrap( + ipcRenderer.invoke(CH.getDefaultExportDir) as Promise>, + ); + }, + + chooseExportDir(): Promise { + return unwrap( + ipcRenderer.invoke(CH.chooseExportDir) as Promise>, + ); + }, + + chooseProjectDir(): Promise { + return unwrap( + ipcRenderer.invoke(CH.chooseProjectDir) as Promise>, + ); + }, + + readProject(dir: string): Promise { + return unwrap( + ipcRenderer.invoke(CH.readProject, dir) as Promise>, + ); + }, + + writeProject(args: WriteProjectArgs): Promise { + return unwrap( + ipcRenderer.invoke(CH.writeProject, args) as Promise>, + ); + }, + + ejectVolume(): Promise { + return unwrap(ipcRenderer.invoke(CH.ejectVolume) as Promise>); + }, + + openPath(dir: string): Promise { + return unwrap(ipcRenderer.invoke(CH.openPath, dir) as Promise>); + }, +}; + +contextBridge.exposeInMainWorld("mpcDesktop", mpcDesktop); diff --git a/electron/vitest.config.ts b/electron/vitest.config.ts new file mode 100644 index 0000000..6d59f81 --- /dev/null +++ b/electron/vitest.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + test: { + environment: "node", + include: ["electron/**/*.test.ts"], + watch: false, + globals: true, + reporters: ["default"], + }, +}); diff --git a/index.html b/index.html new file mode 100644 index 0000000..9aa0ac5 --- /dev/null +++ b/index.html @@ -0,0 +1,22 @@ + + + + + MPC Sample + + + + + + + + + + +
+ + + diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..24e4405 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,9163 @@ +{ + "name": "@worldlinkstudio/mpcsample", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@worldlinkstudio/mpcsample", + "version": "0.0.1", + "dependencies": { + "@tailwindcss/vite": "4.1.12", + "clsx": "^2.1.1", + "fflate": "^0.8.2", + "lucide-react": "0.545.0", + "tailwind-merge": "^2.6.0", + "tailwindcss": "4.1.14", + "tone": "^15.1.22", + "zustand": "^5.0.0" + }, + "devDependencies": { + "@biomejs/biome": "2.4.15", + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0", + "@testing-library/jest-dom": "6.1.4", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.5.2", + "@types/node": "^22.19.9", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.5", + "@types/webmidi": "^2.0.8", + "@vitejs/plugin-react": "^4.2.0", + "electron": "42.3.0", + "electron-builder": "26.8.1", + "electron-vite": "^4.0.0", + "jsdom": "22.1.0", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "tsx": "4.22.4", + "typescript": "^5.8.3", + "vite": "^6.0.0", + "vite-plugin-dts": "^4.0.0", + "vitest": "4.0.18" + }, + "peerDependencies": { + "react": ">=18.0.0 || ^19.0.0", + "react-dom": ">=18.0.0 || ^19.0.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.5.0.tgz", + "integrity": "sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "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.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", + "@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-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.7" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.29.7.tgz", + "integrity": "sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.29.7.tgz", + "integrity": "sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.29.7.tgz", + "integrity": "sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@biomejs/biome": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.4.15.tgz", + "integrity": "sha512-j5VH3a/h/HXTKBM50MDMxRCzkeLv9S2XJcW2WgnZT1+xyisi+0bISrXR82gCX+8S9lvK0skEvHJRN+3Ktr2hlw==", + "dev": true, + "license": "MIT OR Apache-2.0", + "bin": { + "biome": "bin/biome" + }, + "engines": { + "node": ">=14.21.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/biome" + }, + "optionalDependencies": { + "@biomejs/cli-darwin-arm64": "2.4.15", + "@biomejs/cli-darwin-x64": "2.4.15", + "@biomejs/cli-linux-arm64": "2.4.15", + "@biomejs/cli-linux-arm64-musl": "2.4.15", + "@biomejs/cli-linux-x64": "2.4.15", + "@biomejs/cli-linux-x64-musl": "2.4.15", + "@biomejs/cli-win32-arm64": "2.4.15", + "@biomejs/cli-win32-x64": "2.4.15" + } + }, + "node_modules/@biomejs/cli-darwin-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.4.15.tgz", + "integrity": "sha512-rF3PPqLq1yoST79zaQbDjVJwsuIeci/O+9bgNmC5QpgOqz6aqYuzA4abyAGx+mgyiDXn4A049xAN8gijbuR1Qg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-darwin-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.4.15.tgz", + "integrity": "sha512-/5KHXYMfSJs1fNXiX30xFtI8JcCFV6zaVVLxOa0M2sfqBKHkpQhRTv94yxQWxeTY2lzo2OuTlNvPC+hDQt2wcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.4.15.tgz", + "integrity": "sha512-owaAMZD/T4LrD0ELNCk0Km3qrRHuM0X6EAyVE1FSqGY0rbLoiDLrO4Us2tllm6cAeB2Ioa9C2C08NZPdr8+0Ug==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-arm64-musl": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.4.15.tgz", + "integrity": "sha512-ZPcxznxm0pogHBLZhYntyR3sR+MrZjqJIKEr7ZqVen0Rl+P/4upVmfYXjftizi9RoqZntg33fv/1fbdhbYXpEQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.4.15.tgz", + "integrity": "sha512-0jj7THz12GbUOLmMibktK6DZjqz2zV64KFxyBtcFTKPiiOIY0a7vns1elpO1dERvxpsZ5ik0oFfz0oGwFde1+g==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-linux-x64-musl": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.4.15.tgz", + "integrity": "sha512-CNq/9W38SYSH023lfcQ4KKU8K0YX8T//FZUhcgtMMRABDojx5XsMV7jlweAvGSl389wJQB29Qo6Zb/a+jdvt+w==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-arm64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.4.15.tgz", + "integrity": "sha512-ouhkYdlhp/1GghEJPdWwD/Vi3gQ1nFxuSpMolWsbq3Lsq3QUR4jl6UdhhscdCugKU5vOEuMiJhvKj66O0OCq+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@biomejs/cli-win32-x64": { + "version": "2.4.15", + "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.4.15.tgz", + "integrity": "sha512-zBrGq5mx5wwpnow4+2BxUvleDM+GNd4sLbPaMapsSLQLD0NGRCquqPBTgN+7XkUteHvj7M+BstuI8tmnV7+HgQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT OR Apache-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=14.21.3" + } + }, + "node_modules/@develar/schema-utils": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", + "integrity": "sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.0", + "ajv-keywords": "^3.4.1" + }, + "engines": { + "node": ">= 8.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/@electron-toolkit/preload": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@electron-toolkit/preload/-/preload-3.0.2.tgz", + "integrity": "sha512-TWWPToXd8qPRfSXwzf5KVhpXMfONaUuRAZJHsKthKgZR/+LqX1dZVSSClQ8OTAEduvLGdecljCsoT2jSshfoUg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "electron": ">=13.0.0" + } + }, + "node_modules/@electron-toolkit/utils": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@electron-toolkit/utils/-/utils-4.0.0.tgz", + "integrity": "sha512-qXSntwEzluSzKl4z5yFNBknmPGjPa3zFhE4mp9+h0cgokY5ornAeP+CJQDBhKsL1S58aOQfcwkD3NwLZCl+64g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "electron": ">=13.0.0" + } + }, + "node_modules/@electron/asar": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/@electron/asar/-/asar-3.4.1.tgz", + "integrity": "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^5.0.0", + "glob": "^7.1.6", + "minimatch": "^3.0.4" + }, + "bin": { + "asar": "bin/asar.js" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/@electron/asar/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/@electron/asar/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@electron/asar/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@electron/fuses": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@electron/fuses/-/fuses-1.8.0.tgz", + "integrity": "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.1", + "fs-extra": "^9.0.1", + "minimist": "^1.2.5" + }, + "bin": { + "electron-fuses": "dist/bin.js" + } + }, + "node_modules/@electron/fuses/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/@electron/fuses/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/fuses/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/fuses/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/get": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-5.0.0.tgz", + "integrity": "sha512-pjoBpru1KdEtcExBnuHAP1cAc/5faoedw0hzJkL3o4/IJp7HNF1+fbrdxT3gMYRX2oJfvnA/WXeCTVQpYYxyJA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^3.0.0", + "graceful-fs": "^4.2.11", + "progress": "^2.0.3", + "semver": "^7.6.3", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=22.12.0" + }, + "optionalDependencies": { + "undici": "^7.24.4" + } + }, + "node_modules/@electron/get/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@electron/get/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/get/node_modules/undici": { + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.26.0.tgz", + "integrity": "sha512-3O9Tf67pGhgOv9jM35AbhkXAKi13f3oy3aE4CSgr+TckGeY+/iu97ZXN+J7DpHPzLbVApFd1IFhcnBjREYXYcg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/@electron/notarize": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz", + "integrity": "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.1", + "promise-retry": "^2.0.1" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/notarize/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@electron/notarize/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/notarize/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/osx-sign": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@electron/osx-sign/-/osx-sign-1.3.3.tgz", + "integrity": "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "compare-version": "^0.1.2", + "debug": "^4.3.4", + "fs-extra": "^10.0.0", + "isbinaryfile": "^4.0.8", + "minimist": "^1.2.6", + "plist": "^3.0.5" + }, + "bin": { + "electron-osx-flat": "bin/electron-osx-flat.js", + "electron-osx-sign": "bin/electron-osx-sign.js" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@electron/osx-sign/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@electron/osx-sign/node_modules/isbinaryfile": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/@electron/osx-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/osx-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/rebuild": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-4.0.4.tgz", + "integrity": "sha512-Rzc39XPdk/+/wBG8MfwAHohXflep0ITUfulb6Rgz3R0NeSB1noE+E9/M/cb8ftCAiyDD9PPhLuuWgE1GaInbKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.1.1", + "node-abi": "^4.2.0", + "node-api-version": "^0.2.1", + "node-gyp": "^12.2.0", + "read-binary-file-arch": "^1.0.6" + }, + "bin": { + "electron-rebuild": "lib/cli.js" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@electron/universal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@electron/universal/-/universal-2.0.3.tgz", + "integrity": "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/asar": "^3.3.1", + "@malept/cross-spawn-promise": "^2.0.0", + "debug": "^4.3.1", + "dir-compare": "^4.2.0", + "fs-extra": "^11.1.1", + "minimatch": "^9.0.3", + "plist": "^3.1.0" + }, + "engines": { + "node": ">=16.4" + } + }, + "node_modules/@electron/universal/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/@electron/universal/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@electron/universal/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/universal/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/universal/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@electron/universal/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@electron/windows-sign": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@electron/windows-sign/-/windows-sign-1.2.2.tgz", + "integrity": "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "peer": true, + "dependencies": { + "cross-dirname": "^0.1.0", + "debug": "^4.3.4", + "fs-extra": "^11.1.1", + "minimist": "^1.2.8", + "postject": "^1.0.0-alpha.6" + }, + "bin": { + "electron-windows-sign": "bin/electron-windows-sign.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@electron/windows-sign/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@electron/windows-sign/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "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" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@isaacs/fs-minipass/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "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==", + "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==", + "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==", + "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==", + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@malept/cross-spawn-promise": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@malept/cross-spawn-promise/-/cross-spawn-promise-2.0.0.tgz", + "integrity": "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/malept" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/subscription/pkg/npm-.malept-cross-spawn-promise?utm_medium=referral&utm_source=npm_fund" + } + ], + "license": "Apache-2.0", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@malept/flatpak-bundler": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@malept/flatpak-bundler/-/flatpak-bundler-0.4.0.tgz", + "integrity": "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "fs-extra": "^9.0.0", + "lodash": "^4.17.15", + "tmp-promise": "^3.0.2" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@malept/flatpak-bundler/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@microsoft/api-extractor": { + "version": "7.58.7", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor/-/api-extractor-7.58.7.tgz", + "integrity": "sha512-yK6OycD46gIzLRpj6ueVUWPk1ACSpkN1LBo05gY1qPTylbWyUCanXfH7+VgkI5LJrJoRSQR5F04XuCffCXLOBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor-model": "7.33.8", + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1", + "@rushstack/rig-package": "0.7.3", + "@rushstack/terminal": "0.24.0", + "@rushstack/ts-command-line": "5.3.9", + "diff": "~8.0.2", + "minimatch": "10.2.3", + "resolve": "~1.22.1", + "semver": "~7.7.4", + "source-map": "~0.6.1", + "typescript": "5.9.3" + }, + "bin": { + "api-extractor": "bin/api-extractor" + } + }, + "node_modules/@microsoft/api-extractor-model": { + "version": "7.33.8", + "resolved": "https://registry.npmjs.org/@microsoft/api-extractor-model/-/api-extractor-model-7.33.8.tgz", + "integrity": "sha512-aIcoQggPyer3B6Ze3usz0YWC/oBwUHfRH5ETUsr+oT2BRA6SfTJl7IKPcPZkX4UR+PohowzW4uMxsvjrn8vm+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "~0.16.0", + "@microsoft/tsdoc-config": "~0.18.1", + "@rushstack/node-core-library": "5.23.1" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/minimatch": { + "version": "10.2.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.3.tgz", + "integrity": "sha512-Rwi3pnapEqirPSbWbrZaa6N3nmqq4Xer/2XooiOKyV3q12ML06f7MOuc5DVH8ONZIFhwIYQ3yzPH4nt7iWHaTg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@microsoft/api-extractor/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@microsoft/tsdoc": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc/-/tsdoc-0.16.0.tgz", + "integrity": "sha512-xgAyonlVVS+q7Vc7qLW0UrJU7rSFcETRWsqdXZtjzRU8dF+6CkozTK4V4y1LwOX7j8r/vHphjDeMeGI4tNGeGA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@microsoft/tsdoc-config": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/@microsoft/tsdoc-config/-/tsdoc-config-0.18.1.tgz", + "integrity": "sha512-9brPoVdfN9k9g0dcWkFeA7IH9bbcttzDJlXvkf8b2OBzd5MueR1V2wkKBL0abn0otvmkHJC6aapBOTJDDeMCZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/tsdoc": "0.16.0", + "ajv": "~8.18.0", + "jju": "~1.4.0", + "resolve": "~1.22.2" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@microsoft/tsdoc-config/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "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/pluginutils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.4.0.tgz", + "integrity": "sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.4.tgz", + "integrity": "sha512-F5QXMSiFebS9hKZj02XhWLLnRpJ3B3AROP0tWbFBSj+6kCbg5m9j5JoHKd4mmSVy5mS/IMQloYgYxCuJC0fxEQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.4.tgz", + "integrity": "sha512-GxxTKApUpzRhof7poWvCJHRF51C67u1R7D6DiluBE8wKU1u5GWE8t+v81JvJYtbawoBFX1hLv5Ei4eVjkWokaw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.4.tgz", + "integrity": "sha512-tua0TaJxMOB1R0V0RS1jFZ/RpURFDJIOR2A6jWwQeawuFyS4gBW+rntLRaQd0EQ4bd6Vp44Z2rXW+YYDBsj6IA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.4.tgz", + "integrity": "sha512-CSKq7MsP+5PFIcydhAiR1K0UhEI1A2jWXVKHPCBZ151yOutENwvnPocgVHkivu2kviURtCEB6zUQw0vs8RrhMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.4.tgz", + "integrity": "sha512-+O8OkVdyvXMtJEciu2wS/pzm1IxntEEQx3z5TAVy4l32G0etZn+RsA48ARRrFm6Ri8fvqPQfgrvNxSjKAbnd3g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.4.tgz", + "integrity": "sha512-Iw3oMskH3AfNuhU0MSN7vNbdi4me/NiYo2azqPz/Le16zHSa+3RRmliCMWWQmh4lcndccU40xcJuTYJZxNo/lw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.4.tgz", + "integrity": "sha512-EIPRXTVQpHyF8WOo219AD2yEltPehLTcTMz2fn6JsatLYSzQf00hj3rulF+yauOlF9/FtM2WpkT/hJh/KJFGhA==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.4.tgz", + "integrity": "sha512-J3Yh9PzzF1Ovah2At+lHiGQdsYgArxBbXv/zHfSyaiFQEqvNv7DcW98pCrmdjCZBrqBiKrKKe2V+aaSGWuBe/w==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.4.tgz", + "integrity": "sha512-BFDEZMYfUvLn37ONE1yMBojPxnMlTFsdyNoqncT0qFq1mAfllL+ATMMJd8TeuVMiX84s1KbcxcZbXInmcO2mRg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.4.tgz", + "integrity": "sha512-pc9EYOSlOgdQ2uPl1o9PF6/kLSgaUosia7gOuS8mB69IxJvlclko1MECXysjs5ryez1/5zjYqx3+xYU0TU6R1A==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.4.tgz", + "integrity": "sha512-NxnomyxYerDh5n4iLrNa+sH+Z+U4BMEE46V2PgQ/hoB909i8gV1M5wPojWg9fk1jWpO3IQnOs20K4wyZuFLEFQ==", + "cpu": [ + "loong64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.4.tgz", + "integrity": "sha512-nbJnQ8a3z1mtmrwImCYhc6BGpThAyYVRQxw9uKSKG4wR6aAYno9sVjJ0zaZcW9BPJX1GbrDPf+SvdWjgTuDmnw==", + "cpu": [ + "loong64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.4.tgz", + "integrity": "sha512-2EU6acNrQLd8tYvo/LXW535wupT3m6fo7HKo6lr7ktQoItxTyOL1ZCR/GfGCuXl2vR+zmfI6eRXkSemafv+iVg==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.4.tgz", + "integrity": "sha512-WeBtoMuaMxiiIrO2IYP3xs6GMWkJP2C0EoT8beTLkUPmzV1i/UcOSVw1d5r9KBODtHKilG5yFxsGRnBbK3wJ4A==", + "cpu": [ + "ppc64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.4.tgz", + "integrity": "sha512-FJHFfqpKUI3A10WrWKiFbBZ7yVbGT4q4B5o1qKFFojqpaYoh9LrQgqWCmmcxQzVSXYtyB5bzkXrYzlHTs21MYA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.4.tgz", + "integrity": "sha512-mcEl6CUT5IAUmQf1m9FYSmVqCJlpQ8r8eyftFUHG8i9OhY7BkBXSUdnLH5DOf0wCOjcP9v/QO93zpmF1SptCCw==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.4.tgz", + "integrity": "sha512-ynt3JxVd2w2buzoKDWIyiV1pJW93xlQic1THVLXilz429oijRpSHivZAgp65KBu+cMcgf1eVVjdnTLvPxgCuoQ==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.4.tgz", + "integrity": "sha512-Boiz5+MsaROEWDf+GGEwF8VMHGhlUoQMtIPjOgA5fv4osupqTVnJteQNKJwUcnUog2G55jYXH7KZFFiJe0TEzQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.4.tgz", + "integrity": "sha512-+qfSY27qIrFfI/Hom04KYFw3GKZSGU4lXus51wsb5EuySfFlWRwjkKWoE9emgRw/ukoT4Udsj4W/+xxG8VbPKg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.4.tgz", + "integrity": "sha512-VpTfOPHgVXEBeeR8hZ2O0F3aSso+JDWqTWmTmzcQKted54IAdUVbxE+j/MVxUsKa8L20HJhv3vUezVPoquqWjA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.4.tgz", + "integrity": "sha512-IPOsh5aRYuLv/nkU51X10Bf75Bsf6+gZdx1X+QP5QM6lIJFHHqbHLG0uJn/hWthzo13UAc2umiUorqZy3axoZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.4.tgz", + "integrity": "sha512-4QzE9E81OohJ/HKzHhsqU+zcYYojVOXlFMs1DdyMT6qXl/niOH7AVElmmEdUNHHS/oRkc++d5k6Vy85zFs0DEw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.4.tgz", + "integrity": "sha512-zTPgT1YuHHcd+Tmx7h8aml0FWFVelV5N54oHow9SLj+GfoDy/huQ+UV396N/C7KpMDMiPspRktzM1/0r1usYEA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.4.tgz", + "integrity": "sha512-DRS4G7mi9lJxqEDezIkKCaUIKCrLUUDCUaCsTPCi/rtqaC6D/jjwslMQyiDU50Ka0JKpeXeRBFBAXwArY52vBw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.4.tgz", + "integrity": "sha512-QVTUovf40zgTqlFVrKA1uXMVvU2QWEFWfAH8Wdc48IxLvrJMQVMBRjuQyUpzZCDkakImib9eVazbWlC6ksWtJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rushstack/node-core-library": { + "version": "5.23.1", + "resolved": "https://registry.npmjs.org/@rushstack/node-core-library/-/node-core-library-5.23.1.tgz", + "integrity": "sha512-wlKmIKIYCKuCASbITvOxLZXepPbwXvrv7S6ig6XNWFchSyhL/E2txmVXspHY49Wu2dzf7nI27a2k/yV5BA3EiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "~8.18.0", + "ajv-draft-04": "~1.0.0", + "ajv-formats": "~3.0.1", + "fs-extra": "~11.3.0", + "import-lazy": "~4.0.0", + "jju": "~1.4.0", + "resolve": "~1.22.1", + "semver": "~7.7.4" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/@rushstack/node-core-library/node_modules/fs-extra": { + "version": "11.3.5", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.5.tgz", + "integrity": "sha512-eKpRKAovdpZtR1WopLHxlBWvAgPny3c4gX1G5Jhwmmw4XJj0ifSD5qB5TOo8hmA0wlRKDAOAhEE1yVPgs6Fgcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rushstack/node-core-library/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@rushstack/node-core-library/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@rushstack/problem-matcher": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@rushstack/problem-matcher/-/problem-matcher-0.2.1.tgz", + "integrity": "sha512-gulfhBs6n+I5b7DvjKRfhMGyUejtSgOHTclF/eONr8hcgF1APEDjhxIsfdUYYMzC3rvLwGluqLjbwCFZ8nxrog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/rig-package": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@rushstack/rig-package/-/rig-package-0.7.3.tgz", + "integrity": "sha512-aAA518n6wxxjCfnTAOjQnm7ngNE0FVHxHAw2pxKlIhxrMn0XQjGcXKF0oKWpjBgJOmsaJpVob/v+zr3zxgPWuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jju": "~1.4.0", + "resolve": "~1.22.1" + } + }, + "node_modules/@rushstack/terminal": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/@rushstack/terminal/-/terminal-0.24.0.tgz", + "integrity": "sha512-8ZQS4MMaGsv27EXCBiH7WMPkRZrffeDoIevs6z9TM5dzqiY6+Hn4evfK/G+gvgBTjfvfkHIZPQQmalmI2sM4TQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/node-core-library": "5.23.1", + "@rushstack/problem-matcher": "0.2.1", + "supports-color": "~8.1.1" + }, + "peerDependencies": { + "@types/node": "*" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@rushstack/terminal/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/@rushstack/ts-command-line": { + "version": "5.3.9", + "resolved": "https://registry.npmjs.org/@rushstack/ts-command-line/-/ts-command-line-5.3.9.tgz", + "integrity": "sha512-GIHqU+sRGQ3LGWAZu1O+9Yh++qwtyNIIGuNbcWHJjBTm2qRez0cwINUHZ+pQLR8UuzZDcMajrDaNbUYoaL/XtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rushstack/terminal": "0.24.0", + "@types/argparse": "1.0.38", + "argparse": "~1.0.9", + "string-argv": "~0.3.1" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@rushstack/ts-command-line/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dev": true, + "license": "MIT", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.12.tgz", + "integrity": "sha512-3hm9brwvQkZFe++SBt+oLjo4OLDtkvlE8q2WalaD/7QWaeM7KEJbAiY/LJZUaCs7Xa8aUu4xy3uoyX4q54UVdQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.4", + "enhanced-resolve": "^5.18.3", + "jiti": "^2.5.1", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.12" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.12.tgz", + "integrity": "sha512-gM5EoKHW/ukmlEtphNwaGx45fGoEmP10v51t9unv55voWh6WrOL19hfuIdo2FjxIaZzw776/BUQg7Pck++cIVw==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-arm64": "4.1.12", + "@tailwindcss/oxide-darwin-x64": "4.1.12", + "@tailwindcss/oxide-freebsd-x64": "4.1.12", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.12", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.12", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.12", + "@tailwindcss/oxide-linux-x64-musl": "4.1.12", + "@tailwindcss/oxide-wasm32-wasi": "4.1.12", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.12", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.12" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.12.tgz", + "integrity": "sha512-oNY5pq+1gc4T6QVTsZKwZaGpBb2N1H1fsc1GD4o7yinFySqIuRZ2E4NvGasWc6PhYJwGK2+5YT1f9Tp80zUQZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.12.tgz", + "integrity": "sha512-cq1qmq2HEtDV9HvZlTtrj671mCdGB93bVY6J29mwCyaMYCP/JaUBXxrQQQm7Qn33AXXASPUb2HFZlWiiHWFytw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.12.tgz", + "integrity": "sha512-6UCsIeFUcBfpangqlXay9Ffty9XhFH1QuUFn0WV83W8lGdX8cD5/+2ONLluALJD5+yJ7k8mVtwy3zMZmzEfbLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.12.tgz", + "integrity": "sha512-JOH/f7j6+nYXIrHobRYCtoArJdMJh5zy5lr0FV0Qu47MID/vqJAY3r/OElPzx1C/wdT1uS7cPq+xdYYelny1ww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.12.tgz", + "integrity": "sha512-v4Ghvi9AU1SYgGr3/j38PD8PEe6bRfTnNSUE3YCMIRrrNigCFtHZ2TCm8142X8fcSqHBZBceDx+JlFJEfNg5zQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.12.tgz", + "integrity": "sha512-YP5s1LmetL9UsvVAKusHSyPlzSRqYyRB0f+Kl/xcYQSPLEw/BvGfxzbH+ihUciePDjiXwHh+p+qbSP3SlJw+6g==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.12.tgz", + "integrity": "sha512-V8pAM3s8gsrXcCv6kCHSuwyb/gPsd863iT+v1PGXC4fSL/OJqsKhfK//v8P+w9ThKIoqNbEnsZqNy+WDnwQqCA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.12.tgz", + "integrity": "sha512-xYfqYLjvm2UQ3TZggTGrwxjYaLB62b1Wiysw/YE3Yqbh86sOMoTn0feF98PonP7LtjsWOWcXEbGqDL7zv0uW8Q==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.12.tgz", + "integrity": "sha512-ha0pHPamN+fWZY7GCzz5rKunlv9L5R8kdh+YNvP5awe3LtuXb5nRi/H27GeL2U+TdhDOptU7T6Is7mdwh5Ar3A==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.12.tgz", + "integrity": "sha512-4tSyu3dW+ktzdEpuk6g49KdEangu3eCYoqPhWNsZgUhyegEda3M9rG0/j1GV/JjVVsj+lG7jWAyrTlLzd/WEBg==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.5", + "@emnapi/runtime": "^1.4.5", + "@emnapi/wasi-threads": "^1.0.4", + "@napi-rs/wasm-runtime": "^0.2.12", + "@tybys/wasm-util": "^0.10.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.4.5", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.0.4", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.4.5", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "0.2.12", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@tybys/wasm-util": "^0.10.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.0", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.0", + "inBundle": true, + "license": "0BSD", + "optional": true + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.12.tgz", + "integrity": "sha512-iGLyD/cVP724+FGtMWslhcFyg4xyYyM+5F4hGvKA7eifPkXHRAUDFaimu53fpNg9X8dfP75pXx/zFt/jlNF+lg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.12.tgz", + "integrity": "sha512-NKIh5rzw6CpEodv/++r0hGLlfgT/gFN+5WNdZtvh6wpU2BpGNgdjvj6H2oFc8nCM839QM1YOhjpgbAONUb4IxA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.12.tgz", + "integrity": "sha512-4pt0AMFDx7gzIrAOIYgYP0KCBuKWqyW8ayrdiLEjoJTT4pKTjrzG/e4uzWtTLDziC+66R9wbUqZBccJalSE5vQ==", + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.12", + "@tailwindcss/oxide": "4.1.12", + "tailwindcss": "4.1.12" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.12.tgz", + "integrity": "sha512-DzFtxOi+7NsFf7DBtI3BJsynR+0Yp6etH+nRPTbpWnS2pZBaSksv/JGctNwSWzbFjp0vxSqknaUylseZqMDGrA==", + "license": "MIT" + }, + "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.1.4", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.1.4.tgz", + "integrity": "sha512-wpoYrCYwSZ5/AxcrjLxJmCU6I5QAJXslEeSiMQqaWmP2Kzpd1LvF/qxmAIW2qposULGWq2gw30GgVNFLSc2Jnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.3.1", + "@babel/runtime": "^7.9.2", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", + "lodash": "^4.17.15", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + }, + "peerDependencies": { + "@jest/globals": ">= 28", + "@types/jest": ">= 28", + "jest": ">= 28", + "vitest": ">= 0.32" + }, + "peerDependenciesMeta": { + "@jest/globals": { + "optional": true + }, + "@types/jest": { + "optional": true + }, + "jest": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.2", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", + "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.1", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.1.tgz", + "integrity": "sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.1.tgz", + "integrity": "sha512-HqmEUIGRJ5fSXchkVgR5F7qn48bDBzv0kWj/Kfu5e6uci4UlEeng4331LnBkWffb++Ei3FOVLxo8JJWMFBDMeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, + "node_modules/@types/argparse": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-1.0.38.tgz", + "integrity": "sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT", + "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/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/debug": { + "version": "4.1.13", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", + "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@types/fs-extra": { + "version": "9.0.13", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz", + "integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", + "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.19.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.19.tgz", + "integrity": "sha512-dyh/xO2Fh5bYrfWaaqGrRQQGkNdmYw6AmaAUvYeUMNTWQtvb796ikLdmTchRmOlOiIJ1TDXfWgVx1QkUlQ6Hew==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/plist": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/plist/-/plist-3.0.5.tgz", + "integrity": "sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*", + "xmlbuilder": ">=11.0.1" + } + }, + "node_modules/@types/react": { + "version": "19.2.15", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.15.tgz", + "integrity": "sha512-eRwcGNHve+E8qtEQSSRl6urh+rFop4v8gm6O8rGv25CodbvFdLjA1vVQ1KkiFE0w0UPOnb8tDiFKL5lp0rtY5Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.3", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.3.tgz", + "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/responselike": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.3.tgz", + "integrity": "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/verror": { + "version": "1.10.11", + "resolved": "https://registry.npmjs.org/@types/verror/-/verror-1.10.11.tgz", + "integrity": "sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@types/webmidi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/webmidi/-/webmidi-2.1.0.tgz", + "integrity": "sha512-k898MjEUSHB+6rSeCPQk/kLgie0wgWZ2t78GlWj86HbTQ+XmtbBafYg5LNjn8bVHfItEhPGZPf579Xfc6keV6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "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.18", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.18.tgz", + "integrity": "sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "chai": "^6.2.1", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.0.18.tgz", + "integrity": "sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.0.18", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0-0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/mocker/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/@vitest/pretty-format": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.0.18.tgz", + "integrity": "sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.0.18.tgz", + "integrity": "sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.0.18", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.0.18.tgz", + "integrity": "sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.0.18.tgz", + "integrity": "sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.0.18.tgz", + "integrity": "sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.0.18", + "tinyrainbow": "^3.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.35.tgz", + "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.3", + "@vue/shared": "3.5.35", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz", + "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.35", + "@vue/shared": "3.5.35" + } + }, + "node_modules/@vue/compiler-vue2": { + "version": "2.7.16", + "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz", + "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==", + "dev": true, + "license": "MIT", + "dependencies": { + "de-indent": "^1.0.2", + "he": "^1.2.0" + } + }, + "node_modules/@vue/language-core": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-2.2.0.tgz", + "integrity": "sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "~2.4.11", + "@vue/compiler-dom": "^3.5.0", + "@vue/compiler-vue2": "^2.7.16", + "@vue/shared": "^3.5.0", + "alien-signals": "^0.4.9", + "minimatch": "^9.0.3", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@vue/language-core/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/@vue/language-core/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@vue/language-core/node_modules/minimatch": { + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.35", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.35.tgz", + "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@xmldom/xmldom": { + "version": "0.8.13", + "resolved": "https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.8.13.tgz", + "integrity": "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/7zip-bin": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/7zip-bin/-/7zip-bin-5.2.0.tgz", + "integrity": "sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/abab": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", + "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "deprecated": "Use your platform's native atob() and btoa() methods instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.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/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "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/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/alien-signals": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-0.4.14.tgz", + "integrity": "sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "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/app-builder-bin": { + "version": "5.0.0-alpha.12", + "resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-5.0.0-alpha.12.tgz", + "integrity": "sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/app-builder-lib": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-26.8.1.tgz", + "integrity": "sha512-p0Im/Dx5C4tmz8QEE1Yn4MkuPC8PrnlRneMhWJj7BBXQfNTJUshM/bp3lusdEsDbvvfJZpXWnYesgSLvwtM2Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@develar/schema-utils": "~2.6.5", + "@electron/asar": "3.4.1", + "@electron/fuses": "^1.8.0", + "@electron/get": "^3.0.0", + "@electron/notarize": "2.5.0", + "@electron/osx-sign": "1.3.3", + "@electron/rebuild": "^4.0.3", + "@electron/universal": "2.0.3", + "@malept/flatpak-bundler": "^0.4.0", + "@types/fs-extra": "9.0.13", + "async-exit-hook": "^2.0.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chromium-pickle-js": "^0.2.0", + "ci-info": "4.3.1", + "debug": "^4.3.4", + "dotenv": "^16.4.5", + "dotenv-expand": "^11.0.6", + "ejs": "^3.1.8", + "electron-publish": "26.8.1", + "fs-extra": "^10.1.0", + "hosted-git-info": "^4.1.0", + "isbinaryfile": "^5.0.0", + "jiti": "^2.4.2", + "js-yaml": "^4.1.0", + "json5": "^2.2.3", + "lazy-val": "^1.0.5", + "minimatch": "^10.0.3", + "plist": "3.1.0", + "proper-lockfile": "^4.1.2", + "resedit": "^1.7.0", + "semver": "~7.7.3", + "tar": "^7.5.7", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0", + "which": "^5.0.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "dmg-builder": "26.8.1", + "electron-builder-squirrel-windows": "26.8.1" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-3.1.0.tgz", + "integrity": "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.1.1", + "env-paths": "^2.2.0", + "fs-extra": "^8.1.0", + "got": "^11.8.5", + "progress": "^2.0.3", + "semver": "^6.2.0", + "sumchecker": "^3.0.1" + }, + "engines": { + "node": ">=14" + }, + "optionalDependencies": { + "global-agent": "^3.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/app-builder-lib/node_modules/@electron/get/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/app-builder-lib/node_modules/ci-info": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.3.1.tgz", + "integrity": "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/app-builder-lib/node_modules/fs-extra/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/app-builder-lib/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/async-exit-hook": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-2.0.1.tgz", + "integrity": "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/automation-events": { + "version": "7.1.19", + "resolved": "https://registry.npmjs.org/automation-events/-/automation-events-7.1.19.tgz", + "integrity": "sha512-cD+TLhJTI0q4AI3ktd353lrGZiVa9AchowSDzQzzGjSoYe22js4vlS32VUtWuaulghi1Yq0KYNWKk9wWuGymPA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.29.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=18.2.0" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.33", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", + "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/boolean": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", + "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/browserslist": { + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.2.tgz", + "integrity": "sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==", + "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.10.12", + "caniuse-lite": "^1.0.30001782", + "electron-to-chromium": "^1.5.328", + "node-releases": "^2.0.36", + "update-browserslist-db": "^1.2.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builder-util": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/builder-util/-/builder-util-26.8.1.tgz", + "integrity": "sha512-pm1lTYbGyc90DHgCDO7eo8Rl4EqKLciayNbZqGziqnH9jrlKe8ZANGdityLZU+pJh16dfzjAx2xQq9McuIPEtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/debug": "^4.1.6", + "7zip-bin": "~5.2.0", + "app-builder-bin": "5.0.0-alpha.12", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.6", + "debug": "^4.3.4", + "fs-extra": "^10.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "js-yaml": "^4.1.0", + "sanitize-filename": "^1.6.3", + "source-map-support": "^0.5.19", + "stat-mode": "^1.0.0", + "temp-file": "^3.4.0", + "tiny-async-pool": "1.3.0" + } + }, + "node_modules/builder-util-runtime": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-9.5.1.tgz", + "integrity": "sha512-qt41tMfgHTllhResqM5DcnHyDIWNgzHvuY2jDcYP9iaGpkWxTUzV6GQjDeLnlR1/DtdlcsWQbA7sByMpmJFTLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4", + "sax": "^1.2.4" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/builder-util/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/builder-util/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/builder-util/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/builder-util/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/caniuse-lite": { + "version": "1.0.30001793", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", + "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chromium-pickle-js": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz", + "integrity": "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/ci-info": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-4.4.0.tgz", + "integrity": "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz", + "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/compare-version": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/compare-version/-/compare-version-0.1.2.tgz", + "integrity": "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/compare-versions": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.1.tgz", + "integrity": "sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==", + "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/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "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-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/cross-dirname": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", + "integrity": "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, + "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/cross-spawn/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/cross-spawn/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/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": "3.0.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz", + "integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "rrweb-cssom": "^0.6.0" + }, + "engines": { + "node": ">=14" + } + }, + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-4.0.0.tgz", + "integrity": "sha512-/mMTei/JXPqvFqQtfyTowxmJVwr2PVAeCcDxyFf6LhoOu/09TX2OX3kb2wzi4DMXcfj4OItwDOnhl5oziPnT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/de-indent": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", + "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==", + "dev": true, + "license": "MIT" + }, + "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/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "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", + "optional": true, + "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", + "optional": true, + "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/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "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==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/diff": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz", + "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-compare": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", + "integrity": "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimatch": "^3.0.5", + "p-limit": "^3.1.0 " + } + }, + "node_modules/dir-compare/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/dir-compare/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/dir-compare/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dmg-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-26.8.1.tgz", + "integrity": "sha512-glMJgnTreo8CFINujtAhCgN96QAqApDMZ8Vl1r8f0QT8QprvC1UCltV4CcWj20YoIyLZx6IUskaJZ0NV8fokcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "fs-extra": "^10.1.0", + "iconv-lite": "^0.6.2", + "js-yaml": "^4.1.0" + }, + "optionalDependencies": { + "dmg-license": "^1.0.11" + } + }, + "node_modules/dmg-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dmg-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/dmg-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/dmg-license": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/dmg-license/-/dmg-license-1.0.11.tgz", + "integrity": "sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "@types/plist": "^3.0.1", + "@types/verror": "^1.10.3", + "ajv": "^6.10.0", + "crc": "^3.8.0", + "iconv-corefoundation": "^1.1.7", + "plist": "^3.0.4", + "smart-buffer": "^4.0.2", + "verror": "^1.10.0" + }, + "bin": { + "dmg-license": "bin/dmg-license.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/domexception": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", + "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "license": "MIT", + "dependencies": { + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/dotenv-expand": { + "version": "11.0.7", + "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-11.0.7.tgz", + "integrity": "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dotenv": "^16.4.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "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/ejs": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", + "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "jake": "^10.8.5" + }, + "bin": { + "ejs": "bin/cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/electron": { + "version": "42.3.0", + "resolved": "https://registry.npmjs.org/electron/-/electron-42.3.0.tgz", + "integrity": "sha512-9ZiLdRXk+WDxW1OgIUz8J2rIQ5TYU9o629gCOjU48Q3dQiOmym7osWsH5Ubs/Jh4uuFLn6m6SBD2rmRXLAPz9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@electron/get": "^5.0.0", + "@types/node": "^24.9.0", + "extract-zip": "^2.0.1" + }, + "bin": { + "electron": "cli.js", + "install-electron": "install.js" + }, + "engines": { + "node": ">= 22.12.0" + } + }, + "node_modules/electron-builder": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-26.8.1.tgz", + "integrity": "sha512-uWhx1r74NGpCagG0ULs/P9Nqv2nsoo+7eo4fLUOB8L8MdWltq9odW/uuLXMFCDGnPafknYLZgjNX0ZIFRzOQAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "ci-info": "^4.2.0", + "dmg-builder": "26.8.1", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "simple-update-notifier": "2.0.0", + "yargs": "^17.6.2" + }, + "bin": { + "electron-builder": "cli.js", + "install-app-deps": "install-app-deps.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/electron-builder-squirrel-windows": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-builder-squirrel-windows/-/electron-builder-squirrel-windows-26.8.1.tgz", + "integrity": "sha512-o288fIdgPLHA76eDrFADHPoo7VyGkDCYbLV1GzndaMSAVBoZrGvM9m2IehdcVMzdAZJ2eV9bgyissQXHv5tGzA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "app-builder-lib": "26.8.1", + "builder-util": "26.8.1", + "electron-winstaller": "5.4.0" + } + }, + "node_modules/electron-builder/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/electron-builder/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-builder/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-builder/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-publish": { + "version": "26.8.1", + "resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-26.8.1.tgz", + "integrity": "sha512-q+jrSTIh/Cv4eGZa7oVR+grEJo/FoLMYBAnSL5GCtqwUpr1T+VgKB/dn1pnzxIxqD8S/jP1yilT9VrwCqINR4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/fs-extra": "^9.0.11", + "builder-util": "26.8.1", + "builder-util-runtime": "9.5.1", + "chalk": "^4.1.2", + "form-data": "^4.0.5", + "fs-extra": "^10.1.0", + "lazy-val": "^1.0.5", + "mime": "^2.5.2" + } + }, + "node_modules/electron-publish/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/electron-publish/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/electron-publish/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/electron-publish/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.364", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.364.tgz", + "integrity": "sha512-G/dYE3+AYhyHwzTwg8UbnXf7zqMERYh7l2jJ3QujhFsH8agSYwtnGAR2aZ7f0AakIKJXd5En/Hre4igIUrdlYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/electron-vite": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/electron-vite/-/electron-vite-4.0.1.tgz", + "integrity": "sha512-QqacJbA8f1pmwUTqki1qLL5vIBaOQmeq13CZZefZ3r3vKVaIoC7cpoTgE+KPKxJDFTax+iFZV0VYvLVWPiQ8Aw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/plugin-transform-arrow-functions": "^7.27.1", + "cac": "^6.7.14", + "esbuild": "^0.25.5", + "magic-string": "^0.30.17", + "picocolors": "^1.1.1" + }, + "bin": { + "electron-vite": "bin/electron-vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@swc/core": "^1.0.0", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + } + } + }, + "node_modules/electron-winstaller": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/electron-winstaller/-/electron-winstaller-5.4.0.tgz", + "integrity": "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@electron/asar": "^3.2.1", + "debug": "^4.1.1", + "fs-extra": "^7.0.1", + "lodash": "^4.17.21", + "temp": "^0.9.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "optionalDependencies": { + "@electron/windows-sign": "^1.1.2" + } + }, + "node_modules/electron-winstaller/node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/electron/node_modules/@types/node": { + "version": "24.12.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.12.4.tgz", + "integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/electron/node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.22.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.22.1.tgz", + "integrity": "sha512-6QEuw3zoX1SJQc7b87aBXke/no+mG2bTBgw29gWMQonLmpEkWoCAVkl+M49e48AZlWzxiDzDZzYdp6kobcyLww==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "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/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true, + "license": "MIT" + }, + "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-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.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "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/es6-error": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", + "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/esbuild": { + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", + "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/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", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extsprintf": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.4.1.tgz", + "integrity": "sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "optional": true + }, + "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-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "license": "MIT" + }, + "node_modules/filelist": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz", + "integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "minimatch": "^5.0.1" + } + }, + "node_modules/filelist/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/filelist/node_modules/brace-expansion": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/filelist/node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "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/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-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "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-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/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/glob/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz", + "integrity": "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "es6-error": "^4.1.1", + "matcher": "^3.0.0", + "roarr": "^2.15.3", + "semver": "^7.3.2", + "serialize-error": "^7.0.1" + }, + "engines": { + "node": ">=10.0" + } + }, + "node_modules/global-agent/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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", + "optional": true, + "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/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "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==", + "license": "ISC" + }, + "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", + "optional": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "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.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/hosted-git-info/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/html-encoding-sniffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", + "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.2.0.tgz", + "integrity": "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==", + "dev": true, + "license": "BSD-2-Clause" + }, + "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/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-corefoundation": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz", + "integrity": "sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "cli-truncate": "^2.1.0", + "node-addon-api": "^1.6.3" + }, + "engines": { + "node": "^8.11.2 || >=10" + } + }, + "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/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/is-core-module": { + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/isbinaryfile": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", + "integrity": "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/jake": { + "version": "10.9.4", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", + "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "async": "^3.2.6", + "filelist": "^1.0.4", + "picocolors": "^1.1.1" + }, + "bin": { + "jake": "bin/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/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": "22.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-22.1.0.tgz", + "integrity": "sha512-/9AVW7xNbsBv6GfWho4TTNjEo9fe6Zhf9O7s0Fhhr3u+awPwAJMKwAMXnkk5vBxflqLW9hTHX/0cs+P3gW+cQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "cssstyle": "^3.0.0", + "data-urls": "^4.0.0", + "decimal.js": "^10.4.3", + "domexception": "^4.0.0", + "form-data": "^4.0.0", + "html-encoding-sniffer": "^3.0.0", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.1", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.4", + "parse5": "^7.1.2", + "rrweb-cssom": "^0.6.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^4.1.2", + "w3c-xmlserializer": "^4.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^2.0.0", + "whatwg-mimetype": "^3.0.0", + "whatwg-url": "^12.0.1", + "ws": "^8.13.0", + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/jsdom/node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/jsdom/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/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-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true, + "license": "ISC", + "optional": true + }, + "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/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "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/kolorist": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/kolorist/-/kolorist-1.8.0.tgz", + "integrity": "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/lazy-val": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.5.tgz", + "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "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-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "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.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/local-pkg": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-1.2.1.tgz", + "integrity": "sha512-++gUqRDEvcnN6Zhqrr+y/CkVEHhlrR96vZn3nZZPYzMcBUyBtTKzB9NadClFIsIVSsu+3i9tfk/erqy9kAmt7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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.545.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.545.0.tgz", + "integrity": "sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==", + "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==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/matcher": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", + "integrity": "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "escape-string-regexp": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "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/mime": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "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": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mlly": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", + "integrity": "sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "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/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.12", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", + "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", + "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/node-abi": { + "version": "4.31.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-4.31.0.tgz", + "integrity": "sha512-Erq5w/t3syw3s4sDsUaX4QttIdBPsGKTT1DTRsCkTonGggczhlDKm/wDX3o+HPJpQ41EjXCbcmXf0tgr5YZJXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.6.3" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/node-abi/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-api-version": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/node-api-version/-/node-api-version-0.2.1.tgz", + "integrity": "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.3.5" + } + }, + "node_modules/node-api-version/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp": { + "version": "12.3.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", + "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-gyp/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.46", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.46.tgz", + "integrity": "sha512-GYVXHE2KnrzAfsAjl4uP++evGFCrAU1jta4ubEjIG7YWt/64Gqv66a30yKwWczVjA6j3bM4nBwH7Pk1JmDHaxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/nwsapi": { + "version": "2.2.23", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.23.tgz", + "integrity": "sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==", + "dev": true, + "license": "MIT" + }, + "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", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "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/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "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/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/pe-library": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/pe-library/-/pe-library-0.4.1.tgz", + "integrity": "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "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==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } + }, + "node_modules/plist": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/plist/-/plist-3.1.0.tgz", + "integrity": "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@xmldom/xmldom": "^0.8.8", + "base64-js": "^1.5.1", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=10.4.0" + } + }, + "node_modules/postcss": { + "version": "8.5.15", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", + "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", + "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.12", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postject": { + "version": "1.0.0-alpha.6", + "resolved": "https://registry.npmjs.org/postject/-/postject-1.0.0-alpha.6.tgz", + "integrity": "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "commander": "^9.4.0" + }, + "bin": { + "postject": "dist/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/postject/node_modules/commander": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", + "integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": "^12.20.0 || >=14" + } + }, + "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/proc-log": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-6.1.0.tgz", + "integrity": "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.6.tgz", + "integrity": "sha512-sfWGGfavi0xr8Pg0sVsyHMAOziVYKgPLNrS7ig+ivMNb3wbCBw3KxtflsGBAwD3gYQlE/AEZsTLgToRrSCjb0Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.2.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.6.tgz", + "integrity": "sha512-0prMI+hvBbPjsWnxDLxlCGyM8PN6UuWjEUCYmZhO67xIV9Xasa/r/vDnq+Xyq4Lo27g8QSbO5YzARu0D1Sps3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.6" + } + }, + "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/read-binary-file-arch": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/read-binary-file-arch/-/read-binary-file-arch-1.0.6.tgz", + "integrity": "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "bin": { + "read-binary-file-arch": "cli.js" + } + }, + "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/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "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/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/resedit": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/resedit/-/resedit-1.7.2.tgz", + "integrity": "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pe-library": "^0.4.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jet2jet" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "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-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "license": "ISC", + "peer": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/roarr": { + "version": "2.15.4", + "resolved": "https://registry.npmjs.org/roarr/-/roarr-2.15.4.tgz", + "integrity": "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "boolean": "^3.0.1", + "detect-node": "^2.0.4", + "globalthis": "^1.0.1", + "json-stringify-safe": "^5.0.1", + "semver-compare": "^1.0.0", + "sprintf-js": "^1.1.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/rollup": { + "version": "4.60.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.4.tgz", + "integrity": "sha512-WHeFSbZYsPu3+bLoNRUuAO+wavNlocOPf3wSHTP7hcFKVnJeWsYlCDbr3mTS14FCizf9ccIxXA8sGL8zKeQN3g==", + "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.60.4", + "@rollup/rollup-android-arm64": "4.60.4", + "@rollup/rollup-darwin-arm64": "4.60.4", + "@rollup/rollup-darwin-x64": "4.60.4", + "@rollup/rollup-freebsd-arm64": "4.60.4", + "@rollup/rollup-freebsd-x64": "4.60.4", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.4", + "@rollup/rollup-linux-arm-musleabihf": "4.60.4", + "@rollup/rollup-linux-arm64-gnu": "4.60.4", + "@rollup/rollup-linux-arm64-musl": "4.60.4", + "@rollup/rollup-linux-loong64-gnu": "4.60.4", + "@rollup/rollup-linux-loong64-musl": "4.60.4", + "@rollup/rollup-linux-ppc64-gnu": "4.60.4", + "@rollup/rollup-linux-ppc64-musl": "4.60.4", + "@rollup/rollup-linux-riscv64-gnu": "4.60.4", + "@rollup/rollup-linux-riscv64-musl": "4.60.4", + "@rollup/rollup-linux-s390x-gnu": "4.60.4", + "@rollup/rollup-linux-x64-gnu": "4.60.4", + "@rollup/rollup-linux-x64-musl": "4.60.4", + "@rollup/rollup-openbsd-x64": "4.60.4", + "@rollup/rollup-openharmony-arm64": "4.60.4", + "@rollup/rollup-win32-arm64-msvc": "4.60.4", + "@rollup/rollup-win32-ia32-msvc": "4.60.4", + "@rollup/rollup-win32-x64-gnu": "4.60.4", + "@rollup/rollup-win32-x64-msvc": "4.60.4", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz", + "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw==", + "dev": true, + "license": "MIT" + }, + "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/sanitize-filename": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.4.tgz", + "integrity": "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg==", + "dev": true, + "license": "WTFPL OR ISC", + "dependencies": { + "truncate-utf8-bytes": "^1.0.0" + } + }, + "node_modules/sax": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT" + }, + "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/semver-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", + "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/serialize-error": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-7.0.1.tgz", + "integrity": "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "type-fest": "^0.13.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-update-notifier/node_modules/semver": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.1.tgz", + "integrity": "sha512-rkVq3IXh+4FDGch+KwzX3aV9W3kO54GyEgpvBzSyctDA6Xtd7RJQV1xmXbeQp5v7+VzLOfVqiutSE6GICgPFvg==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true, + "license": "BSD-3-Clause", + "optional": true + }, + "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/standardized-audio-context": { + "version": "25.3.77", + "resolved": "https://registry.npmjs.org/standardized-audio-context/-/standardized-audio-context-25.3.77.tgz", + "integrity": "sha512-Ki9zNz6pKcC5Pi+QPjPyVsD9GwJIJWgryji0XL9cAJXMGyn+dPOf6Qik1AHei0+UNVcc4BOCa0hWLBzlwqsW/A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.6", + "automation-events": "^7.0.9", + "tslib": "^2.7.0" + } + }, + "node_modules/stat-mode": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stat-mode/-/stat-mode-1.0.0.tgz", + "integrity": "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "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/string-argv": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz", + "integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sumchecker": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-3.0.1.tgz", + "integrity": "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "debug": "^4.1.0" + }, + "engines": { + "node": ">= 8.0" + } + }, + "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": "2.6.1", + "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.6.1.tgz", + "integrity": "sha512-Oo6tHdpZsGpkKG88HJ8RR1rg/RdnEkQEfMoEk2x1XRI3F1AxeU+ijRXpiVUF4UbLfcxxRGw6TbUINKYdWVsQTQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/dcastil" + } + }, + "node_modules/tailwindcss": { + "version": "4.1.14", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz", + "integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==", + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/tar": { + "version": "7.5.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.15.tgz", + "integrity": "sha512-dzGK0boVlC4W5QFuQN1EFSl3bIDYsk7Tj40U6eIBnK2k/8ml7TZ5agbI5j5+qnoVcAA+rNtBml8SEiLxZpNqRQ==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/tar/node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/temp": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", + "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "mkdirp": "^0.5.1", + "rimraf": "~2.6.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/temp-file": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.4.0.tgz", + "integrity": "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-exit-hook": "^2.0.1", + "fs-extra": "^10.0.0" + } + }, + "node_modules/temp-file/node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/temp-file/node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/temp-file/node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/tiny-async-pool": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tiny-async-pool/-/tiny-async-pool-1.3.0.tgz", + "integrity": "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.5.0" + } + }, + "node_modules/tiny-async-pool/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/tmp-promise": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/tmp-promise/-/tmp-promise-3.0.3.tgz", + "integrity": "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tmp": "^0.2.0" + } + }, + "node_modules/tone": { + "version": "15.1.22", + "resolved": "https://registry.npmjs.org/tone/-/tone-15.1.22.tgz", + "integrity": "sha512-TCScAGD4sLsama5DjvTUXlLDXSqPealhL64nsdV1hhr6frPWve0DeSo63AKnSJwgfg55fhvxj0iPPRwPN5o0ag==", + "license": "MIT", + "dependencies": { + "standardized-audio-context": "^25.3.70", + "tslib": "^2.3.1" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", + "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/tr46": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-4.1.1.tgz", + "integrity": "sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/truncate-utf8-bytes": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz", + "integrity": "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "utf8-byte-length": "^1.0.1" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tsx": { + "version": "4.22.4", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.4.tgz", + "integrity": "sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.28.0" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", + "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", + "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", + "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", + "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", + "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", + "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", + "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", + "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", + "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", + "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", + "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", + "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", + "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", + "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", + "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", + "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", + "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", + "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", + "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", + "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", + "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", + "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", + "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", + "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", + "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", + "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", + "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", + "devOptional": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.0", + "@esbuild/android-arm": "0.28.0", + "@esbuild/android-arm64": "0.28.0", + "@esbuild/android-x64": "0.28.0", + "@esbuild/darwin-arm64": "0.28.0", + "@esbuild/darwin-x64": "0.28.0", + "@esbuild/freebsd-arm64": "0.28.0", + "@esbuild/freebsd-x64": "0.28.0", + "@esbuild/linux-arm": "0.28.0", + "@esbuild/linux-arm64": "0.28.0", + "@esbuild/linux-ia32": "0.28.0", + "@esbuild/linux-loong64": "0.28.0", + "@esbuild/linux-mips64el": "0.28.0", + "@esbuild/linux-ppc64": "0.28.0", + "@esbuild/linux-riscv64": "0.28.0", + "@esbuild/linux-s390x": "0.28.0", + "@esbuild/linux-x64": "0.28.0", + "@esbuild/netbsd-arm64": "0.28.0", + "@esbuild/netbsd-x64": "0.28.0", + "@esbuild/openbsd-arm64": "0.28.0", + "@esbuild/openbsd-x64": "0.28.0", + "@esbuild/openharmony-arm64": "0.28.0", + "@esbuild/sunos-x64": "0.28.0", + "@esbuild/win32-arm64": "0.28.0", + "@esbuild/win32-ia32": "0.28.0", + "@esbuild/win32-x64": "0.28.0" + } + }, + "node_modules/type-fest": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.13.1.tgz", + "integrity": "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.4.tgz", + "integrity": "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", + "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "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/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/utf8-byte-length": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz", + "integrity": "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==", + "dev": true, + "license": "(WTFPL OR MIT)" + }, + "node_modules/verror": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", + "integrity": "sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/vite": { + "version": "6.4.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.2.tgz", + "integrity": "sha512-2N/55r4JDJ4gdrCvGgINMy+HH3iRpNIz8K6SFwVsA+JbQScLiC+clmAxBgwiSPgcG9U15QmvqCGWzMbqda5zGQ==", + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.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 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-dts": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/vite-plugin-dts/-/vite-plugin-dts-4.5.4.tgz", + "integrity": "sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@microsoft/api-extractor": "^7.50.1", + "@rollup/pluginutils": "^5.1.4", + "@volar/typescript": "^2.4.11", + "@vue/language-core": "2.2.0", + "compare-versions": "^6.1.1", + "debug": "^4.4.0", + "kolorist": "^1.8.0", + "local-pkg": "^1.0.0", + "magic-string": "^0.30.17" + }, + "peerDependencies": { + "typescript": "*", + "vite": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "4.0.18", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.0.18.tgz", + "integrity": "sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.0.18", + "@vitest/mocker": "4.0.18", + "@vitest/pretty-format": "4.0.18", + "@vitest/runner": "4.0.18", + "@vitest/snapshot": "4.0.18", + "@vitest/spy": "4.0.18", + "@vitest/utils": "4.0.18", + "es-module-lexer": "^1.7.0", + "expect-type": "^1.2.2", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^3.10.0", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.0.3", + "vite": "^6.0.0 || ^7.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.0.18", + "@vitest/browser-preview": "4.0.18", + "@vitest/browser-webdriverio": "4.0.18", + "@vitest/ui": "4.0.18", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", + "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", + "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-url": { + "version": "12.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz", + "integrity": "sha512-Ed/LrqB8EPlGxjS+TrsXcpUond1mhccS3pchLhzSgPCnTimUCKj3IZE75pAs5m6heB2U2TMerKFUXheyHY+VDQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^4.1.1", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/which": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/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/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.0.tgz", + "integrity": "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==", + "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": "4.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", + "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12" + } + }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0" + } + }, + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zustand": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.14.tgz", + "integrity": "sha512-/8tAspM5LMPr28b3fwLYrtdj77ECpfZviaP75CMTnwO8ISyaE4GDIG/9rDDYq/cH9D2Xw2A2RXglLInmVBQB/g==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b9753ac --- /dev/null +++ b/package.json @@ -0,0 +1,74 @@ +{ + "name": "@worldlinkstudio/mpcsample", + "version": "0.0.1", + "description": "Web + desktop Akai MPC sample drum machine with .xpj project export.", + "author": "World Link Studio", + "type": "module", + "comment:main": "Electron reads `main` as its entry point — it MUST be the built main-process file (out/main/index.js) so `electron-vite dev` and the packaged app run the app, not the library. Library consumers resolve via the `exports` map below (which takes precedence over `main`), and the library bundle stays at ./dist/index.js via `module`/`exports`.", + "main": "./out/main/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "exports": { + "./package.json": "./package.json", + ".": { + "development": "./src/index.ts", + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "default": "./dist/index.js" + } + }, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "build-kits": "tsx scripts/build-kits.mjs", + "electron:dev": "electron-vite dev", + "electron:build": "electron-vite build", + "electron:preview": "electron-vite preview", + "electron:package": "electron-vite build && electron-builder --dir", + "electron:dist": "electron-vite build && electron-builder --mac", + "typecheck": "tsc -p tsconfig.lib.json --noEmit && tsc -p tsconfig.node.json --noEmit", + "lint": "biome lint .", + "format": "biome format --write .", + "check": "biome check --write .", + "test": "vitest run" + }, + "devDependencies": { + "@biomejs/biome": "2.4.15", + "@electron-toolkit/preload": "^3.0.2", + "@electron-toolkit/utils": "^4.0.0", + "@testing-library/jest-dom": "6.1.4", + "@testing-library/react": "^16.3.2", + "@testing-library/user-event": "^14.5.2", + "@types/node": "^22.19.9", + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.5", + "@types/webmidi": "^2.0.8", + "@vitejs/plugin-react": "^4.2.0", + "electron": "42.3.0", + "electron-builder": "26.8.1", + "electron-vite": "^4.0.0", + "jsdom": "22.1.0", + "react": "^19.2.1", + "react-dom": "^19.2.1", + "tsx": "4.22.4", + "typescript": "^5.8.3", + "vite": "^6.0.0", + "vite-plugin-dts": "^4.0.0", + "vitest": "4.0.18" + }, + "peerDependencies": { + "react": ">=18.0.0 || ^19.0.0", + "react-dom": ">=18.0.0 || ^19.0.0" + }, + "dependencies": { + "@tailwindcss/vite": "4.1.12", + "clsx": "^2.1.1", + "fflate": "^0.8.2", + "lucide-react": "0.545.0", + "tailwind-merge": "^2.6.0", + "tailwindcss": "4.1.14", + "tone": "^15.1.22", + "zustand": "^5.0.0" + } +} diff --git a/public/favicon/android-chrome-192x192.png b/public/favicon/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..ecfa58de9633496a20ad6d26164904ce978c6afe GIT binary patch literal 24104 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 literal 0 HcmV?d00001 diff --git a/public/favicon/android-chrome-512x512.png b/public/favicon/android-chrome-512x512.png new file mode 100644 index 0000000000000000000000000000000000000000..28f08e245470cf99a030c7d92162c675cd6b932e GIT binary patch literal 84068 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�vLcc;Q#tt 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%0D-;gz2b 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

(F~dp zw2{75JroPTt3*zjCglYHZg9IQ=awV#wsngX>piAm(7wQ~5<`|n5T;(!Gd#6QOQ zvqjwD;ML_M5}=rR?Y@A1!N-lh=Tcyo3uJNW&VGRij(qm_?`&k&NQ-i6Z>yg|VD&6_ zV7xGI8Klu9Wv+k64Few+@A{~%{4N$lt{|;*0JKv^Ug{ApoU6LCa(mbr`^n$H7AK~n zEC5DjkU|qOhgYG=NsSWtsi@YUzgzl6*gdPj3z>qg%n*&sU??yK^iwbaoB!nuoAtDF zi15*g!80Mf9M96t+J5;SO>mb)SM57J#8T-bngpi5zN>-m_*>O+H_juLX&*_xQ=FJ> z@g3X6iF*LEPZ98(9oYZd;FTUoBhp0+paD)}8ljYYf+zqy4e>UJ>WCO|#<;W)ec$fQ zZiGQf2JCV{j1N}(aA5eo))=~T0U!k&_1$ncm+CY8h+hKhH|VDLP)PHR4RwWc+$(!& z0kZ+E6|2UZ{{s5H0RoJ*gZ=}! z_6KkkZJG2hAnzNXW2iOce*nY&0J^GMW&8ykegljLYwXv4^QC_P_1*w?y=p3I{{<|3 zv!Ha)Jm#1G0J^^cmbwfyj{Xan^kzX?6dmpQ{{Wu;0bIjdX8j9@`v%BvZr%MKz~MiD zo-S6)e*vZb0QxrcYyAgM{|)fwxu&A-FW{R6rTu0xKmP~N`wj5GWvFrTFW{R6X~9&q z3;qN6@&|C8Y+2-Azyf@*GC%>ol6KC2biHpn&J~Jf@xMCkHyyTucIJO{gKs+L6{=VI^jZ@R`6nq|4ax_587ce2`v|Itmp>26l&mX-eM5Z-hM(%P~A(arqf zTV+^Q`>TU_)4@n;NB&1Q|A%jtX<6&94&qG*A+8%~CpbdPxZxGqzR)6pB(jNz`aG7Xa{`dZ32!X;E24K>(;h*sM5G{1l?p+4> zx#nS}{Xg%;^!pom|A{N089e^xe@mXXR?Gjyv@X(Ea*&@&f{IU!{|E2!4X^bq+q(T< zy!f}MDb;Ptruo-R8~?cJBSHO1)4y(t3UX&+P_-Y-e+*D^2J`bzG(71HxqFTS)8<>ZSf_dIQ2$zw{B63SLX1)V(}N#qw5!c;qm6nruj={NDzGG=*%7!= z8}^@ItzNlK3vk+zTRQq1D1mQyVAWRt^RqX+thZpj+LCf3{V(1-E)ZTQ9&N_dfA9|8 z@KR2T+W$AUYM8z-5Z*6{5z2q&=^woBZ+I1t7F7fP;@Q37H5=51{nNwSqiOyR-bwV* z(cdtM|AvPYYxTcK{D#;52d}mGCj4JK1x64aH5O^c+jH-2a3G&@y7*(gvv2K`|5`6G z0E9OJHUv7E{O8)Y==|j^_#N(gHK?2X<7k+Esc+p<@^eoAr@8C5=G4#1+Zq3DuJ6tD zSh{Ky{}a+$-(2duhs{aSKaK&K4rm~ccNH-r`_Eugs^0F!{pphBzY)zB8Z?M=zyQ>L z;odyz@aDNe-RysGVCtaf@CIB2V*Ou#*X?{W@im`S)!(?s2=nwF006wcZgM5YgZ_Ye cduW0K$a8%re_gFff<6IAiOGGa6fyAsKNO|r;{X5v literal 0 HcmV?d00001 diff --git a/public/favicon/apple-touch-icon.png b/public/favicon/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..590cb317fb5525de50e305f8da646df06e87dcbb GIT binary patch literal 21557 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�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 literal 0 HcmV?d00001 diff --git a/public/favicon/favicon-16x16.png b/public/favicon/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..9ef570b685f71fb938a4136d0b3775ddab05cfdb GIT binary patch literal 662 zcmV;H0%`q;P)*DHd(Jg4aDuv-%_B9IfxZy?!~c5m`#e04fd5?U15vUxk|PT^rOD&c zVL2*AB*!&b>(yExusbdg=vzv?xq^z;CcGA^@mf5waUgzM0zv*CasITkHAq6Zw3AtP zz(xUIBtB2Dj9)_;QGzl&pP>moCo|7&1dwxDn}wmTj83bSqkEe{QB7uC3-@aLFzLL> zO_lu%3I2Yheus#ZJ*B1p7ApBC6d_hBn~d}u+Gw>Han00||16iWNef?YBzbbHfXM62 z(xB!Tof_qrJ9w#QAtK={60r!Ozz4en#wPAFFeawm8oL%4pT3G%=tL~2Ay$4FbxbRsfh_pz{8iaP2MVS(AiD>5i}_-ZYnO-dtcPcgZgyVSK;;pZ*kUB?k}l4mg6uAmg( zL7Uo(RAO5R>vV$Ud*$HZ&X;u9iWnIAN>lr1O7b-H4ePOu-{e@?8&nYnj8iUpEzR_d zbhBG&!tnaL2N2QF6-}tWjGo~T0wmFdNavVe2qq<_a;g6vIHrYk*+p~@OBiza;+~J= zY<8gsm_tAj8HvRNY&nl2Sj+YD8McQO&_7be565i|s4tQjwV%v{LV_eIB!sC5^Xc#a z;BvR1fBOOBpq}RqCY;VTYE3UN+sm1BJ)pAjJq?|WJg%!{&|#+Ho0W9k9S0)p`w5g#ZvKq$$CsW2rmMy*C`s$`s`YFfvPpkqwIn$}2S zi6yACNd*(Dl7Qx=Rt+jhc!Z#WfPjKLygcN6xm~W9!9WVmWTw+j?(98hch8>P|F`Gt zexH*6^6!5XfT#6%3f{2(F_QN%8L-98{xh~O-av(>oV1*O;9$9##X(VI#n}iLFJ}8j z5a5+hZo+(#M@0_<;1R0oLuk1hgAOHcXN93@-_92WdwDjY77LSNa!Ze5te%2S(LJi@ zV)QToB;^Xo`r4f*rfBhT20L>IpI%6FdlO3+bfPwRiC!&ebw=WQRHPi0)jgvb{9q)f z=~s9;LUEOnkjYNGf7Y5Wi!$U0Rx`&ZedN&hEJh2!8+ZEvY|PV{J7GC-ho9k5R|ooZ z@8N87nxIKrX=quG+OV6=QIS0TM)E!PBafp6P|l`>ww%aY!>g&Mv9$axhkhTwV8sDZT*cU9kr^8G3s{4*}g^Hou!oBXyjz!E*z~+ za=zq4k~06!G|!hYGu}g2x0(2O8Z)DOQqL5TA3s6lAv7ESS8UAAv2kGsYNHe`T!VVe zemotbczy9fOx4Cx|4NQrbfTeE#r`kW$psB!ylo#JUk;<})(%?bw6r>FiME8b;aB;z zKuufkB9VuXa)<_w;9@hLq?3)Plr}h7=VN6SOLbE=yN(Ca)``?S`bGp=X+$mLl(tLr zQ4%&KpT52h@+)C)R=oHQ<&VdFurP(P+WxGH>OoRIDC(s*DXratfnp^;^X-<}u0hkb zRh;|K*y1h60^d}D)fgQn>Uq! z0Ew9iRMa2hgR`%(YVQFtyv~-ib297XpU9-~+fb{YB5CbBGIHOd`R=E5_UvQl(S!KE z*dsPW=!XCl%bBg=le|>IcSvrB?CVz;vLVvGpBeZ!a_C$v|IDtye?!B7Zp3Lg09$w= z_zLs9J&B7BW`e6TCGqBiJgp}7nSCN3p!#+V7Zc=#Aktup46r3-xiQOvT`)JdV@c3l za*_-OObkd%GZ^6Iy?&pAjnc>eC89OO)jnvt&eO*pRJuyyj%{Vxf_KP?GnMs4R5dJ@ za-7YnZ&Z}ltQOrS6pFJLsWeP=Yon#3mgMYIl)CF!8s(9ZbB@EA9}+S-6$Q1_W@X48 zJq^x)D^-ntqP?cCeLrUt_I+kTU5ko}dSB-Hp1?n@9fiVzoH7-TRvrRE$L0^V%AOr8 zo$rB%{YN-hjiIJVB|RcizL-8?;<#}**<4{yR)kc^5_yT)Vrkked-QZ4fQ3jA96W7{ z%HVDMJ*z0Kt-*b)2Tx9i+Zqe}y6xqPH@D8r*o;Sl&>rOxX}P- zieaLwKRVqRu??iV*924JN}igLLViUe>0hY{^of@4DJ_#nrD9-$vkp6RrIe|o91GG# zZ(=#7mBPwCTy3T@{S}S)($jqaI;s7SXzj?CQficyzoF2jG1KcZ_LkdtA#@fqHx^-N zumV@R3S6v`Ed(ZsqcrjPSGL|^=9_RZG=bn9bS$plh+P^k{ z5sXp0Hu&_!FcY9P08h_b?|yc`hb(K>O#j^n*i{GcV;weOi(BP<{GYu{tq>HMjPUwR zk=!O80X1tPFrX9qx%wl{suo6s_Cb5UHVEyQica?R;orP3JTi8pmYyLdrWVL|_Q9dL zFQB+l7z$J7B82bPT1H`|n?Fuk+vEG1c2Hb>am=z7%2=jJ{|cd%3=N3HIvWRk8`uS> zJp*yD&m@GoHo_@;7nHd8VoN=59PkN&CMX&Ou6`)=2*lx_UN}_QUY`Ep=+|`!oTG=p zO5TH_5YaFgV=@Y0ChskWz%*_gEL%pyQBh!&k%1agZg6?k^};$kXH03*5iw0WAUI|+ zJmcoT*4-a7n|49ES4%YEIL)QKK|A%QwF6c>IdK& z`#r|;^R`YX8~Q$a-`&2ZEjl{7VY6Ff{N(J79rmuMATP?;M}b=-Tx<}8V-154%Q;=o z+717^+w0$*!;{fV|JyY_13qzaFmBf$&H>?Y7hcHx@6)!j*s4Jb4Ds+o8?RW8(f{9dC5mimOEggj8lvtOMX zqM&U&mQ;R!*wfJ+LFD7$utfCfIu_2Z-f#=+hfWV`_dLFfp7G=z!CUlG^;OM*Y7YE+ z91z`Z*dm}KoU;E3bA6df@9}Uq{BHQW`#{jz|67-lsX4wI{yuWpDwS4bb*mWcr=H84 z^ce!BCu38r@D0U@mc8&A?M8HMC!C|*+eLkN(kB?74}2R@w2hP9{4gpc7AIzIQ|W6% zJ256>JA7#O;^*#D-ITitGcvP8Y%SWBo@20vAHOv+f+Bjdjt3O>SvG$k0$ASB!A-S4 zKlh)54{O?^Gs|?1BT?kk0H0V`Lou%jg|=1KI0726-|SbRZ9PM}uko99`etO_JviUR z=AYoL7@M&FR`}JkIew(BR@x7MLi@R6K|V(CyM>b%N@&AxHVTK*xC6cnjYBEMx(^&umck-339dFaa18H{ zHjDFb%aZY$HFTVx{4(t`0d=3en<{(o=ibR_-U9<(-vs9>YusDtKwly=BnF<`s}J*q z?rnW%Ns>L~j6U5~yL!0F{e6luy|?=)q}B06eAvsFIeZC{*~F{gn`q0Y_>I%u8$)T{ z9Y4~aJVKcrP2aCGW$=~W6Om-V|2s#z_bq`kn?`vmZ%#j(pEvLp9dOau3}?CT6!xiv zz6hOzEB14*l-SlmmehHn1$5LOnIb>*t#3*hWmUs{e}2%Ps@(Iea?h1tzX{41ALLkC zyC*^Ug=o8LQY1&DZr;5mdD5_zCV)}AQZK2S&Lt5A1YXuUa;V#HhD_fRnT_GeZ;l_}=pSajuR@aEN<4 z`r>hhuWVy7Wbv)|PYUeqQR}?|Sj+E-2$<;OHsc`~zt@p(Pw{G4*Au19yCP@6JhV49 z#uCc<4%(FuxIed!{{*jatnrkK4YV!YpW?WNU2UT;a*6TQiTD}l!Vl|2-_ZY1x(vq| zv6HlI|Ks9=vh=@WkYU58^m|HhAC#~!UGiJ_2mOR|B3HDPTFSw`9-~p%{Z*Jd)JJyg z6l{7*V;XkTjq#%*wx2e=g7LEIA5qV2W~KApMxw~v8Y6t$Q1G}vID z9H{0%H3zCW@c)zpRpqdR6~@HcEcNl;ZPxhv!;JBr!$y zN&k}mXC5s0E*PS(g)JgqTZ?V<5Hg9I zv?soi*f0bs{j<<6Tc3v{u32~TO4ym3!9=?jV-0JntzfN!Oz7_Z0S$xl% z#L%x2o4ihZ;CS=|HD21zvQzZ!FA(P`tn&i4bsdQhUe8r=SLwis-+r_vE<>#2IQ{N5 zqgNn-W$Og3)`()+4&I8yD2xjfVlqlC z;x0*Vp^$i(xLI<|B8IIH(<&uSSv+A4*0zd8W9|sSvMTIcpfHX*YGaSTv7bW0Rt3Lp z)DAk%TOo$4?KJ@#*~cEvTVhWwG0*GF1C|jdI>))|Ca*`qL-03ew#{X~7X;g8411Qi z@p)p*7s=Pdf?=~SHMS%6e1-8`IWhCaD)m4s&RNIxIz?Jf65A@~8e|h=nI`xP_eu%- z(U6Y^YM9~|woxQztV#S;<{`KgaV;G&BCWi0K4rwFevvp@#wDJu%-M_i`n{X8jgJ#29FXQ5* ze=TE6{4ISDYu3t|5PMg7%)S(2w-rMdV>#(RD*1}Qt|~U6Fkhl2UUrDQ63k3_d4`%Z zD3rC6eM!txArG}7FG6`^6B5|h{jUD9S0}8)cdQ^ep#5BX$r+Rr4><1C3flym;JJh= zl*MzcdgDyyRt(VNSb{?;{W2&AF1RjxLdK7qj*Hxvd-&}panus;*7%%!xFm5t^^Vec zC=}v)`0^SweVeCp2lkTthuHv7wcBwKV zSa}ED3yh387b9FIT~|p@Vb8Is7%&&?M`Gg^G;#xFhTYpPiEEu;63-WH^u!jBqH~cmd|KZiIZ|78>C(Rzz8%bS8 zB0M4yZq#EoRh`FqL;^)l8WA(@GHxL(d!@ogFFTLe{IRNiMA<5%ZoW!AP~hJl%c+OP z(3Yk$R}(j8IehhbH`DHe;a1lj4QB3y$9?7~zQ*P@{cw5UJD5)!_};L;qR;&AQS-4V zd$dL~#GeRDz(M9Kv#F0yQqPpp9u?CD6;Z#R>^~bTT0|i+JP}{isgJMXGqFm4W@$h~ z3dYh-OO8YQ6FCP}#=aEhzH+H&N@>$BH|vU>9!)US!UmJ6yOub4BX{Id%&WxmAC1g= zYB_WF`k0y`nEIfk^DvwW>yHT5>cRU4Z-u$=a_+6)sH-a^r!F}xu9Z^9lm5{{Y!Tm$ zI!Q;rbusD6mNxR8`m7>uDtfUjSL`F#R&2gjzKaf~eJi28tQh+-@~X>6$QCDL)#(UbIh<0sM}_`5S6c`LOHELl+XCKQ6kS`dz~@%A^nG(R9?+XSlAV%x(XZn7R0nk8{nYub`u!aEblJ zGY{8=`zWVrXB>EG21Zi1Mv+(Vx%yx=eVVt3kt_VB&@KxNO3R+miS1`DMavv#3D;0Z zc~N}^wttiK{wBUG`&K5dQ|I>%i7b|STo+1bq$3%~lA#^mneyc?#J}^h*?; z;gGyc3*KjWwxEzcM!xi&nTH>qP`2IJ=bssCl+vyr;eINX7=XE=ljPr7&P7Kb{s{N} zTA@esw=%y@uc$QZ#Q$afM0~;PL8PDa(FtA5wG=mMk35lou7xuHfO@u5;=H|FD-He5 z8{!92?sHi7q?hFL29WnhsdF?Uo3sHrHZE%Hl1$HM75R9Kd*vF}r9|?|%!6GcpAS*5 zRAg+yLdG%CoZ|-BW6aTCX3jf~zF8CU;HMYgApHkby&!b>Rn?Xq~@WuV@NH)Yx2 z?j!My0sT_1ZD=e~CvSTE+^%$TpQ|l(%R9{3r&Qs;RW@<$Iu4ERI-64Y?YTe2uelp5 zdG16#9sxBXGH&O%4SO)pzSD1`g`)K6FF7ClACR{fYJzEF=B6w}0?#R{IeV5lGFLl_ zvF~u=B;GGgfjiHewI7^~5dFDsbKelOo$v+os0MS=PwkI>_)wqRq&yT6=h!XyRaiXY zs8fESeJ&C|iD&oEVNnLfC^FEXMCww#~ANBueqVF1So!Bkf%3{vp zDlwWV)G?8)vxv5$oOVb(_s6`tCL#%^seh$zDQ(4R#i=6YA3f8=W-b-pff z4i3?7ohCkT_VtbEPXcC(ogxk-aknmEHn#H|#IKBbbwhKoxXiwlAvNI#H|Fwxg`FJ*kr+{7QJvwUjv2aMrcpTn6zyFKrzbJwNh^ zH=5v}>=TayGo3i$(nCJ7F zg5a%kCPnF+4y~Ol%E?#NhvWGb@#__yr#(uU6`ZkD_7cy!?C1Lh`9{2C^FuJrXFV^W zUvO9DwNG)G{@4%H^r~Me`(M9*H2hx1wJGI#T#>q@U-hvEy@#)#Gyf%S&8D1Qd}E`E zg|4UmREXos8Q(m{X8T(A#rrR3Ax4k!xYIWq&HoFUMfteIGgsft-}%hWnm+2/, write manifest.json + index.json, + * and generate the authoritative src/xpj/template.skeleton.json. + * + * Usage (from package dir): + * node scripts/build-kits.mjs + * + * Idempotent: safe to re-run. Overwrites existing outputs. + */ + +import { + copyFileSync, + createReadStream, + existsSync, + mkdirSync, + readFileSync, + statSync, + writeFileSync, +} from "node:fs"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; +import { createGunzip } from "node:zlib"; +// Lexeme-preserving JSON codec — keeps float tokens (1.0, 0.0, …) intact so the +// generated skeleton matches the Akai `.xpj` format. Run via `tsx` (see the +// `build-kits` package.json script) so this `.ts` import resolves. +import { parseLossless, stringifyLossless } from "../src/xpj/jsonLossless.ts"; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const PKG_DIR = join(__dirname, ".."); +const PROJECTS_DIR = join(PKG_DIR, "MPC-Sample", "Projects"); +const PUBLIC_KITS_DIR = join(PKG_DIR, "public", "kits"); +const SKELETON_PATH = join(PKG_DIR, "src", "xpj", "template.skeleton.json"); + +// ---- Kit definitions (locked in the plan) -------------------------------- + +/** @type {Array<{sourceBase: string, id: string, displayName: string, exportName: string, key: string, bpm: number}>} */ +const KIT_DEFS = [ + { + sourceBase: "aaa-kit-SA London Cm 114", + id: "london-full", + displayName: "London Full", + exportName: "London Full - SA London Cm 114", + key: "C Minor", + bpm: 114, + }, + { + // Note: leading space in directory/file name + sourceBase: " t.-kit-SA London Cm 114", + id: "london-deluxe", + displayName: "London Deluxe", + exportName: "London Deluxe - SA London Cm 114", + key: "C Minor", + bpm: 114, + }, + { + sourceBase: "et.-kit-SA London Cm 114", + id: "london-essentials", + displayName: "London Essentials", + exportName: "London Essentials - SA London Cm 114", + key: "C Minor", + bpm: 114, + }, + { + sourceBase: "i2.-kit-SA London Cm 114", + id: "london-core", + displayName: "London Core", + exportName: "London Core - SA London Cm 114", + key: "C Minor", + bpm: 114, + }, + { + sourceBase: "project", + id: "london-studio", + displayName: "London Studio", + exportName: "London Studio - SA London Cm 114", + key: "C Minor", + bpm: 114, + }, +]; + +// ---- XPJ parsing ---------------------------------------------------------- + +/** + * Read and decompress an .xpj file. + * Returns the raw string (header + JSON). + * Handles both gzipped (magic 0x1f8b) and plain text files. + * @param {string} filePath + * @returns {Promise} + */ +async function readXpjFile(filePath) { + const bytes = readFileSync(filePath); + const isGzipped = bytes[0] === 0x1f && bytes[1] === 0x8b; + + if (!isGzipped) { + return bytes.toString("utf-8"); + } + + return new Promise((resolve, reject) => { + const chunks = []; + const gunzip = createGunzip(); + + gunzip.on("data", (chunk) => chunks.push(chunk)); + gunzip.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8"))); + gunzip.on("error", reject); + + const stream = createReadStream(filePath); + stream.on("error", reject); + stream.pipe(gunzip); + }); +} + +/** + * Parse .xpj content into a JS object. + * Format: 5 header lines + JSON payload. + * @param {string} content + * @returns {{ header: string[], obj: object }} + */ +function parseXpj(content) { + const lines = content.split("\n"); + const header = lines.slice(0, 5); + const jsonStr = lines.slice(5).join("\n"); + const obj = JSON.parse(jsonStr); + return { header, obj }; +} + +// ---- Pad extraction ------------------------------------------------------- + +/** + * Extract SamplePad entries from parsed .xpj object. + * @param {string} kitId + * @param {object} obj - parsed .xpj root object + * @returns {Array} SamplePad[] + */ +function extractPads(kitId, obj) { + const instruments = obj.data.tracks[0].program.drum.instruments; + const pads = []; + + for (let globalPadIdx = 0; globalPadIdx < instruments.length; globalPadIdx++) { + const inst = instruments[globalPadIdx]; + const layers = inst.layersv; + if (!layers || layers.length === 0) continue; + + const layer = layers[0]; + const sampleFile = layer.sampleFile; + if (!sampleFile || sampleFile.trim() === "") continue; + + const sampleName = layer.sampleName || ""; + const fileName = sampleFile; + const coarseTune = typeof inst.coarseTune === "number" ? inst.coarseTune : 0; + const fineTune = typeof inst.fineTune === "number" ? inst.fineTune : 0; + const gainCoefficient = + layer.volume && typeof layer.volume.gainCoefficient === "number" + ? layer.volume.gainCoefficient + : 1.0; + const pan = typeof layer.pan === "number" ? layer.pan : 0.5; + + /** @type {import('../src/kits/kit.types').SamplePad} */ + const pad = { + globalPadIdx, + sampleId: `${kitId}:${fileName}`, + displayName: sampleName, + sampleName, + fileName, + url: `/kits/${kitId}/${fileName}`, + coarseTune, + fineTune, + gainCoefficient, + pan, + }; + + pads.push(pad); + } + + return pads; +} + +// ---- Skeleton generation -------------------------------------------------- + +/** + * Generate a stripped skeleton from a raw .xpj JSON payload string. + * Blanks all pad instruments, empties samples arrays, clears sequence note + * events, and keeps all other structural keys intact. + * + * The payload is parsed with `parseLossless` so every number is carried as a + * `{__raw__: ""}` tag — this preserves the format's float tokens + * (`1.0`, `0.0`, …) that a plain `JSON.parse`/`JSON.stringify` round-trip would + * destroy. The caller serialises the result with `stringifyLossless`. + * + * @param {string} rawJsonStr - the raw JSON payload (after the 5 header lines) + * @returns {object} skeleton tree (numbers are `{__raw__}` tags) + */ +function generateSkeleton(rawJsonStr) { + const skeleton = parseLossless(rawJsonStr); + + const instruments = skeleton.data.tracks[0].program.drum.instruments; + + // Find a truly blank instrument to use as the blank template. + // Clone with structuredClone (NOT JSON round-trip) so the `{__raw__}` number + // tags — and therefore the float lexemes — are preserved. + let blankInstrument = null; + for (const inst of instruments) { + const layers = inst.layersv; + const isEmpty = + !layers || layers.length === 0 || (!layers[0].sampleFile && !layers[0].sampleName); + if (isEmpty) { + blankInstrument = structuredClone(inst); + break; + } + } + + if (!blankInstrument) { + // Fallback: use the last instrument and blank it manually + blankInstrument = structuredClone(instruments[instruments.length - 1]); + } + + // Ensure blank instrument has empty sample fields + if (blankInstrument.layersv?.[0]) { + blankInstrument.layersv[0].sampleName = ""; + blankInstrument.layersv[0].sampleFile = ""; + } + + // Reset all 128 instruments to the blank template + for (let i = 0; i < instruments.length; i++) { + instruments[i] = structuredClone(blankInstrument); + } + + // Clear samples arrays + skeleton.data.samples = []; + skeleton.data.tracks[0].samples = []; + + // Clear sequence note/midi events + const sequences = skeleton.data.sequences; + if (Array.isArray(sequences)) { + for (const seq of sequences) { + // Handle the { key, value } wrapper structure + const seqData = seq.value || seq; + if (seqData && Array.isArray(seqData.tracks)) { + for (const track of seqData.tracks) { + if ("events" in track) track.events = []; + if ("noteEvents" in track) track.noteEvents = []; + if ("midiEvents" in track) track.midiEvents = []; + } + } + } + } + + return skeleton; +} + +// ---- File operations ------------------------------------------------------ + +/** + * Copy WAV files for a kit, returning total bytes copied. + * @param {object} kit - kit definition + * @param {string[]} fileNames - list of unique WAV filenames to copy + * @returns {{ copiedCount: number, totalBytes: number, missing: string[] }} + */ +function copyWavFiles(kit, fileNames) { + const projectDataDir = join(PROJECTS_DIR, `${kit.sourceBase}_[ProjectData]`); + const destDir = join(PUBLIC_KITS_DIR, kit.id); + mkdirSync(destDir, { recursive: true }); + + let copiedCount = 0; + let totalBytes = 0; + const missing = []; + + for (const fileName of fileNames) { + const srcPath = join(projectDataDir, fileName); + const destPath = join(destDir, fileName); + + if (!existsSync(srcPath)) { + missing.push(fileName); + console.warn(` WARN: missing source WAV: ${srcPath}`); + continue; + } + + copyFileSync(srcPath, destPath); + const size = statSync(destPath).size; + totalBytes += size; + copiedCount++; + } + + return { copiedCount, totalBytes, missing }; +} + +// ---- Main ----------------------------------------------------------------- + +async function main() { + console.log("build-kits: starting...\n"); + + let grandTotalBytes = 0; + /** @type {Array<{id: string, displayName: string, padCount: number}>} */ + const registryEntries = []; + + for (const kit of KIT_DEFS) { + const xpjPath = join(PROJECTS_DIR, `${kit.sourceBase}.xpj`); + + if (!existsSync(xpjPath)) { + console.error(`ERROR: .xpj not found: ${xpjPath}`); + process.exit(1); + } + + console.log(`Processing kit: ${kit.displayName} (${kit.id})`); + console.log(` source: ${xpjPath}`); + + // Parse .xpj + let content; + try { + content = await readXpjFile(xpjPath); + } catch (err) { + console.error(`ERROR reading ${xpjPath}:`, err.message); + process.exit(1); + } + + let obj; + try { + ({ obj } = parseXpj(content)); + } catch (err) { + console.error(`ERROR parsing JSON from ${xpjPath}:`, err.message); + process.exit(1); + } + + // Extract pads + const pads = extractPads(kit.id, obj); + console.log(` pads found: ${pads.length}`); + + // Collect unique file names (a file can theoretically be referenced + // by multiple pads, though uncommon) + const uniqueFileNames = [...new Set(pads.map((p) => p.fileName))]; + + // Copy WAV files + const { copiedCount, totalBytes, missing } = copyWavFiles(kit, uniqueFileNames); + grandTotalBytes += totalBytes; + + if (missing.length > 0) { + console.warn(` WARN: ${missing.length} referenced WAV(s) not found in ProjectData`); + } + + console.log(` copied: ${copiedCount} WAV(s), ${(totalBytes / 1024).toFixed(1)} KB`); + + // Build manifest (KitManifest = SampleKit) + /** @type {import('../src/kits/kit.types').SampleKit} */ + const manifest = { + id: kit.id, + displayName: kit.displayName, + exportName: kit.exportName, + key: kit.key, + bpm: kit.bpm, + pads, + }; + + // Write manifest.json + const manifestPath = join(PUBLIC_KITS_DIR, kit.id, "manifest.json"); + writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf-8"); + console.log(` wrote: ${manifestPath}`); + + // Build registry entry + registryEntries.push({ + id: kit.id, + displayName: kit.displayName, + padCount: pads.length, + }); + + console.log(); + } + + // Write index.json + const indexPath = join(PUBLIC_KITS_DIR, "index.json"); + writeFileSync(indexPath, JSON.stringify(registryEntries, null, 2), "utf-8"); + console.log(`Wrote kit registry: ${indexPath}`); + console.log(` entries: ${registryEntries.map((e) => `${e.id}(${e.padCount})`).join(", ")}`); + console.log(); + + // Generate template.skeleton.json from project.xpj + const projectXpjPath = join(PROJECTS_DIR, "project.xpj"); + if (!existsSync(projectXpjPath)) { + console.error(`ERROR: project.xpj not found: ${projectXpjPath}`); + process.exit(1); + } + + console.log("Generating template.skeleton.json from project.xpj..."); + let projectContent; + try { + projectContent = await readXpjFile(projectXpjPath); + } catch (err) { + console.error("ERROR reading project.xpj:", err.message); + process.exit(1); + } + + // Extract the raw JSON payload (everything after the 5 header lines) so it + // can be parsed losslessly — preserving the float tokens that the firmware + // requires. + const projectJsonStr = projectContent.split("\n").slice(5).join("\n"); + + const skeleton = generateSkeleton(projectJsonStr); + const skeletonJson = stringifyLossless(skeleton); + writeFileSync(SKELETON_PATH, skeletonJson, "utf-8"); + const skeletonSize = statSync(SKELETON_PATH).size; + console.log(`Wrote skeleton: ${SKELETON_PATH} (${(skeletonSize / 1024).toFixed(1)} KB)`); + + // Verify skeleton blanking (plain JSON.parse is fine for these checks) + const skelObj = JSON.parse(skeletonJson); + const skelInstruments = skelObj.data.tracks[0].program.drum.instruments; + const populatedAfterBlank = skelInstruments.filter( + (inst) => inst.layersv?.[0]?.sampleFile, + ).length; + const skelSamplesLen = skelObj.data.samples.length; + + // Verify float tokens survived (regression guard for the "parameter length" + // hardware load failure). A real project.xpj has tens of thousands of `N.0` + // float tokens; a JSON round-trip strips them all to bare integers. + const floatTokenCount = (skeletonJson.match(/:-?\d+\.0\b/g) || []).length; + console.log( + ` Verification: ${populatedAfterBlank} populated pads (expected 0), ${skelSamplesLen} samples (expected 0), ${floatTokenCount} integer-float tokens (expected > 10000)`, + ); + + if (populatedAfterBlank !== 0 || skelSamplesLen !== 0) { + console.error("ERROR: skeleton blanking verification failed!"); + process.exit(1); + } + + if (floatTokenCount < 10000) { + console.error( + `ERROR: skeleton float-token verification failed — only ${floatTokenCount} "N.0" tokens found. ` + + `Float formatting was lost; the exported .xpj would be rejected by the MPC.`, + ); + process.exit(1); + } + + console.log(); + console.log("=".repeat(60)); + console.log("Summary:"); + for (const entry of registryEntries) { + console.log(` ${entry.displayName.padEnd(20)} (${entry.id}): ${entry.padCount} pads`); + } + console.log(` Total WAV data copied: ${(grandTotalBytes / (1024 * 1024)).toFixed(2)} MB`); + console.log(` Skeleton size: ${(skeletonSize / 1024).toFixed(1)} KB`); + console.log("build-kits: done."); +} + +main().catch((err) => { + console.error("FATAL:", err); + process.exit(1); +}); diff --git a/src/App.tsx b/src/App.tsx new file mode 100644 index 0000000..64e84a2 --- /dev/null +++ b/src/App.tsx @@ -0,0 +1,49 @@ +import { useEffect, useState } from "react"; +import { HUD } from "./components/HUD"; +import { KitEditor } from "./components/KitEditor"; +import { Launcher } from "./components/Launcher"; +import { MPCDevice } from "./components/MPCDevice"; +import { StartOverlay } from "./components/StartOverlay"; +import { TweaksPanel } from "./components/TweaksPanel"; +import { ZoomControls } from "./components/ZoomControls"; +import { isDesktop } from "./desktop/bridge"; +import { useAudioEngine } from "./hooks/useAudioEngine"; +import { useKeyboardInput } from "./hooks/useKeyboardInput"; +import { useKitLoader } from "./hooks/useKitLoader"; +import { useMidiInput } from "./hooks/useMidiInput"; +import { useMPCStore } from "./state/store"; + +export function App() { + const audio = useAudioEngine(); + const midi = useMidiInput(); + useKeyboardInput(true); + useKitLoader(audio.isReady); + + useEffect(() => { + const handleStop = () => useMPCStore.getState().stopAll(); + window.addEventListener("mpc:transport-stop", handleStop); + return () => window.removeEventListener("mpc:transport-stop", handleStop); + }, []); + + // Launcher state: shown in Electron until the user picks a kit. + // The Launcher is never rendered in the browser build. + const [kitChosen, setKitChosen] = useState(false); + const showLauncher = isDesktop() && !kitChosen; + + const handleStart = async () => { + await audio.start(); + await midi.start(); + }; + + return ( + <> + {showLauncher && setKitChosen(true)} />} + + + + + + + + ); +} diff --git a/src/audio/SampleEngine.ts b/src/audio/SampleEngine.ts new file mode 100644 index 0000000..522cd74 --- /dev/null +++ b/src/audio/SampleEngine.ts @@ -0,0 +1,471 @@ +import * as Tone from "tone"; +import { useMPCStore } from "../state/store"; +import type { + AudioEngineLike, + KitName, + KnobName, + PadIndex, + SampleId, + SampleKit, + SamplePad, +} from "../types/mpc.types"; + +/** Slim wrapper around a Tone.Player for one-shot drum hits. */ +type PadPlayer = { + player: Tone.Player; + gainNode: Tone.Gain; +}; + +const PREFETCH_CONCURRENCY = 6; + +/** + * SampleEngine — sample-based playback engine implementing `AudioEngineLike`. + * + * Audio graph: + * per-pad Tone.Player → per-pad Tone.Gain (velocity + gainCoefficient) + * → master Tone.Gain → Tone.Waveform(1024) + Tone.FFT(1024) → destination + * + * Design principles: + * - Lazy buffer load: buffers are only fetched on first `trigger` for that pad. + * - Inflight deduplication: concurrent triggers on the same unloaded pad share + * a single fetch Promise; the buffer is stored once and used by all. + * - StrictMode / HMR safety: `start()` is idempotent; `dispose()` is thorough. + * - Per-pad Tone.Player: created on demand at first trigger, reused on retrigger. + */ +export class SampleEngine implements AudioEngineLike { + private master: Tone.Gain | null = null; + private waveform: Tone.Waveform | null = null; + private fft: Tone.FFT | null = null; + private ready = false; + + /** Decoded audio buffers keyed by SampleId. */ + private buffers = new Map(); + + /** + * In-flight fetch promises keyed by SampleId. + * Ensures concurrent triggers on the same unloaded pad share a single fetch. + */ + private inflight = new Map>(); + + /** Current kit pad assignments (globalPadIdx → SamplePad). */ + private padMap = new Map(); + + /** Per-pad Tone.Player + gain nodes (created lazily on first trigger). */ + private padPlayers = new Map(); + + /** Set of pad indices whose buffers are currently being fetched/decoded. */ + private loading = new Set(); + + async start(): Promise { + if (this.ready) return; + await Tone.start(); + this.master = new Tone.Gain(Tone.dbToGain(-6)).toDestination(); + this.waveform = new Tone.Waveform(1024); + this.master.connect(this.waveform); + this.fft = new Tone.FFT(2048); + this.master.connect(this.fft); + this.ready = true; + } + + isReady(): boolean { + return this.ready; + } + + /** + * Load a SampleKit: clear pad assignments and populate from kit.pads. + * Lazy — no buffers are fetched here. + */ + async loadKit(kit: SampleKit): Promise { + // Dispose per-pad players for slots that are changing, to avoid + // stale player references after a kit switch. + for (const [idx, pp] of this.padPlayers) { + if (!kit.pads.some((p) => p.globalPadIdx === idx)) { + pp.player.stop(); + pp.player.dispose(); + pp.gainNode.dispose(); + } + } + this.padMap.clear(); + this.padPlayers.clear(); + this.loading.clear(); + + for (const pad of kit.pads) { + this.padMap.set(pad.globalPadIdx, { ...pad }); + } + } + + setPadSample(idx: PadIndex, pad: SamplePad | null): void { + if (pad === null) { + this.padMap.delete(idx); + const pp = this.padPlayers.get(idx); + if (pp) { + try { + pp.player.stop(); + pp.player.dispose(); + pp.gainNode.dispose(); + } catch { + // ignore — may already be disposed + } + this.padPlayers.delete(idx); + } + } else { + this.padMap.set(idx, { ...pad }); + const pp = this.padPlayers.get(idx); + if (pp) { + try { + pp.player.stop(); + pp.player.dispose(); + pp.gainNode.dispose(); + } catch { + // ignore + } + this.padPlayers.delete(idx); + } + } + } + + setPadTune(idx: PadIndex, coarseTune: number, fineTune: number): void { + const existing = this.padMap.get(idx); + if (!existing) return; + this.padMap.set(idx, { ...existing, coarseTune, fineTune }); + const pp = this.padPlayers.get(idx); + if (pp) { + pp.player.playbackRate = this.computePlaybackRate(coarseTune, fineTune); + } + } + + setPadGain(idx: PadIndex, gainCoefficient: number): void { + const existing = this.padMap.get(idx); + if (!existing) return; + this.padMap.set(idx, { ...existing, gainCoefficient }); + const pp = this.padPlayers.get(idx); + if (pp) { + pp.gainNode.gain.value = gainCoefficient; + } + } + + isPadLoading(idx: PadIndex): boolean { + return this.loading.has(idx); + } + + /** + * Trigger pad at `idx` (GlobalPadIdx, 0..127) with `velocity` in [0,1]. + * + * - If the buffer is already loaded: play immediately. + * - If not yet loaded: mark pad as loading, kick off the fetch, and + * play-on-resolve so the first tap still produces sound (with ~network delay). + * - Concurrent triggers while loading share the same inflight promise (deduped). + */ + trigger(idx: PadIndex, velocity: number, time?: number): void { + if (!this.ready || !this.master) return; + const pad = this.padMap.get(idx); + if (!pad) return; + + const clampedVelocity = Math.max(0.01, Math.min(1, velocity)); + const buf = this.buffers.get(pad.sampleId); + + if (buf) { + // Buffer ready — play synchronously. + try { + this.playBuffer(idx, pad, buf, clampedVelocity, time); + } catch (e) { + console.warn("SampleEngine trigger error", e); + } + return; + } + + // Buffer not yet loaded. + if (!this.loading.has(idx)) { + this.loading.add(idx); + useMPCStore.getState().setPadLoading(idx, true); + } + + this.ensureBuffer(pad) + .then((loadedBuf) => { + this.loading.delete(idx); + useMPCStore.getState().setPadLoading(idx, false); + // Play-on-resolve: use Tone.now() since the scheduled time may be stale. + try { + this.playBuffer(idx, pad, loadedBuf, clampedVelocity, undefined); + } catch (e) { + console.warn("SampleEngine play-on-resolve error", e); + } + }) + .catch((err) => { + this.loading.delete(idx); + useMPCStore.getState().setPadLoading(idx, false); + console.warn(`SampleEngine: failed to load sample "${pad.sampleId}"`, err); + }); + } + + release(_idx: PadIndex): void { + // One-shot samples — no sustained release needed. API completeness only. + } + + stopAll(): void { + for (const [, pp] of this.padPlayers) { + try { + pp.player.stop(); + } catch { + // ignore — player may already be stopped or disposed + } + } + } + + /** + * Eagerly fetch and decode all sample URLs in the currently loaded kit. + * Uses a sliding window of `PREFETCH_CONCURRENCY` concurrent fetches. + * Imported samples (url === null) that are already buffered are skipped. + */ + async prefetchAll(onProgress?: (loaded: number, total: number) => void): Promise { + const pads = [...this.padMap.values()]; + + // Only pads that need network fetching. + const toFetch = pads.filter((p) => !this.buffers.has(p.sampleId) && p.url !== null); + + const total = pads.length; + let loaded = pads.length - toFetch.length; // already-buffered count + + if (toFetch.length === 0) { + onProgress?.(total, total); + return; + } + + // Sliding-window concurrency. + let queueIdx = 0; + + async function runOne(engine: SampleEngine, pad: SamplePad): Promise { + await engine.ensureBuffer(pad); + loaded += 1; + onProgress?.(loaded, total); + } + + async function worker(engine: SampleEngine): Promise { + while (queueIdx < toFetch.length) { + const pad = toFetch[queueIdx++]; + await runOne(engine, pad); + } + } + + const workers = Array.from({ length: Math.min(PREFETCH_CONCURRENCY, toFetch.length) }, () => + worker(this), + ); + await Promise.all(workers); + } + + /** + * Decode raw WAV bytes and register them under `sampleId` for immediate + * playback. Called after the user drag-drops a `.wav` file. + */ + async registerImportedSample(sampleId: SampleId, bytes: Uint8Array): Promise { + // Copy the bytes into a fresh ArrayBuffer to avoid detached-buffer issues. + const copy = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength); + const audioCtx = Tone.getContext().rawContext as AudioContext; + const decoded = await audioCtx.decodeAudioData(copy as ArrayBuffer); + const buf = new Tone.ToneAudioBuffer(decoded); + this.buffers.set(sampleId, buf); + } + + getWaveform(): Float32Array | null { + if (!this.waveform) return null; + return this.waveform.getValue() as Float32Array; + } + + getSpectrum(): Float32Array | null { + if (!this.fft) return null; + return this.fft.getValue() as Float32Array; + } + + getPadChannelData(idx: PadIndex): Float32Array | null { + const pad = this.padMap.get(idx); + if (!pad) return null; + const buf = this.buffers.get(pad.sampleId); + if (!buf) return null; + try { + const audioBuffer = buf.get(); + if (!audioBuffer) return null; + return audioBuffer.getChannelData(0); + } catch { + return null; + } + } + + setMasterDb(db: number): void { + if (this.master) this.master.gain.rampTo(Tone.dbToGain(db), 0.05); + } + + setBpm(bpm: number): void { + Tone.getTransport().bpm.value = bpm; + } + + setKnob(name: KnobName, v: number): void { + // mainVol maps to master volume; k1/k2/k3 are reserved for future FX. + if (name === "mainVol") this.setMasterDb(-40 + v * 46); + } + + /** @deprecated Synth kits retired; this is a no-op on SampleEngine. */ + setKit(_kit: KitName): void { + // no-op — kits are now sample-based, loaded via loadKit(SampleKit). + } + + /** + * Swap the sample assignments of two pads. Replicates the legacy + * `swapPadVoice` behaviour but operates on the sample padMap. + */ + swapPadVoice(idxA: PadIndex, idxB: PadIndex): void { + const a = this.padMap.get(idxA); + const b = this.padMap.get(idxB); + if (a) { + this.padMap.set(idxB, a); + } else { + this.padMap.delete(idxB); + } + if (b) { + this.padMap.set(idxA, b); + } else { + this.padMap.delete(idxA); + } + const ppA = this.padPlayers.get(idxA); + const ppB = this.padPlayers.get(idxB); + if (ppA) { + this.padPlayers.set(idxB, ppA); + } else { + this.padPlayers.delete(idxB); + } + if (ppB) { + this.padPlayers.set(idxA, ppB); + } else { + this.padPlayers.delete(idxA); + } + } + + dispose(): void { + for (const [, pp] of this.padPlayers) { + try { + pp.player.stop(); + pp.player.dispose(); + pp.gainNode.dispose(); + } catch { + // ignore — already disposed + } + } + this.padPlayers.clear(); + + for (const [, buf] of this.buffers) { + try { + buf.dispose(); + } catch { + // ignore + } + } + this.buffers.clear(); + this.inflight.clear(); + this.padMap.clear(); + this.loading.clear(); + + try { + this.waveform?.dispose(); + } catch { + // ignore + } + this.waveform = null; + try { + this.fft?.dispose(); + } catch { + // ignore + } + this.fft = null; + try { + this.master?.dispose(); + } catch { + // ignore + } + this.master = null; + this.ready = false; + } + + /** + * Ensure a buffer is available for the given pad. Returns the buffer once + * decoded. Uses the `inflight` map to deduplicate concurrent fetches for + * the same `sampleId`. + */ + private ensureBuffer(pad: SamplePad): Promise { + const existing = this.buffers.get(pad.sampleId); + if (existing) return Promise.resolve(existing); + + const inFlight = this.inflight.get(pad.sampleId); + if (inFlight) return inFlight; + + if (pad.url === null) { + // Imported sample — must have been registered via registerImportedSample. + // If the buffer is missing, we cannot load it from a URL. + console.warn(`SampleEngine: imported sample "${pad.sampleId}" not yet registered.`); + return Promise.reject(new Error(`Missing imported sample buffer for "${pad.sampleId}"`)); + } + + const fetchPromise: Promise = fetch(pad.url) + .then((res) => { + if (!res.ok) { + throw new Error(`SampleEngine: HTTP ${res.status} fetching "${pad.url}"`); + } + return res.arrayBuffer(); + }) + .then((arrayBuf) => { + const audioCtx = Tone.getContext().rawContext as AudioContext; + return audioCtx.decodeAudioData(arrayBuf); + }) + .then((audioBuffer) => { + const toneBuf = new Tone.ToneAudioBuffer(audioBuffer); + this.buffers.set(pad.sampleId, toneBuf); + this.inflight.delete(pad.sampleId); + return toneBuf; + }) + .catch((err) => { + this.inflight.delete(pad.sampleId); + throw err; + }); + + this.inflight.set(pad.sampleId, fetchPromise); + return fetchPromise; + } + + /** + * Compute `playbackRate = 2^((coarseTune + fineTune / 100) / 12)`. + */ + private computePlaybackRate(coarseTune: number, fineTune: number): number { + return 2 ** ((coarseTune + fineTune / 100) / 12); + } + + /** + * Play a decoded buffer on the given pad, applying per-pad tune and gain. + * Creates or reuses a per-pad Tone.Player + Tone.Gain node pair. + */ + private playBuffer( + idx: PadIndex, + pad: SamplePad, + buf: Tone.ToneAudioBuffer, + velocity: number, + time: number | undefined, + ): void { + if (!this.master) return; + + let pp = this.padPlayers.get(idx); + + if (!pp) { + const gainNode = new Tone.Gain(pad.gainCoefficient * velocity).connect(this.master); + const player = new Tone.Player(buf).connect(gainNode); + player.playbackRate = this.computePlaybackRate(pad.coarseTune, pad.fineTune); + pp = { player, gainNode }; + this.padPlayers.set(idx, pp); + } else { + // Retrigger: update the buffer in case it changed (setPadSample), + // and update playback parameters. + pp.player.buffer = buf; + pp.player.playbackRate = this.computePlaybackRate(pad.coarseTune, pad.fineTune); + pp.gainNode.gain.value = pad.gainCoefficient * velocity; + } + + const playTime = time ?? Tone.now(); + pp.player.start(playTime); + } +} diff --git a/src/audio/__tests__/SampleEngine.test.ts b/src/audio/__tests__/SampleEngine.test.ts new file mode 100644 index 0000000..1429088 --- /dev/null +++ b/src/audio/__tests__/SampleEngine.test.ts @@ -0,0 +1,614 @@ +import * as Tone from "tone"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +// ── Tone mock ────────────────────────────────────────────────────────────────── +// Implementation factories must be regular functions (not arrows) so that +// vitest's vi.fn() wrapper supports `new`-construction (Vitest 4 quirk). + +function makeGain() { + return { + toDestination: vi.fn().mockReturnThis(), + connect: vi.fn().mockReturnThis(), + dispose: vi.fn(), + gain: { + value: 1, + rampTo: vi.fn(), + }, + }; +} + +function makeWaveform() { + return { + getValue: vi.fn().mockReturnValue(new Float32Array(1024)), + dispose: vi.fn(), + }; +} + +function makeFft() { + return { + getValue: vi.fn().mockReturnValue(new Float32Array(1024)), + dispose: vi.fn(), + }; +} + +function makePlayer() { + return { + connect: vi.fn().mockReturnThis(), + start: vi.fn(), + stop: vi.fn(), + dispose: vi.fn(), + playbackRate: 1, + buffer: null as unknown, + }; +} + +function makeToneAudioBuffer(audioBuffer?: AudioBuffer) { + return { + dispose: vi.fn(), + _audioBuffer: audioBuffer ?? null, + }; +} + +// Captured instances for assertion +let mockMasterInstance: ReturnType; +let mockWaveformInstance: ReturnType; +let mockFftInstance: ReturnType; + +const mockTransport = { bpm: { value: 120 } }; + +vi.mock("tone", () => ({ + Gain: vi.fn(function (this: unknown) { + mockMasterInstance = makeGain(); + return mockMasterInstance; + }), + Waveform: vi.fn(function (this: unknown) { + mockWaveformInstance = makeWaveform(); + return mockWaveformInstance; + }), + FFT: vi.fn(function (this: unknown) { + mockFftInstance = makeFft(); + return mockFftInstance; + }), + Player: vi.fn(function (this: unknown) { + return makePlayer(); + }), + ToneAudioBuffer: vi.fn(function (this: unknown, src: unknown) { + return makeToneAudioBuffer(src as AudioBuffer | undefined); + }), + start: vi.fn().mockResolvedValue(undefined), + now: vi.fn().mockReturnValue(0), + dbToGain: vi.fn((db: number) => 10 ** (db / 20)), + getTransport: vi.fn(() => mockTransport), + getContext: vi.fn(() => ({ + rawContext: { + decodeAudioData: vi.fn((buf: ArrayBuffer) => Promise.resolve(buf as unknown as AudioBuffer)), + }, + })), +})); + +// ── Store mock ───────────────────────────────────────────────────────────────── +// We need to intercept setPadLoading calls. +const mockSetPadLoading = vi.fn(); +vi.mock("../../state/store", () => ({ + useMPCStore: { + getState: vi.fn(() => ({ + setPadLoading: mockSetPadLoading, + })), + }, +})); + +// eslint-disable-next-line import/first +import type { SampleKit, SamplePad } from "../../types/mpc.types"; +// ── Helpers ──────────────────────────────────────────────────────────────────── +// eslint-disable-next-line import/first +import { SampleEngine } from "../SampleEngine"; + +function makeSamplePad(overrides: Partial = {}): SamplePad { + return { + globalPadIdx: 0, + sampleId: "kick.wav", + displayName: "Kick", + sampleName: "kick.wav", + fileName: "kick.wav", + url: "/kits/test/kick.wav", + coarseTune: 0, + fineTune: 0, + gainCoefficient: 1.0, + pan: 0.5, + ...overrides, + }; +} + +function makeKit(pads: SamplePad[] = [makeSamplePad()]): SampleKit { + return { + id: "test-kit", + displayName: "Test Kit", + exportName: "TestKit", + key: "C Minor", + bpm: 120, + pads, + }; +} + +// Mock fetch to return a minimal ArrayBuffer. +function mockFetch(ok = true): void { + const ab = new ArrayBuffer(4); + global.fetch = vi.fn().mockResolvedValue({ + ok, + status: ok ? 200 : 404, + statusText: ok ? "OK" : "Not Found", + arrayBuffer: vi.fn().mockResolvedValue(ab), + }); +} + +// ── Tests ────────────────────────────────────────────────────────────────────── + +describe("SampleEngine", () => { + let engine: SampleEngine; + + beforeEach(() => { + vi.clearAllMocks(); + mockTransport.bpm.value = 120; + engine = new SampleEngine(); + }); + + afterEach(() => { + try { + engine.dispose(); + } catch { + // already disposed + } + }); + + // ── Lifecycle ───────────────────────────────────────────────────────────────── + + describe("start()", () => { + it("is idempotent — calling start() twice does not reinitialise nodes", async () => { + await engine.start(); + await engine.start(); + expect(Tone.Gain).toHaveBeenCalledTimes(1); + expect(Tone.Waveform).toHaveBeenCalledTimes(1); + expect(Tone.FFT).toHaveBeenCalledTimes(1); + }); + + it("builds master Gain → Waveform → destination", async () => { + await engine.start(); + expect(engine.isReady()).toBe(true); + expect(Tone.Gain).toHaveBeenCalledTimes(1); + expect(Tone.Waveform).toHaveBeenCalledWith(1024); + // master.toDestination() was called + expect(mockMasterInstance.toDestination).toHaveBeenCalled(); + // master.connect(waveform) was called + expect( + mockMasterInstance.connect.mock.calls.some((c: unknown[]) => c[0] === mockWaveformInstance), + ).toBe(true); + }); + + it("creates Tone.FFT(2048) and connects master to it", async () => { + await engine.start(); + expect(Tone.FFT).toHaveBeenCalledWith(2048); + expect( + mockMasterInstance.connect.mock.calls.some((c: unknown[]) => c[0] === mockFftInstance), + ).toBe(true); + }); + + it("start() is idempotent — Tone.FFT not called twice", async () => { + await engine.start(); + await engine.start(); + expect(Tone.FFT).toHaveBeenCalledTimes(1); + }); + + it("isReady() is false before start()", () => { + expect(engine.isReady()).toBe(false); + }); + }); + + // ── loadKit ─────────────────────────────────────────────────────────────────── + + describe("loadKit()", () => { + it("populates padMap without fetching buffers", async () => { + await engine.start(); + mockFetch(); + const kit = makeKit(); + await engine.loadKit(kit); + + // No fetch should have been triggered — lazy. + expect(global.fetch).not.toHaveBeenCalled(); + // But the pad should be triggerable (will kick off a fetch). + expect(engine.isPadLoading(0)).toBe(false); + }); + + it("replaces a previous kit's pads", async () => { + await engine.start(); + const kit1 = makeKit([makeSamplePad({ globalPadIdx: 0 })]); + const kit2 = makeKit([makeSamplePad({ globalPadIdx: 5 })]); + await engine.loadKit(kit1); + await engine.loadKit(kit2); + // Pad 0 from kit1 should be gone; only pad 5 remains. + // Triggering pad 0 should be a no-op (no pad mapping). + mockFetch(); + await engine.start(); + engine.trigger(0, 0.9); + expect(global.fetch).not.toHaveBeenCalled(); + }); + }); + + // ── trigger ─────────────────────────────────────────────────────────────────── + + describe("trigger()", () => { + it("does nothing when engine is not ready", () => { + const kit = makeKit(); + void engine.loadKit(kit); + expect(() => engine.trigger(0, 0.9)).not.toThrow(); + }); + + it("plays immediately when buffer is already loaded", async () => { + await engine.start(); + mockFetch(); + const pad = makeSamplePad(); + const kit = makeKit([pad]); + await engine.loadKit(kit); + + // Pre-load the buffer by registering an imported sample. + const bytes = new Uint8Array([0, 1, 2, 3]); + await engine.registerImportedSample(pad.sampleId, bytes); + + const MockPlayer = vi.mocked(Tone.Player); + MockPlayer.mockClear(); + + engine.trigger(0, 0.8); + + // A Tone.Player should be created and started. + expect(MockPlayer).toHaveBeenCalledTimes(1); + const playerInst = MockPlayer.mock.results[0].value as { start: ReturnType }; + expect(playerInst.start).toHaveBeenCalled(); + }); + + it("marks pad as loading when buffer is missing and sets store flag", async () => { + await engine.start(); + // Simulate a long fetch by using a deferred promise. + let resolveFetch!: (v: Response) => void; + const ab = new ArrayBuffer(4); + global.fetch = vi.fn().mockReturnValue( + new Promise((res) => { + resolveFetch = res; + }), + ); + + const pad = makeSamplePad(); + const kit = makeKit([pad]); + await engine.loadKit(kit); + + engine.trigger(0, 0.9); + + expect(engine.isPadLoading(0)).toBe(true); + expect(mockSetPadLoading).toHaveBeenCalledWith(0, true); + + // Unblock the fetch. + resolveFetch({ + ok: true, + status: 200, + statusText: "OK", + arrayBuffer: () => Promise.resolve(ab), + } as unknown as Response); + }); + + it("deduplicates concurrent triggers — only one fetch per sampleId", async () => { + await engine.start(); + mockFetch(); + + const pad = makeSamplePad(); + const kit = makeKit([pad]); + await engine.loadKit(kit); + + // Trigger three times concurrently before the fetch resolves. + engine.trigger(0, 0.8); + engine.trigger(0, 0.7); + engine.trigger(0, 0.6); + + // Allow microtasks (fetch mock) to run. + await vi.waitFor(() => { + expect(mockSetPadLoading).toHaveBeenCalledWith(0, false); + }); + + // Only one fetch despite three triggers. + expect(global.fetch).toHaveBeenCalledTimes(1); + }); + + it("plays on resolve after lazy load", async () => { + await engine.start(); + mockFetch(); + + const pad = makeSamplePad(); + await engine.loadKit(makeKit([pad])); + + const MockPlayer = vi.mocked(Tone.Player); + MockPlayer.mockClear(); + + engine.trigger(0, 0.9); + + await vi.waitFor(() => { + expect(mockSetPadLoading).toHaveBeenCalledWith(0, false); + }); + + // After the buffer loaded, a player should have been started. + const allStarts = MockPlayer.mock.results.flatMap( + (r) => (r.value as { start: ReturnType }).start.mock.calls, + ); + expect(allStarts.length).toBeGreaterThan(0); + }); + }); + + // ── Playback rate ───────────────────────────────────────────────────────────── + + describe("playbackRate from coarse/fine tune", () => { + it("applies playbackRate = 2^((coarse + fine/100)/12)", async () => { + await engine.start(); + // 12 semitones = one octave = playbackRate 2. + const pad = makeSamplePad({ coarseTune: 12, fineTune: 0 }); + const bytes = new Uint8Array(4); + await engine.registerImportedSample(pad.sampleId, bytes); + await engine.loadKit(makeKit([pad])); + + const MockPlayer = vi.mocked(Tone.Player); + MockPlayer.mockClear(); + + engine.trigger(0, 1.0); + + expect(MockPlayer).toHaveBeenCalledTimes(1); + const playerInst = MockPlayer.mock.results[0].value as { + playbackRate: number; + }; + expect(playerInst.playbackRate).toBeCloseTo(2, 5); + }); + + it("applies fine tune (50 cents = ~3% speed increase)", async () => { + await engine.start(); + const pad = makeSamplePad({ coarseTune: 0, fineTune: 50 }); + const bytes = new Uint8Array(4); + await engine.registerImportedSample(pad.sampleId, bytes); + await engine.loadKit(makeKit([pad])); + + const MockPlayer = vi.mocked(Tone.Player); + MockPlayer.mockClear(); + engine.trigger(0, 1.0); + + const playerInst = MockPlayer.mock.results[0].value as { + playbackRate: number; + }; + const expected = 2 ** (0.5 / 12); + expect(playerInst.playbackRate).toBeCloseTo(expected, 5); + }); + }); + + // ── prefetchAll ─────────────────────────────────────────────────────────────── + + describe("prefetchAll()", () => { + it("loads all pad buffers and reports progress", async () => { + await engine.start(); + mockFetch(); + + const pads = [ + makeSamplePad({ globalPadIdx: 0, sampleId: "a.wav", url: "/a.wav" }), + makeSamplePad({ globalPadIdx: 1, sampleId: "b.wav", url: "/b.wav" }), + makeSamplePad({ globalPadIdx: 2, sampleId: "c.wav", url: "/c.wav" }), + ]; + await engine.loadKit(makeKit(pads)); + + const progress: Array<[number, number]> = []; + await engine.prefetchAll((loaded, total) => { + progress.push([loaded, total]); + }); + + expect(global.fetch).toHaveBeenCalledTimes(3); + // Final progress report should be 3/3. + const last = progress[progress.length - 1]; + expect(last).toEqual([3, 3]); + }); + + it("skips already-buffered samples in the progress total", async () => { + await engine.start(); + mockFetch(); + + const pads = [ + makeSamplePad({ globalPadIdx: 0, sampleId: "a.wav", url: "/a.wav" }), + makeSamplePad({ globalPadIdx: 1, sampleId: "b.wav", url: "/b.wav" }), + ]; + await engine.loadKit(makeKit(pads)); + + // Pre-load "a.wav". + await engine.registerImportedSample("a.wav", new Uint8Array(4)); + + const progress: Array<[number, number]> = []; + await engine.prefetchAll((loaded, total) => { + progress.push([loaded, total]); + }); + + // Only "b.wav" should be fetched. + expect(global.fetch).toHaveBeenCalledTimes(1); + const last = progress[progress.length - 1]; + expect(last[1]).toBe(2); // total = 2 pads + }); + }); + + // ── registerImportedSample ──────────────────────────────────────────────────── + + describe("registerImportedSample()", () => { + it("decodes bytes and makes the buffer available for playback", async () => { + await engine.start(); + + // Capture the decodeAudioData mock before calling registerImportedSample + // so we get the same reference used internally (getContext() returns a + // fresh object each call — we need to spy at the source). + const decodeAudioDataMock = vi.fn((buf: ArrayBuffer) => + Promise.resolve(buf as unknown as AudioBuffer), + ); + vi.mocked(Tone.getContext).mockReturnValue({ + rawContext: { decodeAudioData: decodeAudioDataMock }, + } as unknown as ReturnType); + + const bytes = new Uint8Array([82, 73, 70, 70]); // RIFF header stub + await engine.registerImportedSample("imported.wav", bytes); + + // Verify the buffer was decoded via decodeAudioData. + expect(decodeAudioDataMock).toHaveBeenCalled(); + + // The buffer should now be triggerable without a fetch. + const pad = makeSamplePad({ + sampleId: "imported.wav", + url: null, + }); + await engine.loadKit(makeKit([pad])); + engine.trigger(0, 0.9); + + // No fetch since buffer is registered. + expect(global.fetch).not.toHaveBeenCalled(); + }); + }); + + // ── Pad tuning / gain ───────────────────────────────────────────────────────── + + describe("setPadTune()", () => { + it("updates the stored pad's tune fields", async () => { + await engine.start(); + const pad = makeSamplePad({ coarseTune: 0, fineTune: 0 }); + await engine.loadKit(makeKit([pad])); + engine.setPadTune(0, 7, 50); + // No error thrown; next trigger will use updated tune values. + expect(() => engine.setPadTune(0, 7, 50)).not.toThrow(); + }); + + it("is a no-op for an unmapped pad", () => { + expect(() => engine.setPadTune(99, 5, 0)).not.toThrow(); + }); + }); + + describe("setPadGain()", () => { + it("updates the stored pad's gainCoefficient", async () => { + await engine.start(); + const pad = makeSamplePad({ gainCoefficient: 1.0 }); + await engine.loadKit(makeKit([pad])); + expect(() => engine.setPadGain(0, 0.5)).not.toThrow(); + }); + + it("is a no-op for an unmapped pad", () => { + expect(() => engine.setPadGain(99, 0.5)).not.toThrow(); + }); + }); + + // ── setMasterDb ─────────────────────────────────────────────────────────────── + + describe("setMasterDb()", () => { + it("calls master.gain.rampTo with dbToGain result and time 0.05", async () => { + await engine.start(); + engine.setMasterDb(-6); + expect(mockMasterInstance.gain.rampTo).toHaveBeenCalledWith(Tone.dbToGain(-6), 0.05); + }); + }); + + // ── setBpm ──────────────────────────────────────────────────────────────────── + + describe("setBpm()", () => { + it("sets Tone.getTransport().bpm.value", async () => { + await engine.start(); + engine.setBpm(140); + expect(mockTransport.bpm.value).toBe(140); + }); + }); + + // ── getWaveform ─────────────────────────────────────────────────────────────── + + describe("getWaveform()", () => { + it("returns null before start()", () => { + expect(engine.getWaveform()).toBeNull(); + }); + + it("returns Float32Array after start()", async () => { + await engine.start(); + const buf = engine.getWaveform(); + expect(buf).toBeInstanceOf(Float32Array); + }); + }); + + // ── getSpectrum ─────────────────────────────────────────────────────────────── + + describe("getSpectrum()", () => { + it("returns null before start()", () => { + expect(engine.getSpectrum()).toBeNull(); + }); + + it("returns Float32Array from FFT analyser after start()", async () => { + await engine.start(); + const result = engine.getSpectrum(); + expect(result).toBeInstanceOf(Float32Array); + expect(mockFftInstance.getValue).toHaveBeenCalled(); + }); + }); + + // ── swapPadVoice ────────────────────────────────────────────────────────────── + + describe("swapPadVoice()", () => { + it("exchanges the pad assignments of two indices", async () => { + await engine.start(); + const padA = makeSamplePad({ globalPadIdx: 0, sampleId: "a.wav" }); + const padB = makeSamplePad({ globalPadIdx: 1, sampleId: "b.wav" }); + await engine.loadKit(makeKit([padA, padB])); + + engine.swapPadVoice(0, 1); + + // After swap, triggering idx 0 should use b.wav, idx 1 should use a.wav. + // We can verify by checking isPadLoading after a trigger with a fetch mock. + mockFetch(); + engine.trigger(0, 0.9); // should try to load b.wav + engine.trigger(1, 0.9); // should try to load a.wav + + // Both fetches should be triggered for the swapped URLs. + await vi.waitFor(() => expect(global.fetch).toHaveBeenCalledTimes(2)); + }); + }); + + // ── setKit (legacy no-op) ───────────────────────────────────────────────────── + + describe("setKit()", () => { + it("is a no-op (does not throw)", async () => { + await engine.start(); + expect(() => engine.setKit("HIP-HOP")).not.toThrow(); + expect(() => engine.setKit("TRAP")).not.toThrow(); + }); + }); + + // ── release (no-op) ─────────────────────────────────────────────────────────── + + describe("release()", () => { + it("does not throw", () => { + expect(() => engine.release(0)).not.toThrow(); + }); + }); + + // ── dispose ─────────────────────────────────────────────────────────────────── + + describe("dispose()", () => { + it("tears down all nodes and resets ready state", async () => { + await engine.start(); + engine.dispose(); + expect(engine.isReady()).toBe(false); + expect(engine.getWaveform()).toBeNull(); + expect(mockWaveformInstance.dispose).toHaveBeenCalled(); + expect(mockMasterInstance.dispose).toHaveBeenCalled(); + }); + + it("disposes the FFT analyser", async () => { + await engine.start(); + engine.dispose(); + expect(mockFftInstance.dispose).toHaveBeenCalled(); + }); + + it("is idempotent — double dispose does not throw", async () => { + await engine.start(); + expect(() => { + engine.dispose(); + engine.dispose(); + }).not.toThrow(); + }); + }); +}); diff --git a/src/components/BankSelector.tsx b/src/components/BankSelector.tsx new file mode 100644 index 0000000..f2f465c --- /dev/null +++ b/src/components/BankSelector.tsx @@ -0,0 +1,73 @@ +import { useCallback } from "react"; +import { BANK_LABELS } from "../data/padLayout"; +import { useMPCStore } from "../state/store"; + +/** + * Segmented bank selector showing A–D always, E–H only when `maxBank >= 4`. + * + * Accessibility: + * - `role="group"` / `aria-label="Pad bank"` wraps all buttons. + * - Each button has an `aria-label` of "Bank A" etc. + * - Active bank button has `aria-pressed={true}`. + * - Full keyboard support via Tab/Enter/Space (native button behaviour). + * - Arrow-key navigation cycles within the visible bank set. + */ +export function BankSelector() { + const bankIdx = useMPCStore((s) => s.bankIdx); + const setBank = useMPCStore((s) => s.setBank); + + // Always show all 8 banks (A–H) so the user can navigate to any bank. + const visibleCount = 8; + + const handleClick = useCallback( + (idx: number) => { + setBank(idx); + }, + [setBank], + ); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "ArrowRight" || e.key === "ArrowDown") { + e.preventDefault(); + const next = Math.min(bankIdx + 1, visibleCount - 1); + setBank(next); + // Move DOM focus to the newly active button. + const group = e.currentTarget; + const buttons = group.querySelectorAll("button"); + buttons[next]?.focus(); + } else if (e.key === "ArrowLeft" || e.key === "ArrowUp") { + e.preventDefault(); + const prev = Math.max(bankIdx - 1, 0); + setBank(prev); + const group = e.currentTarget; + const buttons = group.querySelectorAll("button"); + buttons[prev]?.focus(); + } + }, + [bankIdx, setBank], + ); + + return ( +
+ Bank +
+ {BANK_LABELS.slice(0, visibleCount).map((label, idx) => { + const isActive = idx === bankIdx; + return ( + + ); + })} +
+
+ ); +} diff --git a/src/components/DataEncoder.tsx b/src/components/DataEncoder.tsx new file mode 100644 index 0000000..f261615 --- /dev/null +++ b/src/components/DataEncoder.tsx @@ -0,0 +1,96 @@ +import { useCallback, useEffect, useRef } from "react"; +import "../styles/controls.css"; +import { useMPCStore } from "../state/store"; + +export function DataEncoder() { + const value = useMPCStore((s) => s.knobs.dataEnc); + const setKnob = useMPCStore((s) => s.setKnob); + + // value is cumulative turns; convert to degrees for display + const rotDeg = value * 360; + + const dragStartY = useRef(null); + const dragStartVal = useRef(0); + const encoderRef = useRef(null); + + const handlePointerDown = useCallback( + (e: React.PointerEvent) => { + e.preventDefault(); + dragStartY.current = e.clientY; + dragStartVal.current = value; + (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId); + }, + [value], + ); + + const handlePointerMove = useCallback( + (e: React.PointerEvent) => { + if (dragStartY.current === null) return; + const delta = (dragStartY.current - e.clientY) / 200; + setKnob("dataEnc", dragStartVal.current + delta); + }, + [setKnob], + ); + + const handlePointerUp = useCallback(() => { + dragStartY.current = null; + }, []); + + // Wheel: deltaY * -0.5 degrees → convert to turns (/360) + useEffect(() => { + const el = encoderRef.current; + if (!el) return; + const onWheel = (e: WheelEvent) => { + e.preventDefault(); + const cur = useMPCStore.getState().knobs.dataEnc; + // deltaY * -0.5 degrees = deltaY * -0.5 / 360 turns + const delta = (e.deltaY * -0.5) / 360; + setKnob("dataEnc", cur + delta); + }; + el.addEventListener("wheel", onWheel, { passive: false }); + return () => el.removeEventListener("wheel", onWheel); + }, [setKnob]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + let handled = true; + const cur = useMPCStore.getState().knobs.dataEnc; + // 5° per step = 5/360 turns + switch (e.key) { + case "ArrowUp": + setKnob("dataEnc", cur + 5 / 360); + break; + case "ArrowDown": + setKnob("dataEnc", cur - 5 / 360); + break; + default: + handled = false; + } + if (handled) e.preventDefault(); + }, + [setKnob], + ); + + const displayDeg = Math.round(((rotDeg % 360) + 360) % 360); + + return ( +
+ ); +} diff --git a/src/components/DisplayPanel.tsx b/src/components/DisplayPanel.tsx new file mode 100644 index 0000000..b183993 --- /dev/null +++ b/src/components/DisplayPanel.tsx @@ -0,0 +1,48 @@ +import type { AudioEngineLike } from "../types/mpc.types"; +import { Knob } from "./Knob"; +import { Screen } from "./Screen"; + +type DisplayPanelProps = { + engine: AudioEngineLike | null; +}; + +export function DisplayPanel({ engine }: DisplayPanelProps) { + return ( +
+ {/* Logo area */} +
+
+ AKAIprofessional +
+
MPC
+
+ + {/* Top utility buttons */} +
+
+ + {/* Main volume knob */} +
+ +
MAIN VOLUME
+
+ + {/* Screen */} + + + {/* Speaker grille */} + + ); +} diff --git a/src/components/EraseButtons.tsx b/src/components/EraseButtons.tsx new file mode 100644 index 0000000..cfc617d --- /dev/null +++ b/src/components/EraseButtons.tsx @@ -0,0 +1,22 @@ +import "../styles/controls.css"; + +export function EraseButtons() { + return ( +
+
+ +
COPY
+
+
+ +
TRIPLET
+
+
+ ); +} diff --git a/src/components/ExportButton.tsx b/src/components/ExportButton.tsx new file mode 100644 index 0000000..a73b6c1 --- /dev/null +++ b/src/components/ExportButton.tsx @@ -0,0 +1,512 @@ +/** + * ExportButton.tsx — "EXPORT .XPJ" button with accessible progress dialog. + * + * Reads `activeKit` and `userSamples` from the store. On click: + * 1. Opens an aria-modal progress dialog + * 2. Browser: runs `exportKitToZip` and triggers a ZIP download + * 3. Desktop: runs `exportKitToDisk` and writes unzipped files to the SD card + * 4. Shows error messages (abort, empty kit, missing sample, ENOENT, EEXIST) + * 5. Provides a Cancel button that aborts via AbortController + * + * Desktop overwrite: when the project already exists on disk, an in-dialog + * yes/no confirmation is shown (no `window.confirm`). + * + * Accessibility: + * - Dialog: role="dialog", aria-modal, aria-labelledby, aria-busy while running + * - Progress: aria-live="polite" region announcing phase + count + * - Focus trap: Tab cycles within the dialog; Escape cancels/closes + * - Focus restore: returns focus to the trigger button on close + * - Button: aria-disabled + tooltip when no kit loaded + */ + +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { createPortal } from "react-dom"; +import { desktop, isDesktop } from "../desktop/bridge"; +import { exportKitToDisk } from "../desktop/exportToDisk"; +import { buildExportKit, useMPCStore } from "../state/store"; +import { type ExportProgress, exportKitToZip, triggerDownload } from "../xpj/exportKit"; +import "../styles/export.css"; + +const FOCUSABLE_SELECTORS = + 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; + +function getFocusable(container: HTMLElement): HTMLElement[] { + return Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS)); +} + +function phaseLabel(phase: ExportProgress["phase"]): string { + switch (phase) { + case "fetching": + return "Fetching samples…"; + case "building": + return "Building .xpj…"; + case "zipping": + return "Zipping archive…"; + case "done": + return "Done!"; + default: + return ""; + } +} + +function errorCode(err: unknown): string | undefined { + if ( + typeof err === "object" && + err !== null && + "code" in err && + typeof (err as Record).code === "string" + ) { + return (err as Record).code; + } + return undefined; +} + +export function ExportButton() { + const activeKit = useMPCStore((s) => s.activeKit); + const padMap = useMPCStore((s) => s.padMap); + const userSamples = useMPCStore((s) => s.userSamples); + const setExporting = useMPCStore((s) => s.setExporting); + const setExportProgress = useMPCStore((s) => s.setExportProgress); + const dialogPosition = useMPCStore((s) => s.dialogPosition); + const autoOpenExportFolder = useMPCStore((s) => s.autoOpenExportFolder); + const unmountAfterExport = useMPCStore((s) => s.unmountAfterExport); + + // Derive the kit to export from the live padMap (source of truth). + // activeKit.pads is a one-time snapshot set by loadKit; padMap reflects all + // subsequent drops, swaps, moves, and customisations. + const exportKit = useMemo(() => buildExportKit(activeKit, padMap), [activeKit, padMap]); + + const [dialogOpen, setDialogOpen] = useState(false); + const [running, setRunning] = useState(false); + const [progress, setProgress] = useState(null); + const [errorMsg, setErrorMsg] = useState(null); + const [succeeded, setSucceeded] = useState(false); + const [successPath, setSuccessPath] = useState(null); + const [ejectPhase, setEjectPhase] = useState<"idle" | "ejecting" | "ejected" | "error">("idle"); + const [ejectError, setEjectError] = useState(null); + const [projectName, setProjectName] = useState("New Project"); + + // In-dialog overwrite confirmation state (desktop only) + const [overwriteConfirm, setOverwriteConfirm] = useState<{ + projectName: string; + resolve: (v: boolean) => void; + } | null>(null); + + // AbortController ref for cancellation + const abortRef = useRef(null); + // Trigger button ref for focus restore + const triggerRef = useRef(null); + // Dialog container ref for focus trap + const dialogRef = useRef(null); + // Primary action button ref (receives focus on dialog open) + const primaryBtnRef = useRef(null); + + // exportKit is non-null only when padMap has at least one populated pad. + const hasKit = exportKit !== null; + + const openDialog = useCallback(() => { + setDialogOpen(true); + setRunning(false); + setProgress(null); + setErrorMsg(null); + setSucceeded(false); + setSuccessPath(null); + setOverwriteConfirm(null); + setEjectPhase("idle"); + setEjectError(null); + setProjectName(exportKit?.exportName?.trim() || "New Project"); + }, [exportKit]); + + const closeDialog = useCallback(() => { + setDialogOpen(false); + // Restore focus to trigger button + setTimeout(() => triggerRef.current?.focus(), 0); + }, []); + + const handleCancel = useCallback(() => { + abortRef.current?.abort(); + if (!running) closeDialog(); + }, [running, closeDialog]); + + const handleDialogKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Escape") { + e.stopPropagation(); + handleCancel(); + return; + } + if (e.key === "Tab") { + const el = dialogRef.current; + if (!el) return; + const focusable = getFocusable(el); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey) { + if (document.activeElement === first) { + e.preventDefault(); + last.focus(); + } + } else { + if (document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + } + } + }, + [handleCancel], + ); + + useEffect(() => { + if (dialogOpen) { + const id = setTimeout(() => primaryBtnRef.current?.focus(), 50); + return () => clearTimeout(id); + } + return undefined; + }, [dialogOpen]); + + const handleExport = useCallback(async () => { + if (!exportKit || running) return; + // Apply the user-entered project name + const namedKit = { ...exportKit, exportName: projectName.trim() || "New Project" }; + + const controller = new AbortController(); + abortRef.current = controller; + + setRunning(true); + setErrorMsg(null); + setSucceeded(false); + setSuccessPath(null); + setOverwriteConfirm(null); + setExporting(true); + + const onProgress = (p: ExportProgress) => { + setProgress(p); + setExportProgress({ loaded: p.loaded, total: p.total }); + }; + + try { + if (isDesktop()) { + const onNeedOverwrite = (projectName: string): Promise => + new Promise((resolve) => { + setOverwriteConfirm({ projectName, resolve }); + }); + + const result = await exportKitToDisk(namedKit, userSamples, { + signal: controller.signal, + onProgress, + onNeedOverwrite, + }); + + if (!controller.signal.aborted) { + setSuccessPath(result.written); + setSucceeded(true); + setProgress(null); + setOverwriteConfirm(null); + if (autoOpenExportFolder) { + const exportDir = result.written.replace(/[/\\][^/\\]+$/, ""); + void desktop() + .openPath(exportDir) + .catch(() => undefined); + } + if (unmountAfterExport) { + setEjectPhase("ejecting"); + void desktop() + .ejectVolume() + .then(() => { + setEjectPhase("ejected"); + }) + .catch((err: unknown) => { + setEjectPhase("error"); + setEjectError(err instanceof Error ? err.message : "Failed to eject volume."); + }); + } + } + } else { + const result = await exportKitToZip(namedKit, userSamples, { + signal: controller.signal, + onProgress, + }); + + if (!controller.signal.aborted) { + triggerDownload(result); + setSucceeded(true); + setProgress(null); + } + } + } catch (err: unknown) { + if (err instanceof DOMException && err.name === "AbortError") { + setErrorMsg("Export cancelled."); + } else { + const code = errorCode(err); + if (code === "ENOENT") { + setErrorMsg("MPC SD card not found — ensure it is mounted or choose a different folder."); + } else if (code === "EEXIST") { + setErrorMsg("A project with this name already exists."); + } else if (code === "EACCES") { + setErrorMsg("Permission denied — cannot write to the selected folder."); + } else { + setErrorMsg(err instanceof Error ? err.message : "An unexpected error occurred."); + } + } + setOverwriteConfirm(null); + } finally { + setRunning(false); + setExporting(false); + setExportProgress(null); + abortRef.current = null; + } + }, [ + exportKit, + userSamples, + running, + setExporting, + setExportProgress, + autoOpenExportFolder, + unmountAfterExport, + projectName, + ]); + + const handleEject = useCallback(async () => { + setEjectPhase("ejecting"); + setEjectError(null); + try { + await desktop().ejectVolume(); + setEjectPhase("ejected"); + } catch (err) { + setEjectPhase("error"); + setEjectError(err instanceof Error ? err.message : "Failed to eject volume."); + } + }, []); + + const progressPercent = + progress && progress.total > 0 ? Math.round((progress.loaded / progress.total) * 100) : 0; + + const ariaLiveText = progress + ? `${phaseLabel(progress.phase)} ${progress.loaded} of ${progress.total}` + : succeeded + ? isDesktop() && successPath + ? `Export complete. Written to ${successPath}` + : "Export complete. Download started." + : errorMsg + ? `Export failed: ${errorMsg}` + : ""; + + return ( + <> + {/* Trigger button */} + + + {/* Progress dialog — portalled to document.body to escape mpc-stage transform context */} + {dialogOpen && + createPortal( +
+
e.stopPropagation()} + > +

EXPORT .XPJ

+ + {/* Project name input — shown before export starts */} + {!running && !succeeded && ( +
+ + setProjectName(e.target.value)} + aria-label="Project name" + autoComplete="off" + spellCheck={false} + /> +
+ )} + + {/* aria-live region for screen reader announcements */} +
+ {ariaLiveText} +
+ + {/* Progress bar (shown while fetching) */} + {running && progress?.phase === "fetching" && ( + <> +
+
+
+

+ {progress.loaded} / {progress.total} samples +

+ + )} + + {/* Phase label for non-fetching phases */} + {running && progress && progress.phase !== "fetching" && ( +

{phaseLabel(progress.phase)}

+ )} + + {/* In-dialog overwrite confirmation (desktop only) */} + {overwriteConfirm && ( +
+

+ Project {overwriteConfirm.projectName} already exists. + Overwrite? +

+
+ + +
+
+ )} + + {/* Error message */} + {errorMsg && ( +

+ {errorMsg} +

+ )} + + {/* Success message */} + {succeeded && ( +

+ {isDesktop() && successPath + ? `Exported to ${successPath}` + : "Download started — check your Downloads folder."} +

+ )} + + {/* Eject volume (desktop only, shown after successful export) */} + {succeeded && isDesktop() && ( +
+ {ejectPhase !== "ejected" && ( + + )} + {ejectPhase === "ejected" && ( +

Volume ejected safely.

+ )} + {ejectPhase === "error" && ejectError && ( +

+ {ejectError} +

+ )} +
+ )} + + {/* Action buttons */} +
+ {/* Export / primary action — only shown before running or after error */} + {!running && !succeeded && !overwriteConfirm && ( + + )} + + {/* Cancel while running (but not waiting for overwrite confirm) */} + {running && !overwriteConfirm && ( + + )} + + {/* Close button — always present when not running */} + {!running && !overwriteConfirm && ( + + )} +
+
+
, + document.body, + )} + + ); +} diff --git a/src/components/HUD.tsx b/src/components/HUD.tsx new file mode 100644 index 0000000..a7fac6c --- /dev/null +++ b/src/components/HUD.tsx @@ -0,0 +1,132 @@ +import { useState } from "react"; +import { desktop, isDesktop } from "../desktop/bridge"; +import { loadProjectFromDir } from "../desktop/loadProject"; +import type { SampleKit } from "../kits/kit.types"; +import { useMPCStore } from "../state/store"; +import { ExportButton } from "./ExportButton"; + +const BANK_LETTERS = ["A", "B", "C", "D"] as const; +const MIDI_STATUS_LABELS: Record = { + idle: "MIDI: idle", + searching: "MIDI: searching…", + connected: "MIDI: connected", + "no-devices": "MIDI: no devices", + unsupported: "MIDI: unsupported", + denied: "MIDI: permission denied", +}; + +/** Inline style shared by all HUD chrome buttons. */ +const HUD_BTN_STYLE: React.CSSProperties = { + background: "rgba(255,255,255,0.1)", + color: "#cfd6e4", + border: "1px solid rgba(255,255,255,0.15)", + padding: "4px 8px", + borderRadius: "4px", + fontFamily: "inherit", + cursor: "pointer", + fontSize: "11px", +}; + +export function HUD() { + const bankIdx = useMPCStore((s) => s.bankIdx); + const activeKit = useMPCStore((s) => s.activeKit); + const activeKitId = useMPCStore((s) => s.activeKitId); + const midiStatus = useMPCStore((s) => s.midiStatus); + const midiDeviceName = useMPCStore((s) => s.midiDeviceName); + + const [isLoadingKit, setIsLoadingKit] = useState(false); + + const bankLetter = BANK_LETTERS[bankIdx] ?? "A"; + const kitLabel = activeKit?.displayName ?? activeKitId; + const midiConnected = midiStatus === "connected"; + const midiLabel = + midiConnected && midiDeviceName + ? `MIDI: ${midiDeviceName}` + : (MIDI_STATUS_LABELS[midiStatus] ?? "MIDI: idle"); + + const handleTweaksClick = () => { + window.dispatchEvent(new CustomEvent("mpc:open-tweaks")); + }; + + const handleEditKitClick = () => { + window.dispatchEvent(new CustomEvent("mpc:open-editor")); + }; + + const handleLoadKit = async () => { + setIsLoadingKit(true); + try { + const filePath = await desktop().chooseProjectDir(); + if (filePath === null) return; + await loadProjectFromDir(filePath); + } finally { + setIsLoadingKit(false); + } + }; + + const handleNewKit = () => { + const blank: SampleKit = { + id: `user-${Date.now()}`, + displayName: "New Kit", + exportName: "New Kit", + key: "", + bpm: 120, + pads: [], + }; + useMPCStore.getState().loadKit(blank); + window.dispatchEvent(new CustomEvent("mpc:open-editor")); + }; + + return ( +
+
+ KEYS 1234 · QWER · ASDF · ZXCV +
+
+ BANK {bankLetter} · KIT {kitLabel} +
+
+
+
+ + + + {isDesktop() && ( + + )} + +
+ +
+ ); +} diff --git a/src/components/KitEditor.tsx b/src/components/KitEditor.tsx new file mode 100644 index 0000000..03f6853 --- /dev/null +++ b/src/components/KitEditor.tsx @@ -0,0 +1,528 @@ +/** + * KitEditor.tsx — Kit customization panel. + * + * Opened by dispatching window event `mpc:open-editor`. + * Sections: kit picker, kit rename, pad bank grid, inline pad editor + * (name / tune / gain / move / WAV drag-drop). + * + * Mirror TweaksPanel's modal / focus-trap / Escape / focus-restore pattern. + */ + +import { type DragEvent, useCallback, useEffect, useRef, useState } from "react"; +import "../styles/editor.css"; +import { BANK_LABELS, localToGlobal } from "../data/padLayout"; +import { useReducedMotion } from "../hooks/useReducedMotion"; +import { buildUserSamplePad, importWavFile } from "../kits/importWav"; +import type { GlobalPadIdx } from "../kits/kit.types"; +import { useMPCStore } from "../state/store"; + +const FOCUSABLE_SELECTORS = + 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; + +function getFocusableElements(container: HTMLElement): HTMLElement[] { + return Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS)); +} + +// Row 0 (top) = local 13–16 (indices 12–15) +// Row 3 (bot) = local 1– 4 (indices 0– 3) +const PAD_ROWS: ReadonlyArray> = [ + [12, 13, 14, 15], + [8, 9, 10, 11], + [4, 5, 6, 7], + [0, 1, 2, 3], +]; + +function clamp(v: number, min: number, max: number): number { + return Math.max(min, Math.min(max, v)); +} + +/** Parse a user-typed pad target (1-based displayed pad number, 1..128) to + * a 0-based GlobalPadIdx, or return null on invalid input. */ +function parseTargetPad(raw: string): GlobalPadIdx | null { + const n = parseInt(raw, 10); + if (Number.isNaN(n) || n < 1 || n > 128) return null; + return (n - 1) as GlobalPadIdx; +} + +export function KitEditor() { + const [open, setOpen] = useState(false); + const [selectedPad, setSelectedPad] = useState(null); + const [dragOverPad, setDragOverPad] = useState(null); + const [dropError, setDropError] = useState(""); + const [moveTarget, setMoveTarget] = useState(""); + const [swapTarget, setSwapTarget] = useState(""); + + const prefersReducedMotion = useReducedMotion(); + + const activeKit = useMPCStore((s) => s.activeKit); + const padMap = useMPCStore((s) => s.padMap); + const bankIdx = useMPCStore((s) => s.bankIdx); + const maxBank = useMPCStore((s) => s.maxBank); + const setBank = useMPCStore((s) => s.setBank); + const setKitName = useMPCStore((s) => s.setKitName); + const setPadName = useMPCStore((s) => s.setPadName); + const setPadTune = useMPCStore((s) => s.setPadTune); + const setPadGain = useMPCStore((s) => s.setPadGain); + const movePadSample = useMPCStore((s) => s.movePadSample); + const swapPad = useMPCStore((s) => s.swapPad); + const registerUserSample = useMPCStore((s) => s.registerUserSample); + const setPadSample = useMPCStore((s) => s.setPadSample); + + const panelRef = useRef(null); + const closeBtnRef = useRef(null); + const lastFocusRef = useRef(null); + + const selectedPadData = selectedPad !== null ? padMap[selectedPad] : null; + const visibleBanks = BANK_LABELS.slice(0, maxBank + 1); + + useEffect(() => { + const handler = () => { + lastFocusRef.current = document.activeElement as HTMLElement; + setOpen(true); + }; + window.addEventListener("mpc:open-editor", handler); + return () => window.removeEventListener("mpc:open-editor", handler); + }, []); + + // Focus management on open/close + useEffect(() => { + if (open) { + const id = setTimeout( + () => { + closeBtnRef.current?.focus(); + }, + prefersReducedMotion ? 0 : 220, + ); + return () => clearTimeout(id); + } else { + lastFocusRef.current?.focus(); + } + return undefined; + }, [open, prefersReducedMotion]); + + const closePanel = useCallback(() => { + setOpen(false); + setSelectedPad(null); + setDropError(""); + setMoveTarget(""); + setSwapTarget(""); + }, []); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + if (e.key === "Escape") { + e.stopPropagation(); + closePanel(); + return; + } + if (e.key === "Tab") { + const panel = panelRef.current; + if (!panel) return; + const focusable = getFocusableElements(panel); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey) { + if (document.activeElement === first) { + e.preventDefault(); + last.focus(); + } + } else { + if (document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + } + } + }, + [closePanel], + ); + + const handleKitNameChange = useCallback( + (e: React.ChangeEvent) => { + setKitName(e.target.value); + }, + [setKitName], + ); + + const handlePadNameChange = useCallback( + (e: React.ChangeEvent) => { + if (selectedPad === null) return; + setPadName(selectedPad, e.target.value); + }, + [selectedPad, setPadName], + ); + + const handleCoarseChange = useCallback( + (e: React.ChangeEvent) => { + if (selectedPad === null || !selectedPadData) return; + const coarse = clamp(Number(e.target.value), -36, 36); + setPadTune(selectedPad, coarse, selectedPadData.fineTune); + }, + [selectedPad, selectedPadData, setPadTune], + ); + + const handleFineChange = useCallback( + (e: React.ChangeEvent) => { + if (selectedPad === null || !selectedPadData) return; + const fine = clamp(Number(e.target.value), -100, 100); + setPadTune(selectedPad, selectedPadData.coarseTune, fine); + }, + [selectedPad, selectedPadData, setPadTune], + ); + + const handleGainChange = useCallback( + (e: React.ChangeEvent) => { + if (selectedPad === null) return; + // Slider is 0..200 (representing 0..2 gainCoefficient). + const gain = clamp(Number(e.target.value) / 100, 0, 2); + setPadGain(selectedPad, gain); + }, + [selectedPad, setPadGain], + ); + + const handleMove = useCallback(() => { + if (selectedPad === null) return; + const target = parseTargetPad(moveTarget); + if (target === null) return; + movePadSample(selectedPad, target); + setSelectedPad(target); + setMoveTarget(""); + }, [selectedPad, moveTarget, movePadSample]); + + const handleSwap = useCallback(() => { + if (selectedPad === null) return; + const target = parseTargetPad(swapTarget); + if (target === null) return; + swapPad(selectedPad, target); + setSwapTarget(""); + // Keep selection on current pad (content swapped). + }, [selectedPad, swapTarget, swapPad]); + + const handleDragOver = useCallback((e: DragEvent, globalIdx: GlobalPadIdx) => { + const hasWav = + Array.from(e.dataTransfer.items).some( + (item) => + item.kind === "file" && + (item.type === "audio/wav" || + item.type === "audio/x-wav" || + item.type === "audio/wave" || + item.type === ""), + ) || Array.from(e.dataTransfer.files).some((f) => /\.wav$/i.test(f.name)); + if (hasWav || e.dataTransfer.items.length > 0) { + e.preventDefault(); + e.dataTransfer.dropEffect = "copy"; + setDragOverPad(globalIdx); + } + }, []); + + const handleDragLeave = useCallback(() => { + setDragOverPad(null); + }, []); + + const handleDrop = useCallback( + async (e: DragEvent, globalIdx: GlobalPadIdx) => { + e.preventDefault(); + setDragOverPad(null); + setDropError(""); + + const file = e.dataTransfer.files[0]; + if (!file) return; + + try { + const imported = await importWavFile(file); + registerUserSample(imported.sampleId, imported.bytes); + setPadSample(globalIdx, buildUserSamplePad(globalIdx, imported)); + setSelectedPad(globalIdx); + } catch (err) { + const msg = err instanceof Error ? err.message : "Failed to import file."; + setDropError(msg); + } + }, + [registerUserSample, setPadSample], + ); + + const panelClass = `kit-editor${open ? " open" : ""}`; + + const style: React.CSSProperties = prefersReducedMotion ? { transition: "none" } : {}; + + return ( +
e.stopPropagation()} + > + {/* ── Header ── */} +
+

EDIT KIT

+ +
+ + {/* ── Kit Name ── */} +
+ + +
+ + {/* ── Pad Editor ── */} +
+ + Pads — Bank {BANK_LABELS[bankIdx] ?? "A"} + + + {/* Bank selector */} +
+ {visibleBanks.map((label, i) => ( + + ))} +
+ + {/* 4×4 pad grid */} +
+ {PAD_ROWS.flat().map((localIdx) => { + const globalIdx = localToGlobal(bankIdx, localIdx) as GlobalPadIdx; + const pad = padMap[globalIdx]; + const localNum = localIdx + 1; // 1-based within bank for display + const globalNum = globalIdx + 1; // 1-based global for aria + const isSelected = selectedPad === globalIdx; + const isDragOver = dragOverPad === globalIdx; + + return ( + + ); + })} +
+ + {/* Drop error (aria-live for screen readers) */} + {dropError && ( +
+ {dropError} +
+ )} + + {/* Inline pad editor */} + {selectedPad !== null && ( +
+
+ Pad {selectedPad + 1} + {selectedPadData ? ` — ${selectedPadData.displayName}` : " (empty)"} +
+ + {/* Pad name */} + {selectedPadData && ( + <> +
+ + +
+ + {/* Coarse tune */} +
+ +
+ + + {selectedPadData.coarseTune > 0 + ? `+${selectedPadData.coarseTune}` + : selectedPadData.coarseTune} + +
+
+ + {/* Fine tune */} +
+ +
+ + + {selectedPadData.fineTune > 0 + ? `+${selectedPadData.fineTune}` + : selectedPadData.fineTune} + +
+
+ + {/* Volume */} +
+ +
+ + + {Math.round(selectedPadData.gainCoefficient * 100)}% + +
+
+ + {/* Move */} +
+ +
+ setMoveTarget(e.target.value)} + aria-label="Target pad for move (1 to 128)" + min={1} + max={128} + placeholder="—" + /> + + setSwapTarget(e.target.value)} + aria-label="Target pad for swap (1 to 128)" + min={1} + max={128} + placeholder="—" + /> + +
+
+ + )} + + {/* WAV drop hint on empty pad */} +
Drop a .wav file onto any pad cell to assign it.
+
+ )} + + {/* Global drop hint when no pad selected */} + {selectedPad === null && ( +

+ Select a pad to edit tune, volume, and name. Drop a .wav file onto a pad cell to import. +

+ )} +
+ + {/* ── Export hint ── */} +
+

+ Use the EXPORT button to download a .xpj ZIP for your Akai MPC. +

+
+
+ ); +} diff --git a/src/components/Knob.tsx b/src/components/Knob.tsx new file mode 100644 index 0000000..1dcc847 --- /dev/null +++ b/src/components/Knob.tsx @@ -0,0 +1,145 @@ +import { useCallback, useEffect, useRef } from "react"; +import "../styles/controls.css"; +import { useMPCStore } from "../state/store"; +import type { KnobName } from "../types/mpc.types"; + +export type KnobSize = "sm" | "md" | "lg"; +export type KnobVariant = "silver" | "gold"; + +type KnobProps = { + name: KnobName; + label: string; + size?: KnobSize; + variant?: KnobVariant; +}; + +const SIZE_TO_ORIGIN: Record = { + sm: "50% 20px", + md: "50% 28px", + lg: "50% 34px", +}; + +function clamp01(v: number): number { + return Math.max(0, Math.min(1, v)); +} + +export function Knob({ name, label, size = "md", variant = "silver" }: KnobProps) { + const isContinuous = name === "dataEnc"; + const value = useMPCStore((s) => s.knobs[name]); + const setKnob = useMPCStore((s) => s.setKnob); + + const dragStartY = useRef(null); + const dragStartVal = useRef(0); + + const rotDeg = isContinuous + ? value * 360 // continuous: treat value as turns, show as degrees + : -135 + 270 * value; + + const capRef = useRef(null); + + const handlePointerDown = useCallback( + (e: React.PointerEvent) => { + e.preventDefault(); + dragStartY.current = e.clientY; + dragStartVal.current = value; + (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId); + }, + [value], + ); + + const handlePointerMove = useCallback( + (e: React.PointerEvent) => { + if (dragStartY.current === null) return; + const delta = (dragStartY.current - e.clientY) / 200; + const next = isContinuous + ? dragStartVal.current + delta + : clamp01(dragStartVal.current + delta); + setKnob(name, next); + }, + [isContinuous, name, setKnob], + ); + + const handlePointerUp = useCallback(() => { + dragStartY.current = null; + }, []); + + // Wheel event needs passive: false, so attach imperatively + useEffect(() => { + const el = capRef.current; + if (!el) return; + const onWheel = (e: WheelEvent) => { + e.preventDefault(); + const delta = e.deltaY * -0.001; + const cur = useMPCStore.getState().knobs[name]; + const next = isContinuous ? cur + delta : clamp01(cur + delta); + setKnob(name, next); + }; + el.addEventListener("wheel", onWheel, { passive: false }); + return () => el.removeEventListener("wheel", onWheel); + }, [isContinuous, name, setKnob]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + let handled = true; + const cur = useMPCStore.getState().knobs[name]; + switch (e.key) { + case "ArrowUp": + setKnob(name, isContinuous ? cur + 0.05 : clamp01(cur + 0.05)); + break; + case "ArrowDown": + setKnob(name, isContinuous ? cur - 0.05 : clamp01(cur - 0.05)); + break; + case "PageUp": + setKnob(name, isContinuous ? cur + 0.1 : clamp01(cur + 0.1)); + break; + case "PageDown": + setKnob(name, isContinuous ? cur - 0.1 : clamp01(cur - 0.1)); + break; + case "Home": + if (!isContinuous) setKnob(name, 0); + break; + case "End": + if (!isContinuous) setKnob(name, 1); + break; + default: + handled = false; + } + if (handled) e.preventDefault(); + }, + [isContinuous, name, setKnob], + ); + + const ariaValueNow = isContinuous ? undefined : Math.round(value * 100); + const ariaValueText = isContinuous ? `${Math.round(rotDeg % 360)}°` : undefined; + + return ( +
+
+
{label}
+
+ ); +} diff --git a/src/components/Launcher.tsx b/src/components/Launcher.tsx new file mode 100644 index 0000000..a03dea2 --- /dev/null +++ b/src/components/Launcher.tsx @@ -0,0 +1,182 @@ +/** + * Launcher.tsx — Full-screen startup modal for the Electron desktop app. + * + * Shown once at startup when `isDesktop()` is true and no kit has been chosen. + * Dismissed when the user picks a kit (either loaded or blank). + * + * Accessibility: + * - role="dialog", aria-modal, aria-labelledby on the dialog container + * - Focus trap: Tab cycles within the dialog; Shift+Tab wraps backwards + * - Escape: closes to "New Kit" (calls `onNewKit`) — documented below + * - Error state: role="alert" for screen reader announcements + * - Focus management: primary button receives focus when dialog mounts; + * focus stays inside the dialog throughout + * + * Escape key behaviour: + * Pressing Escape is treated as "New Kit" — i.e. the dialog is dismissed + * immediately with an empty kit rather than blocking the user. This is + * intentional: there is no "cancel without choice" in the launcher because + * the rest of the app requires some kit state to function correctly. + */ + +import { useCallback, useEffect, useRef, useState } from "react"; +import { desktop } from "../desktop/bridge"; +import { loadBlankKit, loadProjectFromDir } from "../desktop/loadProject"; +import "../styles/launcher.css"; + +const FOCUSABLE_SELECTORS = + 'button:not([disabled]), [href], input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])'; + +function getFocusable(container: HTMLElement): HTMLElement[] { + return Array.from(container.querySelectorAll(FOCUSABLE_SELECTORS)); +} + +type LauncherProps = { + /** Called when the user has made a kit choice and the dialog should close. */ + onDismiss: () => void; +}; + +export function Launcher({ onDismiss }: LauncherProps) { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const dialogRef = useRef(null); + const primaryBtnRef = useRef(null); + + // Focus the primary ("Load existing") button when the dialog mounts. + useEffect(() => { + const id = setTimeout(() => primaryBtnRef.current?.focus(), 50); + return () => clearTimeout(id); + }, []); + + const handleNewKit = useCallback(() => { + loadBlankKit(); + onDismiss(); + }, [onDismiss]); + + const handleLoad = useCallback(async () => { + setError(null); + let dir: string | null = null; + + try { + dir = await desktop().chooseProjectDir(); + } catch (err) { + setError(err instanceof Error ? err.message : "Failed to open the file picker."); + return; + } + + // User cancelled the picker — stay on the launcher. + if (dir === null) return; + + setLoading(true); + try { + await loadProjectFromDir(dir); + onDismiss(); + } catch (err) { + setError( + err instanceof Error + ? err.message + : "Could not load the project. Make sure the selected .xpj file is valid.", + ); + } finally { + setLoading(false); + } + }, [onDismiss]); + + const handleKeyDown = useCallback( + (e: React.KeyboardEvent) => { + // Escape → New Kit (documented: keeps the app in a valid state). + if (e.key === "Escape") { + e.stopPropagation(); + handleNewKit(); + return; + } + + if (e.key === "Tab") { + const container = dialogRef.current; + if (!container) return; + const focusable = getFocusable(container); + if (focusable.length === 0) return; + const first = focusable[0]; + const last = focusable[focusable.length - 1]; + if (e.shiftKey) { + if (document.activeElement === first) { + e.preventDefault(); + last.focus(); + } + } else { + if (document.activeElement === last) { + e.preventDefault(); + first.focus(); + } + } + } + }, + [handleNewKit], + ); + + return ( +
+
e.stopPropagation()} + > +
+

+ MPC Sample +

+

Choose how to start

+
+ + {/* Error announcement */} + {error && ( +

+ {error} +

+ )} + + {/* Loading state */} + {loading && ( +
+
+ )} + + {/* Action buttons */} +
+ + + +
+
+
+ ); +} diff --git a/src/components/MPCDevice.tsx b/src/components/MPCDevice.tsx new file mode 100644 index 0000000..e323691 --- /dev/null +++ b/src/components/MPCDevice.tsx @@ -0,0 +1,163 @@ +import { useCallback, useRef } from "react"; +import { useReducedMotion } from "../hooks/useReducedMotion"; +import { useMPCStore } from "../state/store"; +import type { AudioEngineLike } from "../types/mpc.types"; +import { BankSelector } from "./BankSelector"; +import { DataEncoder } from "./DataEncoder"; +import { DisplayPanel } from "./DisplayPanel"; +import { EraseButtons } from "./EraseButtons"; +import { Knob } from "./Knob"; +import { ModeButtons } from "./ModeButtons"; +import { PadGrid } from "./PadGrid"; +import { PadPlayButtons } from "./PadPlayButtons"; +import { PitchFader } from "./PitchFader"; +import { Transport } from "./Transport"; +import { UtilityButtons } from "./UtilityButtons"; + +// Sensitivity: how much one pixel of pointer movement maps to offset pixels. +const DRAG_SENSITIVITY = 1; + +// Ctrl/Cmd+wheel zoom factor: pixels of deltaY → scale delta. +const WHEEL_ZOOM_FACTOR = 0.001; + +// Class added to interactive MPC controls so we can skip drag initiation on them. +const DRAG_HANDLE_CLASS = "mpc-drag-handle"; + +type MPCDeviceProps = { + engine?: AudioEngineLike | null; +}; + +export function MPCDevice({ engine = null }: MPCDeviceProps) { + const uiScale = useMPCStore((s) => s.uiScale); + const uiOffset = useMPCStore((s) => s.uiOffset); + const zoomBy = useMPCStore((s) => s.zoomBy); + const setUiOffset = useMPCStore((s) => s.setUiOffset); + const reducedMotion = useReducedMotion(); + + const isDragging = useRef(false); + const dragStart = useRef<{ x: number; y: number; ox: number; oy: number }>({ + x: 0, + y: 0, + ox: 0, + oy: 0, + }); + const viewportRef = useRef(null); + + const onPointerDown = useCallback( + (e: React.PointerEvent) => { + // Only initiate drag from the drag handle itself. + const target = e.target as HTMLElement; + if (!target.classList.contains(DRAG_HANDLE_CLASS)) return; + + isDragging.current = true; + dragStart.current = { + x: e.clientX, + y: e.clientY, + ox: uiOffset.x, + oy: uiOffset.y, + }; + + const viewport = viewportRef.current; + if (viewport) { + viewport.classList.add("is-dragging"); + (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); + } + }, + [uiOffset], + ); + + const onPointerMove = useCallback( + (e: React.PointerEvent) => { + if (!isDragging.current) return; + const dx = (e.clientX - dragStart.current.x) * DRAG_SENSITIVITY; + const dy = (e.clientY - dragStart.current.y) * DRAG_SENSITIVITY; + setUiOffset(dragStart.current.ox + dx, dragStart.current.oy + dy); + }, + [setUiOffset], + ); + + const onPointerUp = useCallback((e: React.PointerEvent) => { + if (!isDragging.current) return; + isDragging.current = false; + const viewport = viewportRef.current; + if (viewport) { + viewport.classList.remove("is-dragging"); + } + (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId); + }, []); + + const onWheel = useCallback( + (e: React.WheelEvent) => { + if (!e.ctrlKey && !e.metaKey) return; + e.preventDefault(); + zoomBy(-e.deltaY * WHEEL_ZOOM_FACTOR); + }, + [zoomBy], + ); + + // When user scale is not 1 we suppress the CSS media-query on .mpc + // (which would otherwise double-apply a transform). + const isScaled = uiScale !== 1; + + const stageStyle: React.CSSProperties = { + transform: `translate(${uiOffset.x}px, ${uiOffset.y}px) scale(${uiScale})`, + transformOrigin: "top center", + // Disable smooth transition during drag or when reduced motion is on. + transition: reducedMotion ? "none" : undefined, + }; + + return ( +
+ {/* Drag handle: sits behind the MPC but covers the whole viewport */} +