From 2734507c87e9a7d8e3c94b869899e4931d02ae28 Mon Sep 17 00:00:00 2001 From: Stackie Jia Date: Sat, 27 Jun 2026 03:23:15 +0800 Subject: [PATCH 1/3] feat(web-ui): migrate to vite 8 wasm and module worker --- package.json | 2 +- pnpm-lock.yaml | 1049 +++++++++++------ web-ui/src/components/player/video-player.tsx | 5 +- web-ui/src/mpegts/audio/pcm-audio-player.ts | 5 +- web-ui/src/mpegts/audio/wasm-stretcher.ts | 29 +- web-ui/src/mpegts/config.ts | 6 - .../src/mpegts/decoder/mpeg-audio-decoder.ts | 55 +- .../mpegts/decoder/worker-audio-decoder.ts | 11 +- web-ui/src/mpegts/index.ts | 8 - web-ui/src/mpegts/player/mpegts-player.ts | 3 +- web-ui/src/mpegts/vite-env.d.ts | 31 +- web-ui/src/mpegts/wasm/env.ts | 1 + web-ui/src/mpegts/wasm/mp2-decoder.ts | 64 + web-ui/src/mpegts/worker/pipeline.ts | 13 +- web-ui/vite.config.ts | 10 +- 15 files changed, 800 insertions(+), 492 deletions(-) create mode 100644 web-ui/src/mpegts/wasm/env.ts create mode 100644 web-ui/src/mpegts/wasm/mp2-decoder.ts diff --git a/package.json b/package.json index 65094777..bf164d50 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@vitejs/plugin-react-swc": "^4.3.1", "tailwindcss": "^4.3.1", "typescript": "^6.0.3", - "vite": "^7.3.6", + "vite": "^8.1.0", "vite-bundle-analyzer": "^1.3.8", "vitepress": "2.0.0-alpha.17", "vitepress-plugin-llms": "^1.13.2" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 61479108..31dd8c13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,7 +29,7 @@ importers: version: 2.5.1 '@tailwindcss/vite': specifier: ^4.3.1 - version: 4.3.1(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0)) + version: 4.3.1(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)) '@types/node': specifier: ^26.0.1 version: 26.0.1 @@ -41,7 +41,7 @@ importers: version: 19.2.3(@types/react@19.2.17) '@vitejs/plugin-react-swc': specifier: ^4.3.1 - version: 4.3.1(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0)) + version: 4.3.1(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0)) tailwindcss: specifier: ^4.3.1 version: 4.3.1 @@ -49,8 +49,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 vite: - specifier: ^7.3.6 - version: 7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0) + specifier: ^8.1.0 + version: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0) vite-bundle-analyzer: specifier: ^1.3.8 version: 1.3.8 @@ -146,164 +146,173 @@ packages: '@docsearch/sidepanel-js@4.6.3': resolution: {integrity: sha512-grGSmvXzG0if+mrzdIKykvpIAuEQ9u0sEJ2eLRRCaQfJvsWqh2C2/aY04bIzWvDh7myi5rvl8D+tUNsVrjYQ3A==} - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + '@emnapi/core@1.11.1': + resolution: {integrity: sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==} + + '@emnapi/runtime@1.11.1': + resolution: {integrity: sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==} + + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@iconify-json/simple-icons@1.2.86': - resolution: {integrity: sha512-t3jck5qPQuK1qy+bRn9eCoDQhIB7XSazKz1Fjp8hcan3XOAsTI5Mq/s3F0ekOKSvMQqkVORYK6ns6o6T9f5EMA==} + '@iconify-json/simple-icons@1.2.87': + resolution: {integrity: sha512-8YciStObhSji3OZFmWAWK6kBujyqO5bLCxeDwLxf3CR3F4PVelq7keC2LBvgTqviWzSTysj5/g4PCFLiAMVGsw==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} @@ -324,144 +333,248 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@napi-rs/wasm-runtime@1.1.6': + resolution: {integrity: sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@oxc-project/types@0.137.0': + resolution: {integrity: sha512-WT+Gb24i8hmvo85AIv2oEYouEXkRlKAlT9WaCa3TfLgNCN+GhrJOGZuIlMouAh38Qe4QOx26eUOVsq70qXrywA==} + + '@rolldown/binding-android-arm64@1.1.3': + resolution: {integrity: sha512-DT6Z3PhvioeHMvxo+xHc3KtqggrI7CCTXCmC2h/5zUlp5jVitv7XEy+9q5/7v8IolhlioawpMo8Kg0EEBy7J0g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.1.3': + resolution: {integrity: sha512-0NwgwsjM7LrsuVnXMK3koTpagBNOhloc/BNjKqZjv4V5zI5r13qx69uVhRx+o5Z0yy4Hzq+lpy7TAgUG/ocvrw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.1.3': + resolution: {integrity: sha512-YtiBp4disu6V560loT6PjMdiRaWmVvDNrUunAalbiFx2ggeJwxdAsgZMcoGP17uyAsTwAj5V1niksxlHnVQ1Sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.1.3': + resolution: {integrity: sha512-yD3EkEdXk2LypPxnf/kSZHirarsI8gcPzc62SukhR9VJTyvV+F9Q/GxWNuCojc7sXyuVC4DxRGhdDK4X8VSsbw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.1.3': + resolution: {integrity: sha512-c+8vieQbsD7HNAHKIA34w0GJ9FedFFuJGD+7E6vz7Q3uqAIugL5p45fhlsj4UaAsHpcmlqugBWMhA0/j7o0sIg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.1.3': + resolution: {integrity: sha512-50jD0uUwLvur7Zz9LHz17kaAdTPjn5wN93hEgjvmYFRZwiR7ZJYovTd5ipyWJDAnXKvZ+wgc+/Ika6dwSF5OcA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-arm64-musl@1.1.3': + resolution: {integrity: sha512-BO9+oPL8K9poZJBfYPsXNtYjPE5uM3qeehT3aFcW4LITOl+iSqhp0abzjR2nWBUNjIZeKXjAEWBZ64WjNoHd6w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@rolldown/binding-linux-ppc64-gnu@1.1.3': + resolution: {integrity: sha512-f3VpLB1vQ0Eo6ecr/6cekLnvYMFF4YBFoVGkfkvPLq1bAkbAwHYQPZKoAmG6OJyTcxxoC+AvezGx/S1obNC0Mw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-s390x-gnu@1.1.3': + resolution: {integrity: sha512-AmurZ26Pqx/RI9N1gzEOCklkKXl927yjfXWUUS0O7Puh8ARM/Ob8qfrD3qnWksScdw6cSrW5PSHE9DyLu7+PtA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-gnu@1.1.3': + resolution: {integrity: sha512-JJpqs8bRGITDOdbkNKnlojzBabbOHrqjSvDr0IVsZObE1lBcPjxItUEY9eWIDbxaJ3cGrXPWGfGkIxFijg/URg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@rolldown/binding-linux-x64-musl@1.1.3': + resolution: {integrity: sha512-rSJcdjPxzA/by/6/rYs+v+bXU7UjvnbUWz8MJb6kh6+knqB1dCrtHg0uu7C/4haqJvqdkYHQ5IGn+tCH9GLW/g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] + + '@rolldown/binding-openharmony-arm64@1.1.3': + resolution: {integrity: sha512-hQ3/PYkDJICgevvyNcVrihVeqq7k1Pp3VZ9lY+dauAYUJKO+auqApvANhvR1An9BhmqYKvW2Mu1F9u4DXSMLxQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.1.3': + resolution: {integrity: sha512-Elcv/BtML9lXrV6JuKITc/grN2kYV9gjsQpW8Jfw4ioK0TOkjBjye0nnyqQNy9STNaI20lXNaQBRrD5gSgR0Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.1.3': + resolution: {integrity: sha512-2DrEfhluH9yhiaFApmsjsjwrSYbNcY1oFTzYSP1a535jDbV98zCFanA/96TBUd0iDFcxGmw9QRExwGCXz3U+/g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.1.3': + resolution: {integrity: sha512-OL4OMk7UPXOeVGGd3qo5zJyPIljf4AFgk5QAkPPS+OoLuOOozhuaQGC18MxVTnw/06q93gShAJzlwnSCY9YtqA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + '@rolldown/pluginutils@1.0.1': resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/rollup-android-arm-eabi@4.61.1': - resolution: {integrity: sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==} + '@rollup/rollup-android-arm-eabi@4.62.2': + resolution: {integrity: sha512-6o7ZLZK+BeenkZCFNDXqpbjw9bD6nuWonvS/lwQJp7NoVVxm6p3qE7qQ5jGuBjiFsgvqjD8mZAU5oWxTmbOeOg==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.61.1': - resolution: {integrity: sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==} + '@rollup/rollup-android-arm64@4.62.2': + resolution: {integrity: sha512-BaH7BllCACHoH1LguOU56UItGfUWjujlO65kS9LAodViaN4bwIKd7oeW/ZHJ/4ljr/7MIiENnNy3HJ0zXv8Zkw==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.61.1': - resolution: {integrity: sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==} + '@rollup/rollup-darwin-arm64@4.62.2': + resolution: {integrity: sha512-v39RCCvj4He82I9sFmk+M1VZ0PLM9sfsLVikjfx2hYBNALhrrOR2D3JjQA6AhlaSOgcR+RzrKY7e1+bT6SUO/A==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.61.1': - resolution: {integrity: sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==} + '@rollup/rollup-darwin-x64@4.62.2': + resolution: {integrity: sha512-yl0y2vq3S3lHeuXhEdss6TWfKW8vkujImO12tn4ZkG/4oghr09LvdYm2RElVjokTQiUvDUGXLGsYeLqUMCKpGA==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.61.1': - resolution: {integrity: sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==} + '@rollup/rollup-freebsd-arm64@4.62.2': + resolution: {integrity: sha512-tT4pvt4qXD+vEoezupCWi+a1F0vvDiksiHc+PxRlYTOH1I6/X4id9jPxTP+Fg+545euaFT1jJVs4CEdHZAU1vw==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.61.1': - resolution: {integrity: sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==} + '@rollup/rollup-freebsd-x64@4.62.2': + resolution: {integrity: sha512-6nU5F2wCW+qvCBhTn1pdIU3bzsIoF7EUwsCDRxilWGprQR6yd508YnH9+OKFCwpfS8pjZqDUmnCAr7exax0XCg==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': - resolution: {integrity: sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==} + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': + resolution: {integrity: sha512-n1GJHPOvpIfhi3TmrCeh6S6URt9BFCt0KQE3qvexyGCTAKpR4Lg+eWvNZEqu7epxwus/8ElT3hacYEucm49SZg==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.61.1': - resolution: {integrity: sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==} + '@rollup/rollup-linux-arm-musleabihf@4.62.2': + resolution: {integrity: sha512-JqgflS8wEB+UXV/vS1RpRbifGBeN4D5lz8D8oOFbFZw4vedvdOgCFAjfBmIMdW3yL10XpQQ0Ambepw6MXrhOnA==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.61.1': - resolution: {integrity: sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==} + '@rollup/rollup-linux-arm64-gnu@4.62.2': + resolution: {integrity: sha512-wnFJkogWvN4jm/hQRF2UBaeUmk20j5+DmHvoyWii2b8HJDyvz1MF2OU/6ynXt2KR63rbZLWkFpoytpdc/yBuSA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.61.1': - resolution: {integrity: sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==} + '@rollup/rollup-linux-arm64-musl@4.62.2': + resolution: {integrity: sha512-HVu2bp0zhvJ8xHEV9+UUs7S90VadmBSY3LcIMvozbPo4AuMGDWlz3ymHLHZPX4hR67TKTt8Qp5PJ5RBg/i+RMQ==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loong64-gnu@4.61.1': - resolution: {integrity: sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==} + '@rollup/rollup-linux-loong64-gnu@4.62.2': + resolution: {integrity: sha512-mQqqAV8QaoSgr9I2fKDLY2BAVvmKjWoGiu/cSYQonsLvtqwEn1E4QYfnCOcp5zoEqNhsDYin1s6jx/VJmrxlZg==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-loong64-musl@4.61.1': - resolution: {integrity: sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==} + '@rollup/rollup-linux-loong64-musl@4.62.2': + resolution: {integrity: sha512-IxKLoxCQ2IWi6bT2akyDUBGsOImDKB+sPp4EsTmwFQ/fMwpCKm8uLSSgP/Kx/QYUgKis6SEZ5/Nlhup0DIA0PQ==} cpu: [loong64] os: [linux] libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.61.1': - resolution: {integrity: sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==} + '@rollup/rollup-linux-ppc64-gnu@4.62.2': + resolution: {integrity: sha512-Mk5ha2RQSgyFfmYYLkBpPnUk8D8FriBxesO1u9O75X0mHgXL1UQcH5Itl2lurWL2tj0RxV9b9tJgipac0hRY9A==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-musl@4.61.1': - resolution: {integrity: sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==} + '@rollup/rollup-linux-ppc64-musl@4.62.2': + resolution: {integrity: sha512-CjvEnqJL/0/TQ3TXX3OPIJ/kmBellrWd4heXUmHeJlTnmwjKpSJzoehLaL6Xk0ZnMHBu9dZuFADNOrtjF4v+2w==} cpu: [ppc64] os: [linux] libc: [musl] - '@rollup/rollup-linux-riscv64-gnu@4.61.1': - resolution: {integrity: sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==} + '@rollup/rollup-linux-riscv64-gnu@4.62.2': + resolution: {integrity: sha512-1SiZbzwdkaDURsew/tSOrooKiYy7EQGT6m8ufavAi9NEyQb/6VuIxFXAL1fqa4iZe3g4NbNk4P7J32z2tw5Mgg==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.61.1': - resolution: {integrity: sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==} + '@rollup/rollup-linux-riscv64-musl@4.62.2': + resolution: {integrity: sha512-nQts12zJ3NQRoE6uYljOH89v7szzLDvG2JD/vsX+vGXU8w/At1GowTZ5/7qeFQ8m7L55rpR8Okugnuo5bgjy2Q==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.61.1': - resolution: {integrity: sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==} + '@rollup/rollup-linux-s390x-gnu@4.62.2': + resolution: {integrity: sha512-E9/ll019jhPIJgpzfZoIkBGhcz+kKNgVWYRY0zr9srBdPPFVpvOKW8VaJKUbeK+eZXyQF9ltME+Kk6affeaPgg==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.61.1': - resolution: {integrity: sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==} + '@rollup/rollup-linux-x64-gnu@4.62.2': + resolution: {integrity: sha512-5BqxR/pshjey51iliyzTD5Xi3EN0aLmQ2lZ3lvefVV9c82BvrLo2/6OT55iifpWBufs6kdwWbuOKS841DrmK9A==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.61.1': - resolution: {integrity: sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==} + '@rollup/rollup-linux-x64-musl@4.62.2': + resolution: {integrity: sha512-uNN83XxQrRAh/w0/pmAfibcwyb6YWt4gP+dpnQKPVJshAloQ785ii8CT8ZCIxkGg9opVsvAlGhFitSm6D1Jjpg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openbsd-x64@4.61.1': - resolution: {integrity: sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==} + '@rollup/rollup-openbsd-x64@4.62.2': + resolution: {integrity: sha512-srjEIxSH3LRnJN6THczDHWQplqEMFiAJrTab0msUryh9kwNpkICf3Ea6q6MN/2cZwRFUNx5w+h6Hpi4QuHS6Zg==} cpu: [x64] os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.61.1': - resolution: {integrity: sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==} + '@rollup/rollup-openharmony-arm64@4.62.2': + resolution: {integrity: sha512-8hOJnxgbyObnCm5AlRA3A931xX19xq80RjVTKgJOvEKWqJruP/Uf12IbAOaDjjEXYRewwHLfmF0YRIdK3OwKWA==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.61.1': - resolution: {integrity: sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==} + '@rollup/rollup-win32-arm64-msvc@4.62.2': + resolution: {integrity: sha512-mmF4AY1i0hG/bLWUctUq59gtmgaSIRa3cu/A3JFRp/sCNEme2bgDEiDS22P9FbnJB8NJNF4jPJiSP5RHQpUTDg==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.61.1': - resolution: {integrity: sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==} + '@rollup/rollup-win32-ia32-msvc@4.62.2': + resolution: {integrity: sha512-DZgkknc6jhHrk46V25vbAM0zZkyP0nSDkJB8/dRkLTxv470dOmWDqGoEJl/9A0dFfS7yE3REOwNDxpHwSLSt0Q==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.61.1': - resolution: {integrity: sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==} + '@rollup/rollup-win32-x64-gnu@4.62.2': + resolution: {integrity: sha512-T6xr6ucWSFto+VGajA8YH26LdpHRuP4YLHEKAtCWvJDOlnmWcDZVCI2Jmjr+IFHDlt2zRaTAKE4tfjTaWLgJBg==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.61.1': - resolution: {integrity: sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==} + '@rollup/rollup-win32-x64-msvc@4.62.2': + resolution: {integrity: sha512-BfzEnDJOt9T8M989/lA37EcJgat01wLRnoi5dQf3QzOH7jzpqTAzdDbVfRljVr5r+jzKqpbHeyOfAaXxAd0PAA==} cpu: [x64] os: [win32] @@ -489,86 +602,86 @@ packages: '@shikijs/vscode-textmate@10.0.2': resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - '@swc/core-darwin-arm64@1.15.41': - resolution: {integrity: sha512-kREh6J5paQFvP3i7f/4FbqRNOJREutVFVOkder4GVyCBQ39YmER55cW/y1NNjwrchzFqgYswFn0mMDCqbqKzrw==} + '@swc/core-darwin-arm64@1.15.43': + resolution: {integrity: sha512-v1aVuvXdo/BHxJzco9V2xpHrvwWmhfS8t6gziY5wJxd+Z2h8AeJRnAwPD8itCDaGXVBwJ/CaKfxEzTkG0Va0OA==} engines: {node: '>=10'} cpu: [arm64] os: [darwin] - '@swc/core-darwin-x64@1.15.41': - resolution: {integrity: sha512-N8B56ESFazZAWZyIkecADSPCwlLEinW7QLMEeotCpv4J7VXwfH+OLkmRL8o96UZ+1355fwHxDTS6/wK7yucvkA==} + '@swc/core-darwin-x64@1.15.43': + resolution: {integrity: sha512-lp3d4Lamc8dt5huYdGLSR+9hLxmfr1jb0l+4XXG2zPqZwYWRN9R0U2qYoTrggiU2RWW0oV9VbWM3kBnqIc2kdQ==} engines: {node: '>=10'} cpu: [x64] os: [darwin] - '@swc/core-linux-arm-gnueabihf@1.15.41': - resolution: {integrity: sha512-6XrId2fyle0mS5xxON8rU84mPd2Cq1kDJRj+4BnQKTd7u+2kSA6Ww+JkOP0iTNqOqt9OXhPOEAjBHAuonWcdCg==} + '@swc/core-linux-arm-gnueabihf@1.15.43': + resolution: {integrity: sha512-JWTQQELtsG5GgphDrr/XqqmM2pDN3cZqbMS0Mrg+iTiXL3F74sn/S2IyYE/5u4h2KLkTf9qQ7dXyxsbx7YzkeA==} engines: {node: '>=10'} cpu: [arm] os: [linux] - '@swc/core-linux-arm64-gnu@1.15.41': - resolution: {integrity: sha512-ynLIarxlkVnqHn1D0fKOVht6mNU5ks6lrH+MY3kkS+XFaGGgDxFZVjWKJlkYTKm3RCvBTfA8Ng5fLufXheMRKQ==} + '@swc/core-linux-arm64-gnu@1.15.43': + resolution: {integrity: sha512-B4otJRdPWIsmiSBf0uG7Z/+vMWmkufjz5MmYxubwKuZazDW14Zd3symga1N62QR4RT+kEFeHEgsXfZGyn/w0hw==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [glibc] - '@swc/core-linux-arm64-musl@1.15.41': - resolution: {integrity: sha512-dXu/5vd4gh8symyhRF+4G7gOPkjmb4pONhh7sl+6GSiW0LOKZlfu5kXmyFbTz9smOT7jgr002qY9b1nujjXt2A==} + '@swc/core-linux-arm64-musl@1.15.43': + resolution: {integrity: sha512-6zB6OnpViBxYy4tgY3v2i6AZY9fwkcHZ032UOwtwUuW1d19sdT07qF0kZe6/3UR1tUaK6jjg2rmVcUIBCEYVjQ==} engines: {node: '>=10'} cpu: [arm64] os: [linux] libc: [musl] - '@swc/core-linux-ppc64-gnu@1.15.41': - resolution: {integrity: sha512-XGO6zVPXoPE0gf/XnI4jBbafNT13AYgoh6ns0JCSdOetI/kqVf0vhpz7NuNgAzZrMVCsmieqjPoTwViDgh4mOQ==} + '@swc/core-linux-ppc64-gnu@1.15.43': + resolution: {integrity: sha512-coxE1ZWdB3uSDVNoEtYNrRi/1epvckZx9cTJ8ICUxTMTxGk+yvQ/Twacp3ruZSaMPGCriUjP86C37VhaT6nyRg==} engines: {node: '>=10'} cpu: [ppc64] os: [linux] libc: [glibc] - '@swc/core-linux-s390x-gnu@1.15.41': - resolution: {integrity: sha512-0WUglRwyZtW+iMi7J3iFdrCxreZZIKf4egTwEQfIYRsqFax69A0OrFj+NIoFSE03xBT/IFRrg+S8K6f9Ky+4hA==} + '@swc/core-linux-s390x-gnu@1.15.43': + resolution: {integrity: sha512-lXfLhs+LpBsD5inuYx+YDH5WsPPBQ95KPUiy8P5wq9ob9xKDZFqwNfU2QW6bGO8NqRO/H9JQomTSt5Yyh+FGfA==} engines: {node: '>=10'} cpu: [s390x] os: [linux] libc: [glibc] - '@swc/core-linux-x64-gnu@1.15.41': - resolution: {integrity: sha512-VxkuQK59c0tHm6uJZCUrS3cyA2JhGGfdU6e41SZz0x/JS+4Sm7C1mIc97In14vkZJopEt7yXA2TouCqZDSygEA==} + '@swc/core-linux-x64-gnu@1.15.43': + resolution: {integrity: sha512-07XnKwTmKy8TGOZG3D9fRnLWGynxPjwQnZLVmBFbo6F+7vHYzBIOuwXEhemrChBWb6yDNZsVCcMWCPX6FDD2xg==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [glibc] - '@swc/core-linux-x64-musl@1.15.41': - resolution: {integrity: sha512-/0qXIu1ZxggLuovLb22vFfKHq2AA4n6Whw5UwmVCHk4pkw7KWnPIQpMCEqUMPsNkFJig7PPp/TSYFu8ZEb2rtQ==} + '@swc/core-linux-x64-musl@1.15.43': + resolution: {integrity: sha512-TJc+bsSIaBh+hZvZ5GRtW/K1bw66TJ9vsUwvVIsZdiWxU5ObLwZvfcnZ3UpgVfMnFibRes9uriJrQNBHEEogRQ==} engines: {node: '>=10'} cpu: [x64] os: [linux] libc: [musl] - '@swc/core-win32-arm64-msvc@1.15.41': - resolution: {integrity: sha512-Y481sMNZM6rECh9VO4+y26N1lWEDAyxnBZskUf37fl90uHE946VHfmiVQWT0uMFOhyJJFovGTRuF4W82dwewUg==} + '@swc/core-win32-arm64-msvc@1.15.43': + resolution: {integrity: sha512-jfd7s2/bUQYkOHLs+LWQNKZdmDa8+sufKLllhpWAhVQ2GDCwsHe3vR/j+OSiItZNtkzFuaawa3+SAKz9y5gYfw==} engines: {node: '>=10'} cpu: [arm64] os: [win32] - '@swc/core-win32-ia32-msvc@1.15.41': - resolution: {integrity: sha512-BAchBD5qeUzy3hiPSLJtaaoSm4blCLyYffOF1bGE4ETcV+OisqjUAwDQMJj++4bTpvMCDzwC+Bj3PmQyBCtscw==} + '@swc/core-win32-ia32-msvc@1.15.43': + resolution: {integrity: sha512-rLAE8JvucqEW1ZGohxPQrQWPBQeJG4+ypKbWfdlU/qmKScvCkxf9/Jxnzki1dkUQCQ7P5Enp13RlvqOlvx/32g==} engines: {node: '>=10'} cpu: [ia32] os: [win32] - '@swc/core-win32-x64-msvc@1.15.41': - resolution: {integrity: sha512-WOkA+fJ/ViVBQDsSV9JC52NACTe5PhlurA6viASDZGb7HR3KS01ZG7RZ+Bg6SVQFIoq3gSbTsskQVe6EbHFAYw==} + '@swc/core-win32-x64-msvc@1.15.43': + resolution: {integrity: sha512-h8MLDHZcfIukwQWj03rIJZx1I0E81AYj2X7J/nGErG4nz+QAv6G1Z+peotvinL3lqpbo32tLYSMFo32/ySzxKg==} engines: {node: '>=10'} cpu: [x64] os: [win32] - '@swc/core@1.15.41': - resolution: {integrity: sha512-03nQq/082QRJJiOvp3FGbgxTGyyxMxohPTjhk/W9bD2J0tk4ukITI7goOhOO2WbaHn/lsPmo/zf8+DIXhwpgYQ==} + '@swc/core@1.15.43': + resolution: {integrity: sha512-1CuKjFkPxIgGdeHVuNbkxmBxkcbdc08u0aiI43pFq6yY1tTVKmXT9hFEooyyKs/sJ3xf1GPHyEwTtk9Xl8dvQw==} engines: {node: '>=10'} peerDependencies: '@swc/helpers': '>=0.5.17' @@ -579,8 +692,8 @@ packages: '@swc/counter@0.1.3': resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - '@swc/types@0.1.26': - resolution: {integrity: sha512-lyMwd7WGgG79RS7EERZV3T8wMdmPq3xwyg+1nmAM64kIhx5yl+juO2PYIHb7vTiPgPCj8LYjsNV2T5wiQHUEaw==} + '@swc/types@0.1.27': + resolution: {integrity: sha512-K6h3iUlqeM946U4sXFYeahefR1YBbXJvko+hv8WS8/0BNJ4OHiHRywMnQUJCqkR7Y9+hqQ1TvEpiKqUhz7NEFg==} '@tailwindcss/node@4.3.1': resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} @@ -676,6 +789,9 @@ packages: peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 + '@tybys/wasm-util@0.10.3': + resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} + '@types/debug@4.1.13': resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} @@ -717,8 +833,8 @@ packages: '@types/web-bluetooth@0.0.21': resolution: {integrity: sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA==} - '@ungap/structured-clone@1.3.1': - resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + '@ungap/structured-clone@1.3.2': + resolution: {integrity: sha512-5jsZFwgR5rTdKwidH9Qmat75RKwqfpKlWWB1frDkljN127mwqBu8K0PYo7/hFpF03IEJpfVPpCQDY/eDx3iHvA==} '@vitejs/plugin-react-swc@4.3.1': resolution: {integrity: sha512-PaeokKjAGraNN+s5SIApgsktnJprIyt3zgEIu7awnEdfn29QiB2crTcCzyi2XGpX9rUnTc0cKU07Wm0N0g7H2w==} @@ -733,43 +849,43 @@ packages: vite: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 vue: ^3.2.25 - '@vue/compiler-core@3.5.38': - resolution: {integrity: sha512-s99aGxWYig9ErHbct27KXEGhrBYlRI6c4MwAgXErOAbX9xiW37/uMa+XUDO69zLz83dng8UUZ70CTOJrLrYrEQ==} + '@vue/compiler-core@3.5.39': + resolution: {integrity: sha512-16KBTEXAJCpDr0mwlw+AZyhu8iyC7R3S2vBwsI7QnWJU6X3WKc9VKeNEZpiMdZ569qWhz9574L3vV55qRL0Vtw==} - '@vue/compiler-dom@3.5.38': - resolution: {integrity: sha512-JTqp25l8aFfJYF7/KmsXZjAxJz7T+SjmTJLoXVjHtc2BrSgSiW2n9Aem/cWq1OPe68A8JL06B3eVdhlP0H4TVw==} + '@vue/compiler-dom@3.5.39': + resolution: {integrity: sha512-oQPigALqYbNxTNPvNgSOe+czwVExfbVF02lz8jP0S3AXJiu3jxYDygNUiqSep4ezzW8XgnubqH63My2A7JR/vg==} - '@vue/compiler-sfc@3.5.38': - resolution: {integrity: sha512-DuA2GiZawSEW442iw/9+Fkol8hTgb4Ke5KkhmSry65QA7YuyMbIdy8p0XZRMvNwJdgRz307W8g1CSzdvS4nuNg==} + '@vue/compiler-sfc@3.5.39': + resolution: {integrity: sha512-d0ki86iOyN8LoZPBmk5SJWNwHP19CnDDCfuo//+2WJa2g5Ke0Jay983PIBIcSSzldC68I8DrD5GrHV3OSDfodg==} - '@vue/compiler-ssr@3.5.38': - resolution: {integrity: sha512-7s+W5Gc42FGxZMcuwl8H5B29T8BJPMdBT7KHFE+BbAuZ/iTEdTtv7z2XiMjiaUUw4w3ZcCEdHs36RuYJ2VA7bA==} + '@vue/compiler-ssr@3.5.39': + resolution: {integrity: sha512-Ce7/wvwMHai74bdszfXExdazFigYnlF9zgCmEQUcM1j0fOymlouZ7XilTYNo8oUjhlnjYOZbGrcYKuqjz89Ucw==} - '@vue/devtools-api@8.1.2': - resolution: {integrity: sha512-vA0O112YqyDuNA1s7Yb2gCgToQ/OxOWiFDO5ThLCcDy0ldHnSd1dUTaSYhOldbqoNgumE4dxtGAoAaSUKUD1Zg==} + '@vue/devtools-api@8.1.4': + resolution: {integrity: sha512-zphdXRe0VxWfUWH2KLcNV4xWUMxjxASyxCjFS/wRHVYfJCMBulq1ce3RHGkYRxghoVBqwCzOw1TWIIfvIWCY1w==} - '@vue/devtools-kit@8.1.2': - resolution: {integrity: sha512-f75/upc+GCyjXErpgPGz4582ujS0L/adAltGy+tqXMGUJpgAcfGr6CxnnhpZY8BHuMYt6KpbF8uaFrrQG66rGQ==} + '@vue/devtools-kit@8.1.4': + resolution: {integrity: sha512-+GLBwY63hZ46sqTlgXgvd8IcZTpWe0PZzbJgs63ii/8uTYVwg1q9bdIR9xx8ReKcrdWS01RGCbC971jYPvjRCA==} - '@vue/devtools-shared@8.1.2': - resolution: {integrity: sha512-X9RyVFYAdkBe4IUf5v48TxBF/6QPmF8CmWrDAjXzfUHrgQ/HGfTC1A6TqgXqZ03ye66l3AD51BAGD69IvKM9sw==} + '@vue/devtools-shared@8.1.4': + resolution: {integrity: sha512-Earc/zrg0w0Md4KdrvgRR1vC5F17Zn+VzqTNI7PXYXz0fPJDVWENe7fv6NHi6Ja9Sq6Ce6SYUdc2FlXU0OMkjQ==} - '@vue/reactivity@3.5.38': - resolution: {integrity: sha512-pG6LV/NDNRbKizcUjFFLAfjaL8mcv4DmR9avNcUw2gDHBzZneuS2TWCmp633ynzxz9YYKNeEPK2I8Wraqy2HUQ==} + '@vue/reactivity@3.5.39': + resolution: {integrity: sha512-TpsuBJ9gGlZa5d23XcM2y8EXanz9dZeVDQBXRwzy46ItgvM+rWpzs+UVM0wcRLxGvcav0HE5jz2gNL53xlRAog==} - '@vue/runtime-core@3.5.38': - resolution: {integrity: sha512-iyW8WVfF1CpCXxncZY5Ei6rSd6oZr5DgEom//fUjRBRl56AXPD+s9ATvukRt77ZFTuYlnVA1bxY+dJB94tWVYw==} + '@vue/runtime-core@3.5.39': + resolution: {integrity: sha512-9GLtNyRvPAUMbX+7ono0RC2j0guo2LXVi8LvcmAooImACUKm0oFf0jjwbX8/H0AE/t1nxhAkn8RSl9PMCzzxZw==} - '@vue/runtime-dom@3.5.38': - resolution: {integrity: sha512-apX2wt9sdfDshS+a2xueFZLVpt0GkRJZSoPmrW/SA4yzXTznhfcMVW59gr7h4YQeY0vJhdJkk2rsIDwgfFgC5A==} + '@vue/runtime-dom@3.5.39': + resolution: {integrity: sha512-7Y6aAGboKcXAZ3ECuUy7RrS5yy2r47dhTp2SKaJmYxjopImaVFaNa5Ne66NwGovsrxVAl5S5rwc7m22UG7Lmww==} - '@vue/server-renderer@3.5.38': - resolution: {integrity: sha512-vue8vbf2QlV4quHqzwmJy6dWfmRhP1J8l4wtZg60CL6VoKqcPY2oe7may3+1d9qfpedjK5PRLFqd5k3Isj9mUw==} + '@vue/server-renderer@3.5.39': + resolution: {integrity: sha512-yZSakiAGw85rZfG7UM8akMnIF+FmeiNk47uvHf2nVBBSe+dIKUhZuZq9+XgJhbV3nS5Z4ALH23/MpXofW+mbcw==} peerDependencies: - vue: 3.5.38 + vue: 3.5.39 - '@vue/shared@3.5.38': - resolution: {integrity: sha512-FTW0AFZNaK5/mOqvGBwVfUlNLU38TiQn4+DQgIFUnrBBJQ1crMJ82yeGQLV5jyKFsO8yRukpbuP7x+nRbH6aug==} + '@vue/shared@3.5.39': + resolution: {integrity: sha512-l1rrBtBfTnmxvtsvdQDXltUUy8S1Y+ZaqdfUzmAnJkTd8Z8rv5v/ytW+TKiqEOWyHPoqtPlNFSs0lhRmYVSHVA==} '@vueuse/core@14.3.0': resolution: {integrity: sha512-aHfz47g0ZhMtTVHmIzMVpJy8ePhhOy68GY5bv110+5DVtZ+W7BsOx+m61UNQqfrWyPztIHIanWa3E2tib3NFIw==} @@ -928,8 +1044,8 @@ packages: resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true @@ -968,8 +1084,8 @@ packages: picomatch: optional: true - focus-trap@8.2.1: - resolution: {integrity: sha512-6CxwrrFRquH7pDXb1mWxudkU9LSfYBMRZutpgddb2o6iwCk7cIRrBhyY3c8SGKcmIKdeMTrGSNg4Bedh2RSF/w==} + focus-trap@8.2.2: + resolution: {integrity: sha512-qV0g8hRYBqgACcFOH3f9wXc4zPKhr/0z9RI2a6ZijZ72EeBi4g8oBy8zAWuUR1TsMpOzwpUMFvjdasrC41Joug==} format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} @@ -1227,8 +1343,8 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.12: - resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} + nanoid@3.3.15: + resolution: {integrity: sha512-y7Wygv/7mEOvxTuEQDB8StXdMRBWf1kR/tlhAzBRUFkB2jfcLOAxO/SHmOO2zgz1pVgK29/kyupn059/bCHdjA==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -1300,8 +1416,13 @@ packages: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} - rollup@4.61.1: - resolution: {integrity: sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==} + rolldown@1.1.3: + resolution: {integrity: sha512-1F1eEtUBtFvcGm1HQ9TiUIUHPQG7mSAODrhIzjxoUEFuo8OcbrGLiVLkevNgj84TE4lnHvnumwFjhJO5Eu135g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.62.2: + resolution: {integrity: sha512-RFnrW4lhXA3s3eqHDZvN654g8OTjzRfqpIRJYczCGB6HzphckVAi/Qh4tbPUbRuDi7s1Llv8g/NspLkttY3gTA==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -1340,8 +1461,8 @@ packages: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} engines: {node: '>=0.10.0'} - tabbable@6.4.0: - resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} + tabbable@6.5.0: + resolution: {integrity: sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==} tailwindcss@4.3.1: resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} @@ -1363,6 +1484,9 @@ packages: trough@2.2.0: resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} @@ -1445,6 +1569,49 @@ packages: yaml: optional: true + vite@8.1.0: + resolution: {integrity: sha512-BuJcQK/56NQTWDGn4ABea3q4SSBdNPWwNZKTkkUpcMPnLoquSYH8llRtSUIgoL1KSCpHt5eghLShn50mH36y7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.3.0 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + vitepress-plugin-llms@1.13.2: resolution: {integrity: sha512-2O4s0I5pjEZzgnoWgBPCZCyhah9FH5uQB6lGADazMoyF1URJshtG04ZnmX+cbmQmniN3T5JzdJO9B4q8JHDKOQ==} engines: {node: '>=18'} @@ -1464,8 +1631,8 @@ packages: postcss: optional: true - vue@3.5.38: - resolution: {integrity: sha512-vAMKHfImQlYSy0C+PBue4s3ERZ2xGKfgZg5GXAsLInq1dyh2H78ILVP5sK0KPFPVW4kv+OGCIvBEondcjpZp7A==} + vue@3.5.39: + resolution: {integrity: sha512-xmZCYabFGcirU8r0fTuvl/LICc1OU620rnqepaJDL/a141ZigkG7AyaxQLdqJ02ZRYzWe6YPaDHeQx7MfknQfA==} peerDependencies: typescript: '*' peerDependenciesMeta: @@ -1484,8 +1651,8 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} zwitch@2.0.4: @@ -1547,85 +1714,101 @@ snapshots: '@docsearch/sidepanel-js@4.6.3': {} - '@esbuild/aix-ppc64@0.27.7': + '@emnapi/core@1.11.1': + dependencies: + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.11.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.27.7': + '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.27.7': + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.27.7': + '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.27.7': + '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.27.7': + '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.27.7': + '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.27.7': + '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.27.7': + '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.27.7': + '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.27.7': + '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.27.7': + '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.27.7': + '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.27.7': + '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.27.7': + '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.27.7': + '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.27.7': + '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.27.7': + '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.27.7': + '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.27.7': + '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.27.7': + '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.27.7': + '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.27.7': + '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.27.7': + '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.27.7': + '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.27.7': + '@esbuild/win32-x64@0.28.1': optional: true - '@iconify-json/simple-icons@1.2.86': + '@iconify-json/simple-icons@1.2.87': dependencies: '@iconify/types': 2.0.0 @@ -1650,81 +1833,139 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@napi-rs/wasm-runtime@1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@tybys/wasm-util': 0.10.3 + optional: true + + '@oxc-project/types@0.137.0': {} + + '@rolldown/binding-android-arm64@1.1.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.1.3': + optional: true + + '@rolldown/binding-darwin-x64@1.1.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.1.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.1.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.1.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.1.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.1.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.1.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.1.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.1.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.1.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.1.3': + dependencies: + '@emnapi/core': 1.11.1 + '@emnapi/runtime': 1.11.1 + '@napi-rs/wasm-runtime': 1.1.6(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.1.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.1.3': + optional: true + '@rolldown/pluginutils@1.0.1': {} - '@rollup/rollup-android-arm-eabi@4.61.1': + '@rollup/rollup-android-arm-eabi@4.62.2': optional: true - '@rollup/rollup-android-arm64@4.61.1': + '@rollup/rollup-android-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-arm64@4.61.1': + '@rollup/rollup-darwin-arm64@4.62.2': optional: true - '@rollup/rollup-darwin-x64@4.61.1': + '@rollup/rollup-darwin-x64@4.62.2': optional: true - '@rollup/rollup-freebsd-arm64@4.61.1': + '@rollup/rollup-freebsd-arm64@4.62.2': optional: true - '@rollup/rollup-freebsd-x64@4.61.1': + '@rollup/rollup-freebsd-x64@4.62.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.61.1': + '@rollup/rollup-linux-arm-gnueabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.61.1': + '@rollup/rollup-linux-arm-musleabihf@4.62.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.61.1': + '@rollup/rollup-linux-arm64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.61.1': + '@rollup/rollup-linux-arm64-musl@4.62.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.61.1': + '@rollup/rollup-linux-loong64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-loong64-musl@4.61.1': + '@rollup/rollup-linux-loong64-musl@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.61.1': + '@rollup/rollup-linux-ppc64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-ppc64-musl@4.61.1': + '@rollup/rollup-linux-ppc64-musl@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.61.1': + '@rollup/rollup-linux-riscv64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.61.1': + '@rollup/rollup-linux-riscv64-musl@4.62.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.61.1': + '@rollup/rollup-linux-s390x-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.61.1': + '@rollup/rollup-linux-x64-gnu@4.62.2': optional: true - '@rollup/rollup-linux-x64-musl@4.61.1': + '@rollup/rollup-linux-x64-musl@4.62.2': optional: true - '@rollup/rollup-openbsd-x64@4.61.1': + '@rollup/rollup-openbsd-x64@4.62.2': optional: true - '@rollup/rollup-openharmony-arm64@4.61.1': + '@rollup/rollup-openharmony-arm64@4.62.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.61.1': + '@rollup/rollup-win32-arm64-msvc@4.62.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.61.1': + '@rollup/rollup-win32-ia32-msvc@4.62.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.61.1': + '@rollup/rollup-win32-x64-gnu@4.62.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.61.1': + '@rollup/rollup-win32-x64-msvc@4.62.2': optional: true '@shikijs/core@3.23.0': @@ -1765,63 +2006,63 @@ snapshots: '@shikijs/vscode-textmate@10.0.2': {} - '@swc/core-darwin-arm64@1.15.41': + '@swc/core-darwin-arm64@1.15.43': optional: true - '@swc/core-darwin-x64@1.15.41': + '@swc/core-darwin-x64@1.15.43': optional: true - '@swc/core-linux-arm-gnueabihf@1.15.41': + '@swc/core-linux-arm-gnueabihf@1.15.43': optional: true - '@swc/core-linux-arm64-gnu@1.15.41': + '@swc/core-linux-arm64-gnu@1.15.43': optional: true - '@swc/core-linux-arm64-musl@1.15.41': + '@swc/core-linux-arm64-musl@1.15.43': optional: true - '@swc/core-linux-ppc64-gnu@1.15.41': + '@swc/core-linux-ppc64-gnu@1.15.43': optional: true - '@swc/core-linux-s390x-gnu@1.15.41': + '@swc/core-linux-s390x-gnu@1.15.43': optional: true - '@swc/core-linux-x64-gnu@1.15.41': + '@swc/core-linux-x64-gnu@1.15.43': optional: true - '@swc/core-linux-x64-musl@1.15.41': + '@swc/core-linux-x64-musl@1.15.43': optional: true - '@swc/core-win32-arm64-msvc@1.15.41': + '@swc/core-win32-arm64-msvc@1.15.43': optional: true - '@swc/core-win32-ia32-msvc@1.15.41': + '@swc/core-win32-ia32-msvc@1.15.43': optional: true - '@swc/core-win32-x64-msvc@1.15.41': + '@swc/core-win32-x64-msvc@1.15.43': optional: true - '@swc/core@1.15.41': + '@swc/core@1.15.43': dependencies: '@swc/counter': 0.1.3 - '@swc/types': 0.1.26 + '@swc/types': 0.1.27 optionalDependencies: - '@swc/core-darwin-arm64': 1.15.41 - '@swc/core-darwin-x64': 1.15.41 - '@swc/core-linux-arm-gnueabihf': 1.15.41 - '@swc/core-linux-arm64-gnu': 1.15.41 - '@swc/core-linux-arm64-musl': 1.15.41 - '@swc/core-linux-ppc64-gnu': 1.15.41 - '@swc/core-linux-s390x-gnu': 1.15.41 - '@swc/core-linux-x64-gnu': 1.15.41 - '@swc/core-linux-x64-musl': 1.15.41 - '@swc/core-win32-arm64-msvc': 1.15.41 - '@swc/core-win32-ia32-msvc': 1.15.41 - '@swc/core-win32-x64-msvc': 1.15.41 + '@swc/core-darwin-arm64': 1.15.43 + '@swc/core-darwin-x64': 1.15.43 + '@swc/core-linux-arm-gnueabihf': 1.15.43 + '@swc/core-linux-arm64-gnu': 1.15.43 + '@swc/core-linux-arm64-musl': 1.15.43 + '@swc/core-linux-ppc64-gnu': 1.15.43 + '@swc/core-linux-s390x-gnu': 1.15.43 + '@swc/core-linux-x64-gnu': 1.15.43 + '@swc/core-linux-x64-musl': 1.15.43 + '@swc/core-win32-arm64-msvc': 1.15.43 + '@swc/core-win32-ia32-msvc': 1.15.43 + '@swc/core-win32-x64-msvc': 1.15.43 '@swc/counter@0.1.3': {} - '@swc/types@0.1.26': + '@swc/types@0.1.27': dependencies: '@swc/counter': 0.1.3 @@ -1886,12 +2127,17 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 - '@tailwindcss/vite@4.3.1(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))': + '@tailwindcss/vite@4.3.1(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0))': dependencies: '@tailwindcss/node': 4.3.1 '@tailwindcss/oxide': 4.3.1 tailwindcss: 4.3.1 - vite: 7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0) + vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0) + + '@tybys/wasm-util@0.10.3': + dependencies: + tslib: 2.8.1 + optional: true '@types/debug@4.1.13': dependencies: @@ -1934,109 +2180,109 @@ snapshots: '@types/web-bluetooth@0.0.21': {} - '@ungap/structured-clone@1.3.1': {} + '@ungap/structured-clone@1.3.2': {} - '@vitejs/plugin-react-swc@4.3.1(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))': + '@vitejs/plugin-react-swc@4.3.1(vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0))': dependencies: '@rolldown/pluginutils': 1.0.1 - '@swc/core': 1.15.41 - vite: 7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0) + '@swc/core': 1.15.43 + vite: 8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-vue@6.0.7(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))(vue@3.5.38(typescript@6.0.3))': + '@vitejs/plugin-vue@6.0.7(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))(vue@3.5.39(typescript@6.0.3))': dependencies: '@rolldown/pluginutils': 1.0.1 vite: 7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0) - vue: 3.5.38(typescript@6.0.3) + vue: 3.5.39(typescript@6.0.3) - '@vue/compiler-core@3.5.38': + '@vue/compiler-core@3.5.39': dependencies: '@babel/parser': 7.29.7 - '@vue/shared': 3.5.38 + '@vue/shared': 3.5.39 entities: 7.0.1 estree-walker: 2.0.2 source-map-js: 1.2.1 - '@vue/compiler-dom@3.5.38': + '@vue/compiler-dom@3.5.39': dependencies: - '@vue/compiler-core': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/compiler-core': 3.5.39 + '@vue/shared': 3.5.39 - '@vue/compiler-sfc@3.5.38': + '@vue/compiler-sfc@3.5.39': dependencies: '@babel/parser': 7.29.7 - '@vue/compiler-core': 3.5.38 - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/compiler-core': 3.5.39 + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 estree-walker: 2.0.2 magic-string: 0.30.21 postcss: 8.5.15 source-map-js: 1.2.1 - '@vue/compiler-ssr@3.5.38': + '@vue/compiler-ssr@3.5.39': dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/compiler-dom': 3.5.39 + '@vue/shared': 3.5.39 - '@vue/devtools-api@8.1.2': + '@vue/devtools-api@8.1.4': dependencies: - '@vue/devtools-kit': 8.1.2 + '@vue/devtools-kit': 8.1.4 - '@vue/devtools-kit@8.1.2': + '@vue/devtools-kit@8.1.4': dependencies: - '@vue/devtools-shared': 8.1.2 + '@vue/devtools-shared': 8.1.4 birpc: 2.9.0 hookable: 5.5.3 perfect-debounce: 2.1.0 - '@vue/devtools-shared@8.1.2': {} + '@vue/devtools-shared@8.1.4': {} - '@vue/reactivity@3.5.38': + '@vue/reactivity@3.5.39': dependencies: - '@vue/shared': 3.5.38 + '@vue/shared': 3.5.39 - '@vue/runtime-core@3.5.38': + '@vue/runtime-core@3.5.39': dependencies: - '@vue/reactivity': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/reactivity': 3.5.39 + '@vue/shared': 3.5.39 - '@vue/runtime-dom@3.5.38': + '@vue/runtime-dom@3.5.39': dependencies: - '@vue/reactivity': 3.5.38 - '@vue/runtime-core': 3.5.38 - '@vue/shared': 3.5.38 + '@vue/reactivity': 3.5.39 + '@vue/runtime-core': 3.5.39 + '@vue/shared': 3.5.39 csstype: 3.2.3 - '@vue/server-renderer@3.5.38(vue@3.5.38(typescript@6.0.3))': + '@vue/server-renderer@3.5.39(vue@3.5.39(typescript@6.0.3))': dependencies: - '@vue/compiler-ssr': 3.5.38 - '@vue/shared': 3.5.38 - vue: 3.5.38(typescript@6.0.3) + '@vue/compiler-ssr': 3.5.39 + '@vue/shared': 3.5.39 + vue: 3.5.39(typescript@6.0.3) - '@vue/shared@3.5.38': {} + '@vue/shared@3.5.39': {} - '@vueuse/core@14.3.0(vue@3.5.38(typescript@6.0.3))': + '@vueuse/core@14.3.0(vue@3.5.39(typescript@6.0.3))': dependencies: '@types/web-bluetooth': 0.0.21 '@vueuse/metadata': 14.3.0 - '@vueuse/shared': 14.3.0(vue@3.5.38(typescript@6.0.3)) - vue: 3.5.38(typescript@6.0.3) + '@vueuse/shared': 14.3.0(vue@3.5.39(typescript@6.0.3)) + vue: 3.5.39(typescript@6.0.3) - '@vueuse/integrations@14.3.0(focus-trap@8.2.1)(vue@3.5.38(typescript@6.0.3))': + '@vueuse/integrations@14.3.0(focus-trap@8.2.2)(vue@3.5.39(typescript@6.0.3))': dependencies: - '@vueuse/core': 14.3.0(vue@3.5.38(typescript@6.0.3)) - '@vueuse/shared': 14.3.0(vue@3.5.38(typescript@6.0.3)) - vue: 3.5.38(typescript@6.0.3) + '@vueuse/core': 14.3.0(vue@3.5.39(typescript@6.0.3)) + '@vueuse/shared': 14.3.0(vue@3.5.39(typescript@6.0.3)) + vue: 3.5.39(typescript@6.0.3) optionalDependencies: - focus-trap: 8.2.1 + focus-trap: 8.2.2 '@vueuse/metadata@14.3.0': {} - '@vueuse/shared@14.3.0(vue@3.5.38(typescript@6.0.3))': + '@vueuse/shared@14.3.0(vue@3.5.39(typescript@6.0.3))': dependencies: - vue: 3.5.38(typescript@6.0.3) + vue: 3.5.39(typescript@6.0.3) ansi-regex@5.0.1: {} @@ -2117,34 +2363,34 @@ snapshots: entities@7.0.1: {} - esbuild@0.27.7: + esbuild@0.28.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 escalade@3.2.0: {} @@ -2168,9 +2414,9 @@ snapshots: optionalDependencies: picomatch: 4.0.4 - focus-trap@8.2.1: + focus-trap@8.2.2: dependencies: - tabbable: 6.4.0 + tabbable: 6.5.0 format@0.2.2: {} @@ -2338,7 +2584,7 @@ snapshots: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.1 + '@ungap/structured-clone': 1.3.2 devlop: 1.1.0 micromark-util-sanitize-uri: 2.0.1 trim-lines: 3.0.1 @@ -2506,7 +2752,7 @@ snapshots: millify@6.1.0: dependencies: - yargs: 17.7.2 + yargs: 17.7.3 minimatch@10.2.5: dependencies: @@ -2516,7 +2762,7 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.12: {} + nanoid@3.3.15: {} oniguruma-parser@0.12.2: {} @@ -2536,7 +2782,7 @@ snapshots: postcss@8.5.15: dependencies: - nanoid: 3.3.12 + nanoid: 3.3.15 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -2598,35 +2844,56 @@ snapshots: require-directory@2.1.1: {} - rollup@4.61.1: + rolldown@1.1.3: + dependencies: + '@oxc-project/types': 0.137.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.1.3 + '@rolldown/binding-darwin-arm64': 1.1.3 + '@rolldown/binding-darwin-x64': 1.1.3 + '@rolldown/binding-freebsd-x64': 1.1.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.1.3 + '@rolldown/binding-linux-arm64-gnu': 1.1.3 + '@rolldown/binding-linux-arm64-musl': 1.1.3 + '@rolldown/binding-linux-ppc64-gnu': 1.1.3 + '@rolldown/binding-linux-s390x-gnu': 1.1.3 + '@rolldown/binding-linux-x64-gnu': 1.1.3 + '@rolldown/binding-linux-x64-musl': 1.1.3 + '@rolldown/binding-openharmony-arm64': 1.1.3 + '@rolldown/binding-wasm32-wasi': 1.1.3 + '@rolldown/binding-win32-arm64-msvc': 1.1.3 + '@rolldown/binding-win32-x64-msvc': 1.1.3 + + rollup@4.62.2: dependencies: '@types/estree': 1.0.9 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.61.1 - '@rollup/rollup-android-arm64': 4.61.1 - '@rollup/rollup-darwin-arm64': 4.61.1 - '@rollup/rollup-darwin-x64': 4.61.1 - '@rollup/rollup-freebsd-arm64': 4.61.1 - '@rollup/rollup-freebsd-x64': 4.61.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.61.1 - '@rollup/rollup-linux-arm-musleabihf': 4.61.1 - '@rollup/rollup-linux-arm64-gnu': 4.61.1 - '@rollup/rollup-linux-arm64-musl': 4.61.1 - '@rollup/rollup-linux-loong64-gnu': 4.61.1 - '@rollup/rollup-linux-loong64-musl': 4.61.1 - '@rollup/rollup-linux-ppc64-gnu': 4.61.1 - '@rollup/rollup-linux-ppc64-musl': 4.61.1 - '@rollup/rollup-linux-riscv64-gnu': 4.61.1 - '@rollup/rollup-linux-riscv64-musl': 4.61.1 - '@rollup/rollup-linux-s390x-gnu': 4.61.1 - '@rollup/rollup-linux-x64-gnu': 4.61.1 - '@rollup/rollup-linux-x64-musl': 4.61.1 - '@rollup/rollup-openbsd-x64': 4.61.1 - '@rollup/rollup-openharmony-arm64': 4.61.1 - '@rollup/rollup-win32-arm64-msvc': 4.61.1 - '@rollup/rollup-win32-ia32-msvc': 4.61.1 - '@rollup/rollup-win32-x64-gnu': 4.61.1 - '@rollup/rollup-win32-x64-msvc': 4.61.1 + '@rollup/rollup-android-arm-eabi': 4.62.2 + '@rollup/rollup-android-arm64': 4.62.2 + '@rollup/rollup-darwin-arm64': 4.62.2 + '@rollup/rollup-darwin-x64': 4.62.2 + '@rollup/rollup-freebsd-arm64': 4.62.2 + '@rollup/rollup-freebsd-x64': 4.62.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.2 + '@rollup/rollup-linux-arm-musleabihf': 4.62.2 + '@rollup/rollup-linux-arm64-gnu': 4.62.2 + '@rollup/rollup-linux-arm64-musl': 4.62.2 + '@rollup/rollup-linux-loong64-gnu': 4.62.2 + '@rollup/rollup-linux-loong64-musl': 4.62.2 + '@rollup/rollup-linux-ppc64-gnu': 4.62.2 + '@rollup/rollup-linux-ppc64-musl': 4.62.2 + '@rollup/rollup-linux-riscv64-gnu': 4.62.2 + '@rollup/rollup-linux-riscv64-musl': 4.62.2 + '@rollup/rollup-linux-s390x-gnu': 4.62.2 + '@rollup/rollup-linux-x64-gnu': 4.62.2 + '@rollup/rollup-linux-x64-musl': 4.62.2 + '@rollup/rollup-openbsd-x64': 4.62.2 + '@rollup/rollup-openharmony-arm64': 4.62.2 + '@rollup/rollup-win32-arm64-msvc': 4.62.2 + '@rollup/rollup-win32-ia32-msvc': 4.62.2 + '@rollup/rollup-win32-x64-gnu': 4.62.2 + '@rollup/rollup-win32-x64-msvc': 4.62.2 fsevents: 2.3.3 scheduler@0.27.0: {} @@ -2670,7 +2937,7 @@ snapshots: strip-bom-string@1.0.0: {} - tabbable@6.4.0: {} + tabbable@6.5.0: {} tailwindcss@4.3.1: {} @@ -2687,6 +2954,9 @@ snapshots: trough@2.2.0: {} + tslib@2.8.1: + optional: true + typescript@6.0.3: {} uc.micro@2.1.0: {} @@ -2746,11 +3016,11 @@ snapshots: vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0): dependencies: - esbuild: 0.27.7 + esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 - rollup: 4.61.1 + rollup: 4.62.2 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.0.1 @@ -2758,6 +3028,19 @@ snapshots: jiti: 2.7.0 lightningcss: 1.32.0 + vite@8.1.0(@types/node@26.0.1)(esbuild@0.28.1)(jiti@2.7.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.1.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.0.1 + esbuild: 0.28.1 + fsevents: 2.3.3 + jiti: 2.7.0 + vitepress-plugin-llms@1.13.2: dependencies: gray-matter: 4.0.3 @@ -2782,22 +3065,22 @@ snapshots: '@docsearch/css': 4.6.3 '@docsearch/js': 4.6.3 '@docsearch/sidepanel-js': 4.6.3 - '@iconify-json/simple-icons': 1.2.86 + '@iconify-json/simple-icons': 1.2.87 '@shikijs/core': 3.23.0 '@shikijs/transformers': 3.23.0 '@shikijs/types': 3.23.0 '@types/markdown-it': 14.1.2 - '@vitejs/plugin-vue': 6.0.7(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))(vue@3.5.38(typescript@6.0.3)) - '@vue/devtools-api': 8.1.2 - '@vue/shared': 3.5.38 - '@vueuse/core': 14.3.0(vue@3.5.38(typescript@6.0.3)) - '@vueuse/integrations': 14.3.0(focus-trap@8.2.1)(vue@3.5.38(typescript@6.0.3)) - focus-trap: 8.2.1 + '@vitejs/plugin-vue': 6.0.7(vite@7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0))(vue@3.5.39(typescript@6.0.3)) + '@vue/devtools-api': 8.1.4 + '@vue/shared': 3.5.39 + '@vueuse/core': 14.3.0(vue@3.5.39(typescript@6.0.3)) + '@vueuse/integrations': 14.3.0(focus-trap@8.2.2)(vue@3.5.39(typescript@6.0.3)) + focus-trap: 8.2.2 mark.js: 8.11.1 minisearch: 7.2.0 shiki: 3.23.0 vite: 7.3.6(@types/node@26.0.1)(jiti@2.7.0)(lightningcss@1.32.0) - vue: 3.5.38(typescript@6.0.3) + vue: 3.5.39(typescript@6.0.3) optionalDependencies: postcss: 8.5.15 transitivePeerDependencies: @@ -2825,13 +3108,13 @@ snapshots: - universal-cookie - yaml - vue@3.5.38(typescript@6.0.3): + vue@3.5.39(typescript@6.0.3): dependencies: - '@vue/compiler-dom': 3.5.38 - '@vue/compiler-sfc': 3.5.38 - '@vue/runtime-dom': 3.5.38 - '@vue/server-renderer': 3.5.38(vue@3.5.38(typescript@6.0.3)) - '@vue/shared': 3.5.38 + '@vue/compiler-dom': 3.5.39 + '@vue/compiler-sfc': 3.5.39 + '@vue/runtime-dom': 3.5.39 + '@vue/server-renderer': 3.5.39(vue@3.5.39(typescript@6.0.3)) + '@vue/shared': 3.5.39 optionalDependencies: typescript: 6.0.3 @@ -2845,7 +3128,7 @@ snapshots: yargs-parser@21.1.1: {} - yargs@17.7.2: + yargs@17.7.3: dependencies: cliui: 8.0.1 escalade: 3.2.0 diff --git a/web-ui/src/components/player/video-player.tsx b/web-ui/src/components/player/video-player.tsx index 983b9097..af90377a 100644 --- a/web-ui/src/components/player/video-player.tsx +++ b/web-ui/src/components/player/video-player.tsx @@ -21,7 +21,6 @@ import { lagBehindLiveEdge, wallClockToMse, } from "../../mpegts/player/wall-clock"; -import mp2WasmUrl from "../../mpegts/wasm/minimp3/mp2_decoder.wasm?url"; import type { Channel, EPGProgram } from "../../types/player"; import { PLAYER_OVERLAY_SURFACE_CLASS } from "./classnames"; import { PlayerControls } from "./player-controls"; @@ -559,9 +558,7 @@ export function VideoPlayer({ video.volume = volume; video.muted = isMuted; - const p = createPlayer(video, { - wasmDecoders: { mp2: mp2WasmUrl }, - }); + const p = createPlayer(video); p.on("error", (e) => { if (slotPlayerRef(slotId).current === p) { handlePlayerError(e, slotId); diff --git a/web-ui/src/mpegts/audio/pcm-audio-player.ts b/web-ui/src/mpegts/audio/pcm-audio-player.ts index 97df8c43..87a82a9a 100644 --- a/web-ui/src/mpegts/audio/pcm-audio-player.ts +++ b/web-ui/src/mpegts/audio/pcm-audio-player.ts @@ -315,10 +315,7 @@ export class PCMAudioPlayer { } this.stretcherLoading = true; - const wasmUrl = this.config.wasmDecoders.mp2; - const promise = wasmUrl - ? WasmStretcher.create(wasmUrl, chunk.sampleRate, chunk.channels) - : Promise.reject(new Error("MP2 WASM URL is not configured")); + const promise = WasmStretcher.create(chunk.sampleRate, chunk.channels); promise .then((stretcher) => { diff --git a/web-ui/src/mpegts/audio/wasm-stretcher.ts b/web-ui/src/mpegts/audio/wasm-stretcher.ts index 08007369..ba77ab27 100644 --- a/web-ui/src/mpegts/audio/wasm-stretcher.ts +++ b/web-ui/src/mpegts/audio/wasm-stretcher.ts @@ -10,6 +10,7 @@ */ import Log from "../utils/logger"; +import { getMp2DecoderWasmExports, type Mp2DecoderWasmExports } from "../wasm/mp2-decoder"; const TAG = "WasmStretcher"; @@ -25,46 +26,26 @@ export interface Stretcher { destroy(): void; } -interface WsolaExports { - memory: WebAssembly.Memory; - _initialize: () => void; - malloc: (size: number) => number; - free: (ptr: number) => void; - wsola_create: (sampleRate: number, channels: number) => number; - wsola_destroy: (ptr: number) => void; - wsola_reset: (ptr: number) => void; - wsola_set_ratio: (ptr: number, ratio: number) => void; - wsola_position: (ptr: number) => number; - wsola_process: (ptr: number, input: number, inFrames: number, output: number, outCapacity: number) => number; -} - export class WasmStretcher implements Stretcher { readonly sampleRate: number; readonly channels: number; - private exports: WsolaExports; + private exports: Mp2DecoderWasmExports; private handle: number; private inPtr = 0; private inCapacityFrames = 0; private outPtr = 0; private outCapacityFrames = 0; - private constructor(exports: WsolaExports, handle: number, sampleRate: number, channels: number) { + private constructor(exports: Mp2DecoderWasmExports, handle: number, sampleRate: number, channels: number) { this.exports = exports; this.handle = handle; this.sampleRate = sampleRate; this.channels = channels; } - static async create(wasmUrl: string, sampleRate: number, channels: number): Promise { - const imports = { - env: { - emscripten_notify_memory_growth: () => {}, - }, - }; - const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); - const ex = instance.exports as unknown as WsolaExports; - ex._initialize(); + static async create(sampleRate: number, channels: number): Promise { + const ex = getMp2DecoderWasmExports(); const handle = ex.wsola_create(sampleRate, channels); if (!handle) { throw new Error("wsola_create failed"); diff --git a/web-ui/src/mpegts/config.ts b/web-ui/src/mpegts/config.ts index de600e74..9715c12f 100644 --- a/web-ui/src/mpegts/config.ts +++ b/web-ui/src/mpegts/config.ts @@ -17,10 +17,6 @@ export interface PlayerConfig { */ maxBufferHoleMs: number; - /** URLs to WASM decoder files, keyed by codec. Omit to disable software decoding for that codec. - * e.g. `{ mp2: "/assets/mp2_decoder.wasm" }` */ - wasmDecoders: { mp2?: string }; - /** Max backward buffer duration in seconds. Cleanup triggers when buffer exceeds this. @default 180 */ bufferCleanupMaxBackward: number; /** Min backward buffer to retain after cleanup in seconds. @default 120 */ @@ -40,8 +36,6 @@ export const defaultConfig: PlayerConfig = { maxBufferHoleMs: 300, - wasmDecoders: {}, - bufferCleanupMaxBackward: 180, bufferCleanupMinBackward: 120, diff --git a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts index 8fd7b83f..57dd5dea 100644 --- a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts +++ b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts @@ -12,6 +12,8 @@ * readable export/import names. */ +import { getMp2DecoderWasmExports, type Mp2DecoderWasmExports } from "../wasm/mp2-decoder"; + // Maximum samples per frame for MPEG audio (all channels interleaved) const MAX_SAMPLES_PER_FRAME = 1152 * 2; @@ -37,19 +39,8 @@ export interface DecodedAudio { channels: number; } -/** - * WASM import: standalone mode only requires a memory-growth notification callback. - */ -function createWasmImports() { - return { - env: { - emscripten_notify_memory_growth: () => {}, - }, - }; -} - export class MpegAudioDecoder { - private exports: Record | null = null; + private exports: Mp2DecoderWasmExports | null = null; private memoryRef: { memory: WebAssembly.Memory | null } = { memory: null }; private decoderPtr = 0; private inputPtr = 0; @@ -61,8 +52,8 @@ export class MpegAudioDecoder { private _ready: Promise; private _isReady = false; - constructor(wasmUrl: string) { - this._ready = this.init(wasmUrl); + constructor() { + this._ready = this.init(); } get ready(): Promise { @@ -73,24 +64,19 @@ export class MpegAudioDecoder { return this._isReady; } - private async init(wasmUrl: string): Promise { - const imports = createWasmImports(); - const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); - const ex = instance.exports as Record; - - this.memoryRef.memory = ex.memory as WebAssembly.Memory; - this.exports = ex as unknown as Record; + private async init(): Promise { + const ex = getMp2DecoderWasmExports(); - // Standalone WASM reactor initialization - (ex._initialize as CallableFunction)(); + this.memoryRef.memory = ex.memory; + this.exports = ex; - const create = ex.mpeg_audio_decoder_create as () => number; + const create = ex.mpeg_audio_decoder_create; this.decoderPtr = create(); if (!this.decoderPtr) { throw new Error("Failed to create MPEG audio decoder"); } - const malloc = ex.malloc as (size: number) => number; + const malloc = ex.malloc; this.infoPtr = malloc(INFO_I32_COUNT * 4); this._isReady = true; @@ -99,8 +85,8 @@ export class MpegAudioDecoder { decode(input: Uint8Array): DecodedAudio | null { if (!this._isReady || !this.exports || !this.memoryRef.memory) return null; - const malloc = this.exports.malloc as (size: number) => number; - const free = this.exports.free as (ptr: number) => void; + const malloc = this.exports.malloc; + const free = this.exports.free; // Grow input buffer if needed if (input.length > this.inputBufSize) { @@ -122,14 +108,7 @@ export class MpegAudioDecoder { const heap = new Uint8Array(this.memoryRef.memory.buffer); heap.set(input, this.inputPtr); - const decodeFn = this.exports.mpeg_audio_decode_payload as ( - dec: number, - inp: number, - inpSz: number, - out: number, - outCap: number, - info: number, - ) => number; + const decodeFn = this.exports.mpeg_audio_decode_payload; const samples = decodeFn( this.decoderPtr, this.inputPtr, @@ -159,13 +138,13 @@ export class MpegAudioDecoder { /** Reset decoder state (call on stream switch to avoid stale mdct/qmf state) */ reset(): void { if (!this._isReady || !this.exports) return; - (this.exports.mpeg_audio_decoder_reset as (dec: number) => void)(this.decoderPtr); + this.exports.mpeg_audio_decoder_reset(this.decoderPtr); } destroy(): void { if (!this.exports) return; - const free = this.exports.free as (ptr: number) => void; - const destroyFn = this.exports.mpeg_audio_decoder_destroy as (dec: number) => void; + const free = this.exports.free; + const destroyFn = this.exports.mpeg_audio_decoder_destroy; if (this.decoderPtr) { destroyFn(this.decoderPtr); diff --git a/web-ui/src/mpegts/decoder/worker-audio-decoder.ts b/web-ui/src/mpegts/decoder/worker-audio-decoder.ts index bbab0b6f..0bdca062 100644 --- a/web-ui/src/mpegts/decoder/worker-audio-decoder.ts +++ b/web-ui/src/mpegts/decoder/worker-audio-decoder.ts @@ -2,7 +2,6 @@ * Worker Audio Decoder * * Manages MP2 audio decoding in Web Worker environment via WASM. - * Accepts a URL to the .wasm file (provided by consumer via config). */ import Log from "../utils/logger"; @@ -12,15 +11,9 @@ const TAG = "WorkerAudioDecoder"; /** * Audio decoder for use in Web Worker (MP2 only). - * The consumer provides the WASM URL via config — the library does NOT bundle WASM. */ export class WorkerAudioDecoder { private decoder: MpegAudioDecoder | null = null; - private wasmUrl: string; - - constructor(wasmUrl: string) { - this.wasmUrl = wasmUrl; - } async initDecoder(): Promise { if (this.decoder?.isReady) { @@ -29,10 +22,10 @@ export class WorkerAudioDecoder { this.destroyDecoder(); - Log.i(TAG, `Initializing MP2 decoder from ${this.wasmUrl}`); + Log.i(TAG, "Initializing MP2 decoder"); try { - this.decoder = new MpegAudioDecoder(this.wasmUrl); + this.decoder = new MpegAudioDecoder(); await this.decoder.ready; Log.i(TAG, "MP2 decoder initialized successfully"); return true; diff --git a/web-ui/src/mpegts/index.ts b/web-ui/src/mpegts/index.ts index c168f544..0b20da58 100644 --- a/web-ui/src/mpegts/index.ts +++ b/web-ui/src/mpegts/index.ts @@ -23,14 +23,6 @@ function resolveSegmentUrls(segments: PlayerSegment[]): PlayerSegment[] { export function createPlayer(video: HTMLVideoElement, config?: Partial): Player { const fullConfig: PlayerConfig = { ...defaultConfig, ...config }; - // Resolve WASM URLs to absolute so they work inside inline blob workers - if (fullConfig.wasmDecoders.mp2) { - fullConfig.wasmDecoders = { - ...fullConfig.wasmDecoders, - mp2: new URL(fullConfig.wasmDecoders.mp2, document.baseURI).href, - }; - } - let destroyed = false; const errorHandlers = new Set<(e: PlayerError) => void>(); diff --git a/web-ui/src/mpegts/player/mpegts-player.ts b/web-ui/src/mpegts/player/mpegts-player.ts index fbfdb550..965f4734 100644 --- a/web-ui/src/mpegts/player/mpegts-player.ts +++ b/web-ui/src/mpegts/player/mpegts-player.ts @@ -3,7 +3,6 @@ import type { PlayerConfig } from "../config"; import type { PlayerImpl, PlayerSegment } from "../types"; import Log from "../utils/logger"; import type { WorkerCommand, WorkerEvent } from "../worker/messages"; -import TransmuxWorker from "../worker/transmux-worker.ts?worker&inline"; import { type StallJumper, setupLiveSync, setupStartupStallJumper } from "./live-sync"; import { createMSE, type MSE } from "./mse"; import type { LiveSessionAnchor } from "./wall-clock"; @@ -153,7 +152,7 @@ export function createMpegtsPlayer( function ensureWorker(): Worker { if (!worker) { - worker = new TransmuxWorker(); + worker = new Worker(new URL("../worker/transmux-worker.ts", import.meta.url), { type: "module" }); worker.onmessage = handleWorkerMessage; workerInitialized = false; } diff --git a/web-ui/src/mpegts/vite-env.d.ts b/web-ui/src/mpegts/vite-env.d.ts index 8520b743..0654ebbe 100644 --- a/web-ui/src/mpegts/vite-env.d.ts +++ b/web-ui/src/mpegts/vite-env.d.ts @@ -2,7 +2,32 @@ declare const __VERSION__: string; -declare module "*?worker&inline" { - const workerConstructor: new () => Worker; - export default workerConstructor; +declare module "*.wasm" { + export const memory: WebAssembly.Memory; + export function _initialize(): void; + export function malloc(size: number): number; + export function free(ptr: number): void; + export function mpeg_audio_decoder_create(): number; + export function mpeg_audio_decoder_destroy(ptr: number): void; + export function mpeg_audio_decoder_reset(ptr: number): void; + export function mpeg_audio_decode_payload( + dec: number, + inp: number, + inpSz: number, + out: number, + outCap: number, + info: number, + ): number; + export function wsola_create(sampleRate: number, channels: number): number; + export function wsola_destroy(ptr: number): void; + export function wsola_reset(ptr: number): void; + export function wsola_set_ratio(ptr: number, ratio: number): void; + export function wsola_position(ptr: number): number; + export function wsola_process( + ptr: number, + input: number, + inFrames: number, + output: number, + outCapacity: number, + ): number; } diff --git a/web-ui/src/mpegts/wasm/env.ts b/web-ui/src/mpegts/wasm/env.ts new file mode 100644 index 00000000..3a0a13db --- /dev/null +++ b/web-ui/src/mpegts/wasm/env.ts @@ -0,0 +1 @@ +export function emscripten_notify_memory_growth(): void {} diff --git a/web-ui/src/mpegts/wasm/mp2-decoder.ts b/web-ui/src/mpegts/wasm/mp2-decoder.ts new file mode 100644 index 00000000..645d7081 --- /dev/null +++ b/web-ui/src/mpegts/wasm/mp2-decoder.ts @@ -0,0 +1,64 @@ +import { + _initialize, + free, + malloc, + memory, + mpeg_audio_decode_payload, + mpeg_audio_decoder_create, + mpeg_audio_decoder_destroy, + mpeg_audio_decoder_reset, + wsola_create, + wsola_destroy, + wsola_position, + wsola_process, + wsola_reset, + wsola_set_ratio, +} from "./minimp3/mp2_decoder.wasm"; + +export interface Mp2DecoderWasmExports { + memory: WebAssembly.Memory; + malloc: (size: number) => number; + free: (ptr: number) => void; + mpeg_audio_decoder_create: () => number; + mpeg_audio_decoder_destroy: (ptr: number) => void; + mpeg_audio_decoder_reset: (ptr: number) => void; + mpeg_audio_decode_payload: ( + dec: number, + inp: number, + inpSz: number, + out: number, + outCap: number, + info: number, + ) => number; + wsola_create: (sampleRate: number, channels: number) => number; + wsola_destroy: (ptr: number) => void; + wsola_reset: (ptr: number) => void; + wsola_set_ratio: (ptr: number, ratio: number) => void; + wsola_position: (ptr: number) => number; + wsola_process: (ptr: number, input: number, inFrames: number, output: number, outCapacity: number) => number; +} + +let initialized = false; + +export function getMp2DecoderWasmExports(): Mp2DecoderWasmExports { + if (!initialized) { + _initialize(); + initialized = true; + } + + return { + memory, + malloc, + free, + mpeg_audio_decoder_create, + mpeg_audio_decoder_destroy, + mpeg_audio_decoder_reset, + mpeg_audio_decode_payload, + wsola_create, + wsola_destroy, + wsola_reset, + wsola_set_ratio, + wsola_position, + wsola_process, + }; +} diff --git a/web-ui/src/mpegts/worker/pipeline.ts b/web-ui/src/mpegts/worker/pipeline.ts index c8cde906..e49a13b1 100644 --- a/web-ui/src/mpegts/worker/pipeline.ts +++ b/web-ui/src/mpegts/worker/pipeline.ts @@ -406,12 +406,9 @@ class Pipeline { demuxer.onError = this._onDemuxException.bind(this); demuxer.timestampBase = meta.timestampBase * 90000; // seconds → 90kHz ticks - // Set up software audio decode callback when MP2 WASM URL is configured - if (this._config.wasmDecoders.mp2) { - demuxer.onRawAudioData = (frame) => { - this._handleRawAudioFrame(frame); - }; - } + demuxer.onRawAudioData = (frame) => { + this._handleRawAudioFrame(frame); + }; this._remuxer.bindDataSource( demuxer as unknown as { @@ -505,9 +502,7 @@ class Pipeline { private _handleRawAudioFrame(frame: { codec: "mp2"; data: Uint8Array; pts: number }): void { // Lazily create WorkerAudioDecoder on first raw audio frame if (!this._workerAudioDecoder) { - const mp2Url = this._config.wasmDecoders.mp2; - if (!mp2Url) return; - this._workerAudioDecoder = new WorkerAudioDecoder(mp2Url); + this._workerAudioDecoder = new WorkerAudioDecoder(); this._workerAudioDecoderInitPromise = this._workerAudioDecoder.initDecoder(); } diff --git a/web-ui/vite.config.ts b/web-ui/vite.config.ts index f5bad640..6b86c869 100644 --- a/web-ui/vite.config.ts +++ b/web-ui/vite.config.ts @@ -9,13 +9,21 @@ export default defineConfig(({ mode }) => { return { base: "./", plugins: [react(), tailwindcss()], + resolve: { + alias: { + env: resolve(__dirname, "src/mpegts/wasm/env.ts"), + }, + }, define: { "process.env.NODE_ENV": JSON.stringify(mode), }, + worker: { + format: "es", + }, build: { sourcemap: isDev, minify: !isDev, - rollupOptions: { + rolldownOptions: { input: { status: resolve(__dirname, "status.html"), player: resolve(__dirname, "player.html"), From db50c328f674d501b59ae95d9c38478d408ca617 Mon Sep 17 00:00:00 2001 From: Stackie Jia Date: Sat, 27 Jun 2026 03:29:16 +0800 Subject: [PATCH 2/3] revert(web-ui): restore wasm url and inline worker --- web-ui/src/components/player/video-player.tsx | 5 +- web-ui/src/mpegts/audio/pcm-audio-player.ts | 5 +- web-ui/src/mpegts/audio/wasm-stretcher.ts | 29 +++++++-- web-ui/src/mpegts/config.ts | 6 ++ .../src/mpegts/decoder/mpeg-audio-decoder.ts | 55 +++++++++++----- .../mpegts/decoder/worker-audio-decoder.ts | 11 +++- web-ui/src/mpegts/index.ts | 8 +++ web-ui/src/mpegts/player/mpegts-player.ts | 3 +- web-ui/src/mpegts/vite-env.d.ts | 31 +-------- web-ui/src/mpegts/wasm/env.ts | 1 - web-ui/src/mpegts/wasm/mp2-decoder.ts | 64 ------------------- web-ui/src/mpegts/worker/pipeline.ts | 13 ++-- web-ui/vite.config.ts | 8 --- 13 files changed, 107 insertions(+), 132 deletions(-) delete mode 100644 web-ui/src/mpegts/wasm/env.ts delete mode 100644 web-ui/src/mpegts/wasm/mp2-decoder.ts diff --git a/web-ui/src/components/player/video-player.tsx b/web-ui/src/components/player/video-player.tsx index af90377a..983b9097 100644 --- a/web-ui/src/components/player/video-player.tsx +++ b/web-ui/src/components/player/video-player.tsx @@ -21,6 +21,7 @@ import { lagBehindLiveEdge, wallClockToMse, } from "../../mpegts/player/wall-clock"; +import mp2WasmUrl from "../../mpegts/wasm/minimp3/mp2_decoder.wasm?url"; import type { Channel, EPGProgram } from "../../types/player"; import { PLAYER_OVERLAY_SURFACE_CLASS } from "./classnames"; import { PlayerControls } from "./player-controls"; @@ -558,7 +559,9 @@ export function VideoPlayer({ video.volume = volume; video.muted = isMuted; - const p = createPlayer(video); + const p = createPlayer(video, { + wasmDecoders: { mp2: mp2WasmUrl }, + }); p.on("error", (e) => { if (slotPlayerRef(slotId).current === p) { handlePlayerError(e, slotId); diff --git a/web-ui/src/mpegts/audio/pcm-audio-player.ts b/web-ui/src/mpegts/audio/pcm-audio-player.ts index 87a82a9a..97df8c43 100644 --- a/web-ui/src/mpegts/audio/pcm-audio-player.ts +++ b/web-ui/src/mpegts/audio/pcm-audio-player.ts @@ -315,7 +315,10 @@ export class PCMAudioPlayer { } this.stretcherLoading = true; - const promise = WasmStretcher.create(chunk.sampleRate, chunk.channels); + const wasmUrl = this.config.wasmDecoders.mp2; + const promise = wasmUrl + ? WasmStretcher.create(wasmUrl, chunk.sampleRate, chunk.channels) + : Promise.reject(new Error("MP2 WASM URL is not configured")); promise .then((stretcher) => { diff --git a/web-ui/src/mpegts/audio/wasm-stretcher.ts b/web-ui/src/mpegts/audio/wasm-stretcher.ts index ba77ab27..08007369 100644 --- a/web-ui/src/mpegts/audio/wasm-stretcher.ts +++ b/web-ui/src/mpegts/audio/wasm-stretcher.ts @@ -10,7 +10,6 @@ */ import Log from "../utils/logger"; -import { getMp2DecoderWasmExports, type Mp2DecoderWasmExports } from "../wasm/mp2-decoder"; const TAG = "WasmStretcher"; @@ -26,26 +25,46 @@ export interface Stretcher { destroy(): void; } +interface WsolaExports { + memory: WebAssembly.Memory; + _initialize: () => void; + malloc: (size: number) => number; + free: (ptr: number) => void; + wsola_create: (sampleRate: number, channels: number) => number; + wsola_destroy: (ptr: number) => void; + wsola_reset: (ptr: number) => void; + wsola_set_ratio: (ptr: number, ratio: number) => void; + wsola_position: (ptr: number) => number; + wsola_process: (ptr: number, input: number, inFrames: number, output: number, outCapacity: number) => number; +} + export class WasmStretcher implements Stretcher { readonly sampleRate: number; readonly channels: number; - private exports: Mp2DecoderWasmExports; + private exports: WsolaExports; private handle: number; private inPtr = 0; private inCapacityFrames = 0; private outPtr = 0; private outCapacityFrames = 0; - private constructor(exports: Mp2DecoderWasmExports, handle: number, sampleRate: number, channels: number) { + private constructor(exports: WsolaExports, handle: number, sampleRate: number, channels: number) { this.exports = exports; this.handle = handle; this.sampleRate = sampleRate; this.channels = channels; } - static async create(sampleRate: number, channels: number): Promise { - const ex = getMp2DecoderWasmExports(); + static async create(wasmUrl: string, sampleRate: number, channels: number): Promise { + const imports = { + env: { + emscripten_notify_memory_growth: () => {}, + }, + }; + const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + const ex = instance.exports as unknown as WsolaExports; + ex._initialize(); const handle = ex.wsola_create(sampleRate, channels); if (!handle) { throw new Error("wsola_create failed"); diff --git a/web-ui/src/mpegts/config.ts b/web-ui/src/mpegts/config.ts index 9715c12f..de600e74 100644 --- a/web-ui/src/mpegts/config.ts +++ b/web-ui/src/mpegts/config.ts @@ -17,6 +17,10 @@ export interface PlayerConfig { */ maxBufferHoleMs: number; + /** URLs to WASM decoder files, keyed by codec. Omit to disable software decoding for that codec. + * e.g. `{ mp2: "/assets/mp2_decoder.wasm" }` */ + wasmDecoders: { mp2?: string }; + /** Max backward buffer duration in seconds. Cleanup triggers when buffer exceeds this. @default 180 */ bufferCleanupMaxBackward: number; /** Min backward buffer to retain after cleanup in seconds. @default 120 */ @@ -36,6 +40,8 @@ export const defaultConfig: PlayerConfig = { maxBufferHoleMs: 300, + wasmDecoders: {}, + bufferCleanupMaxBackward: 180, bufferCleanupMinBackward: 120, diff --git a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts index 57dd5dea..8fd7b83f 100644 --- a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts +++ b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts @@ -12,8 +12,6 @@ * readable export/import names. */ -import { getMp2DecoderWasmExports, type Mp2DecoderWasmExports } from "../wasm/mp2-decoder"; - // Maximum samples per frame for MPEG audio (all channels interleaved) const MAX_SAMPLES_PER_FRAME = 1152 * 2; @@ -39,8 +37,19 @@ export interface DecodedAudio { channels: number; } +/** + * WASM import: standalone mode only requires a memory-growth notification callback. + */ +function createWasmImports() { + return { + env: { + emscripten_notify_memory_growth: () => {}, + }, + }; +} + export class MpegAudioDecoder { - private exports: Mp2DecoderWasmExports | null = null; + private exports: Record | null = null; private memoryRef: { memory: WebAssembly.Memory | null } = { memory: null }; private decoderPtr = 0; private inputPtr = 0; @@ -52,8 +61,8 @@ export class MpegAudioDecoder { private _ready: Promise; private _isReady = false; - constructor() { - this._ready = this.init(); + constructor(wasmUrl: string) { + this._ready = this.init(wasmUrl); } get ready(): Promise { @@ -64,19 +73,24 @@ export class MpegAudioDecoder { return this._isReady; } - private async init(): Promise { - const ex = getMp2DecoderWasmExports(); + private async init(wasmUrl: string): Promise { + const imports = createWasmImports(); + const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + const ex = instance.exports as Record; + + this.memoryRef.memory = ex.memory as WebAssembly.Memory; + this.exports = ex as unknown as Record; - this.memoryRef.memory = ex.memory; - this.exports = ex; + // Standalone WASM reactor initialization + (ex._initialize as CallableFunction)(); - const create = ex.mpeg_audio_decoder_create; + const create = ex.mpeg_audio_decoder_create as () => number; this.decoderPtr = create(); if (!this.decoderPtr) { throw new Error("Failed to create MPEG audio decoder"); } - const malloc = ex.malloc; + const malloc = ex.malloc as (size: number) => number; this.infoPtr = malloc(INFO_I32_COUNT * 4); this._isReady = true; @@ -85,8 +99,8 @@ export class MpegAudioDecoder { decode(input: Uint8Array): DecodedAudio | null { if (!this._isReady || !this.exports || !this.memoryRef.memory) return null; - const malloc = this.exports.malloc; - const free = this.exports.free; + const malloc = this.exports.malloc as (size: number) => number; + const free = this.exports.free as (ptr: number) => void; // Grow input buffer if needed if (input.length > this.inputBufSize) { @@ -108,7 +122,14 @@ export class MpegAudioDecoder { const heap = new Uint8Array(this.memoryRef.memory.buffer); heap.set(input, this.inputPtr); - const decodeFn = this.exports.mpeg_audio_decode_payload; + const decodeFn = this.exports.mpeg_audio_decode_payload as ( + dec: number, + inp: number, + inpSz: number, + out: number, + outCap: number, + info: number, + ) => number; const samples = decodeFn( this.decoderPtr, this.inputPtr, @@ -138,13 +159,13 @@ export class MpegAudioDecoder { /** Reset decoder state (call on stream switch to avoid stale mdct/qmf state) */ reset(): void { if (!this._isReady || !this.exports) return; - this.exports.mpeg_audio_decoder_reset(this.decoderPtr); + (this.exports.mpeg_audio_decoder_reset as (dec: number) => void)(this.decoderPtr); } destroy(): void { if (!this.exports) return; - const free = this.exports.free; - const destroyFn = this.exports.mpeg_audio_decoder_destroy; + const free = this.exports.free as (ptr: number) => void; + const destroyFn = this.exports.mpeg_audio_decoder_destroy as (dec: number) => void; if (this.decoderPtr) { destroyFn(this.decoderPtr); diff --git a/web-ui/src/mpegts/decoder/worker-audio-decoder.ts b/web-ui/src/mpegts/decoder/worker-audio-decoder.ts index 0bdca062..bbab0b6f 100644 --- a/web-ui/src/mpegts/decoder/worker-audio-decoder.ts +++ b/web-ui/src/mpegts/decoder/worker-audio-decoder.ts @@ -2,6 +2,7 @@ * Worker Audio Decoder * * Manages MP2 audio decoding in Web Worker environment via WASM. + * Accepts a URL to the .wasm file (provided by consumer via config). */ import Log from "../utils/logger"; @@ -11,9 +12,15 @@ const TAG = "WorkerAudioDecoder"; /** * Audio decoder for use in Web Worker (MP2 only). + * The consumer provides the WASM URL via config — the library does NOT bundle WASM. */ export class WorkerAudioDecoder { private decoder: MpegAudioDecoder | null = null; + private wasmUrl: string; + + constructor(wasmUrl: string) { + this.wasmUrl = wasmUrl; + } async initDecoder(): Promise { if (this.decoder?.isReady) { @@ -22,10 +29,10 @@ export class WorkerAudioDecoder { this.destroyDecoder(); - Log.i(TAG, "Initializing MP2 decoder"); + Log.i(TAG, `Initializing MP2 decoder from ${this.wasmUrl}`); try { - this.decoder = new MpegAudioDecoder(); + this.decoder = new MpegAudioDecoder(this.wasmUrl); await this.decoder.ready; Log.i(TAG, "MP2 decoder initialized successfully"); return true; diff --git a/web-ui/src/mpegts/index.ts b/web-ui/src/mpegts/index.ts index 0b20da58..c168f544 100644 --- a/web-ui/src/mpegts/index.ts +++ b/web-ui/src/mpegts/index.ts @@ -23,6 +23,14 @@ function resolveSegmentUrls(segments: PlayerSegment[]): PlayerSegment[] { export function createPlayer(video: HTMLVideoElement, config?: Partial): Player { const fullConfig: PlayerConfig = { ...defaultConfig, ...config }; + // Resolve WASM URLs to absolute so they work inside inline blob workers + if (fullConfig.wasmDecoders.mp2) { + fullConfig.wasmDecoders = { + ...fullConfig.wasmDecoders, + mp2: new URL(fullConfig.wasmDecoders.mp2, document.baseURI).href, + }; + } + let destroyed = false; const errorHandlers = new Set<(e: PlayerError) => void>(); diff --git a/web-ui/src/mpegts/player/mpegts-player.ts b/web-ui/src/mpegts/player/mpegts-player.ts index 965f4734..fbfdb550 100644 --- a/web-ui/src/mpegts/player/mpegts-player.ts +++ b/web-ui/src/mpegts/player/mpegts-player.ts @@ -3,6 +3,7 @@ import type { PlayerConfig } from "../config"; import type { PlayerImpl, PlayerSegment } from "../types"; import Log from "../utils/logger"; import type { WorkerCommand, WorkerEvent } from "../worker/messages"; +import TransmuxWorker from "../worker/transmux-worker.ts?worker&inline"; import { type StallJumper, setupLiveSync, setupStartupStallJumper } from "./live-sync"; import { createMSE, type MSE } from "./mse"; import type { LiveSessionAnchor } from "./wall-clock"; @@ -152,7 +153,7 @@ export function createMpegtsPlayer( function ensureWorker(): Worker { if (!worker) { - worker = new Worker(new URL("../worker/transmux-worker.ts", import.meta.url), { type: "module" }); + worker = new TransmuxWorker(); worker.onmessage = handleWorkerMessage; workerInitialized = false; } diff --git a/web-ui/src/mpegts/vite-env.d.ts b/web-ui/src/mpegts/vite-env.d.ts index 0654ebbe..8520b743 100644 --- a/web-ui/src/mpegts/vite-env.d.ts +++ b/web-ui/src/mpegts/vite-env.d.ts @@ -2,32 +2,7 @@ declare const __VERSION__: string; -declare module "*.wasm" { - export const memory: WebAssembly.Memory; - export function _initialize(): void; - export function malloc(size: number): number; - export function free(ptr: number): void; - export function mpeg_audio_decoder_create(): number; - export function mpeg_audio_decoder_destroy(ptr: number): void; - export function mpeg_audio_decoder_reset(ptr: number): void; - export function mpeg_audio_decode_payload( - dec: number, - inp: number, - inpSz: number, - out: number, - outCap: number, - info: number, - ): number; - export function wsola_create(sampleRate: number, channels: number): number; - export function wsola_destroy(ptr: number): void; - export function wsola_reset(ptr: number): void; - export function wsola_set_ratio(ptr: number, ratio: number): void; - export function wsola_position(ptr: number): number; - export function wsola_process( - ptr: number, - input: number, - inFrames: number, - output: number, - outCapacity: number, - ): number; +declare module "*?worker&inline" { + const workerConstructor: new () => Worker; + export default workerConstructor; } diff --git a/web-ui/src/mpegts/wasm/env.ts b/web-ui/src/mpegts/wasm/env.ts deleted file mode 100644 index 3a0a13db..00000000 --- a/web-ui/src/mpegts/wasm/env.ts +++ /dev/null @@ -1 +0,0 @@ -export function emscripten_notify_memory_growth(): void {} diff --git a/web-ui/src/mpegts/wasm/mp2-decoder.ts b/web-ui/src/mpegts/wasm/mp2-decoder.ts deleted file mode 100644 index 645d7081..00000000 --- a/web-ui/src/mpegts/wasm/mp2-decoder.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { - _initialize, - free, - malloc, - memory, - mpeg_audio_decode_payload, - mpeg_audio_decoder_create, - mpeg_audio_decoder_destroy, - mpeg_audio_decoder_reset, - wsola_create, - wsola_destroy, - wsola_position, - wsola_process, - wsola_reset, - wsola_set_ratio, -} from "./minimp3/mp2_decoder.wasm"; - -export interface Mp2DecoderWasmExports { - memory: WebAssembly.Memory; - malloc: (size: number) => number; - free: (ptr: number) => void; - mpeg_audio_decoder_create: () => number; - mpeg_audio_decoder_destroy: (ptr: number) => void; - mpeg_audio_decoder_reset: (ptr: number) => void; - mpeg_audio_decode_payload: ( - dec: number, - inp: number, - inpSz: number, - out: number, - outCap: number, - info: number, - ) => number; - wsola_create: (sampleRate: number, channels: number) => number; - wsola_destroy: (ptr: number) => void; - wsola_reset: (ptr: number) => void; - wsola_set_ratio: (ptr: number, ratio: number) => void; - wsola_position: (ptr: number) => number; - wsola_process: (ptr: number, input: number, inFrames: number, output: number, outCapacity: number) => number; -} - -let initialized = false; - -export function getMp2DecoderWasmExports(): Mp2DecoderWasmExports { - if (!initialized) { - _initialize(); - initialized = true; - } - - return { - memory, - malloc, - free, - mpeg_audio_decoder_create, - mpeg_audio_decoder_destroy, - mpeg_audio_decoder_reset, - mpeg_audio_decode_payload, - wsola_create, - wsola_destroy, - wsola_reset, - wsola_set_ratio, - wsola_position, - wsola_process, - }; -} diff --git a/web-ui/src/mpegts/worker/pipeline.ts b/web-ui/src/mpegts/worker/pipeline.ts index e49a13b1..c8cde906 100644 --- a/web-ui/src/mpegts/worker/pipeline.ts +++ b/web-ui/src/mpegts/worker/pipeline.ts @@ -406,9 +406,12 @@ class Pipeline { demuxer.onError = this._onDemuxException.bind(this); demuxer.timestampBase = meta.timestampBase * 90000; // seconds → 90kHz ticks - demuxer.onRawAudioData = (frame) => { - this._handleRawAudioFrame(frame); - }; + // Set up software audio decode callback when MP2 WASM URL is configured + if (this._config.wasmDecoders.mp2) { + demuxer.onRawAudioData = (frame) => { + this._handleRawAudioFrame(frame); + }; + } this._remuxer.bindDataSource( demuxer as unknown as { @@ -502,7 +505,9 @@ class Pipeline { private _handleRawAudioFrame(frame: { codec: "mp2"; data: Uint8Array; pts: number }): void { // Lazily create WorkerAudioDecoder on first raw audio frame if (!this._workerAudioDecoder) { - this._workerAudioDecoder = new WorkerAudioDecoder(); + const mp2Url = this._config.wasmDecoders.mp2; + if (!mp2Url) return; + this._workerAudioDecoder = new WorkerAudioDecoder(mp2Url); this._workerAudioDecoderInitPromise = this._workerAudioDecoder.initDecoder(); } diff --git a/web-ui/vite.config.ts b/web-ui/vite.config.ts index 6b86c869..38ac4088 100644 --- a/web-ui/vite.config.ts +++ b/web-ui/vite.config.ts @@ -9,17 +9,9 @@ export default defineConfig(({ mode }) => { return { base: "./", plugins: [react(), tailwindcss()], - resolve: { - alias: { - env: resolve(__dirname, "src/mpegts/wasm/env.ts"), - }, - }, define: { "process.env.NODE_ENV": JSON.stringify(mode), }, - worker: { - format: "es", - }, build: { sourcemap: isDev, minify: !isDev, From 18163daea1af61b9c6cac448e22b29e6c32ffc23 Mon Sep 17 00:00:00 2001 From: Stackie Jia Date: Sat, 27 Jun 2026 03:43:10 +0800 Subject: [PATCH 3/3] fix(web-ui): reuse mp2 wasm instances --- web-ui/src/mpegts/audio/wasm-stretcher.ts | 24 +++++++++++++------ .../src/mpegts/decoder/mpeg-audio-decoder.ts | 19 +++++++++++---- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/web-ui/src/mpegts/audio/wasm-stretcher.ts b/web-ui/src/mpegts/audio/wasm-stretcher.ts index 08007369..85cf51ed 100644 --- a/web-ui/src/mpegts/audio/wasm-stretcher.ts +++ b/web-ui/src/mpegts/audio/wasm-stretcher.ts @@ -38,6 +38,9 @@ interface WsolaExports { wsola_process: (ptr: number, input: number, inFrames: number, output: number, outCapacity: number) => number; } +let cachedWasmUrl: string | null = null; +let cachedWasmInstance: WebAssembly.Instance | null = null; + export class WasmStretcher implements Stretcher { readonly sampleRate: number; readonly channels: number; @@ -57,14 +60,21 @@ export class WasmStretcher implements Stretcher { } static async create(wasmUrl: string, sampleRate: number, channels: number): Promise { - const imports = { - env: { - emscripten_notify_memory_growth: () => {}, - }, - }; - const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + if (!cachedWasmInstance || cachedWasmUrl !== wasmUrl) { + const imports = { + env: { + emscripten_notify_memory_growth: () => {}, + }, + }; + const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + const ex = instance.exports as unknown as WsolaExports; + ex._initialize(); + cachedWasmInstance = instance; + cachedWasmUrl = wasmUrl; + } + + const instance = cachedWasmInstance; const ex = instance.exports as unknown as WsolaExports; - ex._initialize(); const handle = ex.wsola_create(sampleRate, channels); if (!handle) { throw new Error("wsola_create failed"); diff --git a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts index 8fd7b83f..2411bf32 100644 --- a/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts +++ b/web-ui/src/mpegts/decoder/mpeg-audio-decoder.ts @@ -48,6 +48,9 @@ function createWasmImports() { }; } +let cachedWasmUrl: string | null = null; +let cachedWasmInstance: WebAssembly.Instance | null = null; + export class MpegAudioDecoder { private exports: Record | null = null; private memoryRef: { memory: WebAssembly.Memory | null } = { memory: null }; @@ -74,16 +77,22 @@ export class MpegAudioDecoder { } private async init(wasmUrl: string): Promise { - const imports = createWasmImports(); - const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + if (!cachedWasmInstance || cachedWasmUrl !== wasmUrl) { + const imports = createWasmImports(); + const { instance } = await WebAssembly.instantiateStreaming(fetch(wasmUrl), imports); + const ex = instance.exports as Record; + // Standalone WASM reactor initialization, once per cached instance. + (ex._initialize as CallableFunction)(); + cachedWasmInstance = instance; + cachedWasmUrl = wasmUrl; + } + + const instance = cachedWasmInstance; const ex = instance.exports as Record; this.memoryRef.memory = ex.memory as WebAssembly.Memory; this.exports = ex as unknown as Record; - // Standalone WASM reactor initialization - (ex._initialize as CallableFunction)(); - const create = ex.mpeg_audio_decoder_create as () => number; this.decoderPtr = create(); if (!this.decoderPtr) {