diff --git a/.gitignore b/.gitignore index 1b4b313..3faf97a 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,9 @@ yarn-error.log* stats.html -test-results.xml \ No newline at end of file +test-results.xml + +dist/* + +# Native macOS vibrancy (built by scripts/build-macos-effects.mjs) +src/bun/libMacWindowEffects.dylib \ No newline at end of file diff --git a/Jenkinsfile b/Jenkinsfile index 1900ce6..5fd1dd0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,7 +1,57 @@ properties([ - buildDiscarder(logRotator(numToKeepStr: '20')) + buildDiscarder(logRotator(numToKeepStr: '10')) ]) +def bunBinDir() { + if (isUnix()) { + return "${env.HOME}/.bun/bin" + } + return "${env.USERPROFILE}/.bun/bin" +} + +def withBun(Closure body) { + def sep = isUnix() ? ':' : ';' + withEnv(["PATH=${bunBinDir()}${sep}${env.PATH}"]) { + body() + } +} + +def checkBun() { + if (isUnix()) { + sh 'bun -v' + } else { + bat 'bun -v' + } +} + +def writeBuildMetadata() { + if (isUnix()) { + sh ''' + bun --eval "await Bun.write('src/buildInfo.json', JSON.stringify({ buildNumber: process.env.BUILD_NUMBER || 'dev' }, null, 2) + '\\n')" + ''' + } else { + bat ''' + bun --eval "await Bun.write('src/buildInfo.json', JSON.stringify({ buildNumber: process.env.BUILD_NUMBER || 'dev' }, null, 2) + '\\n')" + ''' + } +} + +def runBuild(buildCommand) { + def releaseBaseUrl = + "https://dist.farmcontrol.app/jenkins/farmcontrol/farmcontrol-ui" + withEnv([ + "VITE_BUILD_NUMBER=${env.BUILD_NUMBER ?: 'dev'}", + 'NODE_ENV=production', + "ELECTROBUN_RELEASE_BASE_URL=${releaseBaseUrl}", + ]) { + if (isUnix()) { + sh buildCommand + } else { + bat buildCommand + } + } +} + def deploy() { node('ubuntu') { try { @@ -30,7 +80,6 @@ def deploy() { stage('Deploy (Ubuntu)') { nodejs(nodeJSInstallationName: 'Node23') { - // Deploy to Cloudflare Pages using wrangler withCredentials([string(credentialsId: 'cloudflare-api-token', variable: 'CLOUDFLARE_API_TOKEN')]) { sh 'pnpm wrangler pages deploy build --branch main' } @@ -42,66 +91,87 @@ def deploy() { } } -def buildOnLabel(label, buildCommand) { +def prepareMacBuildWorkspace() { + if (isUnix()) { + sh ''' + df -h . + for vol in /Volumes/Farm\\ Control*; do + if [ -d "$vol" ]; then + hdiutil detach "$vol" -force || true + fi + done + rm -rf build/stable-macos-*/.dmg-staging build/stable-macos-*/.finalize-dmg-staging 2>/dev/null || true + ''' + } +} + +def buildOnLabel(label, buildCommand, bundleCef = false) { + def cefLabel = bundleCef ? 'cef' : 'native' return { node(label) { - stage("Checkout (${label})") { - checkout scm - } + try { + stage("Checkout (${label}/${cefLabel})") { + checkout scm + } - stage("Setup Node.js (${label})") { - nodejs(nodeJSInstallationName: 'Node23') { - if (isUnix()) { - sh 'node -v' - sh 'pnpm -v' - } else { - bat 'node -v' - bat 'pnpm -v' + withBun { + stage("Check Bun (${label}/${cefLabel})") { + checkBun() + } + + if (label.startsWith('macos')) { + stage("Prepare macOS workspace (${label}/${cefLabel})") { + prepareMacBuildWorkspace() + } + } + + stage("Install Dependencies (${label}/${cefLabel})") { + if (isUnix()) { + sh 'bun install --frozen-lockfile' + } else { + bat 'bun install --frozen-lockfile' + } + } + + stage("Write Build Metadata (${label}/${cefLabel})") { + writeBuildMetadata() + } + + stage("Build (${label}/${cefLabel})") { + withEnv(["ELECTROBUN_BUNDLE_CEF=${bundleCef ? 'true' : 'false'}"]) { + runBuild(buildCommand) + } } } - } - stage("Install Dependencies (${label})") { - nodejs(nodeJSInstallationName: 'Node23') { - if (isUnix()) { - sh 'pnpm install --frozen-lockfile --production=false' - } else { - bat 'pnpm install --frozen-lockfile --production=false' - } + stage("Archive Artifacts (${label}/${cefLabel})") { + archiveArtifacts artifacts: 'app_dist/farmcontrol-*', fingerprint: true } - } - - stage("Build (${label})") { - nodejs(nodeJSInstallationName: 'Node23') { - if (isUnix()) { - sh "VITE_BUILD_NUMBER=${env.BUILD_NUMBER} NODE_ENV=production ${buildCommand}" - } else { - bat "set VITE_BUILD_NUMBER=${env.BUILD_NUMBER} && set NODE_ENV=production && ${buildCommand}" - } - } - } - - stage("Archive Artifacts (${label})") { - archiveArtifacts artifacts: 'app_dist/**/farmcontrol-*.dmg, app_dist/**/farmcontrol-*.exe, app_dist/**/farmcontrol-*.pkg, app_dist/**/farmcontrol-*.msi', fingerprint: true + } finally { + cleanWs() } } } } +def buildMacOnLabel(label, targetArch, bundleCef = false) { + return buildOnLabel(label, "ELECTROBUN_TARGET_ARCH=${targetArch} bun run build:app:mac", bundleCef) +} + def setBuildNameFromPackageVersion() { node('ubuntu') { stage('Set Build Name') { checkout scm - def version - nodejs(nodeJSInstallationName: 'Node23') { - version = sh( - script: "node -p \"require('./package.json').version\"", + withBun { + checkBun() + def version = sh( + script: "bun --eval \"console.log(JSON.parse(await Bun.file('package.json').text()).version)\"", returnStdout: true ).trim() + def buildName = "v${version}-b${env.BUILD_NUMBER}" + currentBuild.displayName = buildName + echo "Build name set to: ${buildName}" } - def buildName = "v${version}-b${env.BUILD_NUMBER}" - currentBuild.displayName = buildName - echo "Build name set to: ${buildName}" } } } @@ -110,8 +180,12 @@ try { setBuildNameFromPackageVersion() parallel( - 'Windows Build': buildOnLabel('windows', 'pnpm build:electron'), - 'MacOS Build': buildOnLabel('macos', 'pnpm build:electron'), + 'Windows Build': buildOnLabel('windows', 'bun run build:app', false), + 'Windows CEF Build': buildOnLabel('windows', 'bun run build:app', true), + 'MacOS x64 Build': buildMacOnLabel('macos', 'x64', false), + 'MacOS x64 CEF Build': buildMacOnLabel('macos', 'x64', true), + 'MacOS arm64 Build': buildMacOnLabel('macos', 'arm64', false), + 'MacOS arm64 CEF Build': buildMacOnLabel('macos', 'arm64', true), 'Ubuntu Deploy': { deploy() } ) diff --git a/assets/dmg/background.png b/assets/dmg/background.png index 6a8b823..ade18f0 100644 Binary files a/assets/dmg/background.png and b/assets/dmg/background.png differ diff --git a/assets/dmg/background@2x.png b/assets/dmg/background@2x.png index bb10936..1fd369c 100644 Binary files a/assets/dmg/background@2x.png and b/assets/dmg/background@2x.png differ diff --git a/assets/icon.ico b/assets/icon.ico new file mode 100644 index 0000000..e7dec75 Binary files /dev/null and b/assets/icon.ico differ diff --git a/assets/icon.iconset/icon_128x128.png b/assets/icon.iconset/icon_128x128.png new file mode 100644 index 0000000..3060d7f Binary files /dev/null and b/assets/icon.iconset/icon_128x128.png differ diff --git a/assets/icon.iconset/icon_128x128@2x.png b/assets/icon.iconset/icon_128x128@2x.png new file mode 100644 index 0000000..6276a5b Binary files /dev/null and b/assets/icon.iconset/icon_128x128@2x.png differ diff --git a/assets/icon.iconset/icon_16x16.png b/assets/icon.iconset/icon_16x16.png new file mode 100644 index 0000000..9e3a149 Binary files /dev/null and b/assets/icon.iconset/icon_16x16.png differ diff --git a/assets/icon.iconset/icon_16x16@2x.png b/assets/icon.iconset/icon_16x16@2x.png new file mode 100644 index 0000000..c1423b6 Binary files /dev/null and b/assets/icon.iconset/icon_16x16@2x.png differ diff --git a/assets/icon.iconset/icon_256x256.png b/assets/icon.iconset/icon_256x256.png new file mode 100644 index 0000000..6276a5b Binary files /dev/null and b/assets/icon.iconset/icon_256x256.png differ diff --git a/assets/icon.iconset/icon_256x256@2x.png b/assets/icon.iconset/icon_256x256@2x.png new file mode 100644 index 0000000..57cf6f2 Binary files /dev/null and b/assets/icon.iconset/icon_256x256@2x.png differ diff --git a/assets/icon.iconset/icon_32x32.png b/assets/icon.iconset/icon_32x32.png new file mode 100644 index 0000000..c1423b6 Binary files /dev/null and b/assets/icon.iconset/icon_32x32.png differ diff --git a/assets/icon.iconset/icon_32x32@2x.png b/assets/icon.iconset/icon_32x32@2x.png new file mode 100644 index 0000000..a38f9e2 Binary files /dev/null and b/assets/icon.iconset/icon_32x32@2x.png differ diff --git a/assets/icon.iconset/icon_512x512.png b/assets/icon.iconset/icon_512x512.png new file mode 100644 index 0000000..57cf6f2 Binary files /dev/null and b/assets/icon.iconset/icon_512x512.png differ diff --git a/assets/icon.iconset/icon_512x512@2x.png b/assets/icon.iconset/icon_512x512@2x.png new file mode 100644 index 0000000..78a9224 Binary files /dev/null and b/assets/icon.iconset/icon_512x512@2x.png differ diff --git a/assets/icon.png b/assets/icon.png new file mode 100644 index 0000000..6276a5b Binary files /dev/null and b/assets/icon.png differ diff --git a/assets/installer.ico b/assets/installer.ico new file mode 100644 index 0000000..a6e0876 Binary files /dev/null and b/assets/installer.ico differ diff --git a/assets/installer.iconset/icon_128x128.png b/assets/installer.iconset/icon_128x128.png new file mode 100644 index 0000000..572a905 Binary files /dev/null and b/assets/installer.iconset/icon_128x128.png differ diff --git a/assets/installer.iconset/icon_128x128@2x.png b/assets/installer.iconset/icon_128x128@2x.png new file mode 100644 index 0000000..18d0eb4 Binary files /dev/null and b/assets/installer.iconset/icon_128x128@2x.png differ diff --git a/assets/installer.iconset/icon_16x16.png b/assets/installer.iconset/icon_16x16.png new file mode 100644 index 0000000..d604551 Binary files /dev/null and b/assets/installer.iconset/icon_16x16.png differ diff --git a/assets/installer.iconset/icon_16x16@2x.png b/assets/installer.iconset/icon_16x16@2x.png new file mode 100644 index 0000000..8df3646 Binary files /dev/null and b/assets/installer.iconset/icon_16x16@2x.png differ diff --git a/assets/installer.iconset/icon_256x256.png b/assets/installer.iconset/icon_256x256.png new file mode 100644 index 0000000..18d0eb4 Binary files /dev/null and b/assets/installer.iconset/icon_256x256.png differ diff --git a/assets/installer.iconset/icon_256x256@2x.png b/assets/installer.iconset/icon_256x256@2x.png new file mode 100644 index 0000000..4f8f38e Binary files /dev/null and b/assets/installer.iconset/icon_256x256@2x.png differ diff --git a/assets/installer.iconset/icon_32x32.png b/assets/installer.iconset/icon_32x32.png new file mode 100644 index 0000000..8df3646 Binary files /dev/null and b/assets/installer.iconset/icon_32x32.png differ diff --git a/assets/installer.iconset/icon_32x32@2x.png b/assets/installer.iconset/icon_32x32@2x.png new file mode 100644 index 0000000..b930f1d Binary files /dev/null and b/assets/installer.iconset/icon_32x32@2x.png differ diff --git a/assets/installer.iconset/icon_512x512.png b/assets/installer.iconset/icon_512x512.png new file mode 100644 index 0000000..4f8f38e Binary files /dev/null and b/assets/installer.iconset/icon_512x512.png differ diff --git a/assets/installer.iconset/icon_512x512@2x.png b/assets/installer.iconset/icon_512x512@2x.png new file mode 100644 index 0000000..705fb91 Binary files /dev/null and b/assets/installer.iconset/icon_512x512@2x.png differ diff --git a/assets/logos/farmcontrolinstaller.png b/assets/logos/farmcontrolinstaller.png new file mode 100644 index 0000000..fad5f5d Binary files /dev/null and b/assets/logos/farmcontrolinstaller.png differ diff --git a/assets/logos/farmcontroluninstaller.png b/assets/logos/farmcontroluninstaller.png new file mode 100644 index 0000000..9168a7d Binary files /dev/null and b/assets/logos/farmcontroluninstaller.png differ diff --git a/assets/stylesheets/App.css b/assets/stylesheets/App.css index 2d2b8be..6a3737d 100644 --- a/assets/stylesheets/App.css +++ b/assets/stylesheets/App.css @@ -105,23 +105,146 @@ } .electron-navigation-wrapper { - -webkit-app-region: drag; + user-select: none; + --webkit-user-select: none; } -.electron-navigation-wrapper li, -.electron-navigation-wrapper button, -.electron-navigation-wrapper .ant-tag { - -webkit-app-region: no-drag; +.electron-body * { + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -o-user-select: none; + user-select: none; +} + +.electron-body .ant-descriptions-item-content *, +.electron-body .ant-table-cell * { + -webkit-user-select: text; + -khtml-user-select: text; + -moz-user-select: text; + -o-user-select: text; + user-select: text; +} + +/* Native macOS vibrancy — transparent web content over NSVisualEffectView */ +html.macos-vibrancy { + --macos-window-corner-radius: 15px; /* keep in sync with MAC_WINDOW_CORNER_RADIUS */ +} + +html.macos-vibrancy, +html.macos-vibrancy body, +html.macos-vibrancy #root { + background: transparent !important; +} + +html.macos-vibrancy .ant-layout.ant-layout-has-sider, +html.macos-vibrancy .main-layout { + background: transparent !important; +} + +html.macos-vibrancy .light-mode .ant-layout.main-content-layout { + background: rgba(255, 255, 255, 0.88) !important; +} + +html.macos-vibrancy .dark-mode .ant-layout.main-content-layout { + background: rgba(0, 0, 0, 0.88) !important; +} + +html.macos-vibrancy .light-mode .ant-layout-sider { + background: rgba(244, 244, 244, 0.82) !important; +} + +html.macos-vibrancy .dark-mode .ant-layout-sider { + background: rgba(10, 10, 10, 0.82) !important; +} + +html.macos-vibrancy .light-mode .ant-layout-content { + background: transparent !important; +} + +html.macos-vibrancy .dark-mode .ant-layout-content { + background: transparent !important; +} + +html.macos-vibrancy .ant-layout-sider-light, +html.macos-vibrancy .electron-sider .ant-menu-light { + background: transparent !important; +} + +html.macos-vibrancy + .dark-mode + .electron-sider + .ant-menu-light + .ant-menu-item-selected { + background-color: color-mix(in srgb, var(--color-primary) 30%, #00000010); + color: color-mix(in srgb, var(--color-primary) 75%, #ffffff); +} + +html.macos-vibrancy + .light-mode + .electron-sider + .ant-menu-light + .ant-menu-item-selected { + background-color: color-mix(in srgb, var(--color-primary) 80%, #ffffff3d); + color: #ffffff; +} + +html.macos-vibrancy .dark-mode .electron-navigation-wrapper { + background: rgba(10, 10, 10, 0.9) !important; +} + +html.macos-vibrancy .light-mode .electron-navigation-wrapper { + background: rgba(255, 255, 255, 0.9) !important; +} + +html.macos-vibrancy .electron-navigation { + background: rgba(0, 0, 0, 0) !important; +} + +html.macos-vibrancy .light-mode .ant-layout.main-content-layout .ant-card { + background: rgba(255, 255, 255, 0.5) !important; +} +html.macos-vibrancy .dark-mode .ant-layout.main-content-layout .ant-card { + background: rgba(31, 31, 31, 0.5) !important; +} + +.redTrafficLight { + width: 12px; + height: 12px; + background-color: #fe5f57; + border-radius: 50%; +} + +.yellowTrafficLight { + width: 12px; + height: 12px; + background-color: #febc2e; + border-radius: 50%; +} + +.greenTrafficLight { + width: 12px; + height: 12px; + background-color: #28c840; + border-radius: 50%; } .electron-navigation { line-height: 40px; } +.electron-sidebar.ant-menu-inline .ant-menu-item { + padding-left: 20px !important; +} + .electron-navigation .ant-menu-overflow-item-rest { padding-inline: 10px; } +.electron-navigation.ant-menu-horizontal .ant-menu-item { + padding-inline: 12px; +} + .electron-sidebar .ant-menu-item, .electron-sidebar .ant-menu-submenu-title { height: 32.5px !important; @@ -842,3 +965,124 @@ span.ant-skeleton-input.ant-skeleton-input-sm.text-skeleton { width: 100%; height: 100%; } + +.electron-body .ant-modal-wrap, +.electron-body .ant-modal-mask { + top: 41px; +} + +@keyframes h-progress-macos-wave { + 0% { + transform: translateX(0); + } + 100% { + /* One gradient period (40cqw of a 200cqw-wide element) for a seamless loop */ + transform: translateX(20%); + } +} + +.h-progress { + display: inline-block; + width: 100%; + font-size: 14px; + line-height: 1; +} + +.h-progress-outer { + display: inline-flex; + align-items: center; + width: 100%; +} + +.h-progress-inner { + position: relative; + display: inline-block; + width: 100%; + flex: 1; + overflow: hidden; + vertical-align: middle; + /* Lets the wave size itself against the full track via cqw units */ + container-type: inline-size; +} + +.h-progress-bg, +.h-progress-success-bg { + position: relative; + transition: all 0.1s cubic-bezier(0.78, 0.14, 0.15, 0.86); +} + +.h-progress-success-bg { + position: absolute; + inset-block-start: 0; + inset-inline-start: 0; +} + +/* Mask that clips the wave to the filled portion of the bar. Its width + tracks the fill, while the wave inside keeps a constant width so Safari + doesn't restart/freeze the animation when progress updates. */ +.h-progress-bg-mask { + position: absolute; + inset-block: 0; + inset-inline-start: 0; + overflow: hidden; + pointer-events: none; + transition: width 0.1s cubic-bezier(0.78, 0.14, 0.15, 0.86); +} + +.h-progress-bg-wave { + position: absolute; + inset-block: 0; + /* Constant width relative to the full track (.h-progress-inner), + independent of the mask's changing width. Starts one period early so + the pattern always covers the track while sliding right. */ + inset-inline-start: -40cqw; + width: 200cqw; + background: repeating-linear-gradient( + 90deg, + rgba(255, 255, 255, 0) 0, + rgba(255, 255, 255, 0.35) 20cqw, + rgba(255, 255, 255, 0) 40cqw + ); + animation: h-progress-macos-wave 1s linear infinite; +} + +.h-progress-text { + display: inline-block; + margin-inline-start: 8px; + line-height: 1; + width: 2em; + white-space: nowrap; + text-align: start; + vertical-align: middle; + word-break: normal; +} + +.h-progress-text-start { + width: max-content; + margin-inline-start: 0; + margin-inline-end: 8px; +} + +.h-progress-text-inner { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + margin-inline-start: 0; + padding: 0 4px; + color: #fff; +} + +.h-progress-layout-bottom { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.h-progress-layout-bottom .h-progress-text { + width: max-content; + margin-inline-start: 0; + margin-top: 4px; +} diff --git a/assets/trafficlights/closecolored.svg b/assets/trafficlights/closecolored.svg new file mode 100644 index 0000000..7aead9a --- /dev/null +++ b/assets/trafficlights/closecolored.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/trafficlights/closedowncolored.svg b/assets/trafficlights/closedowncolored.svg new file mode 100644 index 0000000..707b68f --- /dev/null +++ b/assets/trafficlights/closedowncolored.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/trafficlights/closehovercolored.svg b/assets/trafficlights/closehovercolored.svg new file mode 100644 index 0000000..3c0db94 --- /dev/null +++ b/assets/trafficlights/closehovercolored.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/assets/trafficlights/exitfullscreendowncolored.svg b/assets/trafficlights/exitfullscreendowncolored.svg new file mode 100644 index 0000000..62abef8 --- /dev/null +++ b/assets/trafficlights/exitfullscreendowncolored.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/assets/trafficlights/exitfullscreenhovercolored.svg b/assets/trafficlights/exitfullscreenhovercolored.svg new file mode 100644 index 0000000..177210b --- /dev/null +++ b/assets/trafficlights/exitfullscreenhovercolored.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/assets/trafficlights/fullscreencolored.svg b/assets/trafficlights/fullscreencolored.svg new file mode 100644 index 0000000..c098917 --- /dev/null +++ b/assets/trafficlights/fullscreencolored.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/trafficlights/fullscreendowncolored.svg b/assets/trafficlights/fullscreendowncolored.svg new file mode 100644 index 0000000..e9dd466 --- /dev/null +++ b/assets/trafficlights/fullscreendowncolored.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/trafficlights/fullscreenhovercolored.svg b/assets/trafficlights/fullscreenhovercolored.svg new file mode 100644 index 0000000..38ef153 --- /dev/null +++ b/assets/trafficlights/fullscreenhovercolored.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/assets/trafficlights/minimizecolored.svg b/assets/trafficlights/minimizecolored.svg new file mode 100644 index 0000000..480df43 --- /dev/null +++ b/assets/trafficlights/minimizecolored.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/trafficlights/minimizedowncolored.svg b/assets/trafficlights/minimizedowncolored.svg new file mode 100644 index 0000000..f2ff3e4 --- /dev/null +++ b/assets/trafficlights/minimizedowncolored.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/trafficlights/minimizehovercolored.svg b/assets/trafficlights/minimizehovercolored.svg new file mode 100644 index 0000000..6cad028 --- /dev/null +++ b/assets/trafficlights/minimizehovercolored.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/assets/trafficlights/nofocus.svg b/assets/trafficlights/nofocus.svg new file mode 100644 index 0000000..79efe5e --- /dev/null +++ b/assets/trafficlights/nofocus.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/assets/uninstaller.ico b/assets/uninstaller.ico new file mode 100644 index 0000000..a2f4302 Binary files /dev/null and b/assets/uninstaller.ico differ diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..2797dce --- /dev/null +++ b/bun.lock @@ -0,0 +1,3419 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "farmcontrol-ui", + "dependencies": { + "@ant-design/icons": "^6.1.0", + "@babel/plugin-transform-private-property-in-object": "^7.27.1", + "@codemirror/commands": "6.10.4", + "@codemirror/lang-cpp": "^6.0.3", + "@codemirror/lang-css": "^6.3.1", + "@codemirror/lang-go": "^6.0.1", + "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-java": "^6.0.2", + "@codemirror/lang-javascript": "^6.2.4", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/lang-markdown": "^6.3.4", + "@codemirror/lang-php": "^6.0.2", + "@codemirror/lang-python": "^6.2.1", + "@codemirror/lang-rust": "^6.0.2", + "@codemirror/lang-sql": "^6.9.1", + "@codemirror/lang-xml": "^6.1.0", + "@codemirror/lang-yaml": "^6.1.2", + "@codemirror/language": "6.12.1", + "@codemirror/state": "6.7.1", + "@codemirror/theme-one-dark": "^6.1.3", + "@codemirror/view": "6.39.12", + "@simplewebauthn/browser": "^13.1.2", + "@tanstack/react-query": "^5.90.10", + "@tiptap/extension-link": "^3.20.1", + "@tiptap/extension-placeholder": "^3.20.1", + "@tiptap/extension-underline": "^3.20.1", + "@tiptap/markdown": "^3.20.1", + "@tiptap/pm": "^3.20.1", + "@tiptap/react": "^3.20.1", + "@tiptap/starter-kit": "^3.20.1", + "@tsparticles/react": "^3.0.0", + "@tsparticles/slim": "^3.9.1", + "@uiw/react-codemirror": "^4.25.1", + "@vscode/sudo-prompt": "^9.3.2", + "antd": "^5.27.1", + "antd-style": "^3.7.1", + "axios": "^1.11.0", + "blurhash": "^2.0.5", + "codemirror": "^6.0.2", + "country-list": "^2.4.1", + "cross-env": "^10.0.0", + "dayjs": "^1.11.18", + "dotenv": "^17.2.1", + "electron-store": "^11.0.2", + "gcode-preview": "^2.18.0", + "json-schema-traverse": "^1.0.0", + "keycloak-js": "^26.2.0", + "lodash": "^4.17.23", + "loglevel": "^1.9.2", + "nanoid": "^5.1.14", + "online-3d-viewer": "^0.16.0", + "prop-types": "^15.8.1", + "react": "^19.1.1", + "react-country-flag": "^3.1.0", + "react-dom": "^19.1.1", + "react-markdown": "^10.1.0", + "react-responsive": "^10.0.1", + "react-router-dom": "^7.8.2", + "recharts": "^3.8.1", + "remark-gfm": "^4.0.1", + "simplebar-react": "^3.3.2", + "socket.io-client": "*", + "styled-components": "^6.1.19", + "three": "^0.179.1", + "tsparticles": "^3.9.1", + "web-vitals": "^5.1.0", + }, + "devDependencies": { + "@babel/plugin-proposal-private-property-in-object": "^7.21.11", + "@eslint/js": "^9.39.2", + "@vitejs/plugin-react": "^5.0.2", + "concurrently": "^9.2.1", + "electrobun": "1.18.1", + "electron": "^38.7.1", + "electron-builder": "^26.0.12", + "electron-packager": "^17.1.2", + "eslint": "^9.34.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", + "eslint-plugin-react": "^7.37.5", + "eslint-plugin-react-hooks": "^5.2.0", + "eslint-plugin-react-refresh": "^0.4.20", + "express": "^5.1.0", + "globals": "^15.12.0", + "jimp": "^1.6.1", + "png-to-ico": "^2.1.8", + "prettier": "^3.6.2", + "prettier-eslint": "^16.4.2", + "rcedit": "^4.0.1", + "rollup-plugin-visualizer": "^6.0.5", + "serve": "^14.2.4", + "standard": "^17.1.2", + "svgo": "^4.0.0", + "svgo-loader": "^4.0.0", + "vite": "^7.1.3", + "vite-plugin-eslint": "^1.8.1", + "vite-plugin-svgo": "^2.0.0", + "vite-plugin-svgr": "^4.5.0", + "wrangler": "^3.100.0", + }, + }, + }, + "packages": { + "@ant-design/colors": ["@ant-design/colors@8.0.1", "", { "dependencies": { "@ant-design/fast-color": "3.0.1" } }, "sha512-foPVl0+SWIslGUtD/xBr1p9U4AKzPhNYEseXYRRo5QSzGACYZrQbe11AYJbYfAWnWSpGBx6JjBmSeugUsD9vqQ=="], + + "@ant-design/cssinjs": ["@ant-design/cssinjs@1.24.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@emotion/hash": "0.8.0", "@emotion/unitless": "0.7.5", "classnames": "2.5.1", "csstype": "3.2.3", "rc-util": "5.44.4", "stylis": "4.3.6" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-K4cYrJBsgvL+IoozUXYjbT6LHHNt+19a9zkvpBPxLjFHas1UpPM2A5MlhROb0BT8N8WoavM5VsP9MeSeNK/3mg=="], + + "@ant-design/cssinjs-utils": ["@ant-design/cssinjs-utils@1.1.3", "", { "dependencies": { "@ant-design/cssinjs": "1.24.0", "@babel/runtime": "7.28.6", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-nOoQMLW1l+xR1Co8NFVYiP8pZp3VjIIzqV6D6ShYF2ljtdwWJn5WSsH+7kvCktXL/yhEtWURKOfH5Xz/gzlwsg=="], + + "@ant-design/fast-color": ["@ant-design/fast-color@2.0.6", "", { "dependencies": { "@babel/runtime": "7.28.6" } }, "sha512-y2217gk4NqL35giHl72o6Zzqji9O7vHh9YmhUVkPtAOpoTCH4uWxo/pr4VE8t0+ChEPs0qo4eJRC5Q1eXWo3vA=="], + + "@ant-design/icons": ["@ant-design/icons@6.1.0", "", { "dependencies": { "@ant-design/colors": "8.0.1", "@ant-design/icons-svg": "4.4.2", "@rc-component/util": "1.8.1", "clsx": "2.1.1" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-KrWMu1fIg3w/1F2zfn+JlfNDU8dDqILfA5Tg85iqs1lf8ooyGlbkA+TkwfOKKgqpUmAiRY1PTFpuOU2DAIgSUg=="], + + "@ant-design/icons-svg": ["@ant-design/icons-svg@4.4.2", "", {}, "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA=="], + + "@ant-design/react-slick": ["@ant-design/react-slick@1.1.2", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "json2mq": "0.2.0", "resize-observer-polyfill": "1.5.1", "throttle-debounce": "5.0.2" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-EzlvzE6xQUBrZuuhSAFTdsr4P2bBBHGZwKFemEfq8gIGyIQCxalYfZW/T2ORbtQx5rU69o+WycP3exY/7T1hGA=="], + + "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "7.28.5", "js-tokens": "4.0.0", "picocolors": "1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], + + "@babel/compat-data": ["@babel/compat-data@7.29.0", "", {}, "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg=="], + + "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.0", "@babel/helper-compilation-targets": "7.28.6", "@babel/helper-module-transforms": "7.28.6", "@babel/helpers": "7.28.6", "@babel/parser": "7.29.0", "@babel/template": "7.28.6", "@babel/traverse": "7.29.0", "@babel/types": "7.29.0", "@jridgewell/remapping": "2.3.5", "convert-source-map": "2.0.0", "debug": "4.4.3", "gensync": "1.0.0-beta.2", "json5": "2.2.3", "semver": "6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], + + "@babel/generator": ["@babel/generator@7.29.0", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0", "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31", "jsesc": "3.1.0" } }, "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ=="], + + "@babel/helper-annotate-as-pure": ["@babel/helper-annotate-as-pure@7.27.3", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg=="], + + "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "7.29.0", "@babel/helper-validator-option": "7.27.1", "browserslist": "4.28.1", "lru-cache": "5.1.1", "semver": "6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], + + "@babel/helper-create-class-features-plugin": ["@babel/helper-create-class-features-plugin@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-member-expression-to-functions": "7.28.5", "@babel/helper-optimise-call-expression": "7.27.1", "@babel/helper-replace-supers": "7.28.6", "@babel/helper-skip-transparent-expression-wrappers": "7.27.1", "@babel/traverse": "7.29.0", "semver": "6.3.1" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow=="], + + "@babel/helper-globals": ["@babel/helper-globals@7.28.0", "", {}, "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw=="], + + "@babel/helper-member-expression-to-functions": ["@babel/helper-member-expression-to-functions@7.28.5", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg=="], + + "@babel/helper-module-imports": ["@babel/helper-module-imports@7.28.6", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw=="], + + "@babel/helper-module-transforms": ["@babel/helper-module-transforms@7.28.6", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/helper-validator-identifier": "7.28.5", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA=="], + + "@babel/helper-optimise-call-expression": ["@babel/helper-optimise-call-expression@7.27.1", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw=="], + + "@babel/helper-plugin-utils": ["@babel/helper-plugin-utils@7.28.6", "", {}, "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug=="], + + "@babel/helper-replace-supers": ["@babel/helper-replace-supers@7.28.6", "", { "dependencies": { "@babel/helper-member-expression-to-functions": "7.28.5", "@babel/helper-optimise-call-expression": "7.27.1", "@babel/traverse": "7.29.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg=="], + + "@babel/helper-skip-transparent-expression-wrappers": ["@babel/helper-skip-transparent-expression-wrappers@7.27.1", "", { "dependencies": { "@babel/traverse": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg=="], + + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.27.1", "", {}, "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA=="], + + "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.28.5", "", {}, "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q=="], + + "@babel/helper-validator-option": ["@babel/helper-validator-option@7.27.1", "", {}, "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg=="], + + "@babel/helpers": ["@babel/helpers@7.28.6", "", { "dependencies": { "@babel/template": "7.28.6", "@babel/types": "7.29.0" } }, "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw=="], + + "@babel/parser": ["@babel/parser@7.29.0", "", { "dependencies": { "@babel/types": "7.29.0" }, "bin": "./bin/babel-parser.js" }, "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww=="], + + "@babel/plugin-proposal-private-property-in-object": ["@babel/plugin-proposal-private-property-in-object@7.21.11", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-create-class-features-plugin": "7.28.6", "@babel/helper-plugin-utils": "7.28.6", "@babel/plugin-syntax-private-property-in-object": "7.14.5" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-0QZ8qP/3RLDVBwBFoWAwCtgcDZJVwA5LUJRZU8x2YFfKNuFq161wK3cuGrALu5yiPu+vzwTAg/sMWVNeWeNyaw=="], + + "@babel/plugin-syntax-private-property-in-object": ["@babel/plugin-syntax-private-property-in-object@7.14.5", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg=="], + + "@babel/plugin-transform-private-property-in-object": ["@babel/plugin-transform-private-property-in-object@7.28.6", "", { "dependencies": { "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-create-class-features-plugin": "7.28.6", "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-b97jvNSOb5+ehyQmBpmhOCiUC5oVK4PMnpRvO7+ymFBoqYjeDHIU9jnrNUuwHOiL9RpGDoKBpSViarV+BU+eVA=="], + + "@babel/plugin-transform-react-jsx-self": ["@babel/plugin-transform-react-jsx-self@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw=="], + + "@babel/plugin-transform-react-jsx-source": ["@babel/plugin-transform-react-jsx-source@7.27.1", "", { "dependencies": { "@babel/helper-plugin-utils": "7.28.6" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw=="], + + "@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="], + + "@babel/template": ["@babel/template@7.28.6", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/parser": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ=="], + + "@babel/traverse": ["@babel/traverse@7.29.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "@babel/generator": "7.29.0", "@babel/helper-globals": "7.28.0", "@babel/parser": "7.29.0", "@babel/template": "7.28.6", "@babel/types": "7.29.0", "debug": "4.4.3" } }, "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA=="], + + "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "7.27.1", "@babel/helper-validator-identifier": "7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], + + "@babylonjs/core": ["@babylonjs/core@7.54.3", "", {}, "sha512-P5ncXVd8GEUJLhwloP9V0oVwQYIrvZztguVeLlvd5Rx+9aQnenKjpV8auJ6SRsUlAmNZU4pFTKzwF6o2EUfhAw=="], + + "@borewit/text-codec": ["@borewit/text-codec@0.2.2", "", {}, "sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ=="], + + "@cloudflare/kv-asset-handler": ["@cloudflare/kv-asset-handler@0.3.4", "", { "dependencies": { "mime": "3.0.0" } }, "sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q=="], + + "@cloudflare/unenv-preset": ["@cloudflare/unenv-preset@2.0.2", "", { "optionalDependencies": { "workerd": "1.20250718.0" }, "peerDependencies": { "unenv": "2.0.0-rc.14" } }, "sha512-nyzYnlZjjV5xT3LizahG1Iu6mnrCaxglJ04rZLpDwlDVDZ7v46lNsfxhV3A/xtfgQuSHmLnc6SVI+KwBpc3Lwg=="], + + "@cloudflare/workerd-darwin-64": ["@cloudflare/workerd-darwin-64@1.20250718.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-FHf4t7zbVN8yyXgQ/r/GqLPaYZSGUVzeR7RnL28Mwj2djyw2ZergvytVc7fdGcczl6PQh+VKGfZCfUqpJlbi9g=="], + + "@cloudflare/workerd-darwin-arm64": ["@cloudflare/workerd-darwin-arm64@1.20250718.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-fUiyUJYyqqp4NqJ0YgGtp4WJh/II/YZsUnEb6vVy5Oeas8lUOxnN+ZOJ8N/6/5LQCVAtYCChRiIrBbfhTn5Z8Q=="], + + "@cloudflare/workerd-linux-64": ["@cloudflare/workerd-linux-64@1.20250718.0", "", { "os": "linux", "cpu": "x64" }, "sha512-5+eb3rtJMiEwp08Kryqzzu8d1rUcK+gdE442auo5eniMpT170Dz0QxBrqkg2Z48SFUPYbj+6uknuA5tzdRSUSg=="], + + "@cloudflare/workerd-linux-arm64": ["@cloudflare/workerd-linux-arm64@1.20250718.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-Aa2M/DVBEBQDdATMbn217zCSFKE+ud/teS+fFS+OQqKABLn0azO2qq6ANAHYOIE6Q3Sq4CxDIQr8lGdaJHwUog=="], + + "@cloudflare/workerd-windows-64": ["@cloudflare/workerd-windows-64@1.20250718.0", "", { "os": "win32", "cpu": "x64" }, "sha512-dY16RXKffmugnc67LTbyjdDHZn5NoTF1yHEf2fN4+OaOnoGSp3N1x77QubTDwqZ9zECWxgQfDLjddcH8dWeFhg=="], + + "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.0", "", { "dependencies": { "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.0" } }, "sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg=="], + + "@codemirror/commands": ["@codemirror/commands@6.10.4", "", { "dependencies": { "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.2" } }, "sha512-Ryk9y9T0FFVF0cUGhAknveAyUOl/A1qReTFi+qPKtOh2Z9F4AUBz3XOrYD4ZEgZirdugVzHvd/2/Wcwy5OliTg=="], + + "@codemirror/lang-cpp": ["@codemirror/lang-cpp@6.0.3", "", { "dependencies": { "@codemirror/language": "6.12.1", "@lezer/cpp": "1.1.5" } }, "sha512-URM26M3vunFFn9/sm6rzqrBzDgfWuDixp85uTY49wKudToc2jTHUrKIGGKs+QWND+YLofNNZpxcNGRynFJfvgA=="], + + "@codemirror/lang-css": ["@codemirror/lang-css@6.3.1", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/css": "1.3.0" } }, "sha512-kr5fwBGiGtmz6l0LSJIbno9QrifNMUusivHbnA1H6Dmqy4HZFte3UAICix1VuKo0lMPKQr2rqB+0BkKi/S3Ejg=="], + + "@codemirror/lang-go": ["@codemirror/lang-go@6.0.1", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/go": "1.0.1" } }, "sha512-7fNvbyNylvqCphW9HD6WFnRpcDjr+KXX/FgqXy5H5ZS0eC5edDljukm/yNgYkwTsgp2busdod50AOTIy6Jikfg=="], + + "@codemirror/lang-html": ["@codemirror/lang-html@6.4.11", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/lang-css": "6.3.1", "@codemirror/lang-javascript": "6.2.4", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.0", "@lezer/css": "1.3.0", "@lezer/html": "1.3.13" } }, "sha512-9NsXp7Nwp891pQchI7gPdTwBuSuT3K65NGTHWHNJ55HjYcHLllr0rbIZNdOzas9ztc1EUVBlHou85FFZS4BNnw=="], + + "@codemirror/lang-java": ["@codemirror/lang-java@6.0.2", "", { "dependencies": { "@codemirror/language": "6.12.1", "@lezer/java": "1.1.3" } }, "sha512-m5Nt1mQ/cznJY7tMfQTJchmrjdjQ71IDs+55d1GAa8DGaB8JXWsVCkVT284C3RTASaY43YknrK2X3hPO/J3MOQ=="], + + "@codemirror/lang-javascript": ["@codemirror/lang-javascript@6.2.4", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/lint": "6.9.3", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.0", "@lezer/javascript": "1.5.4" } }, "sha512-0WVmhp1QOqZ4Rt6GlVGwKJN3KW7Xh4H2q8ZZNGZaP6lRdxXJzmjm4FqvmOojVj6khWJHIb9sp7U/72W7xQgqAA=="], + + "@codemirror/lang-json": ["@codemirror/lang-json@6.0.2", "", { "dependencies": { "@codemirror/language": "6.12.1", "@lezer/json": "1.0.3" } }, "sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ=="], + + "@codemirror/lang-markdown": ["@codemirror/lang-markdown@6.5.0", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/lang-html": "6.4.11", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.0", "@lezer/markdown": "1.6.3" } }, "sha512-0K40bZ35jpHya6FriukbgaleaqzBLZfOh7HuzqbMxBXkbYMJDxfF39c23xOgxFezR+3G+tR2/Mup+Xk865OMvw=="], + + "@codemirror/lang-php": ["@codemirror/lang-php@6.0.2", "", { "dependencies": { "@codemirror/lang-html": "6.4.11", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/php": "1.0.5" } }, "sha512-ZKy2v1n8Fc8oEXj0Th0PUMXzQJ0AIR6TaZU+PbDHExFwdu+guzOA4jmCHS1Nz4vbFezwD7LyBdDnddSJeScMCA=="], + + "@codemirror/lang-python": ["@codemirror/lang-python@6.2.1", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/python": "1.1.18" } }, "sha512-IRjC8RUBhn9mGR9ywecNhB51yePWCGgvHfY1lWN/Mrp3cKuHr0isDKia+9HnvhiWNnMpbGhWrkhuWOc09exRyw=="], + + "@codemirror/lang-rust": ["@codemirror/lang-rust@6.0.2", "", { "dependencies": { "@codemirror/language": "6.12.1", "@lezer/rust": "1.0.2" } }, "sha512-EZaGjCUegtiU7kSMvOfEZpaCReowEf3yNidYu7+vfuGTm9ow4mthAparY5hisJqOHmJowVH3Upu+eJlUji6qqA=="], + + "@codemirror/lang-sql": ["@codemirror/lang-sql@6.10.0", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-6ayPkEd/yRw0XKBx5uAiToSgGECo/GY2NoJIHXIIQh1EVwLuKoU8BP/qK0qH5NLXAbtJRLuT73hx7P9X34iO4w=="], + + "@codemirror/lang-xml": ["@codemirror/lang-xml@6.1.0", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.0", "@lezer/xml": "1.0.6" } }, "sha512-3z0blhicHLfwi2UgkZYRPioSgVTo9PV5GP5ducFH6FaHy0IAJRg+ixj5gTR1gnT/glAIC8xv4w2VL1LoZfs+Jg=="], + + "@codemirror/lang-yaml": ["@codemirror/lang-yaml@6.1.2", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8", "@lezer/yaml": "1.0.4" } }, "sha512-dxrfG8w5Ce/QbT7YID7mWZFKhdhsaTNOYjOkSIMt1qmC4VQnXSDSYVHHHn8k6kJUfIhtLo8t1JJgltlxWdsITw=="], + + "@codemirror/language": ["@codemirror/language@6.12.1", "", { "dependencies": { "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/common": "1.5.2", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8", "style-mod": "4.1.3" } }, "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ=="], + + "@codemirror/lint": ["@codemirror/lint@6.9.3", "", { "dependencies": { "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "crelt": "1.0.6" } }, "sha512-y3YkYhdnhjDBAe0VIA0c4wVoFOvnp8CnAvfLqi0TqotIv92wIlAAP7HELOpLBsKwjAX6W92rSflA6an/2zBvXw=="], + + "@codemirror/search": ["@codemirror/search@6.6.0", "", { "dependencies": { "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "crelt": "1.0.7" } }, "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw=="], + + "@codemirror/state": ["@codemirror/state@6.7.1", "", { "dependencies": { "@marijn/find-cluster-break": "1.0.3" } }, "sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A=="], + + "@codemirror/theme-one-dark": ["@codemirror/theme-one-dark@6.1.3", "", { "dependencies": { "@codemirror/language": "6.12.1", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12", "@lezer/highlight": "1.2.3" } }, "sha512-NzBdIvEJmx6fjeremiGp3t/okrLPYT0d9orIc7AFun8oZcRk58aejkqhv6spnz4MLAevrKNPMQYXEWMg4s+sKA=="], + + "@codemirror/view": ["@codemirror/view@6.39.12", "", { "dependencies": { "@codemirror/state": "6.7.1", "crelt": "1.0.7", "style-mod": "4.1.3", "w3c-keyname": "2.2.8" } }, "sha512-f+/VsHVn/kOA9lltk/GFzuYwVVAKmOnNjxbrhkk3tPHntFqjWeI2TbIXx006YkBkqC10wZ4NsnWXCQiFPeAISQ=="], + + "@cspotcode/source-map-support": ["@cspotcode/source-map-support@0.8.1", "", { "dependencies": { "@jridgewell/trace-mapping": "0.3.9" } }, "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw=="], + + "@electron/asar": ["@electron/asar@3.4.1", "", { "dependencies": { "commander": "^5.0.0", "glob": "^7.1.6", "minimatch": "^3.0.4" }, "bin": { "asar": "bin/asar.js" } }, "sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA=="], + + "@electron/fuses": ["@electron/fuses@1.8.0", "", { "dependencies": { "chalk": "^4.1.1", "fs-extra": "^9.0.1", "minimist": "^1.2.5" }, "bin": { "electron-fuses": "dist/bin.js" } }, "sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw=="], + + "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], + + "@electron/notarize": ["@electron/notarize@1.2.4", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1" } }, "sha512-W5GQhJEosFNafewnS28d3bpQ37/s91CDWqxVchHfmv2dQSTWpOzNlUVQwYzC1ay5bChRV/A9BTL68yj0Pa+TSg=="], + + "@electron/osx-sign": ["@electron/osx-sign@1.3.3", "", { "dependencies": { "compare-version": "^0.1.2", "debug": "^4.3.4", "fs-extra": "^10.0.0", "isbinaryfile": "^4.0.8", "minimist": "^1.2.6", "plist": "^3.0.5" }, "bin": { "electron-osx-flat": "bin/electron-osx-flat.js", "electron-osx-sign": "bin/electron-osx-sign.js" } }, "sha512-KZ8mhXvWv2rIEgMbWZ4y33bDHyUKMXnx4M0sTyPNK/vcB81ImdeY9Ggdqy0SWbMDgmbqyQ+phgejh6V3R2QuSg=="], + + "@electron/rebuild": ["@electron/rebuild@4.2.0", "", { "dependencies": { "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.1.1", "node-abi": "^4.2.0", "node-api-version": "^0.2.1", "node-gyp": "^12.2.0", "read-binary-file-arch": "^1.0.6" }, "bin": { "electron-rebuild": "lib/cli.js" } }, "sha512-RKL/O+jGoXJMxrx/5771y1n0xTKmFuOYGO3gMmwypBM6rsH0kou0mswwdXA2JrhIkE4xyC7v9vGk0n6NPzgOxQ=="], + + "@electron/universal": ["@electron/universal@1.5.1", "", { "dependencies": { "@electron/asar": "^3.2.1", "@malept/cross-spawn-promise": "^1.1.0", "debug": "^4.3.1", "dir-compare": "^3.0.0", "fs-extra": "^9.0.1", "minimatch": "^3.0.4", "plist": "^3.0.4" } }, "sha512-kbgXxyEauPJiQQUNG2VgUeyfQNFk6hBF11ISN2PNI6agUgPl55pv4eQmaqHzTAzchBvqZ2tQuRVaPStGf0mxGw=="], + + "@electron/windows-sign": ["@electron/windows-sign@1.2.2", "", { "dependencies": { "cross-dirname": "^0.1.0", "debug": "^4.3.4", "fs-extra": "^11.1.1", "minimist": "^1.2.8", "postject": "^1.0.0-alpha.6" }, "bin": { "electron-windows-sign": "bin/electron-windows-sign.js" } }, "sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ=="], + + "@emnapi/runtime": ["@emnapi/runtime@1.8.1", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg=="], + + "@emotion/babel-plugin": ["@emotion/babel-plugin@11.13.5", "", { "dependencies": { "@babel/helper-module-imports": "7.28.6", "@babel/runtime": "7.28.6", "@emotion/hash": "0.9.2", "@emotion/memoize": "0.9.0", "@emotion/serialize": "1.3.3", "babel-plugin-macros": "3.1.0", "convert-source-map": "1.9.0", "escape-string-regexp": "4.0.0", "find-root": "1.1.0", "source-map": "0.5.7", "stylis": "4.2.0" } }, "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ=="], + + "@emotion/cache": ["@emotion/cache@11.14.0", "", { "dependencies": { "@emotion/memoize": "0.9.0", "@emotion/sheet": "1.4.0", "@emotion/utils": "1.4.2", "@emotion/weak-memoize": "0.4.0", "stylis": "4.2.0" } }, "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA=="], + + "@emotion/css": ["@emotion/css@11.13.5", "", { "dependencies": { "@emotion/babel-plugin": "11.13.5", "@emotion/cache": "11.14.0", "@emotion/serialize": "1.3.3", "@emotion/sheet": "1.4.0", "@emotion/utils": "1.4.2" } }, "sha512-wQdD0Xhkn3Qy2VNcIzbLP9MR8TafI0MJb7BEAXKp+w4+XqErksWR4OXomuDzPsN4InLdGhVe6EYcn2ZIUCpB8w=="], + + "@emotion/hash": ["@emotion/hash@0.8.0", "", {}, "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow=="], + + "@emotion/is-prop-valid": ["@emotion/is-prop-valid@1.4.0", "", { "dependencies": { "@emotion/memoize": "0.9.0" } }, "sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw=="], + + "@emotion/memoize": ["@emotion/memoize@0.9.0", "", {}, "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ=="], + + "@emotion/react": ["@emotion/react@11.14.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@emotion/babel-plugin": "11.13.5", "@emotion/cache": "11.14.0", "@emotion/serialize": "1.3.3", "@emotion/use-insertion-effect-with-fallbacks": "1.2.0", "@emotion/utils": "1.4.2", "@emotion/weak-memoize": "0.4.0", "hoist-non-react-statics": "3.3.2" }, "optionalDependencies": { "@types/react": "19.2.10" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA=="], + + "@emotion/serialize": ["@emotion/serialize@1.3.3", "", { "dependencies": { "@emotion/hash": "0.9.2", "@emotion/memoize": "0.9.0", "@emotion/unitless": "0.10.0", "@emotion/utils": "1.4.2", "csstype": "3.2.3" } }, "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA=="], + + "@emotion/sheet": ["@emotion/sheet@1.4.0", "", {}, "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg=="], + + "@emotion/unitless": ["@emotion/unitless@0.10.0", "", {}, "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg=="], + + "@emotion/use-insertion-effect-with-fallbacks": ["@emotion/use-insertion-effect-with-fallbacks@1.2.0", "", { "peerDependencies": { "react": "19.2.4" } }, "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg=="], + + "@emotion/utils": ["@emotion/utils@1.4.2", "", {}, "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA=="], + + "@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="], + + "@epic-web/invariant": ["@epic-web/invariant@1.0.0", "", {}, "sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA=="], + + "@esbuild-plugins/node-globals-polyfill": ["@esbuild-plugins/node-globals-polyfill@0.2.3", "", { "peerDependencies": { "esbuild": "0.17.19" } }, "sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw=="], + + "@esbuild-plugins/node-modules-polyfill": ["@esbuild-plugins/node-modules-polyfill@0.2.2", "", { "dependencies": { "escape-string-regexp": "4.0.0", "rollup-plugin-node-polyfills": "0.2.1" }, "peerDependencies": { "esbuild": "0.17.19" } }, "sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA=="], + + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.2", "", { "os": "android", "cpu": "arm64" }, "sha512-pvz8ZZ7ot/RBphf8fv60ljmaoydPU12VuXHImtAs0XhLLw+EXBi2BLe3OYSBslR4rryHvweW5gmkKFwTiFy6KA=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.2", "", { "os": "android", "cpu": "x64" }, "sha512-z8Ank4Byh4TJJOh4wpz8g2vDy75zFL0TlZlkUkEwYXuPSgX8yzep596n6mT7905kA9uHZsf/o2OJZubl2l3M7A=="], + + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.2", "", { "os": "darwin", "cpu": "arm64" }, "sha512-davCD2Zc80nzDVRwXTcQP/28fiJbcOwvdolL0sOiOsbwBa72kegmVU0Wrh1MYrbuCL98Omp5dVhQFWRKR2ZAlg=="], + + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.2", "", { "os": "darwin", "cpu": "x64" }, "sha512-ZxtijOmlQCBWGwbVmwOF/UCzuGIbUkqB1faQRf5akQmxRJ1ujusWsb3CVfk/9iZKr2L5SMU5wPBi1UWbvL+VQA=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.2", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-lS/9CN+rgqQ9czogxlMcBMGd+l8Q3Nj1MFQwBZJyoEKI50XGxwuzznYdwcav6lpOGv5BqaZXqvBSiB/kJ5op+g=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.2", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tAfqtNYb4YgPnJlEFu4c212HYjQWSO/w/h/lQaBK7RbwGIkBOuNKQI9tqWzx7Wtp7bTPaGC6MJvWI608P3wXYA=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.2", "", { "os": "linux", "cpu": "arm" }, "sha512-vWfq4GaIMP9AIe4yj1ZUW18RDhx6EPQKjwe7n8BbIecFtCQG4CfHGaHuh7fdfq+y3LIA2vGS/o9ZBGVxIDi9hw=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.2", "", { "os": "linux", "cpu": "arm64" }, "sha512-hYxN8pr66NsCCiRFkHUAsxylNOcAQaxSSkHMMjcpx0si13t1LHFphxJZUiGwojB1a/Hd5OiPIqDdXONia6bhTw=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.2", "", { "os": "linux", "cpu": "ia32" }, "sha512-MJt5BRRSScPDwG2hLelYhAAKh9imjHK5+NE/tvnRLbIqUWa+0E9N4WNMjmp/kXXPHZGqPLxggwVhz7QP8CTR8w=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-lugyF1atnAT463aO6KPshVCJK5NgRnU4yb3FUumyVz+cGvZbontBgzeGFO1nF+dPueHD367a2ZXe1NtUkAjOtg=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-nlP2I6ArEBewvJ2gjrrkESEZkB5mIoaTswuqNFRv/WYd+ATtUpe9Y09RnJvgvdag7he0OWgEZWhviS1OTOKixw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.2", "", { "os": "linux", "cpu": "ppc64" }, "sha512-C92gnpey7tUQONqg1n6dKVbx3vphKtTHJaNG2Ok9lGwbZil6DrfyecMsp9CrmXGQJmZ7iiVXvvZH6Ml5hL6XdQ=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.2", "", { "os": "linux", "cpu": "none" }, "sha512-B5BOmojNtUyN8AXlK0QJyvjEZkWwy/FKvakkTDCziX95AowLZKR6aCDhG7LeF7uMCXEJqwa8Bejz5LTPYm8AvA=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.2", "", { "os": "linux", "cpu": "s390x" }, "sha512-p4bm9+wsPwup5Z8f4EpfN63qNagQ47Ua2znaqGH6bqLlmJ4bx97Y9JdqxgGZ6Y8xVTixUnEkoKSHcpRlDnNr5w=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.2", "", { "os": "linux", "cpu": "x64" }, "sha512-uwp2Tip5aPmH+NRUwTcfLb+W32WXjpFejTIOWZFw/v7/KnpCDKG66u4DLcurQpiYTiYwQ9B7KOeMJvLCu/OvbA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-Kj6DiBlwXrPsCRDeRvGAUb/LNrBASrfqAIok+xB0LxK8CHqxZ037viF13ugfsIpePH93mX7xfJp97cyDuTZ3cw=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.2", "", { "os": "none", "cpu": "x64" }, "sha512-HwGDZ0VLVBY3Y+Nw0JexZy9o/nUAWq9MlV7cahpaXKW6TOzfVno3y3/M8Ga8u8Yr7GldLOov27xiCnqRZf0tCA=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.2", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-DNIHH2BPQ5551A7oSHD0CKbwIA/Ox7+78/AWkbS5QoRzaqlev2uFayfSxq68EkonB+IKjiuxBFoV8ESJy8bOHA=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.2", "", { "os": "openbsd", "cpu": "x64" }, "sha512-/it7w9Nb7+0KFIzjalNJVR5bOzA9Vay+yIPLVHfIQYG/j+j9VTH84aNB8ExGKPU4AzfaEvN9/V4HV+F+vo8OEg=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.2", "", { "os": "none", "cpu": "arm64" }, "sha512-LRBbCmiU51IXfeXk59csuX/aSaToeG7w48nMwA6049Y4J4+VbWALAuXcs+qcD04rHDuSCSRKdmY63sruDS5qag=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.2", "", { "os": "sunos", "cpu": "x64" }, "sha512-kMtx1yqJHTmqaqHPAzKCAkDaKsffmXkPHThSfRwZGyuqyIeBvf08KSsYXl+abf5HDAPMJIPnbBfXvP2ZC2TfHg=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-Yaf78O/B3Kkh+nKABUF++bvJv5Ijoy9AN1ww904rOXZFLWVc5OLOfL56W+C8F9xn5JQZa3UX6m+IktJnIb1Jjg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-Iuws0kxo4yusk7sw70Xa2E2imZU5HoixzxfGCdxwBdhiDgt9vX9VUCBhqcwY7/uh//78A1hMkkROMJq9l27oLQ=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.2", "", { "os": "win32", "cpu": "x64" }, "sha512-sRdU18mcKf7F+YgheI/zGf5alZatMUTKj/jNS6l744f9u3WFu4v7twcUI9vu4mknF4Y9aDlblIie0IM+5xxaqQ=="], + + "@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "3.4.3" }, "peerDependencies": { "eslint": "8.57.1" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="], + + "@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="], + + "@eslint/config-array": ["@eslint/config-array@0.21.1", "", { "dependencies": { "@eslint/object-schema": "2.1.7", "debug": "4.4.3", "minimatch": "3.1.2" } }, "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA=="], + + "@eslint/config-helpers": ["@eslint/config-helpers@0.4.2", "", { "dependencies": { "@eslint/core": "0.17.0" } }, "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw=="], + + "@eslint/core": ["@eslint/core@0.17.0", "", { "dependencies": { "@types/json-schema": "7.0.15" } }, "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ=="], + + "@eslint/eslintrc": ["@eslint/eslintrc@3.3.3", "", { "dependencies": { "ajv": "6.12.6", "debug": "4.4.3", "espree": "10.4.0", "globals": "14.0.0", "ignore": "5.3.2", "import-fresh": "3.3.1", "js-yaml": "4.1.1", "minimatch": "3.1.2", "strip-json-comments": "3.1.1" } }, "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ=="], + + "@eslint/js": ["@eslint/js@9.39.2", "", {}, "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA=="], + + "@eslint/object-schema": ["@eslint/object-schema@2.1.7", "", {}, "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA=="], + + "@eslint/plugin-kit": ["@eslint/plugin-kit@0.4.1", "", { "dependencies": { "@eslint/core": "0.17.0", "levn": "0.4.1" } }, "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA=="], + + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + + "@floating-ui/core": ["@floating-ui/core@1.7.5", "", { "dependencies": { "@floating-ui/utils": "0.2.11" } }, "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ=="], + + "@floating-ui/dom": ["@floating-ui/dom@1.7.6", "", { "dependencies": { "@floating-ui/core": "1.7.5", "@floating-ui/utils": "0.2.11" } }, "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ=="], + + "@floating-ui/utils": ["@floating-ui/utils@0.2.11", "", {}, "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg=="], + + "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], + + "@humanfs/node": ["@humanfs/node@0.16.7", "", { "dependencies": { "@humanfs/core": "0.19.1", "@humanwhocodes/retry": "0.4.3" } }, "sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ=="], + + "@humanwhocodes/config-array": ["@humanwhocodes/config-array@0.13.0", "", { "dependencies": { "@humanwhocodes/object-schema": "2.0.3", "debug": "4.4.3", "minimatch": "3.1.2" } }, "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw=="], + + "@humanwhocodes/module-importer": ["@humanwhocodes/module-importer@1.0.1", "", {}, "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA=="], + + "@humanwhocodes/object-schema": ["@humanwhocodes/object-schema@2.0.3", "", {}, "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA=="], + + "@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="], + + "@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.0.4" }, "os": "darwin", "cpu": "arm64" }, "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ=="], + + "@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.0.4" }, "os": "darwin", "cpu": "x64" }, "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q=="], + + "@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.0.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg=="], + + "@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.0.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ=="], + + "@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.0.5", "", { "os": "linux", "cpu": "arm" }, "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g=="], + + "@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA=="], + + "@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.0.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA=="], + + "@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw=="], + + "@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.0.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA=="], + + "@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.0.4", "", { "os": "linux", "cpu": "x64" }, "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw=="], + + "@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.0.5" }, "os": "linux", "cpu": "arm" }, "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ=="], + + "@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA=="], + + "@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.0.4" }, "os": "linux", "cpu": "s390x" }, "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q=="], + + "@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA=="], + + "@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" }, "os": "linux", "cpu": "arm64" }, "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g=="], + + "@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.33.5", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.0.4" }, "os": "linux", "cpu": "x64" }, "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw=="], + + "@img/sharp-wasm32": ["@img/sharp-wasm32@0.33.5", "", { "dependencies": { "@emnapi/runtime": "1.8.1" }, "cpu": "none" }, "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg=="], + + "@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.33.5", "", { "os": "win32", "cpu": "ia32" }, "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ=="], + + "@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.33.5", "", { "os": "win32", "cpu": "x64" }, "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg=="], + + "@isaacs/fs-minipass": ["@isaacs/fs-minipass@4.0.1", "", { "dependencies": { "minipass": "^7.0.4" } }, "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w=="], + + "@jest/schemas": ["@jest/schemas@29.6.3", "", { "dependencies": { "@sinclair/typebox": "0.27.8" } }, "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA=="], + + "@jimp/core": ["@jimp/core@1.6.1", "", { "dependencies": { "@jimp/file-ops": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "await-to-js": "^3.0.0", "exif-parser": "^0.1.12", "file-type": "^21.3.3", "mime": "3" } }, "sha512-+BoKC5G6hkrSy501zcJ2EpfnllP+avPevcBfRcZe/CW+EwEfY6X1EZ8QWyT7NpDIvEEJb1fdJnMMfUnFkxmw9A=="], + + "@jimp/diff": ["@jimp/diff@1.6.1", "", { "dependencies": { "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "pixelmatch": "^5.3.0" } }, "sha512-YkKDPdHjLgo1Api3+Bhc0GLAygldlpt97NfOKoNg1U6IUNXA6X2MgosCjPfSBiSvJvrrz1fsIR+/4cfYXBI/HQ=="], + + "@jimp/file-ops": ["@jimp/file-ops@1.6.1", "", {}, "sha512-T+gX6osHjprbDRad0/B71Evyre7ZdVY1z/gFGEG9Z8KOtZPKboWvPeP2UjbZYWQLy9UKCPQX1FNAnDiOPkJL7w=="], + + "@jimp/js-bmp": ["@jimp/js-bmp@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "bmp-ts": "^1.0.9" } }, "sha512-xzWzNT4/u5zGrTT3Tme9sGU7YzIKxi13+BCQwLqACbt5DXf9SAfdzRkopZQnmDko+6In5nqaT89Gjs43/WdnYQ=="], + + "@jimp/js-gif": ["@jimp/js-gif@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "gifwrap": "^0.10.1", "omggif": "^1.0.10" } }, "sha512-YjY2W26rQa05XhanYhRZ7dingCiNN+T2Ymb1JiigIbABY0B28wHE3v3Cf1/HZPWGu0hOg36ylaKgV5KxF2M58w=="], + + "@jimp/js-jpeg": ["@jimp/js-jpeg@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "jpeg-js": "^0.4.4" } }, "sha512-HT9H3yOmlOFzYmdI15IYdfy6ggQhSRIaHeA+OTJSEORXBqEo97sUZu/DsgHIcX5NJ7TkJBTgZ9BZXsV6UbsyMg=="], + + "@jimp/js-png": ["@jimp/js-png@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "pngjs": "^7.0.0" } }, "sha512-SZ/KVhI5UjcSzzlXsXdIi/LhJ7UShf2NkMOtVrbZQcGzsqNtynAelrOXeoTxcanfVqmNhAoVHg8yR2cYoqrYjA=="], + + "@jimp/js-tiff": ["@jimp/js-tiff@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "utif2": "^4.1.0" } }, "sha512-jDG/eJquID1M4MBlKMmDRBmz2TpXMv7TUyu2nIRUxhlUc2ogC82T+VQUkca9GJH1BBJ9dx5sSE5dGkWNjIbZxw=="], + + "@jimp/plugin-blit": ["@jimp/plugin-blit@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-MwnI7C7K81uWddY9FLw1fCOIy6SsPIUftUz36Spt7jisCn8/40DhQMlSxpxTNelnZb/2SnloFimQfRZAmHLOqQ=="], + + "@jimp/plugin-blur": ["@jimp/plugin-blur@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/utils": "1.6.1" } }, "sha512-lIo7Tzp5jQu30EFFSK/phXANK3citKVEjepDjQ6ljHoIFtuMRrnybnmI2Md24ulvWlDaz+hh3n6qrMb8ydwhZQ=="], + + "@jimp/plugin-circle": ["@jimp/plugin-circle@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-kK1PavY6cKHNNKce37vdV4Tmpc1/zDKngGoeOV3j+EMatoHFZUinV3s6F9aWryPs3A0xhCLZgdJ6Zeea1d5LCQ=="], + + "@jimp/plugin-color": ["@jimp/plugin-color@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "tinycolor2": "^1.6.0", "zod": "^3.23.8" } }, "sha512-LtUN1vAP+LRlZAtTNVhDRSiXx+26Kbz3zJaG6a5k59gQ95jgT5mknnF8lxkHcqJthM4MEk3/tPxkdJpEybyF/A=="], + + "@jimp/plugin-contain": ["@jimp/plugin-contain@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-m0qhrfA8jkTqretGv4w+T/ADFR4GwBpE0sCOC2uJ0dzr44/ddOMsIdrpi89kabqYiPYIrxkgdCVCLm3zn1Vkkg=="], + + "@jimp/plugin-cover": ["@jimp/plugin-cover@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-hZytnsth0zoll6cPf434BrT+p/v569Wr5tyO6Dp0dH1IDPhzhB5F38sZGMLDo7bzQiN9JFVB3fxkcJ/WYCJ3Mg=="], + + "@jimp/plugin-crop": ["@jimp/plugin-crop@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-EerRSLlclXyKDnYc/H9w/1amZW7b7v3OGi/VlerPd2M/pAu5X8TkyYWtfqYCXnNp1Ixtd8oCo9zGfY9zoXT4rg=="], + + "@jimp/plugin-displace": ["@jimp/plugin-displace@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-K07QVl7xQwIfD6KfxRV/c3E9e7ZBXxUXdWuvoTWcKHL2qV48MOF5Nqbz/aJW4ThnQARIsxvYlZjPFiqkCjlU+g=="], + + "@jimp/plugin-dither": ["@jimp/plugin-dither@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1" } }, "sha512-+2V+GCV2WycMoX1/z977TkZ8Zq/4MVSKElHYatgUqtwXMi2fDK2gKYU2g9V39IqFvTJsTIsK0+58VFz/ROBVew=="], + + "@jimp/plugin-fisheye": ["@jimp/plugin-fisheye@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-XtS5ZyoZ0vxZxJ6gkqI63SivhtI58vX95foMPM+cyzYkRsJXMOYCr8DScxF5bp4Xr003NjYm/P+7+08tibwzHA=="], + + "@jimp/plugin-flip": ["@jimp/plugin-flip@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-ws38W/sGj7LobNRayQ83garxiktOyWxM5vO/y4a/2cy9v65SLEUzVkrj+oeAaUSSObdz4HcCEla7XtGlnAGAaA=="], + + "@jimp/plugin-hash": ["@jimp/plugin-hash@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/js-bmp": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/js-tiff": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "any-base": "^1.1.0" } }, "sha512-sZt6ZcMX6i8vFWb4GYnw0pR/o9++ef0dTVcboTB5B/g7nrxCODIB4wfEkJ/YqZM5wUvol77K1qeS0/rVO6z21A=="], + + "@jimp/plugin-mask": ["@jimp/plugin-mask@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-SIG0/FcmEj3tkwFxc7fAGLO8o4uNzMpSOdQOhbCgxefQKq5wOVMk9BQx/sdMPBwtMLr9WLq0GzLA/rk6t2v20A=="], + + "@jimp/plugin-print": ["@jimp/plugin-print@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/types": "1.6.1", "parse-bmfont-ascii": "^1.0.6", "parse-bmfont-binary": "^1.0.6", "parse-bmfont-xml": "^1.1.6", "simple-xml-to-json": "^1.2.2", "zod": "^3.23.8" } }, "sha512-BYVz/X3Xzv8XYilVeDy11NOp0h7BTDjlOtu0BekIFHP1yHVd24AXNzbOy52XlzYZWQ0Dl36HOHEpl/nSNrzc6w=="], + + "@jimp/plugin-quantize": ["@jimp/plugin-quantize@1.6.1", "", { "dependencies": { "image-q": "^4.0.0", "zod": "^3.23.8" } }, "sha512-J2En9PLURfP+vwYDtuZ9T8yBW6BWYZBScydAjRiPBmJfEhTcNQqiiQODrZf7EqbbX/Sy5H6dAeRiqkgoV9N6Ww=="], + + "@jimp/plugin-resize": ["@jimp/plugin-resize@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/types": "1.6.1", "zod": "^3.23.8" } }, "sha512-CLkrtJoIz2HdWnpYiN6p8KYcPc00rCH/SUu6o+lfZL05Q4uhecJlnvXuj9x+U6mDn3ldPmJj6aZqMHuUJzdVqg=="], + + "@jimp/plugin-rotate": ["@jimp/plugin-rotate@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-nOjVjbbj705B02ksysKnh0POAwEBXZtJ9zQ5qC+X7Tavl3JNn+P3BzQovbBxLPSbUSld6XID9z5ijin4PtOAUg=="], + + "@jimp/plugin-threshold": ["@jimp/plugin-threshold@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-hash": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1", "zod": "^3.23.8" } }, "sha512-JOKv9F8s6tnVLf4sB/2fF0F339EFnHvgEdFYugO6VhowKLsap0pEZmLyE/DlRnYtIj2RddHZVxVMp/eKJ04l2Q=="], + + "@jimp/types": ["@jimp/types@1.6.1", "", { "dependencies": { "zod": "^3.23.8" } }, "sha512-leI7YbveTNi565m910XgIOwXyuu074H5qazAD1357HImJSv2hqxnWXpwxQbadGWZ7goZRYBDZy5lpqud0p7q5w=="], + + "@jimp/utils": ["@jimp/utils@1.6.1", "", { "dependencies": { "@jimp/types": "1.6.1", "tinycolor2": "^1.6.0" } }, "sha512-veFPRd93FCnS7AgmCkPgARVGoDRrJ9cm1ujuNyA+UfQ5VKbED2002sm5XfFLFwTsKC8j04heTrwe+tU1dluXOw=="], + + "@jridgewell/gen-mapping": ["@jridgewell/gen-mapping@0.3.13", "", { "dependencies": { "@jridgewell/sourcemap-codec": "1.5.5", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA=="], + + "@jridgewell/remapping": ["@jridgewell/remapping@2.3.5", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ=="], + + "@jridgewell/resolve-uri": ["@jridgewell/resolve-uri@3.1.2", "", {}, "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw=="], + + "@jridgewell/source-map": ["@jridgewell/source-map@0.3.11", "", { "dependencies": { "@jridgewell/gen-mapping": "0.3.13", "@jridgewell/trace-mapping": "0.3.31" } }, "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA=="], + + "@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="], + + "@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.31", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw=="], + + "@lezer/common": ["@lezer/common@1.5.2", "", {}, "sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ=="], + + "@lezer/cpp": ["@lezer/cpp@1.1.5", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-DIhSXmYtJKLehrjzDFN+2cPt547ySQ41nA8yqcDf/GxMc+YM736xqltFkvADL2M0VebU5I+3+4ks2Vv+Kyq3Aw=="], + + "@lezer/css": ["@lezer/css@1.3.0", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-pBL7hup88KbI7hXnZV3PQsn43DHy6TWyzuyk2AO9UyoXcDltvIdqWKE1dLL/45JVZ+YZkHe1WVHqO6wugZZWcw=="], + + "@lezer/go": ["@lezer/go@1.0.1", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-xToRsYxwsgJNHTgNdStpcvmbVuKxTapV0dM0wey1geMMRc9aggoVyKgzYp41D2/vVOx+Ii4hmE206kvxIXBVXQ=="], + + "@lezer/highlight": ["@lezer/highlight@1.2.3", "", { "dependencies": { "@lezer/common": "1.5.0" } }, "sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g=="], + + "@lezer/html": ["@lezer/html@1.3.13", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-oI7n6NJml729m7pjm9lvLvmXbdoMoi2f+1pwSDJkl9d68zGr7a9Btz8NdHTGQZtW2DA25ybeuv/SyDb9D5tseg=="], + + "@lezer/java": ["@lezer/java@1.1.3", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-yHquUfujwg6Yu4Fd1GNHCvidIvJwi/1Xu2DaKl/pfWIA2c1oXkVvawH3NyXhCaFx4OdlYBVX5wvz2f7Aoa/4Xw=="], + + "@lezer/javascript": ["@lezer/javascript@1.5.4", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA=="], + + "@lezer/json": ["@lezer/json@1.0.3", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ=="], + + "@lezer/lr": ["@lezer/lr@1.4.8", "", { "dependencies": { "@lezer/common": "1.5.0" } }, "sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA=="], + + "@lezer/markdown": ["@lezer/markdown@1.6.3", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3" } }, "sha512-jpGm5Ps+XErS+xA4urw7ogEGkeZOahVQF21Z6oECF0sj+2liwZopd2+I8uH5I/vZsRuuze3OxBREIANLf6KKUw=="], + + "@lezer/php": ["@lezer/php@1.0.5", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-W7asp9DhM6q0W6DYNwIkLSKOvxlXRrif+UXBMxzsJUuqmhE7oVU+gS3THO4S/Puh7Xzgm858UNaFi6dxTP8dJA=="], + + "@lezer/python": ["@lezer/python@1.1.18", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-31FiUrU7z9+d/ElGQLJFXl+dKOdx0jALlP3KEOsGTex8mvj+SoE1FgItcHWK/axkxCHGUSpqIHt6JAWfWu9Rhg=="], + + "@lezer/rust": ["@lezer/rust@1.0.2", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-Lz5sIPBdF2FUXcWeCu1//ojFAZqzTQNRga0aYv6dYXqJqPfMdCAI0NzajWUd4Xijj1IKJLtjoXRPMvTKWBcqKg=="], + + "@lezer/xml": ["@lezer/xml@1.0.6", "", { "dependencies": { "@lezer/common": "1.5.0", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-CdDwirL0OEaStFue/66ZmFSeppuL6Dwjlk8qk153mSQwiSH/Dlri4GNymrNWnUmPl2Um7QfV1FO9KFUyX3Twww=="], + + "@lezer/yaml": ["@lezer/yaml@1.0.4", "", { "dependencies": { "@lezer/common": "1.5.2", "@lezer/highlight": "1.2.3", "@lezer/lr": "1.4.8" } }, "sha512-2lrrHqxalACEbxIbsjhqGpSW8kWpUKuY6RHgnSAFZa6qK62wvnPxA8hGOwOoDbwHcOFs5M4o27mjGu+P7TvBmw=="], + + "@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@1.1.1", "", { "dependencies": { "cross-spawn": "7.0.6" } }, "sha512-RTBGWL5FWQcg9orDOCcp4LvItNzUPcyEU9bwaeJX0rJ1IQxzucC48Y0/sQLp/g6t99IQgAlGIaesJS+gTn7tVQ=="], + + "@malept/flatpak-bundler": ["@malept/flatpak-bundler@0.4.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.0", "lodash": "^4.17.15", "tmp-promise": "^3.0.2" } }, "sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q=="], + + "@marijn/find-cluster-break": ["@marijn/find-cluster-break@1.0.3", "", {}, "sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA=="], + + "@noble/hashes": ["@noble/hashes@2.2.0", "", {}, "sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg=="], + + "@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "1.2.0" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="], + + "@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="], + + "@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "1.20.1" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="], + + "@peculiar/asn1-schema": ["@peculiar/asn1-schema@2.8.0", "", { "dependencies": { "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-7YT0U/ze0tF2QOBbE15gKZwy5tvgGyLRiRHLzhlbOpf7BT032oBSd0haZqXn5W6l26WLlu3dyxzjM+2638/z2Q=="], + + "@peculiar/json-schema": ["@peculiar/json-schema@1.1.12", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w=="], + + "@peculiar/utils": ["@peculiar/utils@2.0.3", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ=="], + + "@peculiar/webcrypto": ["@peculiar/webcrypto@1.7.1", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/json-schema": "^1.1.12", "@peculiar/utils": "^2.0.2", "tslib": "^2.8.1", "webcrypto-core": "^1.9.2" } }, "sha512-ODOov0sGMJMf3jPonOkgGqPknTsu+DdQ7kD++gz8aI+aFMOMHFbWAA2taqXXVTdP+OTOQR/znGvSpmkeI0WTYQ=="], + + "@pkgr/core": ["@pkgr/core@0.2.9", "", {}, "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA=="], + + "@rc-component/async-validator": ["@rc-component/async-validator@5.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6" } }, "sha512-n4HcR5siNUXRX23nDizbZBQPO0ZM/5oTtmKZ6/eqL0L2bo747cklFdZGRN2f+c9qWGICwDzrhW0H7tE9PptdcA=="], + + "@rc-component/color-picker": ["@rc-component/color-picker@2.0.1", "", { "dependencies": { "@ant-design/fast-color": "2.0.6", "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-WcZYwAThV/b2GISQ8F+7650r5ZZJ043E57aVBFkQ+kSY4C6wdofXgB0hBx+GPGpIU0Z81eETNoDUJMr7oy/P8Q=="], + + "@rc-component/context": ["@rc-component/context@1.4.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-kFcNxg9oLRMoL3qki0OMxK+7g5mypjgaaJp/pkOis/6rVxma9nJBF/8kCIuTYHUQNr0ii7MxqE33wirPZLJQ2w=="], + + "@rc-component/mini-decimal": ["@rc-component/mini-decimal@1.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6" } }, "sha512-jS4E7T9Li2GuYwI6PyiVXmxTiM6b07rlD9Ge8uGZSCz3WlzcG5ZK7g5bbuKNeZ9pgUuPK/5guV781ujdVpm4HQ=="], + + "@rc-component/mutate-observer": ["@rc-component/mutate-observer@1.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-QjrOsDXQusNwGZPf4/qRQasg7UFEj06XiCJ8iuiq/Io7CrHrgVi6Uuetw60WAMG1799v+aM8kyc+1L/GBbHSlw=="], + + "@rc-component/portal": ["@rc-component/portal@1.1.2", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-6f813C0IsasTZms08kfA8kPAGxbbkYToa8ALaiDIGGECU4i9hj8Plgbx0sNJDrey3EtHO30hmdaxtT0138xZcg=="], + + "@rc-component/qrcode": ["@rc-component/qrcode@1.1.1", "", { "dependencies": { "@babel/runtime": "7.28.6" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-LfLGNymzKdUPjXUbRP+xOhIWY4jQ+YMj5MmWAcgcAq1Ij8XP7tRmAXqyuv96XvLUBE/5cA8hLFl9eO1JQMujrA=="], + + "@rc-component/tour": ["@rc-component/tour@1.15.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/portal": "1.1.2", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Tr2t7J1DKZUpfJuDZWHxyxWpfmj8EZrqSgyMZ+BCdvKZ6r1UDsfU46M/iWAAFBy961Ssfom2kv5f3UcjIL2CmQ=="], + + "@rc-component/trigger": ["@rc-component/trigger@2.3.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/portal": "1.1.2", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ORENF39PeXTzM+gQEshuk460Z8N4+6DkjpxlpE7Q3gYy1iBpLrx0FOJz3h62ryrJZ/3zCAUIkT1Pb/8hHWpb3A=="], + + "@rc-component/util": ["@rc-component/util@1.8.1", "", { "dependencies": { "is-mobile": "5.0.0", "react-is": "18.3.1" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Ku6BzF0Ov5L9U3ewFJZDQ//iWCR2nIkLBBiYSrhxIVl3PqeUqiYP2W8gNI8qoKAFQKZdYcS0+B6+SQTDtv/erw=="], + + "@reduxjs/toolkit": ["@reduxjs/toolkit@2.12.0", "", { "dependencies": { "@standard-schema/spec": "1.1.0", "@standard-schema/utils": "0.3.0", "immer": "11.1.8", "redux": "5.0.1", "redux-thunk": "3.1.0", "reselect": "5.1.1" }, "optionalDependencies": { "react": "19.2.4", "react-redux": "9.3.0" } }, "sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw=="], + + "@remirror/core-constants": ["@remirror/core-constants@3.0.0", "", {}, "sha512-42aWfPrimMfDKDi4YegyS7x+/0tlzaqwPQCULLanv3DMIlu96KTJR0fM5isWX2UViOqlGnX6YFgqWepcX+XMNg=="], + + "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], + + "@rollup/pluginutils": ["@rollup/pluginutils@4.2.1", "", { "dependencies": { "estree-walker": "2.0.2", "picomatch": "2.3.1" } }, "sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ=="], + + "@rollup/rollup-android-arm-eabi": ["@rollup/rollup-android-arm-eabi@4.57.1", "", { "os": "android", "cpu": "arm" }, "sha512-A6ehUVSiSaaliTxai040ZpZ2zTevHYbvu/lDoeAteHI8QnaosIzm4qwtezfRg1jOYaUmnzLX1AOD6Z+UJjtifg=="], + + "@rollup/rollup-android-arm64": ["@rollup/rollup-android-arm64@4.57.1", "", { "os": "android", "cpu": "arm64" }, "sha512-dQaAddCY9YgkFHZcFNS/606Exo8vcLHwArFZ7vxXq4rigo2bb494/xKMMwRRQW6ug7Js6yXmBZhSBRuBvCCQ3w=="], + + "@rollup/rollup-darwin-arm64": ["@rollup/rollup-darwin-arm64@4.57.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-crNPrwJOrRxagUYeMn/DZwqN88SDmwaJ8Cvi/TN1HnWBU7GwknckyosC2gd0IqYRsHDEnXf328o9/HC6OkPgOg=="], + + "@rollup/rollup-darwin-x64": ["@rollup/rollup-darwin-x64@4.57.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ji8g8ChVbKrhFtig5QBV7iMaJrGtpHelkB3lsaKzadFBe58gmjfGXAOfI5FV0lYMH8wiqsxKQ1C9B0YTRXVy4w=="], + + "@rollup/rollup-freebsd-arm64": ["@rollup/rollup-freebsd-arm64@4.57.1", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-R+/WwhsjmwodAcz65guCGFRkMb4gKWTcIeLy60JJQbXrJ97BOXHxnkPFrP+YwFlaS0m+uWJTstrUA9o+UchFug=="], + + "@rollup/rollup-freebsd-x64": ["@rollup/rollup-freebsd-x64@4.57.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-IEQTCHeiTOnAUC3IDQdzRAGj3jOAYNr9kBguI7MQAAZK3caezRrg0GxAb6Hchg4lxdZEI5Oq3iov/w/hnFWY9Q=="], + + "@rollup/rollup-linux-arm-gnueabihf": ["@rollup/rollup-linux-arm-gnueabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw=="], + + "@rollup/rollup-linux-arm-musleabihf": ["@rollup/rollup-linux-arm-musleabihf@4.57.1", "", { "os": "linux", "cpu": "arm" }, "sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw=="], + + "@rollup/rollup-linux-arm64-gnu": ["@rollup/rollup-linux-arm64-gnu@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g=="], + + "@rollup/rollup-linux-arm64-musl": ["@rollup/rollup-linux-arm64-musl@4.57.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q=="], + + "@rollup/rollup-linux-loong64-gnu": ["@rollup/rollup-linux-loong64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA=="], + + "@rollup/rollup-linux-loong64-musl": ["@rollup/rollup-linux-loong64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw=="], + + "@rollup/rollup-linux-ppc64-gnu": ["@rollup/rollup-linux-ppc64-gnu@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w=="], + + "@rollup/rollup-linux-ppc64-musl": ["@rollup/rollup-linux-ppc64-musl@4.57.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw=="], + + "@rollup/rollup-linux-riscv64-gnu": ["@rollup/rollup-linux-riscv64-gnu@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A=="], + + "@rollup/rollup-linux-riscv64-musl": ["@rollup/rollup-linux-riscv64-musl@4.57.1", "", { "os": "linux", "cpu": "none" }, "sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw=="], + + "@rollup/rollup-linux-s390x-gnu": ["@rollup/rollup-linux-s390x-gnu@4.57.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg=="], + + "@rollup/rollup-linux-x64-gnu": ["@rollup/rollup-linux-x64-gnu@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg=="], + + "@rollup/rollup-linux-x64-musl": ["@rollup/rollup-linux-x64-musl@4.57.1", "", { "os": "linux", "cpu": "x64" }, "sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw=="], + + "@rollup/rollup-openbsd-x64": ["@rollup/rollup-openbsd-x64@4.57.1", "", { "os": "openbsd", "cpu": "x64" }, "sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw=="], + + "@rollup/rollup-openharmony-arm64": ["@rollup/rollup-openharmony-arm64@4.57.1", "", { "os": "none", "cpu": "arm64" }, "sha512-4wYoDpNg6o/oPximyc/NG+mYUejZrCU2q+2w6YZqrAs2UcNUChIZXjtafAiiZSUc7On8v5NyNj34Kzj/Ltk6dQ=="], + + "@rollup/rollup-win32-arm64-msvc": ["@rollup/rollup-win32-arm64-msvc@4.57.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-O54mtsV/6LW3P8qdTcamQmuC990HDfR71lo44oZMZlXU4tzLrbvTii87Ni9opq60ds0YzuAlEr/GNwuNluZyMQ=="], + + "@rollup/rollup-win32-ia32-msvc": ["@rollup/rollup-win32-ia32-msvc@4.57.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-P3dLS+IerxCT/7D2q2FYcRdWRl22dNbrbBEtxdWhXrfIMPP9lQhb5h4Du04mdl5Woq05jVCDPCMF7Ub0NAjIew=="], + + "@rollup/rollup-win32-x64-gnu": ["@rollup/rollup-win32-x64-gnu@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-VMBH2eOOaKGtIJYleXsi2B8CPVADrh+TyNxJ4mWPnKfLB/DBUmzW+5m1xUrcwWoMfSLagIRpjUFeW5CO5hyciQ=="], + + "@rollup/rollup-win32-x64-msvc": ["@rollup/rollup-win32-x64-msvc@4.57.1", "", { "os": "win32", "cpu": "x64" }, "sha512-mxRFDdHIWRxg3UfIIAwCm6NzvxG0jDX/wBN6KsQFTvKFqqg9vTrWUE68qEjHt19A5wwx5X5aUi2zuZT7YR0jrA=="], + + "@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="], + + "@simonwep/pickr": ["@simonwep/pickr@1.9.0", "", { "dependencies": { "core-js": "3.32.2", "nanopop": "2.3.0" } }, "sha512-oEYvv15PyfZzjoAzvXYt3UyNGwzsrpFxLaZKzkOSd0WYBVwLd19iJerePDONxC1iF6+DpcswPdLIM2KzCJuYFg=="], + + "@simplewebauthn/browser": ["@simplewebauthn/browser@13.2.2", "", {}, "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.27.8", "", {}, "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="], + + "@sindresorhus/is": ["@sindresorhus/is@4.6.0", "", {}, "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw=="], + + "@socket.io/component-emitter": ["@socket.io/component-emitter@3.1.2", "", {}, "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA=="], + + "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="], + + "@standard-schema/utils": ["@standard-schema/utils@0.3.0", "", {}, "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="], + + "@svgr/babel-plugin-add-jsx-attribute": ["@svgr/babel-plugin-add-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g=="], + + "@svgr/babel-plugin-remove-jsx-attribute": ["@svgr/babel-plugin-remove-jsx-attribute@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA=="], + + "@svgr/babel-plugin-remove-jsx-empty-expression": ["@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA=="], + + "@svgr/babel-plugin-replace-jsx-attribute-value": ["@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ=="], + + "@svgr/babel-plugin-svg-dynamic-title": ["@svgr/babel-plugin-svg-dynamic-title@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og=="], + + "@svgr/babel-plugin-svg-em-dimensions": ["@svgr/babel-plugin-svg-em-dimensions@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g=="], + + "@svgr/babel-plugin-transform-react-native-svg": ["@svgr/babel-plugin-transform-react-native-svg@8.1.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q=="], + + "@svgr/babel-plugin-transform-svg-component": ["@svgr/babel-plugin-transform-svg-component@8.0.0", "", { "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw=="], + + "@svgr/babel-preset": ["@svgr/babel-preset@8.1.0", "", { "dependencies": { "@svgr/babel-plugin-add-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-attribute": "8.0.0", "@svgr/babel-plugin-remove-jsx-empty-expression": "8.0.0", "@svgr/babel-plugin-replace-jsx-attribute-value": "8.0.0", "@svgr/babel-plugin-svg-dynamic-title": "8.0.0", "@svgr/babel-plugin-svg-em-dimensions": "8.0.0", "@svgr/babel-plugin-transform-react-native-svg": "8.1.0", "@svgr/babel-plugin-transform-svg-component": "8.0.0" }, "peerDependencies": { "@babel/core": "7.29.0" } }, "sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug=="], + + "@svgr/core": ["@svgr/core@8.1.0", "", { "dependencies": { "@babel/core": "7.29.0", "@svgr/babel-preset": "8.1.0", "camelcase": "6.3.0", "cosmiconfig": "8.3.6", "snake-case": "3.0.4" } }, "sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA=="], + + "@svgr/hast-util-to-babel-ast": ["@svgr/hast-util-to-babel-ast@8.0.0", "", { "dependencies": { "@babel/types": "7.29.0", "entities": "4.5.0" } }, "sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q=="], + + "@svgr/plugin-jsx": ["@svgr/plugin-jsx@8.1.0", "", { "dependencies": { "@babel/core": "7.29.0", "@svgr/babel-preset": "8.1.0", "@svgr/hast-util-to-babel-ast": "8.0.0", "svg-parser": "2.0.4" }, "peerDependencies": { "@svgr/core": "8.1.0" } }, "sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA=="], + + "@szmarczak/http-timer": ["@szmarczak/http-timer@4.0.6", "", { "dependencies": { "defer-to-connect": "^2.0.0" } }, "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w=="], + + "@tanstack/query-core": ["@tanstack/query-core@5.90.20", "", {}, "sha512-OMD2HLpNouXEfZJWcKeVKUgQ5n+n3A2JFmBaScpNDUqSrQSjiveC7dKMe53uJUg1nDG16ttFPz2xfilz6i2uVg=="], + + "@tanstack/react-query": ["@tanstack/react-query@5.90.20", "", { "dependencies": { "@tanstack/query-core": "5.90.20" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-vXBxa+qeyveVO7OA0jX1z+DeyCA4JKnThKv411jd5SORpBKgkcVnYKCiBgECvADvniBX7tobwBmg01qq9JmMJw=="], + + "@tiptap/core": ["@tiptap/core@3.20.1", "", { "peerDependencies": { "@tiptap/pm": "3.20.1" } }, "sha512-SwkPEWIfaDEZjC8SEIi4kZjqIYUbRgLUHUuQezo5GbphUNC8kM1pi3C3EtoOPtxXrEbY6e4pWEzW54Pcrd+rVA=="], + + "@tiptap/extension-blockquote": ["@tiptap/extension-blockquote@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-WzNXk/63PQI2fav4Ta6P0GmYRyu8Gap1pV3VUqaVK829iJ6Zt1T21xayATHEHWMK27VT1GLPJkx9Ycr2jfDyQw=="], + + "@tiptap/extension-bold": ["@tiptap/extension-bold@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-fz++Qv6Rk/Hov0IYG/r7TJ1Y4zWkuGONe0UN5g0KY32NIMg3HeOHicbi4xsNWTm9uAOl3eawWDkezEMrleObMw=="], + + "@tiptap/extension-bubble-menu": ["@tiptap/extension-bubble-menu@3.20.1", "", { "dependencies": { "@floating-ui/dom": "1.7.6" }, "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-XaPvO6aCoWdFnCBus0s88lnj17NR/OopV79i8Qhgz3WMR0vrsL5zsd45l0lZuu9pSvm5VW47SoxakkJiZC1suw=="], + + "@tiptap/extension-bullet-list": ["@tiptap/extension-bullet-list@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "3.20.1" } }, "sha512-mbrlvOZo5OF3vLhp+3fk9KuL/6J/wsN0QxF6ZFRAHzQ9NkJdtdfARcBeBnkWXGN8inB6YxbTGY1/E4lmBkOpOw=="], + + "@tiptap/extension-code": ["@tiptap/extension-code@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-509DHINIA/Gg+eTG7TEkfsS8RUiPLH5xZNyLRT0A1oaoaJmECKfrV6aAm05IdfTyqDqz6LW5pbnX6DdUC4keug=="], + + "@tiptap/extension-code-block": ["@tiptap/extension-code-block@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-vKejwBq+Nlj4Ybd3qOyDxIQKzYymdNH+8eXkKwGShk2nfLJIxq69DCyGvmuHgipIO1qcYPJ149UNpGN+YGcdmA=="], + + "@tiptap/extension-document": ["@tiptap/extension-document@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-9vrqdGmRV7bQCSY3NLgu7UhIwgOCDp4sKqMNsoNRX0aZ021QQMTvBQDPkiRkCf7MNsnWrNNnr52PVnULEn3vFQ=="], + + "@tiptap/extension-dropcursor": ["@tiptap/extension-dropcursor@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "3.20.1" } }, "sha512-K18L9FX4znn+ViPSIbTLOGcIaXMx/gLNwAPE8wPLwswbHhQqdiY1zzdBw6drgOc1Hicvebo2dIoUlSXOZsOEcw=="], + + "@tiptap/extension-floating-menu": ["@tiptap/extension-floating-menu@3.20.1", "", { "peerDependencies": { "@floating-ui/dom": "1.7.6", "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-BeDC6nfOesIMn5pFuUnkEjOxGv80sOJ8uk1mdt9/3Fkvra8cB9NIYYCVtd6PU8oQFmJ8vFqPrRkUWrG5tbqnOg=="], + + "@tiptap/extension-gapcursor": ["@tiptap/extension-gapcursor@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "3.20.1" } }, "sha512-kZOtttV6Ai8VUAgEng3h4WKFbtdSNJ6ps7r0cRPY+FctWhVmgNb/JJwwyC+vSilR7nRENAhrA/Cv/RxVlvLw+g=="], + + "@tiptap/extension-hard-break": ["@tiptap/extension-hard-break@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-9sKpmg/IIdlLXimYWUZ3PplIRcehv4Oc7V1miTqlnAthMzjMqigDkjjgte4JZV67RdnDJTQkRw8TklCAU28Emg=="], + + "@tiptap/extension-heading": ["@tiptap/extension-heading@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-unudyfQP6FxnyWinxvPqe/51DG91J6AaJm666RnAubgYMCgym+33kBftx4j4A6qf+ddWYbD00thMNKOnVLjAEQ=="], + + "@tiptap/extension-horizontal-rule": ["@tiptap/extension-horizontal-rule@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-rjFKFXNntdl0jay8oIGFvvykHlpyQTLmrH3Ag2fj3i8yh6MVvqhtaDomYQbw5sxECd5hBkL+T4n2d2DRuVw/QQ=="], + + "@tiptap/extension-italic": ["@tiptap/extension-italic@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-ZYRX13Kt8tR8JOzSXirH3pRpi8x30o7LHxZY58uXBdUvr3tFzOkh03qbN523+diidSVeHP/aMd/+IrplHRkQug=="], + + "@tiptap/extension-link": ["@tiptap/extension-link@3.20.1", "", { "dependencies": { "linkifyjs": "4.3.2" }, "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-oYTTIgsQMqpkSnJAuAc+UtIKMuI4lv9e1y4LfI1iYm6NkEUHhONppU59smhxHLzb3Ww7YpDffbp5IgDTAiJztA=="], + + "@tiptap/extension-list": ["@tiptap/extension-list@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-euBRAn0mkV7R2VEE+AuOt3R0j9RHEMFXamPFmtvTo8IInxDClusrm6mJoDjS8gCGAXsQCRiAe1SCQBPgGbOOwg=="], + + "@tiptap/extension-list-item": ["@tiptap/extension-list-item@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "3.20.1" } }, "sha512-tzgnyTW82lYJkUnadYbatwkI9dLz/OWRSWuFpQPRje/ItmFMWuQ9c9NDD8qLbXPdEYnvrgSAA+ipCD/1G0qA0Q=="], + + "@tiptap/extension-list-keymap": ["@tiptap/extension-list-keymap@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "3.20.1" } }, "sha512-Dr0xsQKx0XPOgDg7xqoWwfv7FFwZ3WeF3eOjqh3rDXlNHMj1v+UW5cj1HLphrsAZHTrVTn2C+VWPJkMZrSbpvQ=="], + + "@tiptap/extension-ordered-list": ["@tiptap/extension-ordered-list@3.20.1", "", { "peerDependencies": { "@tiptap/extension-list": "3.20.1" } }, "sha512-Y+3Ad7OwAdagqdYwCnbqf7/to5ypD4NnUNHA0TXRCs7cAHRA8AdgPoIcGFpaaSpV86oosNU3yfeJouYeroffog=="], + + "@tiptap/extension-paragraph": ["@tiptap/extension-paragraph@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-QFrAtXNyv7JSnomMQc1nx5AnG9mMznfbYJAbdOQYVdbLtAzTfiTuNPNbQrufy5ZGtGaHxDCoaygu2QEfzaKG+Q=="], + + "@tiptap/extension-placeholder": ["@tiptap/extension-placeholder@3.20.1", "", { "peerDependencies": { "@tiptap/extensions": "3.20.1" } }, "sha512-k+jfbCugYGuIFBdojukgEopGazIMOgHrw46FnyN2X/6ICOIjQP2rh2ObslrsUOsJYoEevxCsNF9hZl1HvWX66g=="], + + "@tiptap/extension-strike": ["@tiptap/extension-strike@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-EYgyma10lpsY+rwbVQL9u+gA7hBlKLSMFH7Zgd37FSxukOjr+HE8iKPQQ+SwbGejyDsPlLT8Z5Jnuxo5Ng90Pg=="], + + "@tiptap/extension-text": ["@tiptap/extension-text@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-7PlIbYW8UenV6NPOXHmv8IcmPGlGx6HFq66RmkJAOJRPXPkTLAiX0N8rQtzUJ6jDEHqoJpaHFEHJw0xzW1yF+A=="], + + "@tiptap/extension-underline": ["@tiptap/extension-underline@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1" } }, "sha512-fmHvDKzwCgnZUwRreq8tYkb1YyEwgzZ6QQkAQ0CsCRtvRMqzerr3Duz0Als4i8voZTuGDEL3VR6nAJbLAb/wPg=="], + + "@tiptap/extensions": ["@tiptap/extensions@3.20.1", "", { "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-JRc/v+OBH0qLTdvQ7HvHWTxGJH73QOf1MC0R8NhOX2QnAbg2mPFv1h+FjGa2gfLGuCXBdWQomjekWkUKbC4e5A=="], + + "@tiptap/markdown": ["@tiptap/markdown@3.20.1", "", { "dependencies": { "marked": "17.0.4" }, "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-dNrtP7kmabDomgjv9G/6+JSFL6WraPaFbmKh1eHSYKdDGvIwBfJnVPTV2VS3bP1OuYJEDJN/2ydtiCHyOTrQsQ=="], + + "@tiptap/pm": ["@tiptap/pm@3.20.1", "", { "dependencies": { "prosemirror-changeset": "2.4.0", "prosemirror-collab": "1.3.1", "prosemirror-commands": "1.7.1", "prosemirror-dropcursor": "1.8.2", "prosemirror-gapcursor": "1.4.0", "prosemirror-history": "1.5.0", "prosemirror-inputrules": "1.5.1", "prosemirror-keymap": "1.2.3", "prosemirror-markdown": "1.13.4", "prosemirror-menu": "1.3.0", "prosemirror-model": "1.25.4", "prosemirror-schema-basic": "1.2.4", "prosemirror-schema-list": "1.5.1", "prosemirror-state": "1.4.4", "prosemirror-tables": "1.8.5", "prosemirror-trailing-node": "3.0.0", "prosemirror-transform": "1.11.0", "prosemirror-view": "1.41.6" } }, "sha512-6kCiGLvpES4AxcEuOhb7HR7/xIeJWMjZlb6J7e8zpiIh5BoQc7NoRdctsnmFEjZvC19bIasccshHQ7H2zchWqw=="], + + "@tiptap/react": ["@tiptap/react@3.20.1", "", { "dependencies": { "@types/use-sync-external-store": "0.0.6", "fast-equals": "5.4.0", "use-sync-external-store": "1.6.0" }, "optionalDependencies": { "@tiptap/extension-bubble-menu": "3.20.1", "@tiptap/extension-floating-menu": "3.20.1" }, "peerDependencies": { "@tiptap/core": "3.20.1", "@tiptap/pm": "3.20.1", "@types/react": "19.2.10", "@types/react-dom": "19.2.3", "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-UH1NpVpCaZBGB3Yr5N6aTS+rsCMDl9wHfrt/w+6+Gz4KHFZ2OILA82hELxZzhNc1Lmjz8vgCArKcsYql9gbzJA=="], + + "@tiptap/starter-kit": ["@tiptap/starter-kit@3.20.1", "", { "dependencies": { "@tiptap/core": "3.20.1", "@tiptap/extension-blockquote": "3.20.1", "@tiptap/extension-bold": "3.20.1", "@tiptap/extension-bullet-list": "3.20.1", "@tiptap/extension-code": "3.20.1", "@tiptap/extension-code-block": "3.20.1", "@tiptap/extension-document": "3.20.1", "@tiptap/extension-dropcursor": "3.20.1", "@tiptap/extension-gapcursor": "3.20.1", "@tiptap/extension-hard-break": "3.20.1", "@tiptap/extension-heading": "3.20.1", "@tiptap/extension-horizontal-rule": "3.20.1", "@tiptap/extension-italic": "3.20.1", "@tiptap/extension-link": "3.20.1", "@tiptap/extension-list": "3.20.1", "@tiptap/extension-list-item": "3.20.1", "@tiptap/extension-list-keymap": "3.20.1", "@tiptap/extension-ordered-list": "3.20.1", "@tiptap/extension-paragraph": "3.20.1", "@tiptap/extension-strike": "3.20.1", "@tiptap/extension-text": "3.20.1", "@tiptap/extension-underline": "3.20.1", "@tiptap/extensions": "3.20.1", "@tiptap/pm": "3.20.1" } }, "sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw=="], + + "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="], + + "@trysound/sax": ["@trysound/sax@0.2.0", "", {}, "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="], + + "@tsparticles/basic": ["@tsparticles/basic@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1", "@tsparticles/move-base": "3.9.1", "@tsparticles/plugin-hex-color": "3.9.1", "@tsparticles/plugin-hsl-color": "3.9.1", "@tsparticles/plugin-rgb-color": "3.9.1", "@tsparticles/shape-circle": "3.9.1", "@tsparticles/updater-color": "3.9.1", "@tsparticles/updater-opacity": "3.9.1", "@tsparticles/updater-out-modes": "3.9.1", "@tsparticles/updater-size": "3.9.1" } }, "sha512-ijr2dHMx0IQHqhKW3qA8tfwrR2XYbbWYdaJMQuBo2CkwBVIhZ76U+H20Y492j/NXpd1FUnt2aC0l4CEVGVGdeQ=="], + + "@tsparticles/engine": ["@tsparticles/engine@3.9.1", "", {}, "sha512-DpdgAhWMZ3Eh2gyxik8FXS6BKZ8vyea+Eu5BC4epsahqTGY9V3JGGJcXC6lRJx6cPMAx1A0FaQAojPF3v6rkmQ=="], + + "@tsparticles/interaction-external-attract": ["@tsparticles/interaction-external-attract@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-5AJGmhzM9o4AVFV24WH5vSqMBzOXEOzIdGLIr+QJf4fRh9ZK62snsusv/ozKgs2KteRYQx+L7c5V3TqcDy2upg=="], + + "@tsparticles/interaction-external-bounce": ["@tsparticles/interaction-external-bounce@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-bv05+h70UIHOTWeTsTI1AeAmX6R3s8nnY74Ea6p6AbQjERzPYIa0XY19nq/hA7+Nrg+EissP5zgoYYeSphr85A=="], + + "@tsparticles/interaction-external-bubble": ["@tsparticles/interaction-external-bubble@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-tbd8ox/1GPl+zr+KyHQVV1bW88GE7OM6i4zql801YIlCDrl9wgTDdDFGIy9X7/cwTvTrCePhrfvdkUamXIribQ=="], + + "@tsparticles/interaction-external-connect": ["@tsparticles/interaction-external-connect@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-sq8YfUNsIORjXHzzW7/AJQtfi/qDqLnYG2qOSE1WOsog39MD30RzmiOloejOkfNeUdcGUcfsDgpUuL3UhzFUOA=="], + + "@tsparticles/interaction-external-grab": ["@tsparticles/interaction-external-grab@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-QwXza+sMMWDaMiFxd8y2tJwUK6c+nNw554+/9+tEZeTTk2fCbB0IJ7p/TH6ZGWDL0vo2muK54Njv2fEey191ow=="], + + "@tsparticles/interaction-external-pause": ["@tsparticles/interaction-external-pause@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-Gzv4/FeNir0U/tVM9zQCqV1k+IAgaFjDU3T30M1AeAsNGh/rCITV2wnT7TOGFkbcla27m4Yxa+Fuab8+8pzm+g=="], + + "@tsparticles/interaction-external-push": ["@tsparticles/interaction-external-push@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-GvnWF9Qy4YkZdx+WJL2iy9IcgLvzOIu3K7aLYJFsQPaxT8d9TF8WlpoMlWKnJID6H5q4JqQuMRKRyWH8aAKyQw=="], + + "@tsparticles/interaction-external-remove": ["@tsparticles/interaction-external-remove@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-yPThm4UDWejDOWW5Qc8KnnS2EfSo5VFcJUQDWc1+Wcj17xe7vdSoiwwOORM0PmNBzdDpSKQrte/gUnoqaUMwOA=="], + + "@tsparticles/interaction-external-repulse": ["@tsparticles/interaction-external-repulse@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-/LBppXkrMdvLHlEKWC7IykFhzrz+9nebT2fwSSFXK4plEBxDlIwnkDxd3FbVOAbnBvx4+L8+fbrEx+RvC8diAw=="], + + "@tsparticles/interaction-external-slow": ["@tsparticles/interaction-external-slow@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-1ZYIR/udBwA9MdSCfgADsbDXKSFS0FMWuPWz7bm79g3sUxcYkihn+/hDhc6GXvNNR46V1ocJjrj0u6pAynS1KQ=="], + + "@tsparticles/interaction-external-trail": ["@tsparticles/interaction-external-trail@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-Au0v2oiqfKTemI/4bzjD4dUXzIngB5Q2T4nJcMCYpP24uZfwZh5xTjUMH7gyJyyaRTdMl9IJrp8ySjyYbLfeGg=="], + + "@tsparticles/interaction-particles-attract": ["@tsparticles/interaction-particles-attract@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-CYYYowJuGwRLUixQcSU/48PTKM8fCUYThe0hXwQ+yRMLAn053VHzL7NNZzKqEIeEyt5oJoy9KcvubjKWbzMBLQ=="], + + "@tsparticles/interaction-particles-collisions": ["@tsparticles/interaction-particles-collisions@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-ggGyjW/3v1yxvYW1IF1EMT15M6w31y5zfNNUPkqd/IXRNPYvm0Z0ayhp+FKmz70M5p0UxxPIQHTvAv9Jqnuj8w=="], + + "@tsparticles/interaction-particles-links": ["@tsparticles/interaction-particles-links@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-MsLbMjy1vY5M5/hu/oa5OSRZAUz49H3+9EBMTIOThiX+a+vpl3sxc9AqNd9gMsPbM4WJlub8T6VBZdyvzez1Vg=="], + + "@tsparticles/move-base": ["@tsparticles/move-base@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-X4huBS27d8srpxwOxliWPUt+NtCwY+8q/cx1DvQxyqmTA8VFCGpcHNwtqiN+9JicgzOvSuaORVqUgwlsc7h4pQ=="], + + "@tsparticles/move-parallax": ["@tsparticles/move-parallax@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-whlOR0bVeyh6J/hvxf/QM3DqvNnITMiAQ0kro6saqSDItAVqg4pYxBfEsSOKq7EhjxNvfhhqR+pFMhp06zoCVA=="], + + "@tsparticles/plugin-absorbers": ["@tsparticles/plugin-absorbers@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-q9SQllpbPPgw1+euxHPYCFawOVUazQkkwnleiIgpYSiimlCyjIdwGnFPSNe1Sypzqmr2h6oOyX2vkK5ZVNEu8A=="], + + "@tsparticles/plugin-easing-quad": ["@tsparticles/plugin-easing-quad@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-C2UJOca5MTDXKUTBXj30Kiqr5UyID+xrY/LxicVWWZPczQW2bBxbIbfq9ULvzGDwBTxE2rdvIB8YFKmDYO45qw=="], + + "@tsparticles/plugin-emitters": ["@tsparticles/plugin-emitters@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-h7opR8SoFWBmVHceDLJUerLENaPfkJSh2zQYvzmLj2L+V3VLS1QDgty+4QZVeZfqNROmgQw2eLFA5El1E0sqqw=="], + + "@tsparticles/plugin-emitters-shape-circle": ["@tsparticles/plugin-emitters-shape-circle@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1", "@tsparticles/plugin-emitters": "3.9.1" } }, "sha512-z+9MsAPWr++sNz6N6303rRDjusW0BIPhHY51E5eXGDcRdOqrESDs6y99AJ/6Kdb/PpibCIYjFY9jVi2JJADPRA=="], + + "@tsparticles/plugin-emitters-shape-square": ["@tsparticles/plugin-emitters-shape-square@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1", "@tsparticles/plugin-emitters": "3.9.1" } }, "sha512-dhA1c7FKs19B8lgTf25OTA3JoptNA+rjorsqCFuY1BZDI8g9E8DNqikUge14/W7nZN96+98hY+ghxSl4K2YsgA=="], + + "@tsparticles/plugin-hex-color": ["@tsparticles/plugin-hex-color@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-vZgZ12AjUicJvk7AX4K2eAmKEQX/D1VEjEPFhyjbgI7A65eX72M465vVKIgNA6QArLZ1DLs7Z787LOE6GOBWsg=="], + + "@tsparticles/plugin-hsl-color": ["@tsparticles/plugin-hsl-color@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-jJd1iGgRwX6eeNjc1zUXiJivaqC5UE+SC2A3/NtHwwoQrkfxGWmRHOsVyLnOBRcCPgBp/FpdDe6DIDjCMO715w=="], + + "@tsparticles/plugin-rgb-color": ["@tsparticles/plugin-rgb-color@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-SBxk7f1KBfXeTnnklbE2Hx4jBgh6I6HOtxb+Os1gTp0oaghZOkWcCD2dP4QbUu7fVNCMOcApPoMNC8RTFcy9wQ=="], + + "@tsparticles/react": ["@tsparticles/react@3.0.0", "", { "peerDependencies": { "@tsparticles/engine": "3.9.1", "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q=="], + + "@tsparticles/shape-circle": ["@tsparticles/shape-circle@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-DqZFLjbuhVn99WJ+A9ajz9YON72RtCcvubzq6qfjFmtwAK7frvQeb6iDTp6Ze9FUipluxVZWVRG4vWTxi2B+/g=="], + + "@tsparticles/shape-emoji": ["@tsparticles/shape-emoji@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-ifvY63usuT+hipgVHb8gelBHSeF6ryPnMxAAEC1RGHhhXfpSRWMtE6ybr+pSsYU52M3G9+TF84v91pSwNrb9ZQ=="], + + "@tsparticles/shape-image": ["@tsparticles/shape-image@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-fCA5eme8VF3oX8yNVUA0l2SLDKuiZObkijb0z3Ky0qj1HUEVlAuEMhhNDNB9E2iELTrWEix9z7BFMePp2CC7AA=="], + + "@tsparticles/shape-line": ["@tsparticles/shape-line@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-wT8NSp0N9HURyV05f371cHKcNTNqr0/cwUu6WhBzbshkYGy1KZUP9CpRIh5FCrBpTev34mEQfOXDycgfG0KiLQ=="], + + "@tsparticles/shape-polygon": ["@tsparticles/shape-polygon@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-dA77PgZdoLwxnliH6XQM/zF0r4jhT01pw5y7XTeTqws++hg4rTLV9255k6R6eUqKq0FPSW1/WBsBIl7q/MmrqQ=="], + + "@tsparticles/shape-square": ["@tsparticles/shape-square@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-DKGkDnRyZrAm7T2ipqNezJahSWs6xd9O5LQLe5vjrYm1qGwrFxJiQaAdlb00UNrexz1/SA7bEoIg4XKaFa7qhQ=="], + + "@tsparticles/shape-star": ["@tsparticles/shape-star@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-kdMJpi8cdeb6vGrZVSxTG0JIjCwIenggqk0EYeKAwtOGZFBgL7eHhF2F6uu1oq8cJAbXPujEoabnLsz6mW8XaA=="], + + "@tsparticles/shape-text": ["@tsparticles/shape-text@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-oNsLHI0lGkIXoUw3W598iwd7dtoHCDrwpwJRGnQzgfk6T5a9dCpSD5vDeQN89lr3BUbVui4lhxq+/TyC64oAqA=="], + + "@tsparticles/slim": ["@tsparticles/slim@3.9.1", "", { "dependencies": { "@tsparticles/basic": "3.9.1", "@tsparticles/engine": "3.9.1", "@tsparticles/interaction-external-attract": "3.9.1", "@tsparticles/interaction-external-bounce": "3.9.1", "@tsparticles/interaction-external-bubble": "3.9.1", "@tsparticles/interaction-external-connect": "3.9.1", "@tsparticles/interaction-external-grab": "3.9.1", "@tsparticles/interaction-external-pause": "3.9.1", "@tsparticles/interaction-external-push": "3.9.1", "@tsparticles/interaction-external-remove": "3.9.1", "@tsparticles/interaction-external-repulse": "3.9.1", "@tsparticles/interaction-external-slow": "3.9.1", "@tsparticles/interaction-particles-attract": "3.9.1", "@tsparticles/interaction-particles-collisions": "3.9.1", "@tsparticles/interaction-particles-links": "3.9.1", "@tsparticles/move-parallax": "3.9.1", "@tsparticles/plugin-easing-quad": "3.9.1", "@tsparticles/shape-emoji": "3.9.1", "@tsparticles/shape-image": "3.9.1", "@tsparticles/shape-line": "3.9.1", "@tsparticles/shape-polygon": "3.9.1", "@tsparticles/shape-square": "3.9.1", "@tsparticles/shape-star": "3.9.1", "@tsparticles/updater-life": "3.9.1", "@tsparticles/updater-rotate": "3.9.1", "@tsparticles/updater-stroke-color": "3.9.1" } }, "sha512-CL5cDmADU7sDjRli0So+hY61VMbdroqbArmR9Av+c1Fisa5ytr6QD7Jv62iwU2S6rvgicEe9OyRmSy5GIefwZw=="], + + "@tsparticles/updater-color": ["@tsparticles/updater-color@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-XGWdscrgEMA8L5E7exsE0f8/2zHKIqnTrZymcyuFBw2DCB6BIV+5z6qaNStpxrhq3DbIxxhqqcybqeOo7+Alpg=="], + + "@tsparticles/updater-destroy": ["@tsparticles/updater-destroy@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-MjMzEhZwCQIbxO6ZRM0eXsHVwmlXuUqwC43WCPZCpjhK3AJrMu3KR4xsJieFTWIbVNguAvbgoTB10FfJOUU5VA=="], + + "@tsparticles/updater-life": ["@tsparticles/updater-life@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-Oi8aF2RIwMMsjssUkCB6t3PRpENHjdZf6cX92WNfAuqXtQphr3OMAkYFJFWkvyPFK22AVy3p/cFt6KE5zXxwAA=="], + + "@tsparticles/updater-opacity": ["@tsparticles/updater-opacity@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-w778LQuRZJ+IoWzeRdrGykPYSSaTeWfBvLZ2XwYEkh/Ss961InOxZKIpcS6i5Kp/Zfw0fS1ZAuqeHwuj///Osw=="], + + "@tsparticles/updater-out-modes": ["@tsparticles/updater-out-modes@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-cKQEkAwbru+hhKF+GTsfbOvuBbx2DSB25CxOdhtW2wRvDBoCnngNdLw91rs+0Cex4tgEeibkebrIKFDDE6kELg=="], + + "@tsparticles/updater-roll": ["@tsparticles/updater-roll@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-zl4JeM3gUBJ0uttmIsond3lrZ3f3AkItFeS0Lhj/7jiCKfUoRyyOMrcBk8R1AhW7lI+7ko1iBs3jhO0jnxz9vg=="], + + "@tsparticles/updater-rotate": ["@tsparticles/updater-rotate@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-9BfKaGfp28JN82MF2qs6Ae/lJr9EColMfMTHqSKljblwbpVDHte4umuwKl3VjbRt87WD9MGtla66NTUYl+WxuQ=="], + + "@tsparticles/updater-size": ["@tsparticles/updater-size@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-3NSVs0O2ApNKZXfd+y/zNhTXSFeG1Pw4peI8e6z/q5+XLbmue9oiEwoPy/tQLaark3oNj3JU7Q903ZijPyXSzw=="], + + "@tsparticles/updater-stroke-color": ["@tsparticles/updater-stroke-color@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-3x14+C2is9pZYTg9T2TiA/aM1YMq4wLdYaZDcHm3qO30DZu5oeQq0rm/6w+QOGKYY1Z3Htg9rlSUZkhTHn7eDA=="], + + "@tsparticles/updater-tilt": ["@tsparticles/updater-tilt@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-PB2yaoyXRmSk4iIVgjtRrzOxXMK9mjeAQHIJGtT4faq46Z8cbIIEFgjTwqrUV8qOrNg/h4sm5NE/s0qsTYjp1Q=="], + + "@tsparticles/updater-twinkle": ["@tsparticles/updater-twinkle@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-xgTcYr6LmP44IPIBeQmEExN2Y5Nfl3ikmC08eOh5nZy/ta6ORP+JTsprrnfuv/O2DwTyoqFLkZ16hZfkdc1yOQ=="], + + "@tsparticles/updater-wobble": ["@tsparticles/updater-wobble@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1" } }, "sha512-c99Ogy9q4QWO+zsDXol0UnpUwZiY2UucFb8ltuDv9AlbGUeprygoub8jhgT5pEDv+GdzWOJGSgq7rfgv9cHBrg=="], + + "@types/babel__core": ["@types/babel__core@7.20.5", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0", "@types/babel__generator": "7.27.0", "@types/babel__template": "7.4.4", "@types/babel__traverse": "7.28.0" } }, "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA=="], + + "@types/babel__generator": ["@types/babel__generator@7.27.0", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg=="], + + "@types/babel__template": ["@types/babel__template@7.4.4", "", { "dependencies": { "@babel/parser": "7.29.0", "@babel/types": "7.29.0" } }, "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A=="], + + "@types/babel__traverse": ["@types/babel__traverse@7.28.0", "", { "dependencies": { "@babel/types": "7.29.0" } }, "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q=="], + + "@types/bun": ["@types/bun@1.3.14", "", { "dependencies": { "bun-types": "1.3.14" } }, "sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw=="], + + "@types/cacheable-request": ["@types/cacheable-request@6.0.3", "", { "dependencies": { "@types/http-cache-semantics": "*", "@types/keyv": "^3.1.4", "@types/node": "*", "@types/responselike": "^1.0.0" } }, "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw=="], + + "@types/d3-array": ["@types/d3-array@3.2.2", "", {}, "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw=="], + + "@types/d3-color": ["@types/d3-color@3.1.3", "", {}, "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A=="], + + "@types/d3-ease": ["@types/d3-ease@3.0.2", "", {}, "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA=="], + + "@types/d3-interpolate": ["@types/d3-interpolate@3.0.4", "", { "dependencies": { "@types/d3-color": "3.1.3" } }, "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA=="], + + "@types/d3-path": ["@types/d3-path@3.1.1", "", {}, "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg=="], + + "@types/d3-scale": ["@types/d3-scale@4.0.9", "", { "dependencies": { "@types/d3-time": "3.0.4" } }, "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw=="], + + "@types/d3-shape": ["@types/d3-shape@3.1.8", "", { "dependencies": { "@types/d3-path": "3.1.1" } }, "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w=="], + + "@types/d3-time": ["@types/d3-time@3.0.4", "", {}, "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g=="], + + "@types/d3-timer": ["@types/d3-timer@3.0.2", "", {}, "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw=="], + + "@types/debug": ["@types/debug@4.1.12", "", { "dependencies": { "@types/ms": "2.1.0" } }, "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ=="], + + "@types/eslint": ["@types/eslint@9.6.1", "", { "dependencies": { "@types/estree": "1.0.9", "@types/json-schema": "7.0.15" } }, "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag=="], + + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], + + "@types/estree-jsx": ["@types/estree-jsx@1.0.5", "", { "dependencies": { "@types/estree": "1.0.8" } }, "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg=="], + + "@types/fs-extra": ["@types/fs-extra@9.0.13", "", { "dependencies": { "@types/node": "*" } }, "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA=="], + + "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], + + "@types/http-cache-semantics": ["@types/http-cache-semantics@4.2.0", "", {}, "sha512-L3LgimLHXtGkWikKnsPg0/VFx9OGZaC+eN1u4r+OB1XRqH3meBIAVC2zr1WdMH+RHmnRkqliQAOHNJ/E0j/e0Q=="], + + "@types/json-schema": ["@types/json-schema@7.0.15", "", {}, "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA=="], + + "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], + + "@types/keyv": ["@types/keyv@3.1.4", "", { "dependencies": { "@types/node": "*" } }, "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg=="], + + "@types/linkify-it": ["@types/linkify-it@5.0.0", "", {}, "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q=="], + + "@types/markdown-it": ["@types/markdown-it@14.1.2", "", { "dependencies": { "@types/linkify-it": "5.0.0", "@types/mdurl": "2.0.0" } }, "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog=="], + + "@types/mdast": ["@types/mdast@4.0.4", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA=="], + + "@types/mdurl": ["@types/mdurl@2.0.0", "", {}, "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg=="], + + "@types/ms": ["@types/ms@2.1.0", "", {}, "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA=="], + + "@types/node": ["@types/node@22.20.1", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-EANqOCF9QFyra+4pfxUcX9STKJpCLjMbObVzljIJomAWSnuSIEAvyzEU53GaajbXJEgdh0iEcPL+DGvpUd4k1Q=="], + + "@types/parse-json": ["@types/parse-json@4.0.2", "", {}, "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw=="], + + "@types/react": ["@types/react@19.2.10", "", { "dependencies": { "csstype": "3.2.3" } }, "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw=="], + + "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "19.2.10" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], + + "@types/responselike": ["@types/responselike@1.0.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw=="], + + "@types/stylis": ["@types/stylis@4.2.7", "", {}, "sha512-VgDNokpBoKF+wrdvhAAfS55OMQpL6QRglwTwNC3kIgBrzZxA4WsFj+2eLfEA/uMUDzBcEhYmjSbwQakn/i3ajA=="], + + "@types/unist": ["@types/unist@3.0.3", "", {}, "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q=="], + + "@types/use-sync-external-store": ["@types/use-sync-external-store@0.0.6", "", {}, "sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg=="], + + "@types/yauzl": ["@types/yauzl@2.10.3", "", { "dependencies": { "@types/node": "*" } }, "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q=="], + + "@typescript-eslint/parser": ["@typescript-eslint/parser@6.21.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", "@typescript-eslint/typescript-estree": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "4.4.3" }, "optionalDependencies": { "typescript": "5.9.3" }, "peerDependencies": { "eslint": "8.57.1" } }, "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ=="], + + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0" } }, "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg=="], + + "@typescript-eslint/types": ["@typescript-eslint/types@6.21.0", "", {}, "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg=="], + + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "@typescript-eslint/visitor-keys": "6.21.0", "debug": "4.4.3", "globby": "11.1.0", "is-glob": "4.0.3", "minimatch": "9.0.3", "semver": "7.7.3", "ts-api-utils": "1.4.3" }, "optionalDependencies": { "typescript": "5.9.3" } }, "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ=="], + + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@6.21.0", "", { "dependencies": { "@typescript-eslint/types": "6.21.0", "eslint-visitor-keys": "3.4.3" } }, "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A=="], + + "@uiw/codemirror-extensions-basic-setup": ["@uiw/codemirror-extensions-basic-setup@4.25.4", "", { "peerDependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/commands": "6.10.4", "@codemirror/language": "6.12.1", "@codemirror/lint": "6.9.3", "@codemirror/search": "6.6.0", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12" } }, "sha512-YzNwkm0AbPv1EXhCHYR5v0nqfemG2jEB0Z3Att4rBYqKrlG7AA9Rhjc3IyBaOzsBu18wtrp9/+uhTyu7TXSRng=="], + + "@uiw/react-codemirror": ["@uiw/react-codemirror@4.25.4", "", { "dependencies": { "@codemirror/commands": "6.10.4", "@uiw/codemirror-extensions-basic-setup": "4.25.4" }, "peerDependencies": { "@babel/runtime": "7.28.6", "@codemirror/state": "6.7.1", "@codemirror/theme-one-dark": "6.1.3", "@codemirror/view": "6.39.12", "codemirror": "6.0.2", "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ipO067oyfUw+DVaXhQCxkB0ZD9b7RnY+ByrprSYSKCHaULvJ3sqWYC/Zen6zVQ8/XC4o5EPBfatGiX20kC7XGA=="], + + "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], + + "@vitejs/plugin-react": ["@vitejs/plugin-react@5.1.2", "", { "dependencies": { "@babel/core": "7.29.0", "@babel/plugin-transform-react-jsx-self": "7.27.1", "@babel/plugin-transform-react-jsx-source": "7.27.1", "@rolldown/pluginutils": "1.0.0-beta.53", "@types/babel__core": "7.20.5", "react-refresh": "0.18.0" }, "peerDependencies": { "vite": "7.3.1" } }, "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ=="], + + "@vscode/sudo-prompt": ["@vscode/sudo-prompt@9.3.2", "", {}, "sha512-gcXoCN00METUNFeQOFJ+C9xUI0DKB+0EGMVg7wbVYRHBw2Eq3fKisDZOkRdOz3kqXRKOENMfShPOmypw1/8nOw=="], + + "@xmldom/xmldom": ["@xmldom/xmldom@0.8.13", "", {}, "sha512-KRYzxepc14G/CEpEGc3Yn+JKaAeT63smlDr+vjB8jRfgTBBI9wRj/nkQEO+ucV8p8I9bfKLWp37uHgFrbntPvw=="], + + "@zeit/schemas": ["@zeit/schemas@2.36.0", "", {}, "sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg=="], + + "abbrev": ["abbrev@4.0.0", "", {}, "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA=="], + + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "3.0.2", "negotiator": "1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="], + + "acorn-jsx": ["acorn-jsx@5.3.2", "", { "peerDependencies": { "acorn": "8.15.0" } }, "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="], + + "acorn-walk": ["acorn-walk@8.3.2", "", {}, "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A=="], + + "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-json-stable-stringify": "2.1.0", "json-schema-traverse": "0.4.1", "uri-js": "4.4.1" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="], + + "ansi-align": ["ansi-align@3.0.1", "", { "dependencies": { "string-width": "4.2.3" } }, "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w=="], + + "ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + + "ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + + "antd": ["antd@5.29.3", "", { "dependencies": { "@ant-design/colors": "7.2.1", "@ant-design/cssinjs": "1.24.0", "@ant-design/cssinjs-utils": "1.1.3", "@ant-design/fast-color": "2.0.6", "@ant-design/icons": "5.6.1", "@ant-design/react-slick": "1.1.2", "@babel/runtime": "7.28.6", "@rc-component/color-picker": "2.0.1", "@rc-component/mutate-observer": "1.1.0", "@rc-component/qrcode": "1.1.1", "@rc-component/tour": "1.15.1", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "copy-to-clipboard": "3.3.3", "dayjs": "1.11.19", "rc-cascader": "3.34.0", "rc-checkbox": "3.5.0", "rc-collapse": "3.9.0", "rc-dialog": "9.6.0", "rc-drawer": "7.3.0", "rc-dropdown": "4.2.1", "rc-field-form": "2.7.1", "rc-image": "7.12.0", "rc-input": "1.8.0", "rc-input-number": "9.5.0", "rc-mentions": "2.20.0", "rc-menu": "9.16.1", "rc-motion": "2.9.5", "rc-notification": "5.6.4", "rc-pagination": "5.1.0", "rc-picker": "4.11.3", "rc-progress": "4.0.0", "rc-rate": "2.13.1", "rc-resize-observer": "1.4.3", "rc-segmented": "2.7.1", "rc-select": "14.16.8", "rc-slider": "11.1.9", "rc-steps": "6.0.1", "rc-switch": "4.1.0", "rc-table": "7.54.0", "rc-tabs": "15.7.0", "rc-textarea": "1.10.2", "rc-tooltip": "6.4.0", "rc-tree": "5.13.1", "rc-tree-select": "5.27.0", "rc-upload": "4.11.0", "rc-util": "5.44.4", "scroll-into-view-if-needed": "3.1.0", "throttle-debounce": "5.0.2" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-3DdbGCa9tWAJGcCJ6rzR8EJFsv2CtyEbkVabZE14pfgUHfCicWCj0/QzQVLDYg8CPfQk9BH7fHCoTXHTy7MP/A=="], + + "antd-style": ["antd-style@3.7.1", "", { "dependencies": { "@ant-design/cssinjs": "1.24.0", "@babel/runtime": "7.28.6", "@emotion/cache": "11.14.0", "@emotion/css": "11.13.5", "@emotion/react": "11.14.0", "@emotion/serialize": "1.3.3", "@emotion/utils": "1.4.2", "use-merge-value": "1.2.0" }, "peerDependencies": { "antd": "5.29.3", "react": "19.2.4" } }, "sha512-CQOfddVp4aOvBfCepa+Kj2e7ap+2XBINg1Kn2osdE3oQvrD7KJu/K0sfnLcFLkgCJygbxmuazYdWLKb+drPDYA=="], + + "any-base": ["any-base@1.1.0", "", {}, "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="], + + "app-builder-lib": ["app-builder-lib@26.15.3", "", { "dependencies": { "@electron/asar": "3.4.1", "@electron/fuses": "^1.8.0", "@electron/get": "^3.0.0", "@electron/notarize": "2.5.0", "@electron/osx-sign": "1.3.3", "@electron/rebuild": "^4.0.4", "@electron/universal": "2.0.3", "@malept/flatpak-bundler": "^0.4.0", "@noble/hashes": "^2.2.0", "@peculiar/webcrypto": "^1.7.1", "@types/fs-extra": "9.0.13", "ajv": "^8.18.0", "asn1js": "^3.0.10", "async-exit-hook": "^2.0.1", "builder-util": "26.15.3", "builder-util-runtime": "9.7.0", "chromium-pickle-js": "^0.2.0", "ci-info": "4.3.1", "debug": "^4.3.4", "dotenv": "^16.4.5", "dotenv-expand": "^11.0.6", "ejs": "^3.1.8", "electron-publish": "26.15.3", "fs-extra": "^10.1.0", "hosted-git-info": "^4.1.0", "isbinaryfile": "^5.0.0", "jiti": "^2.4.2", "js-yaml": "^4.1.0", "json5": "^2.2.3", "lazy-val": "^1.0.5", "minimatch": "^10.2.5", "pkijs": "^3.4.0", "plist": "3.1.0", "proper-lockfile": "^4.1.2", "resedit": "^1.7.0", "semver": "~7.7.3", "tar": "^7.5.7", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0", "unzipper": "^0.12.3", "which": "^5.0.0" }, "peerDependencies": { "dmg-builder": "26.15.3", "electron-builder-squirrel-windows": "26.15.3" } }, "sha512-2VnyWkqsP5v5XbBhL3tD5Syx8iNPBYsoU7kY4S2fz7wg8Rj/nztWKCUzGKaFRTv0Xwf3/H058CR1Kvtd/3lRow=="], + + "arch": ["arch@2.2.0", "", {}, "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ=="], + + "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], + + "argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], + + "array-buffer-byte-length": ["array-buffer-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "is-array-buffer": "3.0.5" } }, "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw=="], + + "array-includes": ["array-includes@3.1.9", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "is-string": "1.1.1", "math-intrinsics": "1.1.0" } }, "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ=="], + + "array-union": ["array-union@2.1.0", "", {}, "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="], + + "array.prototype.findlast": ["array.prototype.findlast@1.2.5", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "es-shim-unscopables": "1.1.0" } }, "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ=="], + + "array.prototype.findlastindex": ["array.prototype.findlastindex@1.2.6", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "es-shim-unscopables": "1.1.0" } }, "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ=="], + + "array.prototype.flat": ["array.prototype.flat@1.3.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-shim-unscopables": "1.1.0" } }, "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg=="], + + "array.prototype.flatmap": ["array.prototype.flatmap@1.3.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-shim-unscopables": "1.1.0" } }, "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg=="], + + "array.prototype.tosorted": ["array.prototype.tosorted@1.1.4", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-shim-unscopables": "1.1.0" } }, "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA=="], + + "arraybuffer.prototype.slice": ["arraybuffer.prototype.slice@1.0.4", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "is-array-buffer": "3.0.5" } }, "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ=="], + + "as-table": ["as-table@1.0.55", "", { "dependencies": { "printable-characters": "1.0.42" } }, "sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ=="], + + "asn1js": ["asn1js@3.0.10", "", { "dependencies": { "pvtsutils": "^1.3.6", "pvutils": "^1.1.5", "tslib": "^2.8.1" } }, "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg=="], + + "ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "^2.0.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="], + + "async": ["async@3.2.6", "", {}, "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA=="], + + "async-exit-hook": ["async-exit-hook@2.0.1", "", {}, "sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw=="], + + "async-function": ["async-function@1.0.0", "", {}, "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA=="], + + "asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="], + + "at-least-node": ["at-least-node@1.0.0", "", {}, "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="], + + "atomically": ["atomically@2.1.1", "", { "dependencies": { "stubborn-fs": "^2.0.0", "when-exit": "^2.1.4" } }, "sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ=="], + + "author-regex": ["author-regex@1.0.0", "", {}, "sha512-KbWgR8wOYRAPekEmMXrYYdc7BRyhn2Ftk7KWfMUnQ43hFdojWEFRxhhRUm3/OFEdPa1r0KAvTTg9YQK57xTe0g=="], + + "available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "1.1.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="], + + "await-to-js": ["await-to-js@3.0.0", "", {}, "sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g=="], + + "aws4": ["aws4@1.13.2", "", {}, "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw=="], + + "axios": ["axios@1.13.4", "", { "dependencies": { "follow-redirects": "1.15.11", "form-data": "4.0.5", "proxy-from-env": "1.1.0" } }, "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg=="], + + "babel-plugin-macros": ["babel-plugin-macros@3.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "cosmiconfig": "7.1.0", "resolve": "1.22.11" } }, "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg=="], + + "bail": ["bail@2.0.2", "", {}, "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw=="], + + "balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="], + + "base64-js": ["base64-js@1.5.1", "", {}, "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="], + + "baseline-browser-mapping": ["baseline-browser-mapping@2.11.4", "", { "bin": { "baseline-browser-mapping": "dist/cli.cjs" } }, "sha512-s4+sLr9mZ/CyqeRritFeYV/Zx73OAtmaHn6kkBS1XRoJn1hrg3xIDUcpicAEX68tkcIN0iBCgti31C8zxtkhsQ=="], + + "basic-ftp": ["basic-ftp@5.3.1", "", {}, "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw=="], + + "blake3-wasm": ["blake3-wasm@2.1.5", "", {}, "sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g=="], + + "bluebird": ["bluebird@3.7.2", "", {}, "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="], + + "blurhash": ["blurhash@2.0.5", "", {}, "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w=="], + + "bmp-ts": ["bmp-ts@1.0.9", "", {}, "sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw=="], + + "body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "3.1.2", "content-type": "1.0.5", "debug": "4.4.3", "http-errors": "2.0.1", "iconv-lite": "0.7.2", "on-finished": "2.4.1", "qs": "6.14.1", "raw-body": "3.0.2", "type-is": "2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="], + + "boolbase": ["boolbase@1.0.0", "", {}, "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww=="], + + "boolean": ["boolean@3.2.0", "", {}, "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw=="], + + "boxen": ["boxen@7.0.0", "", { "dependencies": { "ansi-align": "3.0.1", "camelcase": "7.0.1", "chalk": "5.0.1", "cli-boxes": "3.0.0", "string-width": "5.1.2", "type-fest": "2.19.0", "widest-line": "4.0.1", "wrap-ansi": "8.1.0" } }, "sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg=="], + + "brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "1.0.2", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="], + + "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], + + "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "2.11.4", "caniuse-lite": "1.0.30001806", "electron-to-chromium": "1.5.283", "node-releases": "2.0.27", "update-browserslist-db": "1.2.3" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], + + "buffer-crc32": ["buffer-crc32@0.2.13", "", {}, "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ=="], + + "buffer-equal": ["buffer-equal@1.0.1", "", {}, "sha512-QoV3ptgEaQpvVwbXdSO39iqPQTCxSF7A5U99AxbHYqUdCizL/lH2Z0A2y6nbZucxMEOtNyZfG2s6gsVugGpKkg=="], + + "buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="], + + "builder-util": ["builder-util@26.15.3", "", { "dependencies": { "@types/debug": "^4.1.6", "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", "cross-spawn": "^7.0.6", "debug": "^4.3.4", "fs-extra": "^10.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.0", "js-yaml": "^4.1.0", "sanitize-filename": "^1.6.3", "source-map-support": "^0.5.19", "stat-mode": "^1.0.0", "temp-file": "^3.4.0", "tiny-async-pool": "1.3.0" } }, "sha512-q2hn7Mbo2nFNkVekPiHFx6Nfo3hURmES3tfBn+k5Pqxl2RkmP3QGqZUhH/q9Pch/4G05NRhPjDlVj1O8q4Txvw=="], + + "builder-util-runtime": ["builder-util-runtime@9.7.0", "", { "dependencies": { "debug": "^4.3.4", "sax": "^1.2.4" } }, "sha512-g/kR520giAFYkSXTzcmF3kqQq7wi8F6N6SzeDgZrqTBN+VHdmgWOyTdD1yD7AATDId/yXLvuP34CxW46/BwCdw=="], + + "builtins": ["builtins@5.1.0", "", { "dependencies": { "semver": "7.7.3" } }, "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg=="], + + "bun-types": ["bun-types@1.3.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "bytestreamjs": ["bytestreamjs@2.0.1", "", {}, "sha512-U1Z/ob71V/bXfVABvNr/Kumf5VyeQRBEm6Txb0PQ6S7V5GpBM3w4Cbqz/xPDicR5tN0uvDifng8C+5qECeGwyQ=="], + + "cacheable-lookup": ["cacheable-lookup@5.0.4", "", {}, "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA=="], + + "cacheable-request": ["cacheable-request@7.0.4", "", { "dependencies": { "clone-response": "^1.0.2", "get-stream": "^5.1.0", "http-cache-semantics": "^4.0.0", "keyv": "^4.0.0", "lowercase-keys": "^2.0.0", "normalize-url": "^6.0.1", "responselike": "^2.0.0" } }, "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg=="], + + "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "get-intrinsic": "1.3.0", "set-function-length": "1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "1.3.0", "function-bind": "1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "get-intrinsic": "1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], + + "camelcase": ["camelcase@7.0.1", "", {}, "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw=="], + + "camelize": ["camelize@1.0.1", "", {}, "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ=="], + + "caniuse-lite": ["caniuse-lite@1.0.30001806", "", {}, "sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw=="], + + "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], + + "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "4.3.0", "supports-color": "7.2.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], + + "chalk-template": ["chalk-template@0.4.0", "", { "dependencies": { "chalk": "4.1.2" } }, "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg=="], + + "character-entities": ["character-entities@2.0.2", "", {}, "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ=="], + + "character-entities-html4": ["character-entities-html4@2.1.0", "", {}, "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA=="], + + "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], + + "character-reference-invalid": ["character-reference-invalid@2.0.1", "", {}, "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw=="], + + "chownr": ["chownr@3.0.0", "", {}, "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g=="], + + "chromium-pickle-js": ["chromium-pickle-js@0.2.0", "", {}, "sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw=="], + + "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + + "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], + + "cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="], + + "clipboardy": ["clipboardy@3.0.0", "", { "dependencies": { "arch": "2.2.0", "execa": "5.1.1", "is-wsl": "2.2.0" } }, "sha512-Su+uU5sr1jkUy1sGRpLKjKrvEOVXgSgiSInwa/qeID6aJ07yh+5NWc3h2QfjHjBnfX4LhtFcuAWKUsJ3r+fjbg=="], + + "cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "4.2.3", "strip-ansi": "6.0.1", "wrap-ansi": "7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="], + + "clone-response": ["clone-response@1.0.3", "", { "dependencies": { "mimic-response": "^1.0.0" } }, "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA=="], + + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], + + "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "6.20.0", "@codemirror/commands": "6.10.4", "@codemirror/language": "6.12.1", "@codemirror/lint": "6.9.3", "@codemirror/search": "6.6.0", "@codemirror/state": "6.7.1", "@codemirror/view": "6.39.12" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], + + "color": ["color@4.2.3", "", { "dependencies": { "color-convert": "2.0.1", "color-string": "1.9.1" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="], + + "color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], + + "color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "1.1.4", "simple-swizzle": "0.2.4" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="], + + "combined-stream": ["combined-stream@1.0.8", "", { "dependencies": { "delayed-stream": "1.0.0" } }, "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="], + + "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], + + "commander": ["commander@11.1.0", "", {}, "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ=="], + + "common-tags": ["common-tags@1.8.2", "", {}, "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="], + + "compare-version": ["compare-version@0.1.2", "", {}, "sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A=="], + + "compressible": ["compressible@2.0.18", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="], + + "compression": ["compression@1.8.1", "", { "dependencies": { "bytes": "3.1.2", "compressible": "2.0.18", "debug": "2.6.9", "negotiator": "0.6.4", "on-headers": "1.1.0", "safe-buffer": "5.2.1", "vary": "1.1.2" } }, "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w=="], + + "compute-scroll-into-view": ["compute-scroll-into-view@3.1.1", "", {}, "sha512-VRhuHOLoKYOy4UbilLbUzbYg93XLjv2PncJC50EuTWPA3gaja1UjBsUP/D/9/juV3vQFr6XBEzn9KCAHdUvOHw=="], + + "concat-map": ["concat-map@0.0.1", "", {}, "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="], + + "concurrently": ["concurrently@9.2.1", "", { "dependencies": { "chalk": "4.1.2", "rxjs": "7.8.2", "shell-quote": "1.8.3", "supports-color": "8.1.1", "tree-kill": "1.2.2", "yargs": "17.7.2" }, "bin": { "conc": "dist/bin/concurrently.js", "concurrently": "dist/bin/concurrently.js" } }, "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng=="], + + "conf": ["conf@15.1.0", "", { "dependencies": { "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "atomically": "^2.0.3", "debounce-fn": "^6.0.0", "dot-prop": "^10.0.0", "env-paths": "^3.0.0", "json-schema-typed": "^8.0.1", "semver": "^7.7.2", "uint8array-extras": "^1.5.0" } }, "sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og=="], + + "content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "copy-to-clipboard": ["copy-to-clipboard@3.3.3", "", { "dependencies": { "toggle-selection": "1.0.6" } }, "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA=="], + + "core-js": ["core-js@3.32.2", "", {}, "sha512-pxXSw1mYZPDGvTQqEc5vgIb83jGQKFGYWY76z4a7weZXUolw3G+OvpZqSRcfYOoOVUQJYEPsWeQK8pKEnUtWxQ=="], + + "core-util-is": ["core-util-is@1.0.3", "", {}, "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="], + + "cosmiconfig": ["cosmiconfig@8.3.6", "", { "dependencies": { "import-fresh": "3.3.1", "js-yaml": "4.1.1", "parse-json": "5.2.0", "path-type": "4.0.0" }, "optionalDependencies": { "typescript": "5.9.3" } }, "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA=="], + + "country-list": ["country-list@2.4.1", "", {}, "sha512-KhVV/UfUV3dSNpsWIqHTQxLpYDKPKz1UwkRjadt+YbX2PRhyCEihEoS5XgB7J7AMXpkicvl+tRHvkNI5wbji/g=="], + + "crelt": ["crelt@1.0.7", "", {}, "sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA=="], + + "cross-dirname": ["cross-dirname@0.1.0", "", {}, "sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q=="], + + "cross-env": ["cross-env@10.1.0", "", { "dependencies": { "@epic-web/invariant": "1.0.0", "cross-spawn": "7.0.6" }, "bin": { "cross-env": "dist/bin/cross-env.js", "cross-env-shell": "dist/bin/cross-env-shell.js" } }, "sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "cross-spawn-windows-exe": ["cross-spawn-windows-exe@1.2.0", "", { "dependencies": { "@malept/cross-spawn-promise": "1.1.1", "is-wsl": "2.2.0", "which": "2.0.2" } }, "sha512-mkLtJJcYbDCxEG7Js6eUnUNndWjyUZwJ3H7bErmmtOYU/Zb99DyUkpamuIZE0b3bhmJyZ7D90uS6f+CGxRRjOw=="], + + "css-color-keywords": ["css-color-keywords@1.0.0", "", {}, "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg=="], + + "css-mediaquery": ["css-mediaquery@0.1.2", "", {}, "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q=="], + + "css-select": ["css-select@5.2.2", "", { "dependencies": { "boolbase": "1.0.0", "css-what": "6.2.2", "domhandler": "5.0.3", "domutils": "3.2.2", "nth-check": "2.1.1" } }, "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw=="], + + "css-to-react-native": ["css-to-react-native@3.2.0", "", { "dependencies": { "camelize": "1.0.1", "css-color-keywords": "1.0.0", "postcss-value-parser": "4.2.0" } }, "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ=="], + + "css-tree": ["css-tree@3.1.0", "", { "dependencies": { "mdn-data": "2.12.2", "source-map-js": "1.2.1" } }, "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w=="], + + "css-what": ["css-what@6.2.2", "", {}, "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA=="], + + "csso": ["csso@5.0.5", "", { "dependencies": { "css-tree": "2.2.1" } }, "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ=="], + + "csstype": ["csstype@3.2.3", "", {}, "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="], + + "d3-array": ["d3-array@3.2.4", "", { "dependencies": { "internmap": "2.0.3" } }, "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg=="], + + "d3-color": ["d3-color@3.1.0", "", {}, "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA=="], + + "d3-ease": ["d3-ease@3.0.1", "", {}, "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w=="], + + "d3-format": ["d3-format@3.1.2", "", {}, "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg=="], + + "d3-interpolate": ["d3-interpolate@3.0.1", "", { "dependencies": { "d3-color": "3.1.0" } }, "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g=="], + + "d3-path": ["d3-path@3.1.0", "", {}, "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ=="], + + "d3-scale": ["d3-scale@4.0.2", "", { "dependencies": { "d3-array": "3.2.4", "d3-format": "3.1.2", "d3-interpolate": "3.0.1", "d3-time": "3.1.0", "d3-time-format": "4.1.0" } }, "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ=="], + + "d3-shape": ["d3-shape@3.2.0", "", { "dependencies": { "d3-path": "3.1.0" } }, "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA=="], + + "d3-time": ["d3-time@3.1.0", "", { "dependencies": { "d3-array": "3.2.4" } }, "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q=="], + + "d3-time-format": ["d3-time-format@4.1.0", "", { "dependencies": { "d3-time": "3.1.0" } }, "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg=="], + + "d3-timer": ["d3-timer@3.0.1", "", {}, "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA=="], + + "data-uri-to-buffer": ["data-uri-to-buffer@6.0.2", "", {}, "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw=="], + + "data-view-buffer": ["data-view-buffer@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ=="], + + "data-view-byte-length": ["data-view-byte-length@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ=="], + + "data-view-byte-offset": ["data-view-byte-offset@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-data-view": "1.0.2" } }, "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ=="], + + "dayjs": ["dayjs@1.11.19", "", {}, "sha512-t5EcLVS6QPBNqM2z8fakk/NKel+Xzshgt8FFKAn+qwlD1pzZWxh0nVCrvFK7ZDb6XucZeF9z8C7CBWTRIVApAw=="], + + "debounce-fn": ["debounce-fn@6.0.0", "", { "dependencies": { "mimic-function": "^5.0.0" } }, "sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ=="], + + "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "decimal.js-light": ["decimal.js-light@2.5.1", "", {}, "sha512-qIMFpTMZmny+MMIitAB6D7iVPEorVw6YQRWkvarTkT4tBeSLLiHzcwj6q0MmYSFCiVpiqPJTJEYIrpcPzVEIvg=="], + + "decode-named-character-reference": ["decode-named-character-reference@1.3.0", "", { "dependencies": { "character-entities": "2.0.2" } }, "sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q=="], + + "decompress-response": ["decompress-response@6.0.0", "", { "dependencies": { "mimic-response": "^3.1.0" } }, "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="], + + "deep-extend": ["deep-extend@0.6.0", "", {}, "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="], + + "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], + + "defer-to-connect": ["defer-to-connect@2.0.1", "", {}, "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg=="], + + "define-data-property": ["define-data-property@1.1.4", "", { "dependencies": { "es-define-property": "1.0.1", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A=="], + + "define-lazy-prop": ["define-lazy-prop@2.0.0", "", {}, "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="], + + "define-properties": ["define-properties@1.2.1", "", { "dependencies": { "define-data-property": "1.1.4", "has-property-descriptors": "1.0.2", "object-keys": "1.1.1" } }, "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg=="], + + "defu": ["defu@6.1.4", "", {}, "sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg=="], + + "degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", "esprima": "^4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="], + + "delayed-stream": ["delayed-stream@1.0.0", "", {}, "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], + + "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], + + "detect-node": ["detect-node@2.1.0", "", {}, "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="], + + "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "2.0.3" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], + + "dir-compare": ["dir-compare@3.3.0", "", { "dependencies": { "buffer-equal": "^1.0.0", "minimatch": "^3.0.4" } }, "sha512-J7/et3WlGUCxjdnD3HAAzQ6nsnc0WL6DD7WcwJb7c39iH1+AWfg+9OqzJNaI6PkBwBvm1mhZNL9iY/nRiZXlPg=="], + + "dir-glob": ["dir-glob@3.0.1", "", { "dependencies": { "path-type": "4.0.0" } }, "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="], + + "dlv": ["dlv@1.1.3", "", {}, "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="], + + "dmg-builder": ["dmg-builder@26.15.3", "", { "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", "fs-extra": "^10.1.0", "js-yaml": "^4.1.0" } }, "sha512-O3zJUFUYHJKgzPqioHxfxzBzlSC1eXCSr79gMSBKBP5AgjjpmrydMsMLotEg9fAJF36vdUncb+4ndRNxoPdlSQ=="], + + "doctrine": ["doctrine@2.1.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="], + + "dom-serializer": ["dom-serializer@2.0.0", "", { "dependencies": { "domelementtype": "2.3.0", "domhandler": "5.0.3", "entities": "4.5.0" } }, "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg=="], + + "domelementtype": ["domelementtype@2.3.0", "", {}, "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw=="], + + "domhandler": ["domhandler@5.0.3", "", { "dependencies": { "domelementtype": "2.3.0" } }, "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w=="], + + "domutils": ["domutils@3.2.2", "", { "dependencies": { "dom-serializer": "2.0.0", "domelementtype": "2.3.0", "domhandler": "5.0.3" } }, "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw=="], + + "dot-case": ["dot-case@3.0.4", "", { "dependencies": { "no-case": "3.0.4", "tslib": "2.8.1" } }, "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="], + + "dot-prop": ["dot-prop@10.2.0", "", { "dependencies": { "type-fest": "^5.0.0" } }, "sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw=="], + + "dotenv": ["dotenv@17.2.3", "", {}, "sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w=="], + + "dotenv-expand": ["dotenv-expand@11.0.7", "", { "dependencies": { "dotenv": "^16.4.5" } }, "sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-errors": "1.3.0", "gopd": "1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "duplexer2": ["duplexer2@0.1.4", "", { "dependencies": { "readable-stream": "^2.0.2" } }, "sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA=="], + + "eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "ejs": ["ejs@3.1.10", "", { "dependencies": { "jake": "^10.8.5" }, "bin": { "ejs": "bin/cli.js" } }, "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA=="], + + "electrobun": ["electrobun@1.18.1", "", { "dependencies": { "@babylonjs/core": "^7.45.0", "@types/bun": "^1.3.8", "png-to-ico": "^2.1.8", "proxy-agent": "^6.5.0", "rcedit": "^4.0.1", "three": "^0.165.0" }, "bin": { "electrobun": "bin/electrobun.cjs" } }, "sha512-tgZ+WKGskn/1/Y5i1mpVCCkgRa1O31Tz7MIArBTK44GfPzT43uOq9c/HvxdQGrLeZV8ZvjK1lQrwqSXCgh6tvA=="], + + "electron": ["electron@38.8.6", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^22.7.7", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-lyBhcVi9QYAZL6FO6r5twAWAjWnYomo3iVDvrb5SJZlq928BGemHOKG0tPIq41NOLaCu9f3XdEEjMkjQPjprRg=="], + + "electron-builder": ["electron-builder@26.15.3", "", { "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", "ci-info": "^4.2.0", "dmg-builder": "26.15.3", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "simple-update-notifier": "2.0.0", "yargs": "^17.6.2" }, "bin": { "electron-builder": "./cli.js", "install-app-deps": "./install-app-deps.js" } }, "sha512-a1KM5heqS3gQCZzizXEI8RjJy3QVogULPdeSknt76uLDpBIW/HDGsMg/XgP0riP6PI9COsRvFITKKGDqA8fJxA=="], + + "electron-builder-squirrel-windows": ["electron-builder-squirrel-windows@26.15.3", "", { "dependencies": { "app-builder-lib": "26.15.3", "builder-util": "26.15.3", "electron-winstaller": "5.4.0" } }, "sha512-Jc19XPV9y9+2bAdZPkXuVNGNIEFBq9poHC61l8Kv6FdK7DRG3+Ic0rerC0DXOaeHNz8yW0fg/JnF8GQROOF5MA=="], + + "electron-packager": ["electron-packager@17.1.2", "", { "dependencies": { "@electron/asar": "^3.2.1", "@electron/get": "^2.0.0", "@electron/notarize": "^1.2.3", "@electron/osx-sign": "^1.0.5", "@electron/universal": "^1.3.2", "cross-spawn-windows-exe": "^1.2.0", "debug": "^4.0.1", "extract-zip": "^2.0.0", "filenamify": "^4.1.0", "fs-extra": "^11.1.0", "galactus": "^1.0.0", "get-package-info": "^1.0.0", "junk": "^3.1.0", "parse-author": "^2.0.0", "plist": "^3.0.0", "rcedit": "^3.0.1", "resolve": "^1.1.6", "semver": "^7.1.3", "yargs-parser": "^21.1.1" }, "bin": { "electron-packager": "bin/electron-packager.js" } }, "sha512-XofXdikjYI7MVBcnXeoOvRR+yFFFHOLs3J7PF5KYQweigtgLshcH4W660PsvHr4lYZ03JBpLyEcUB8DzHZ+BNw=="], + + "electron-publish": ["electron-publish@26.15.3", "", { "dependencies": { "@types/fs-extra": "^9.0.11", "aws4": "^1.13.2", "builder-util": "26.15.3", "builder-util-runtime": "9.7.0", "chalk": "^4.1.2", "form-data": "^4.0.5", "fs-extra": "^10.1.0", "lazy-val": "^1.0.5", "mime": "^2.5.2" } }, "sha512-g/2bn8YTavY4cuS5F+jOS7zmZbXXBV8KZ8yHKfJjFPoKtzBqrpCdNPxBd3tqdBwP7BVd0lGzf7Bk2s0KesWZ4Q=="], + + "electron-store": ["electron-store@11.0.2", "", { "dependencies": { "conf": "^15.0.2", "type-fest": "^5.0.1" } }, "sha512-4VkNRdN+BImL2KcCi41WvAYbh6zLX5AUTi4so68yPqiItjbgTjqpEnGAqasgnG+lB6GuAyUltKwVopp6Uv+gwQ=="], + + "electron-to-chromium": ["electron-to-chromium@1.5.283", "", {}, "sha512-3vifjt1HgrGW/h76UEeny+adYApveS9dH2h3p57JYzBSXJIKUJAvtmIytDKjcSCt9xHfrNCFJ7gts6vkhuq++w=="], + + "electron-winstaller": ["electron-winstaller@5.4.0", "", { "dependencies": { "@electron/asar": "^3.2.1", "debug": "^4.1.1", "fs-extra": "^7.0.1", "lodash": "^4.17.21", "temp": "^0.9.0" }, "optionalDependencies": { "@electron/windows-sign": "^1.1.2" } }, "sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg=="], + + "emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="], + + "engine.io-client": ["engine.io-client@6.6.4", "", { "dependencies": { "@socket.io/component-emitter": "3.1.2", "debug": "4.4.3", "engine.io-parser": "5.2.3", "ws": "8.18.3", "xmlhttprequest-ssl": "2.1.2" } }, "sha512-+kjUJnZGwzewFDw951CDWcwj35vMNf2fcj7xQWOctq1F2i1jkDdVvdFG9kM/BEChymCH36KgjnW0NsL58JYRxw=="], + + "engine.io-parser": ["engine.io-parser@5.2.3", "", {}, "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q=="], + + "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], + + "env-paths": ["env-paths@2.2.1", "", {}, "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A=="], + + "err-code": ["err-code@2.0.3", "", {}, "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA=="], + + "error-ex": ["error-ex@1.3.4", "", { "dependencies": { "is-arrayish": "0.2.1" } }, "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ=="], + + "es-abstract": ["es-abstract@1.24.1", "", { "dependencies": { "array-buffer-byte-length": "1.0.2", "arraybuffer.prototype.slice": "1.0.4", "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "call-bound": "1.0.4", "data-view-buffer": "1.0.2", "data-view-byte-length": "1.0.2", "data-view-byte-offset": "1.0.1", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "es-set-tostringtag": "2.1.0", "es-to-primitive": "1.3.0", "function.prototype.name": "1.1.8", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "get-symbol-description": "1.1.0", "globalthis": "1.0.4", "gopd": "1.2.0", "has-property-descriptors": "1.0.2", "has-proto": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.2", "internal-slot": "1.1.0", "is-array-buffer": "3.0.5", "is-callable": "1.2.7", "is-data-view": "1.0.2", "is-negative-zero": "2.0.3", "is-regex": "1.2.1", "is-set": "2.0.3", "is-shared-array-buffer": "1.0.4", "is-string": "1.1.1", "is-typed-array": "1.1.15", "is-weakref": "1.1.1", "math-intrinsics": "1.1.0", "object-inspect": "1.13.4", "object-keys": "1.1.1", "object.assign": "4.1.7", "own-keys": "1.0.1", "regexp.prototype.flags": "1.5.4", "safe-array-concat": "1.1.3", "safe-push-apply": "1.0.0", "safe-regex-test": "1.1.0", "set-proto": "1.0.0", "stop-iteration-iterator": "1.1.0", "string.prototype.trim": "1.2.10", "string.prototype.trimend": "1.0.9", "string.prototype.trimstart": "1.0.8", "typed-array-buffer": "1.0.3", "typed-array-byte-length": "1.0.3", "typed-array-byte-offset": "1.0.4", "typed-array-length": "1.0.7", "unbox-primitive": "1.1.0", "which-typed-array": "1.1.20" } }, "sha512-zHXBLhP+QehSSbsS9Pt23Gg964240DPd6QCf8WpkqEXxQ7fhdZzYsocOr5u7apWonsS5EjZDmTF+/slGMyasvw=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-iterator-helpers": ["es-iterator-helpers@1.2.2", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-set-tostringtag": "2.1.0", "function-bind": "1.1.2", "get-intrinsic": "1.3.0", "globalthis": "1.0.4", "gopd": "1.2.0", "has-property-descriptors": "1.0.2", "has-proto": "1.2.0", "has-symbols": "1.1.0", "internal-slot": "1.1.0", "iterator.prototype": "1.1.5", "safe-array-concat": "1.1.3" } }, "sha512-BrUQ0cPTB/IwXj23HtwHjS9n7O4h9FX94b4xc5zlTHxeLgTAdzYUDyy6KdExAl9lbN5rtfe44xpjpmj9grxs5w=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "es-set-tostringtag": ["es-set-tostringtag@2.1.0", "", { "dependencies": { "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "has-tostringtag": "1.0.2", "hasown": "2.0.2" } }, "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA=="], + + "es-shim-unscopables": ["es-shim-unscopables@1.1.0", "", { "dependencies": { "hasown": "2.0.2" } }, "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw=="], + + "es-to-primitive": ["es-to-primitive@1.3.0", "", { "dependencies": { "is-callable": "1.2.7", "is-date-object": "1.1.0", "is-symbol": "1.1.1" } }, "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g=="], + + "es-toolkit": ["es-toolkit@1.47.1", "", {}, "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q=="], + + "es6-error": ["es6-error@4.1.1", "", {}, "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg=="], + + "esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="], + + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "escape-string-regexp": ["escape-string-regexp@4.0.0", "", {}, "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="], + + "escodegen": ["escodegen@2.1.0", "", { "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", "esutils": "^2.0.2" }, "optionalDependencies": { "source-map": "~0.6.1" }, "bin": { "esgenerate": "bin/esgenerate.js", "escodegen": "bin/escodegen.js" } }, "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w=="], + + "eslint": ["eslint@9.39.2", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/config-array": "0.21.1", "@eslint/config-helpers": "0.4.2", "@eslint/core": "0.17.0", "@eslint/eslintrc": "3.3.3", "@eslint/js": "9.39.2", "@eslint/plugin-kit": "0.4.1", "@humanfs/node": "0.16.7", "@humanwhocodes/module-importer": "1.0.1", "@humanwhocodes/retry": "0.4.3", "@types/estree": "1.0.8", "ajv": "6.12.6", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "escape-string-regexp": "4.0.0", "eslint-scope": "8.4.0", "eslint-visitor-keys": "4.2.1", "espree": "10.4.0", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "8.0.0", "find-up": "5.0.0", "glob-parent": "6.0.2", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "json-stable-stringify-without-jsonify": "1.0.1", "lodash.merge": "4.6.2", "minimatch": "3.1.2", "natural-compare": "1.4.0", "optionator": "0.9.4" }, "optionalDependencies": { "jiti": "2.6.1" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw=="], + + "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": "9.39.2" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], + + "eslint-config-standard": ["eslint-config-standard@17.1.0", "", { "peerDependencies": { "eslint": "8.57.1", "eslint-plugin-import": "2.32.0", "eslint-plugin-n": "15.7.0", "eslint-plugin-promise": "6.6.0" } }, "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q=="], + + "eslint-config-standard-jsx": ["eslint-config-standard-jsx@11.0.0", "", { "peerDependencies": { "eslint": "8.57.1", "eslint-plugin-react": "7.37.5" } }, "sha512-+1EV/R0JxEK1L0NGolAr8Iktm3Rgotx3BKwgaX+eAuSX8D952LULKtjgZD3F+e6SvibONnhLwoTi9DPxN5LvvQ=="], + + "eslint-import-resolver-node": ["eslint-import-resolver-node@0.3.9", "", { "dependencies": { "debug": "3.2.7", "is-core-module": "2.16.1", "resolve": "1.22.11" } }, "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g=="], + + "eslint-module-utils": ["eslint-module-utils@2.12.1", "", { "dependencies": { "debug": "3.2.7" }, "optionalDependencies": { "eslint": "9.39.2", "eslint-import-resolver-node": "0.3.9" } }, "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw=="], + + "eslint-plugin-es": ["eslint-plugin-es@4.1.0", "", { "dependencies": { "eslint-utils": "2.1.0", "regexpp": "3.2.0" }, "peerDependencies": { "eslint": "9.39.2" } }, "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ=="], + + "eslint-plugin-import": ["eslint-plugin-import@2.32.0", "", { "dependencies": { "@rtsao/scc": "1.1.0", "array-includes": "3.1.9", "array.prototype.findlastindex": "1.2.6", "array.prototype.flat": "1.3.3", "array.prototype.flatmap": "1.3.3", "debug": "3.2.7", "doctrine": "2.1.0", "eslint-import-resolver-node": "0.3.9", "eslint-module-utils": "2.12.1", "hasown": "2.0.2", "is-core-module": "2.16.1", "is-glob": "4.0.3", "minimatch": "3.1.2", "object.fromentries": "2.0.8", "object.groupby": "1.0.3", "object.values": "1.2.1", "semver": "6.3.1", "string.prototype.trimend": "1.0.9", "tsconfig-paths": "3.15.0" }, "peerDependencies": { "eslint": "9.39.2" } }, "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA=="], + + "eslint-plugin-n": ["eslint-plugin-n@15.7.0", "", { "dependencies": { "builtins": "5.1.0", "eslint-plugin-es": "4.1.0", "eslint-utils": "3.0.0", "ignore": "5.3.2", "is-core-module": "2.16.1", "minimatch": "3.1.2", "resolve": "1.22.11", "semver": "7.7.3" }, "peerDependencies": { "eslint": "9.39.2" } }, "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q=="], + + "eslint-plugin-prettier": ["eslint-plugin-prettier@5.5.5", "", { "dependencies": { "prettier-linter-helpers": "1.0.1", "synckit": "0.11.12" }, "optionalDependencies": { "@types/eslint": "9.6.1", "eslint-config-prettier": "10.1.8" }, "peerDependencies": { "eslint": "9.39.2", "prettier": "3.8.1" } }, "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw=="], + + "eslint-plugin-promise": ["eslint-plugin-promise@6.6.0", "", { "peerDependencies": { "eslint": "9.39.2" } }, "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ=="], + + "eslint-plugin-react": ["eslint-plugin-react@7.37.5", "", { "dependencies": { "array-includes": "3.1.9", "array.prototype.findlast": "1.2.5", "array.prototype.flatmap": "1.3.3", "array.prototype.tosorted": "1.1.4", "doctrine": "2.1.0", "es-iterator-helpers": "1.2.2", "estraverse": "5.3.0", "hasown": "2.0.2", "jsx-ast-utils": "3.3.5", "minimatch": "3.1.2", "object.entries": "1.1.9", "object.fromentries": "2.0.8", "object.values": "1.2.1", "prop-types": "15.8.1", "resolve": "2.0.0-next.5", "semver": "6.3.1", "string.prototype.matchall": "4.0.12", "string.prototype.repeat": "1.0.0" }, "peerDependencies": { "eslint": "8.57.1" } }, "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA=="], + + "eslint-plugin-react-hooks": ["eslint-plugin-react-hooks@5.2.0", "", { "peerDependencies": { "eslint": "9.39.2" } }, "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg=="], + + "eslint-plugin-react-refresh": ["eslint-plugin-react-refresh@0.4.26", "", { "peerDependencies": { "eslint": "9.39.2" } }, "sha512-1RETEylht2O6FM/MvgnyvT+8K21wLqDNg4qD51Zj3guhjt433XbnnkVttHMyaVyAFD03QSV4LPS5iE3VQmO7XQ=="], + + "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], + + "eslint-utils": ["eslint-utils@3.0.0", "", { "dependencies": { "eslint-visitor-keys": "2.1.0" }, "peerDependencies": { "eslint": "9.39.2" } }, "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="], + + "eslint-visitor-keys": ["eslint-visitor-keys@4.2.1", "", {}, "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ=="], + + "espree": ["espree@10.4.0", "", { "dependencies": { "acorn": "8.15.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "4.2.1" } }, "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ=="], + + "esprima": ["esprima@4.0.1", "", { "bin": { "esparse": "./bin/esparse.js", "esvalidate": "./bin/esvalidate.js" } }, "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="], + + "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], + + "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "5.3.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], + + "estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="], + + "estree-util-is-identifier-name": ["estree-util-is-identifier-name@3.0.0", "", {}, "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg=="], + + "estree-walker": ["estree-walker@2.0.2", "", {}, "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="], + + "esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], + + "execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "7.0.6", "get-stream": "6.0.1", "human-signals": "2.1.0", "is-stream": "2.0.1", "merge-stream": "2.0.0", "npm-run-path": "4.0.1", "onetime": "5.1.2", "signal-exit": "3.0.7", "strip-final-newline": "2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="], + + "exif-parser": ["exif-parser@0.1.12", "", {}, "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw=="], + + "exit-hook": ["exit-hook@2.2.1", "", {}, "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw=="], + + "exponential-backoff": ["exponential-backoff@3.1.3", "", {}, "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA=="], + + "express": ["express@5.2.1", "", { "dependencies": { "accepts": "2.0.0", "body-parser": "2.2.2", "content-disposition": "1.0.1", "content-type": "1.0.5", "cookie": "0.7.2", "cookie-signature": "1.2.2", "debug": "4.4.3", "depd": "2.0.0", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "finalhandler": "2.1.1", "fresh": "2.0.0", "http-errors": "2.0.1", "merge-descriptors": "2.0.0", "mime-types": "3.0.2", "on-finished": "2.4.1", "once": "1.4.0", "parseurl": "1.3.3", "proxy-addr": "2.0.7", "qs": "6.14.1", "range-parser": "1.2.1", "router": "2.2.0", "send": "1.2.1", "serve-static": "2.2.1", "statuses": "2.0.2", "type-is": "2.0.1", "vary": "1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="], + + "exsolve": ["exsolve@1.0.8", "", {}, "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA=="], + + "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], + + "extract-zip": ["extract-zip@2.0.1", "", { "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "optionalDependencies": { "@types/yauzl": "^2.9.1" }, "bin": { "extract-zip": "cli.js" } }, "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-diff": ["fast-diff@1.3.0", "", {}, "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw=="], + + "fast-equals": ["fast-equals@5.4.0", "", {}, "sha512-jt2DW/aNFNwke7AUd+Z+e6pz39KO5rzdbbFCg2sGafS4mk13MI7Z8O5z9cADNn5lhGODIgLwug6TZO2ctf7kcw=="], + + "fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "@nodelib/fs.walk": "1.2.8", "glob-parent": "5.1.2", "merge2": "1.4.1", "micromatch": "4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="], + + "fast-uri": ["fast-uri@3.1.5", "", {}, "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw=="], + + "fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "1.1.0" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="], + + "fd-slicer": ["fd-slicer@1.1.0", "", { "dependencies": { "pend": "~1.2.0" } }, "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g=="], + + "fdir": ["fdir@6.5.0", "", { "optionalDependencies": { "picomatch": "4.0.3" } }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "4.0.1" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="], + + "file-type": ["file-type@21.3.4", "", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g=="], + + "filelist": ["filelist@1.0.6", "", { "dependencies": { "minimatch": "^5.0.1" } }, "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA=="], + + "filename-reserved-regex": ["filename-reserved-regex@2.0.0", "", {}, "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ=="], + + "filenamify": ["filenamify@4.3.0", "", { "dependencies": { "filename-reserved-regex": "^2.0.0", "strip-outer": "^1.0.1", "trim-repeated": "^1.0.0" } }, "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg=="], + + "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], + + "finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "4.4.3", "encodeurl": "2.0.0", "escape-html": "1.0.3", "on-finished": "2.4.1", "parseurl": "1.3.3", "statuses": "2.0.2" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="], + + "find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="], + + "find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "6.0.0", "path-exists": "4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="], + + "flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "3.3.3", "keyv": "4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="], + + "flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="], + + "flora-colossus": ["flora-colossus@2.0.0", "", { "dependencies": { "debug": "^4.3.4", "fs-extra": "^10.1.0" } }, "sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA=="], + + "follow-redirects": ["follow-redirects@1.15.11", "", {}, "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ=="], + + "for-each": ["for-each@0.3.5", "", { "dependencies": { "is-callable": "1.2.7" } }, "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg=="], + + "form-data": ["form-data@4.0.5", "", { "dependencies": { "asynckit": "0.4.0", "combined-stream": "1.0.8", "es-set-tostringtag": "2.1.0", "hasown": "2.0.2", "mime-types": "2.1.35" } }, "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "fs-extra": ["fs-extra@10.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ=="], + + "fs.realpath": ["fs.realpath@1.0.0", "", {}, "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="], + + "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "function.prototype.name": ["function.prototype.name@1.1.8", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "functions-have-names": "1.2.3", "hasown": "2.0.2", "is-callable": "1.2.7" } }, "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q=="], + + "functions-have-names": ["functions-have-names@1.2.3", "", {}, "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ=="], + + "galactus": ["galactus@1.0.0", "", { "dependencies": { "debug": "^4.3.4", "flora-colossus": "^2.0.0", "fs-extra": "^10.1.0" } }, "sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ=="], + + "gcode-preview": ["gcode-preview@2.18.0", "", { "dependencies": { "lil-gui": "0.19.2", "three": "0.159.0" } }, "sha512-uc9QYciG6ES/A6BWJpUZk4fHxCPvt5EnvDhHIHDbNdR/m3f9VkGvpSMh9HDygXjAXX0x1Lbz/e9ZGlIrYNB29A=="], + + "generator-function": ["generator-function@2.0.1", "", {}, "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g=="], + + "gensync": ["gensync@1.0.0-beta.2", "", {}, "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="], + + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "1.0.2", "es-define-property": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "function-bind": "1.1.2", "get-proto": "1.0.1", "gopd": "1.2.0", "has-symbols": "1.1.0", "hasown": "2.0.2", "math-intrinsics": "1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-package-info": ["get-package-info@1.0.0", "", { "dependencies": { "bluebird": "^3.1.1", "debug": "^2.2.0", "lodash.get": "^4.0.0", "read-pkg-up": "^2.0.0" } }, "sha512-SCbprXGAPdIhKAXiG+Mk6yeoFH61JlYunqdFQFHDtLjJlDjFf6x07dsS8acO+xWt52jpdVo49AlVDnUVK1sDNw=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "1.0.1", "es-object-atoms": "1.1.1" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "get-source": ["get-source@2.0.12", "", { "dependencies": { "data-uri-to-buffer": "2.0.2", "source-map": "0.6.1" } }, "sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w=="], + + "get-stdin": ["get-stdin@8.0.0", "", {}, "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg=="], + + "get-stream": ["get-stream@5.2.0", "", { "dependencies": { "pump": "^3.0.0" } }, "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA=="], + + "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], + + "get-uri": ["get-uri@6.0.5", "", { "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", "debug": "^4.3.4" } }, "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg=="], + + "gifwrap": ["gifwrap@0.10.1", "", { "dependencies": { "image-q": "^4.0.0", "omggif": "^1.0.10" } }, "sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw=="], + + "glob": ["glob@7.2.3", "", { "dependencies": { "fs.realpath": "1.0.0", "inflight": "1.0.6", "inherits": "2.0.4", "minimatch": "3.1.2", "once": "1.4.0", "path-is-absolute": "1.0.1" } }, "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q=="], + + "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], + + "glob-to-regexp": ["glob-to-regexp@0.4.1", "", {}, "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="], + + "global-agent": ["global-agent@3.0.0", "", { "dependencies": { "boolean": "^3.0.1", "es6-error": "^4.1.1", "matcher": "^3.0.0", "roarr": "^2.15.3", "semver": "^7.3.2", "serialize-error": "^7.0.1" } }, "sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q=="], + + "globals": ["globals@15.15.0", "", {}, "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg=="], + + "globalthis": ["globalthis@1.0.4", "", { "dependencies": { "define-properties": "1.2.1", "gopd": "1.2.0" } }, "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ=="], + + "globby": ["globby@11.1.0", "", { "dependencies": { "array-union": "2.1.0", "dir-glob": "3.0.1", "fast-glob": "3.3.3", "ignore": "5.3.2", "merge2": "1.4.1", "slash": "3.0.0" } }, "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "got": ["got@11.8.6", "", { "dependencies": { "@sindresorhus/is": "^4.0.0", "@szmarczak/http-timer": "^4.0.5", "@types/cacheable-request": "^6.0.1", "@types/responselike": "^1.0.0", "cacheable-lookup": "^5.0.3", "cacheable-request": "^7.0.2", "decompress-response": "^6.0.0", "http2-wrapper": "^1.0.0-beta.5.2", "lowercase-keys": "^2.0.0", "p-cancelable": "^2.0.0", "responselike": "^2.0.0" } }, "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g=="], + + "graceful-fs": ["graceful-fs@4.2.11", "", {}, "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="], + + "graphemer": ["graphemer@1.4.0", "", {}, "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag=="], + + "has-ansi": ["has-ansi@2.0.0", "", { "dependencies": { "ansi-regex": "2.1.1" } }, "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg=="], + + "has-bigints": ["has-bigints@1.1.0", "", {}, "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg=="], + + "has-flag": ["has-flag@4.0.0", "", {}, "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="], + + "has-property-descriptors": ["has-property-descriptors@1.0.2", "", { "dependencies": { "es-define-property": "1.0.1" } }, "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg=="], + + "has-proto": ["has-proto@1.2.0", "", { "dependencies": { "dunder-proto": "1.0.1" } }, "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "has-tostringtag": ["has-tostringtag@1.0.2", "", { "dependencies": { "has-symbols": "1.1.0" } }, "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "hast-util-to-jsx-runtime": ["hast-util-to-jsx-runtime@2.3.6", "", { "dependencies": { "@types/estree": "1.0.8", "@types/hast": "3.0.4", "@types/unist": "3.0.3", "comma-separated-tokens": "2.0.3", "devlop": "1.1.0", "estree-util-is-identifier-name": "3.0.0", "hast-util-whitespace": "3.0.0", "mdast-util-mdx-expression": "2.0.1", "mdast-util-mdx-jsx": "3.2.0", "mdast-util-mdxjs-esm": "2.0.1", "property-information": "7.1.0", "space-separated-tokens": "2.0.2", "style-to-js": "1.1.21", "unist-util-position": "5.0.0", "vfile-message": "4.0.3" } }, "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg=="], + + "hast-util-whitespace": ["hast-util-whitespace@3.0.0", "", { "dependencies": { "@types/hast": "3.0.4" } }, "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw=="], + + "hoist-non-react-statics": ["hoist-non-react-statics@3.3.2", "", { "dependencies": { "react-is": "16.13.1" } }, "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="], + + "hosted-git-info": ["hosted-git-info@4.1.0", "", { "dependencies": { "lru-cache": "^6.0.0" } }, "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA=="], + + "html-url-attributes": ["html-url-attributes@3.0.1", "", {}, "sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ=="], + + "http-cache-semantics": ["http-cache-semantics@4.2.0", "", {}, "sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ=="], + + "http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.2", "toidentifier": "1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="], + + "http-proxy-agent": ["http-proxy-agent@7.0.2", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig=="], + + "http2-wrapper": ["http2-wrapper@1.0.3", "", { "dependencies": { "quick-lru": "^5.1.1", "resolve-alpn": "^1.0.0" } }, "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg=="], + + "https-proxy-agent": ["https-proxy-agent@7.0.6", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3" } }, "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw=="], + + "human-signals": ["human-signals@2.1.0", "", {}, "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="], + + "hyphenate-style-name": ["hyphenate-style-name@1.1.0", "", {}, "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw=="], + + "iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": "2.1.2" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="], + + "ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], + + "image-q": ["image-q@4.0.0", "", { "dependencies": { "@types/node": "16.9.1" } }, "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw=="], + + "immer": ["immer@10.2.0", "", {}, "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw=="], + + "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "1.0.1", "resolve-from": "4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], + + "imurmurhash": ["imurmurhash@0.1.4", "", {}, "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA=="], + + "indent-string": ["indent-string@4.0.0", "", {}, "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="], + + "inflight": ["inflight@1.0.6", "", { "dependencies": { "once": "1.4.0", "wrappy": "1.0.2" } }, "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ini": ["ini@1.3.8", "", {}, "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="], + + "inline-style-parser": ["inline-style-parser@0.2.7", "", {}, "sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA=="], + + "internal-slot": ["internal-slot@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "hasown": "2.0.2", "side-channel": "1.1.0" } }, "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw=="], + + "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], + + "ip-address": ["ip-address@10.1.0", "", {}, "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-alphabetical": ["is-alphabetical@2.0.1", "", {}, "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ=="], + + "is-alphanumerical": ["is-alphanumerical@2.0.1", "", { "dependencies": { "is-alphabetical": "2.0.1", "is-decimal": "2.0.1" } }, "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw=="], + + "is-array-buffer": ["is-array-buffer@3.0.5", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A=="], + + "is-arrayish": ["is-arrayish@0.2.1", "", {}, "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="], + + "is-async-function": ["is-async-function@2.1.1", "", { "dependencies": { "async-function": "1.0.0", "call-bound": "1.0.4", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ=="], + + "is-bigint": ["is-bigint@1.1.0", "", { "dependencies": { "has-bigints": "1.1.0" } }, "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ=="], + + "is-boolean-object": ["is-boolean-object@1.2.2", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A=="], + + "is-callable": ["is-callable@1.2.7", "", {}, "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA=="], + + "is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="], + + "is-data-view": ["is-data-view@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw=="], + + "is-date-object": ["is-date-object@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg=="], + + "is-decimal": ["is-decimal@2.0.1", "", {}, "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A=="], + + "is-docker": ["is-docker@2.2.1", "", { "bin": { "is-docker": "cli.js" } }, "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="], + + "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], + + "is-finalizationregistry": ["is-finalizationregistry@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg=="], + + "is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="], + + "is-generator-function": ["is-generator-function@1.1.2", "", { "dependencies": { "call-bound": "1.0.4", "generator-function": "2.0.1", "get-proto": "1.0.1", "has-tostringtag": "1.0.2", "safe-regex-test": "1.1.0" } }, "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA=="], + + "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], + + "is-hexadecimal": ["is-hexadecimal@2.0.1", "", {}, "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg=="], + + "is-map": ["is-map@2.0.3", "", {}, "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw=="], + + "is-mobile": ["is-mobile@5.0.0", "", {}, "sha512-Tz/yndySvLAEXh+Uk8liFCxOwVH6YutuR74utvOcu7I9Di+DwM0mtdPVZNaVvvBUM2OXxne/NhOs1zAO7riusQ=="], + + "is-negative-zero": ["is-negative-zero@2.0.3", "", {}, "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw=="], + + "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], + + "is-number-object": ["is-number-object@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw=="], + + "is-path-inside": ["is-path-inside@3.0.3", "", {}, "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="], + + "is-plain-obj": ["is-plain-obj@4.1.0", "", {}, "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg=="], + + "is-port-reachable": ["is-port-reachable@4.0.0", "", {}, "sha512-9UoipoxYmSk6Xy7QFgRv2HDyaysmgSG75TFQs6S+3pDM7ZhKTF/bskZV+0UlABHzKjNVhPjYCLfeZUEg1wXxig=="], + + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "is-regex": ["is-regex@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "gopd": "1.2.0", "has-tostringtag": "1.0.2", "hasown": "2.0.2" } }, "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g=="], + + "is-set": ["is-set@2.0.3", "", {}, "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg=="], + + "is-shared-array-buffer": ["is-shared-array-buffer@1.0.4", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A=="], + + "is-stream": ["is-stream@2.0.1", "", {}, "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="], + + "is-string": ["is-string@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-tostringtag": "1.0.2" } }, "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA=="], + + "is-symbol": ["is-symbol@1.1.1", "", { "dependencies": { "call-bound": "1.0.4", "has-symbols": "1.1.0", "safe-regex-test": "1.1.0" } }, "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w=="], + + "is-typed-array": ["is-typed-array@1.1.15", "", { "dependencies": { "which-typed-array": "1.1.20" } }, "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ=="], + + "is-weakmap": ["is-weakmap@2.0.2", "", {}, "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w=="], + + "is-weakref": ["is-weakref@1.1.1", "", { "dependencies": { "call-bound": "1.0.4" } }, "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew=="], + + "is-weakset": ["is-weakset@2.0.4", "", { "dependencies": { "call-bound": "1.0.4", "get-intrinsic": "1.3.0" } }, "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ=="], + + "is-wsl": ["is-wsl@2.2.0", "", { "dependencies": { "is-docker": "2.2.1" } }, "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="], + + "isarray": ["isarray@2.0.5", "", {}, "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="], + + "isbinaryfile": ["isbinaryfile@5.0.7", "", {}, "sha512-gnWD14Jh3FzS3CPhF0AxNOJ8CxqeblPTADzI38r0wt8ZyQl5edpy75myt08EG2oKvpyiqSqsx+Wkz9vtkbTqYQ=="], + + "isexe": ["isexe@3.1.5", "", {}, "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w=="], + + "iterator.prototype": ["iterator.prototype@1.1.5", "", { "dependencies": { "define-data-property": "1.1.4", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "has-symbols": "1.1.0", "set-function-name": "2.0.2" } }, "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g=="], + + "jake": ["jake@10.9.4", "", { "dependencies": { "async": "^3.2.6", "filelist": "^1.0.4", "picocolors": "^1.1.1" }, "bin": { "jake": "bin/cli.js" } }, "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA=="], + + "jimp": ["jimp@1.6.1", "", { "dependencies": { "@jimp/core": "1.6.1", "@jimp/diff": "1.6.1", "@jimp/js-bmp": "1.6.1", "@jimp/js-gif": "1.6.1", "@jimp/js-jpeg": "1.6.1", "@jimp/js-png": "1.6.1", "@jimp/js-tiff": "1.6.1", "@jimp/plugin-blit": "1.6.1", "@jimp/plugin-blur": "1.6.1", "@jimp/plugin-circle": "1.6.1", "@jimp/plugin-color": "1.6.1", "@jimp/plugin-contain": "1.6.1", "@jimp/plugin-cover": "1.6.1", "@jimp/plugin-crop": "1.6.1", "@jimp/plugin-displace": "1.6.1", "@jimp/plugin-dither": "1.6.1", "@jimp/plugin-fisheye": "1.6.1", "@jimp/plugin-flip": "1.6.1", "@jimp/plugin-hash": "1.6.1", "@jimp/plugin-mask": "1.6.1", "@jimp/plugin-print": "1.6.1", "@jimp/plugin-quantize": "1.6.1", "@jimp/plugin-resize": "1.6.1", "@jimp/plugin-rotate": "1.6.1", "@jimp/plugin-threshold": "1.6.1", "@jimp/types": "1.6.1", "@jimp/utils": "1.6.1" } }, "sha512-hNQh6rZtWfSVWSNVmvq87N5BPJsNH7k7I7qyrXf9DOma9xATQk3fsyHazCQe51nCjdkoWdTmh0vD7bjVSLoxxw=="], + + "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], + + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], + + "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], + + "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + + "jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="], + + "json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="], + + "json-parse-better-errors": ["json-parse-better-errors@1.0.2", "", {}, "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="], + + "json-parse-even-better-errors": ["json-parse-even-better-errors@2.3.1", "", {}, "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="], + + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + + "json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="], + + "json-stable-stringify-without-jsonify": ["json-stable-stringify-without-jsonify@1.0.1", "", {}, "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="], + + "json-stringify-safe": ["json-stringify-safe@5.0.1", "", {}, "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="], + + "json2mq": ["json2mq@0.2.0", "", { "dependencies": { "string-convert": "0.2.1" } }, "sha512-SzoRg7ux5DWTII9J2qkrZrqV1gt+rTaoufMxEzXbS26Uid0NwaJd123HcoB80TgubEppxxIGdNxCx50fEoEWQA=="], + + "json5": ["json5@2.2.3", "", { "bin": { "json5": "lib/cli.js" } }, "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="], + + "jsonfile": ["jsonfile@6.2.1", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q=="], + + "jsx-ast-utils": ["jsx-ast-utils@3.3.5", "", { "dependencies": { "array-includes": "3.1.9", "array.prototype.flat": "1.3.3", "object.assign": "4.1.7", "object.values": "1.2.1" } }, "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ=="], + + "junk": ["junk@3.1.0", "", {}, "sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ=="], + + "keycloak-js": ["keycloak-js@26.2.2", "", {}, "sha512-ug7pNZ1xNkd7PPkerOJCEU2VnUhS7CYStDOCFJgqCNQ64h53ppxaKrh4iXH0xM8hFu5b1W6e6lsyYWqBMvaQFg=="], + + "keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="], + + "lazy-val": ["lazy-val@1.0.5", "", {}, "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q=="], + + "levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "1.2.1", "type-check": "0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="], + + "lil-gui": ["lil-gui@0.19.2", "", {}, "sha512-nU8j4ND702ouGfQZoaTN4dfXxacvGOAVK0DtmZBVcUYUAeYQXLQAjAN50igMHiba3T5jZyKEjXZU+Ntm1Qs6ZQ=="], + + "lines-and-columns": ["lines-and-columns@1.2.4", "", {}, "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="], + + "linkify-it": ["linkify-it@5.0.0", "", { "dependencies": { "uc.micro": "2.1.0" } }, "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ=="], + + "linkifyjs": ["linkifyjs@4.3.2", "", {}, "sha512-NT1CJtq3hHIreOianA8aSXn6Cw0JzYOuDQbOrSPe7gqFnCpKP++MQe3ODgO3oh2GJFORkAAdqredOa60z63GbA=="], + + "load-json-file": ["load-json-file@5.3.0", "", { "dependencies": { "graceful-fs": "4.2.11", "parse-json": "4.0.0", "pify": "4.0.1", "strip-bom": "3.0.0", "type-fest": "0.3.1" } }, "sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw=="], + + "locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="], + + "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], + + "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], + + "lodash.get": ["lodash.get@4.4.2", "", {}, "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ=="], + + "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], + + "loglevel": ["loglevel@1.9.2", "", {}, "sha512-HgMmCqIJSAKqo68l0rS2AanEWfkxaZ5wNiEFb5ggm08lDs9Xl2KxBlX3PTcaD2chBM1gXAYf491/M2Rv8Jwayg=="], + + "loglevel-colored-level-prefix": ["loglevel-colored-level-prefix@1.0.0", "", { "dependencies": { "chalk": "1.1.3", "loglevel": "1.9.2" } }, "sha512-u45Wcxxc+SdAlh4yeF/uKlC1SPUPCy0gullSNKXod5I4bmifzk+Q4lSLExNEVn19tGaJipbZ4V4jbFn79/6mVA=="], + + "longest-streak": ["longest-streak@3.1.0", "", {}, "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g=="], + + "loose-envify": ["loose-envify@1.4.0", "", { "dependencies": { "js-tokens": "4.0.0" }, "bin": { "loose-envify": "cli.js" } }, "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="], + + "lower-case": ["lower-case@2.0.2", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="], + + "lowercase-keys": ["lowercase-keys@2.0.0", "", {}, "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA=="], + + "lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="], + + "magic-string": ["magic-string@0.25.9", "", { "dependencies": { "sourcemap-codec": "1.4.8" } }, "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ=="], + + "markdown-it": ["markdown-it@14.1.1", "", { "dependencies": { "argparse": "2.0.1", "entities": "4.5.0", "linkify-it": "5.0.0", "mdurl": "2.0.0", "punycode.js": "2.3.1", "uc.micro": "2.1.0" }, "bin": { "markdown-it": "bin/markdown-it.mjs" } }, "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA=="], + + "markdown-table": ["markdown-table@3.0.4", "", {}, "sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw=="], + + "marked": ["marked@17.0.4", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-NOmVMM+KAokHMvjWmC5N/ZOvgmSWuqJB8FoYI019j4ogb/PeRMKoKIjReZ2w3376kkA8dSJIP8uD993Kxc0iRQ=="], + + "matcher": ["matcher@3.0.0", "", { "dependencies": { "escape-string-regexp": "^4.0.0" } }, "sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng=="], + + "matchmediaquery": ["matchmediaquery@0.4.2", "", { "dependencies": { "css-mediaquery": "0.1.2" } }, "sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "mdast-util-find-and-replace": ["mdast-util-find-and-replace@3.0.2", "", { "dependencies": { "@types/mdast": "4.0.4", "escape-string-regexp": "5.0.0", "unist-util-is": "6.0.1", "unist-util-visit-parents": "6.0.2" } }, "sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg=="], + + "mdast-util-from-markdown": ["mdast-util-from-markdown@2.0.2", "", { "dependencies": { "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "mdast-util-to-string": "4.0.0", "micromark": "4.0.2", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-decode-string": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2", "unist-util-stringify-position": "4.0.0" } }, "sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA=="], + + "mdast-util-gfm": ["mdast-util-gfm@3.1.0", "", { "dependencies": { "mdast-util-from-markdown": "2.0.2", "mdast-util-gfm-autolink-literal": "2.0.1", "mdast-util-gfm-footnote": "2.1.0", "mdast-util-gfm-strikethrough": "2.0.0", "mdast-util-gfm-table": "2.0.0", "mdast-util-gfm-task-list-item": "2.0.0", "mdast-util-to-markdown": "2.1.2" } }, "sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ=="], + + "mdast-util-gfm-autolink-literal": ["mdast-util-gfm-autolink-literal@2.0.1", "", { "dependencies": { "@types/mdast": "4.0.4", "ccount": "2.0.1", "devlop": "1.1.0", "mdast-util-find-and-replace": "3.0.2", "micromark-util-character": "2.1.1" } }, "sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ=="], + + "mdast-util-gfm-footnote": ["mdast-util-gfm-footnote@2.1.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2", "micromark-util-normalize-identifier": "2.0.1" } }, "sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ=="], + + "mdast-util-gfm-strikethrough": ["mdast-util-gfm-strikethrough@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2" } }, "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg=="], + + "mdast-util-gfm-table": ["mdast-util-gfm-table@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "markdown-table": "3.0.4", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2" } }, "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg=="], + + "mdast-util-gfm-task-list-item": ["mdast-util-gfm-task-list-item@2.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2" } }, "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ=="], + + "mdast-util-mdx-expression": ["mdast-util-mdx-expression@2.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2" } }, "sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ=="], + + "mdast-util-mdx-jsx": ["mdast-util-mdx-jsx@3.2.0", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "ccount": "2.0.1", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2", "parse-entities": "4.0.2", "stringify-entities": "4.0.4", "unist-util-stringify-position": "4.0.0", "vfile-message": "4.0.3" } }, "sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q=="], + + "mdast-util-mdxjs-esm": ["mdast-util-mdxjs-esm@2.0.1", "", { "dependencies": { "@types/estree-jsx": "1.0.5", "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "devlop": "1.1.0", "mdast-util-from-markdown": "2.0.2", "mdast-util-to-markdown": "2.1.2" } }, "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg=="], + + "mdast-util-phrasing": ["mdast-util-phrasing@4.1.0", "", { "dependencies": { "@types/mdast": "4.0.4", "unist-util-is": "6.0.1" } }, "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w=="], + + "mdast-util-to-hast": ["mdast-util-to-hast@13.2.1", "", { "dependencies": { "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "@ungap/structured-clone": "1.3.0", "devlop": "1.1.0", "micromark-util-sanitize-uri": "2.0.1", "trim-lines": "3.0.1", "unist-util-position": "5.0.0", "unist-util-visit": "5.1.0", "vfile": "6.0.3" } }, "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA=="], + + "mdast-util-to-markdown": ["mdast-util-to-markdown@2.1.2", "", { "dependencies": { "@types/mdast": "4.0.4", "@types/unist": "3.0.3", "longest-streak": "3.1.0", "mdast-util-phrasing": "4.1.0", "mdast-util-to-string": "4.0.0", "micromark-util-classify-character": "2.0.1", "micromark-util-decode-string": "2.0.1", "unist-util-visit": "5.1.0", "zwitch": "2.0.4" } }, "sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA=="], + + "mdast-util-to-string": ["mdast-util-to-string@4.0.0", "", { "dependencies": { "@types/mdast": "4.0.4" } }, "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg=="], + + "mdn-data": ["mdn-data@2.12.2", "", {}, "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA=="], + + "mdurl": ["mdurl@2.0.0", "", {}, "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "merge-stream": ["merge-stream@2.0.0", "", {}, "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="], + + "merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="], + + "micromark": ["micromark@4.0.2", "", { "dependencies": { "@types/debug": "4.1.12", "debug": "4.4.3", "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "micromark-core-commonmark": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-chunked": "2.0.1", "micromark-util-combine-extensions": "2.0.1", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-encode": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-subtokenize": "2.1.0", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA=="], + + "micromark-core-commonmark": ["micromark-core-commonmark@2.0.3", "", { "dependencies": { "decode-named-character-reference": "1.3.0", "devlop": "1.1.0", "micromark-factory-destination": "2.0.1", "micromark-factory-label": "2.0.1", "micromark-factory-space": "2.0.1", "micromark-factory-title": "2.0.1", "micromark-factory-whitespace": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-chunked": "2.0.1", "micromark-util-classify-character": "2.0.1", "micromark-util-html-tag-name": "2.0.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-subtokenize": "2.1.0", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg=="], + + "micromark-extension-gfm": ["micromark-extension-gfm@3.0.0", "", { "dependencies": { "micromark-extension-gfm-autolink-literal": "2.1.0", "micromark-extension-gfm-footnote": "2.1.0", "micromark-extension-gfm-strikethrough": "2.1.0", "micromark-extension-gfm-table": "2.1.1", "micromark-extension-gfm-tagfilter": "2.0.0", "micromark-extension-gfm-task-list-item": "2.1.0", "micromark-util-combine-extensions": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w=="], + + "micromark-extension-gfm-autolink-literal": ["micromark-extension-gfm-autolink-literal@2.1.0", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw=="], + + "micromark-extension-gfm-footnote": ["micromark-extension-gfm-footnote@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-core-commonmark": "2.0.3", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-normalize-identifier": "2.0.1", "micromark-util-sanitize-uri": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw=="], + + "micromark-extension-gfm-strikethrough": ["micromark-extension-gfm-strikethrough@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-chunked": "2.0.1", "micromark-util-classify-character": "2.0.1", "micromark-util-resolve-all": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw=="], + + "micromark-extension-gfm-table": ["micromark-extension-gfm-table@2.1.1", "", { "dependencies": { "devlop": "1.1.0", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg=="], + + "micromark-extension-gfm-tagfilter": ["micromark-extension-gfm-tagfilter@2.0.0", "", { "dependencies": { "micromark-util-types": "2.0.2" } }, "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg=="], + + "micromark-extension-gfm-task-list-item": ["micromark-extension-gfm-task-list-item@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw=="], + + "micromark-factory-destination": ["micromark-factory-destination@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA=="], + + "micromark-factory-label": ["micromark-factory-label@2.0.1", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg=="], + + "micromark-factory-space": ["micromark-factory-space@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-types": "2.0.2" } }, "sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg=="], + + "micromark-factory-title": ["micromark-factory-title@2.0.1", "", { "dependencies": { "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw=="], + + "micromark-factory-whitespace": ["micromark-factory-whitespace@2.0.1", "", { "dependencies": { "micromark-factory-space": "2.0.1", "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ=="], + + "micromark-util-character": ["micromark-util-character@2.1.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q=="], + + "micromark-util-chunked": ["micromark-util-chunked@2.0.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA=="], + + "micromark-util-classify-character": ["micromark-util-classify-character@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q=="], + + "micromark-util-combine-extensions": ["micromark-util-combine-extensions@2.0.1", "", { "dependencies": { "micromark-util-chunked": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg=="], + + "micromark-util-decode-numeric-character-reference": ["micromark-util-decode-numeric-character-reference@2.0.2", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw=="], + + "micromark-util-decode-string": ["micromark-util-decode-string@2.0.1", "", { "dependencies": { "decode-named-character-reference": "1.3.0", "micromark-util-character": "2.1.1", "micromark-util-decode-numeric-character-reference": "2.0.2", "micromark-util-symbol": "2.0.1" } }, "sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ=="], + + "micromark-util-encode": ["micromark-util-encode@2.0.1", "", {}, "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw=="], + + "micromark-util-html-tag-name": ["micromark-util-html-tag-name@2.0.1", "", {}, "sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA=="], + + "micromark-util-normalize-identifier": ["micromark-util-normalize-identifier@2.0.1", "", { "dependencies": { "micromark-util-symbol": "2.0.1" } }, "sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q=="], + + "micromark-util-resolve-all": ["micromark-util-resolve-all@2.0.1", "", { "dependencies": { "micromark-util-types": "2.0.2" } }, "sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg=="], + + "micromark-util-sanitize-uri": ["micromark-util-sanitize-uri@2.0.1", "", { "dependencies": { "micromark-util-character": "2.1.1", "micromark-util-encode": "2.0.1", "micromark-util-symbol": "2.0.1" } }, "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ=="], + + "micromark-util-subtokenize": ["micromark-util-subtokenize@2.1.0", "", { "dependencies": { "devlop": "1.1.0", "micromark-util-chunked": "2.0.1", "micromark-util-symbol": "2.0.1", "micromark-util-types": "2.0.2" } }, "sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA=="], + + "micromark-util-symbol": ["micromark-util-symbol@2.0.1", "", {}, "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q=="], + + "micromark-util-types": ["micromark-util-types@2.0.2", "", {}, "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA=="], + + "micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "3.0.3", "picomatch": "2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="], + + "mime": ["mime@3.0.0", "", { "bin": { "mime": "cli.js" } }, "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="], + + "mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="], + + "mimic-function": ["mimic-function@5.0.1", "", {}, "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA=="], + + "mimic-response": ["mimic-response@3.1.0", "", {}, "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="], + + "miniflare": ["miniflare@3.20250718.3", "", { "dependencies": { "@cspotcode/source-map-support": "0.8.1", "acorn": "8.14.0", "acorn-walk": "8.3.2", "exit-hook": "2.2.1", "glob-to-regexp": "0.4.1", "stoppable": "1.1.0", "undici": "5.29.0", "workerd": "1.20250718.0", "ws": "8.18.0", "youch": "3.3.4", "zod": "3.22.3" }, "bin": { "miniflare": "bootstrap.js" } }, "sha512-JuPrDJhwLrNLEJiNLWO7ZzJrv/Vv9kZuwMYCfv0LskQDM6Eonw4OvywO3CH/wCGjgHzha/qyjUh8JQ068TjDgQ=="], + + "minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="], + + "minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], + + "minizlib": ["minizlib@3.1.0", "", { "dependencies": { "minipass": "^7.1.2" } }, "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw=="], + + "mkdirp": ["mkdirp@0.5.6", "", { "dependencies": { "minimist": "^1.2.6" }, "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "mustache": ["mustache@4.2.0", "", { "bin": { "mustache": "bin/mustache" } }, "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ=="], + + "nanoid": ["nanoid@5.1.14", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-5c8l8kVzqpnDPaicbEop/fV0Q1w16FmbWtVhMqugTozAwYdlIQojWH5a/M7UfziFmGdQRrUdV+EPzc9Xng3VAQ=="], + + "nanopop": ["nanopop@2.3.0", "", {}, "sha512-fzN+T2K7/Ah25XU02MJkPZ5q4Tj5FpjmIYq4rvoHX4yb16HzFdCO6JxFFn5Y/oBhQ8no8fUZavnyIv9/+xkBBw=="], + + "natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "netmask": ["netmask@2.1.1", "", {}, "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA=="], + + "no-case": ["no-case@3.0.4", "", { "dependencies": { "lower-case": "2.0.2", "tslib": "2.8.1" } }, "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="], + + "node-abi": ["node-abi@4.33.0", "", { "dependencies": { "semver": "^7.6.3" } }, "sha512-vLBWCKb+7LWsX+TbfzWOkw0W81m377tyx3hOweBTjO43CXZnRGS1/JPWs20fr0PgZyDXk6ROYrylsEycK8raDA=="], + + "node-api-version": ["node-api-version@0.2.1", "", { "dependencies": { "semver": "^7.3.5" } }, "sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q=="], + + "node-gyp": ["node-gyp@12.4.0", "", { "dependencies": { "env-paths": "^2.2.0", "exponential-backoff": "^3.1.1", "graceful-fs": "^4.2.6", "nopt": "^9.0.0", "proc-log": "^6.0.0", "semver": "^7.3.5", "tar": "^7.5.4", "tinyglobby": "^0.2.12", "undici": "^6.25.0", "which": "^6.0.0" }, "bin": { "node-gyp": "bin/node-gyp.js" } }, "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw=="], + + "node-int64": ["node-int64@0.4.0", "", {}, "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw=="], + + "node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="], + + "nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="], + + "normalize-package-data": ["normalize-package-data@2.5.0", "", { "dependencies": { "hosted-git-info": "^2.1.4", "resolve": "^1.10.0", "semver": "2 || 3 || 4 || 5", "validate-npm-package-license": "^3.0.1" } }, "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="], + + "normalize-url": ["normalize-url@6.1.0", "", {}, "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="], + + "npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "3.1.1" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="], + + "nth-check": ["nth-check@2.1.1", "", { "dependencies": { "boolbase": "1.0.0" } }, "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "object-keys": ["object-keys@1.1.1", "", {}, "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="], + + "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1", "has-symbols": "1.1.0", "object-keys": "1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + + "object.entries": ["object.entries@1.1.9", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw=="], + + "object.fromentries": ["object.fromentries@2.0.8", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-object-atoms": "1.1.1" } }, "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ=="], + + "object.groupby": ["object.groupby@1.0.3", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1" } }, "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ=="], + + "object.values": ["object.values@1.2.1", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA=="], + + "ohash": ["ohash@2.0.11", "", {}, "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ=="], + + "omggif": ["omggif@1.0.10", "", {}, "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "on-headers": ["on-headers@1.1.0", "", {}, "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1.0.2" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="], + + "online-3d-viewer": ["online-3d-viewer@0.16.0", "", { "dependencies": { "@simonwep/pickr": "1.9.0", "fflate": "0.8.2", "three": "0.176.0" } }, "sha512-Mcmo41TM3K+svlMDRH8ySKSY2e8s7Sssdb5U9LV3gkFKVWGGuS304Vk5gqxopAJbE72DpsC67Ve3YNtcAuROwQ=="], + + "open": ["open@8.4.2", "", { "dependencies": { "define-lazy-prop": "2.0.0", "is-docker": "2.2.1", "is-wsl": "2.2.0" } }, "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ=="], + + "optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "0.1.4", "fast-levenshtein": "2.0.6", "levn": "0.4.1", "prelude-ls": "1.2.1", "type-check": "0.4.0", "word-wrap": "1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], + + "orderedmap": ["orderedmap@2.1.1", "", {}, "sha512-TvAWxi0nDe1j/rtMcWcIj94+Ffe6n7zhow33h40SKxmsmozs6dz/e+EajymfoFcHd7sxNn8yHM8839uixMOV6g=="], + + "own-keys": ["own-keys@1.0.1", "", { "dependencies": { "get-intrinsic": "1.3.0", "object-keys": "1.1.1", "safe-push-apply": "1.0.0" } }, "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg=="], + + "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], + + "p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="], + + "p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "3.1.0" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="], + + "p-try": ["p-try@1.0.0", "", {}, "sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww=="], + + "pac-proxy-agent": ["pac-proxy-agent@7.2.0", "", { "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.1.2", "debug": "^4.3.4", "get-uri": "^6.0.1", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.6", "pac-resolver": "^7.0.1", "socks-proxy-agent": "^8.0.5" } }, "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA=="], + + "pac-resolver": ["pac-resolver@7.0.1", "", { "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" } }, "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg=="], + + "pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="], + + "parent-module": ["parent-module@1.0.1", "", { "dependencies": { "callsites": "3.1.0" } }, "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="], + + "parse-author": ["parse-author@2.0.0", "", { "dependencies": { "author-regex": "^1.0.0" } }, "sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw=="], + + "parse-bmfont-ascii": ["parse-bmfont-ascii@1.0.6", "", {}, "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA=="], + + "parse-bmfont-binary": ["parse-bmfont-binary@1.0.6", "", {}, "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA=="], + + "parse-bmfont-xml": ["parse-bmfont-xml@1.1.6", "", { "dependencies": { "xml-parse-from-string": "^1.0.0", "xml2js": "^0.5.0" } }, "sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA=="], + + "parse-entities": ["parse-entities@4.0.2", "", { "dependencies": { "@types/unist": "2.0.11", "character-entities-legacy": "3.0.0", "character-reference-invalid": "2.0.1", "decode-named-character-reference": "1.3.0", "is-alphanumerical": "2.0.1", "is-decimal": "2.0.1", "is-hexadecimal": "2.0.1" } }, "sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw=="], + + "parse-json": ["parse-json@5.2.0", "", { "dependencies": { "@babel/code-frame": "7.29.0", "error-ex": "1.3.4", "json-parse-even-better-errors": "2.3.1", "lines-and-columns": "1.2.4" } }, "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-exists": ["path-exists@4.0.0", "", {}, "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="], + + "path-is-absolute": ["path-is-absolute@1.0.1", "", {}, "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="], + + "path-is-inside": ["path-is-inside@1.0.2", "", {}, "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="], + + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], + + "path-type": ["path-type@4.0.0", "", {}, "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="], + + "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], + + "pe-library": ["pe-library@0.4.1", "", {}, "sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw=="], + + "pend": ["pend@1.2.0", "", {}, "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg=="], + + "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], + + "picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="], + + "pify": ["pify@4.0.1", "", {}, "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g=="], + + "pixelmatch": ["pixelmatch@5.3.0", "", { "dependencies": { "pngjs": "^6.0.0" }, "bin": { "pixelmatch": "bin/pixelmatch" } }, "sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q=="], + + "pkg-conf": ["pkg-conf@3.1.0", "", { "dependencies": { "find-up": "3.0.0", "load-json-file": "5.3.0" } }, "sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ=="], + + "pkijs": ["pkijs@3.4.0", "", { "dependencies": { "@noble/hashes": "1.4.0", "asn1js": "^3.0.6", "bytestreamjs": "^2.0.1", "pvtsutils": "^1.3.6", "pvutils": "^1.1.3", "tslib": "^2.8.1" } }, "sha512-emEcLuomt2j03vxD54giVB4SxTjnsqkU692xZOZXHDVoYyypEm+b3jpiTcc+Cf+myooc+/Ly0z01jqeNHVgJGw=="], + + "plist": ["plist@3.1.0", "", { "dependencies": { "@xmldom/xmldom": "^0.8.8", "base64-js": "^1.5.1", "xmlbuilder": "^15.1.1" } }, "sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ=="], + + "png-to-ico": ["png-to-ico@2.1.8", "", { "dependencies": { "@types/node": "^17.0.36", "minimist": "^1.2.6", "pngjs": "^6.0.0" }, "bin": { "png-to-ico": "bin/cli.js" } }, "sha512-Nf+IIn/cZ/DIZVdGveJp86NG5uNib1ZXMiDd/8x32HCTeKSvgpyg6D/6tUBn1QO/zybzoMK0/mc3QRgAyXdv9w=="], + + "pngjs": ["pngjs@6.0.0", "", {}, "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg=="], + + "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], + + "postcss": ["postcss@8.5.6", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg=="], + + "postcss-value-parser": ["postcss-value-parser@4.2.0", "", {}, "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="], + + "postject": ["postject@1.0.0-alpha.6", "", { "dependencies": { "commander": "^9.4.0" }, "bin": { "postject": "dist/cli.js" } }, "sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A=="], + + "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], + + "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + + "prettier-eslint": ["prettier-eslint@16.4.2", "", { "dependencies": { "@typescript-eslint/parser": "6.21.0", "common-tags": "1.8.2", "dlv": "1.1.3", "eslint": "8.57.1", "indent-string": "4.0.0", "lodash.merge": "4.6.2", "loglevel-colored-level-prefix": "1.0.0", "prettier": "3.8.1", "pretty-format": "29.7.0", "require-relative": "0.8.7", "tslib": "2.8.1", "vue-eslint-parser": "9.4.3" } }, "sha512-vtJAQEkaN8fW5QKl08t7A5KCjlZuDUNeIlr9hgolMS5s3+uzbfRHDwaRnzrdqnY2YpHDmeDS/8zY0MKQHXJtaA=="], + + "prettier-linter-helpers": ["prettier-linter-helpers@1.0.1", "", { "dependencies": { "fast-diff": "1.3.0" } }, "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg=="], + + "pretty-format": ["pretty-format@29.7.0", "", { "dependencies": { "@jest/schemas": "29.6.3", "ansi-styles": "5.2.0", "react-is": "18.3.1" } }, "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ=="], + + "printable-characters": ["printable-characters@1.0.42", "", {}, "sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ=="], + + "proc-log": ["proc-log@6.1.0", "", {}, "sha512-iG+GYldRf2BQ0UDUAd6JQ/RwzaQy6mXmsk/IzlYyal4A4SNFw54MeH4/tLkF4I5WoWG9SQwuqWzS99jaFQHBuQ=="], + + "process-nextick-args": ["process-nextick-args@2.0.1", "", {}, "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="], + + "progress": ["progress@2.0.3", "", {}, "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="], + + "promise-retry": ["promise-retry@2.0.1", "", { "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" } }, "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g=="], + + "prop-types": ["prop-types@15.8.1", "", { "dependencies": { "loose-envify": "1.4.0", "object-assign": "4.1.1", "react-is": "16.13.1" } }, "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="], + + "proper-lockfile": ["proper-lockfile@4.1.2", "", { "dependencies": { "graceful-fs": "^4.2.4", "retry": "^0.12.0", "signal-exit": "^3.0.2" } }, "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA=="], + + "property-information": ["property-information@7.1.0", "", {}, "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ=="], + + "prosemirror-changeset": ["prosemirror-changeset@2.4.0", "", { "dependencies": { "prosemirror-transform": "1.11.0" } }, "sha512-LvqH2v7Q2SF6yxatuPP2e8vSUKS/L+xAU7dPDC4RMyHMhZoGDfBC74mYuyYF4gLqOEG758wajtyhNnsTkuhvng=="], + + "prosemirror-collab": ["prosemirror-collab@1.3.1", "", { "dependencies": { "prosemirror-state": "1.4.4" } }, "sha512-4SnynYR9TTYaQVXd/ieUvsVV4PDMBzrq2xPUWutHivDuOshZXqQ5rGbZM84HEaXKbLdItse7weMGOUdDVcLKEQ=="], + + "prosemirror-commands": ["prosemirror-commands@1.7.1", "", { "dependencies": { "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0" } }, "sha512-rT7qZnQtx5c0/y/KlYaGvtG411S97UaL6gdp6RIZ23DLHanMYLyfGBV5DtSnZdthQql7W+lEVbpSfwtO8T+L2w=="], + + "prosemirror-dropcursor": ["prosemirror-dropcursor@1.8.2", "", { "dependencies": { "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0", "prosemirror-view": "1.41.6" } }, "sha512-CCk6Gyx9+Tt2sbYk5NK0nB1ukHi2ryaRgadV/LvyNuO3ena1payM2z6Cg0vO1ebK8cxbzo41ku2DE5Axj1Zuiw=="], + + "prosemirror-gapcursor": ["prosemirror-gapcursor@1.4.0", "", { "dependencies": { "prosemirror-keymap": "1.2.3", "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-view": "1.41.6" } }, "sha512-z00qvurSdCEWUIulij/isHaqu4uLS8r/Fi61IbjdIPJEonQgggbJsLnstW7Lgdk4zQ68/yr6B6bf7sJXowIgdQ=="], + + "prosemirror-history": ["prosemirror-history@1.5.0", "", { "dependencies": { "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0", "prosemirror-view": "1.41.6", "rope-sequence": "1.3.4" } }, "sha512-zlzTiH01eKA55UAf1MEjtssJeHnGxO0j4K4Dpx+gnmX9n+SHNlDqI2oO1Kv1iPN5B1dm5fsljCfqKF9nFL6HRg=="], + + "prosemirror-inputrules": ["prosemirror-inputrules@1.5.1", "", { "dependencies": { "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0" } }, "sha512-7wj4uMjKaXWAQ1CDgxNzNtR9AlsuwzHfdFH1ygEHA2KHF2DOEaXl1CJfNPAKCg9qNEh4rum975QLaCiQPyY6Fw=="], + + "prosemirror-keymap": ["prosemirror-keymap@1.2.3", "", { "dependencies": { "prosemirror-state": "1.4.4", "w3c-keyname": "2.2.8" } }, "sha512-4HucRlpiLd1IPQQXNqeo81BGtkY8Ai5smHhKW9jjPKRc2wQIxksg7Hl1tTI2IfT2B/LgX6bfYvXxEpJl7aKYKw=="], + + "prosemirror-markdown": ["prosemirror-markdown@1.13.4", "", { "dependencies": { "@types/markdown-it": "14.1.2", "markdown-it": "14.1.1", "prosemirror-model": "1.25.4" } }, "sha512-D98dm4cQ3Hs6EmjK500TdAOew4Z03EV71ajEFiWra3Upr7diytJsjF4mPV2dW+eK5uNectiRj0xFxYI9NLXDbw=="], + + "prosemirror-menu": ["prosemirror-menu@1.3.0", "", { "dependencies": { "crelt": "1.0.6", "prosemirror-commands": "1.7.1", "prosemirror-history": "1.5.0", "prosemirror-state": "1.4.4" } }, "sha512-TImyPXCHPcDsSka2/lwJ6WjTASr4re/qWq1yoTTuLOqfXucwF6VcRa2LWCkM/EyTD1UO3CUwiH8qURJoWJRxwg=="], + + "prosemirror-model": ["prosemirror-model@1.25.4", "", { "dependencies": { "orderedmap": "2.1.1" } }, "sha512-PIM7E43PBxKce8OQeezAs9j4TP+5yDpZVbuurd1h5phUxEKIu+G2a+EUZzIC5nS1mJktDJWzbqS23n1tsAf5QA=="], + + "prosemirror-schema-basic": ["prosemirror-schema-basic@1.2.4", "", { "dependencies": { "prosemirror-model": "1.25.4" } }, "sha512-ELxP4TlX3yr2v5rM7Sb70SqStq5NvI15c0j9j/gjsrO5vaw+fnnpovCLEGIcpeGfifkuqJwl4fon6b+KdrODYQ=="], + + "prosemirror-schema-list": ["prosemirror-schema-list@1.5.1", "", { "dependencies": { "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0" } }, "sha512-927lFx/uwyQaGwJxLWCZRkjXG0p48KpMj6ueoYiu4JX05GGuGcgzAy62dfiV8eFZftgyBUvLx76RsMe20fJl+Q=="], + + "prosemirror-state": ["prosemirror-state@1.4.4", "", { "dependencies": { "prosemirror-model": "1.25.4", "prosemirror-transform": "1.11.0", "prosemirror-view": "1.41.6" } }, "sha512-6jiYHH2CIGbCfnxdHbXZ12gySFY/fz/ulZE333G6bPqIZ4F+TXo9ifiR86nAHpWnfoNjOb3o5ESi7J8Uz1jXHw=="], + + "prosemirror-tables": ["prosemirror-tables@1.8.5", "", { "dependencies": { "prosemirror-keymap": "1.2.3", "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0", "prosemirror-view": "1.41.6" } }, "sha512-V/0cDCsHKHe/tfWkeCmthNUcEp1IVO3p6vwN8XtwE9PZQLAZJigbw3QoraAdfJPir4NKJtNvOB8oYGKRl+t0Dw=="], + + "prosemirror-trailing-node": ["prosemirror-trailing-node@3.0.0", "", { "dependencies": { "@remirror/core-constants": "3.0.0", "escape-string-regexp": "4.0.0" }, "peerDependencies": { "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-view": "1.41.6" } }, "sha512-xiun5/3q0w5eRnGYfNlW1uU9W6x5MoFKWwq/0TIRgt09lv7Hcser2QYV8t4muXbEr+Fwo0geYn79Xs4GKywrRQ=="], + + "prosemirror-transform": ["prosemirror-transform@1.11.0", "", { "dependencies": { "prosemirror-model": "1.25.4" } }, "sha512-4I7Ce4KpygXb9bkiPS3hTEk4dSHorfRw8uI0pE8IhxlK2GXsqv5tIA7JUSxtSu7u8APVOTtbUBxTmnHIxVkIJw=="], + + "prosemirror-view": ["prosemirror-view@1.41.6", "", { "dependencies": { "prosemirror-model": "1.25.4", "prosemirror-state": "1.4.4", "prosemirror-transform": "1.11.0" } }, "sha512-mxpcDG4hNQa/CPtzxjdlir5bJFDlm0/x5nGBbStB2BWX+XOQ9M8ekEG+ojqB5BcVu2Rc80/jssCMZzSstJuSYg=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "^7.1.2", "debug": "^4.3.4", "http-proxy-agent": "^7.0.1", "https-proxy-agent": "^7.0.6", "lru-cache": "^7.14.1", "pac-proxy-agent": "^7.1.0", "proxy-from-env": "^1.1.0", "socks-proxy-agent": "^8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="], + + "proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="], + + "pump": ["pump@3.0.4", "", { "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" } }, "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "punycode.js": ["punycode.js@2.3.1", "", {}, "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA=="], + + "pvtsutils": ["pvtsutils@1.3.6", "", { "dependencies": { "tslib": "^2.8.1" } }, "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg=="], + + "pvutils": ["pvutils@1.1.5", "", {}, "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA=="], + + "qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="], + + "queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="], + + "quick-lru": ["quick-lru@5.1.1", "", {}, "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.1", "iconv-lite": "0.7.2", "unpipe": "1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], + + "rc": ["rc@1.2.8", "", { "dependencies": { "deep-extend": "0.6.0", "ini": "1.3.8", "minimist": "1.2.8", "strip-json-comments": "2.0.1" }, "bin": { "rc": "./cli.js" } }, "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw=="], + + "rc-cascader": ["rc-cascader@3.34.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-select": "14.16.8", "rc-tree": "5.13.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-KpXypcvju9ptjW9FaN2NFcA2QH9E9LHKq169Y0eWtH4e/wHQ5Wh5qZakAgvb8EKZ736WZ3B0zLLOBsrsja5Dag=="], + + "rc-checkbox": ["rc-checkbox@3.5.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-aOAQc3E98HteIIsSqm6Xk2FPKIER6+5vyEFMZfo73TqM+VVAIqOkHoPjgKLqSNtVLWScoaM7vY2ZrGEheI79yg=="], + + "rc-collapse": ["rc-collapse@3.9.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-swDdz4QZ4dFTo4RAUMLL50qP0EY62N2kvmk2We5xYdRwcRn8WcYtuetCJpwpaCbUfUt5+huLpVxhvmnK+PHrkA=="], + + "rc-dialog": ["rc-dialog@9.6.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/portal": "1.1.2", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ApoVi9Z8PaCQg6FsUzS8yvBEQy0ZL2PkuvAgrmohPkN3okps5WZ5WQWPc1RNuiOKaAYv8B97ACdsFU5LizzCqg=="], + + "rc-drawer": ["rc-drawer@7.3.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/portal": "1.1.2", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-DX6CIgiBWNpJIMGFO8BAISFkxiuKitoizooj4BDyee8/SnBn0zwO2FHrNDpqqepj0E/TFTDpmEBCyFuTgC7MOg=="], + + "rc-dropdown": ["rc-dropdown@4.2.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-YDAlXsPv3I1n42dv1JpdM7wJ+gSUBfeyPK59ZpBD9jQhK9jVuxpjj3NmWQHOBceA1zEPVX84T2wbdb2SD0UjmA=="], + + "rc-field-form": ["rc-field-form@2.7.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/async-validator": "5.1.0", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-vKeSifSJ6HoLaAB+B8aq/Qgm8a3dyxROzCtKNCsBQgiverpc4kWDQihoUwzUj+zNWJOykwSY4dNX3QrGwtVb9A=="], + + "rc-image": ["rc-image@7.12.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/portal": "1.1.2", "classnames": "2.5.1", "rc-dialog": "9.6.0", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-cZ3HTyyckPnNnUb9/DRqduqzLfrQRyi+CdHjdqgsyDpI3Ln5UX1kXnAhPBSJj9pVRzwRFgqkN7p9b6HBDjmu/Q=="], + + "rc-input": ["rc-input@1.8.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-KXvaTbX+7ha8a/k+eg6SYRVERK0NddX8QX7a7AnRvUa/rEH0CNMlpcBzBkhI0wp2C8C4HlMoYl8TImSN+fuHKA=="], + + "rc-input-number": ["rc-input-number@9.5.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/mini-decimal": "1.1.0", "classnames": "2.5.1", "rc-input": "1.8.0", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-bKaEvB5tHebUURAEXw35LDcnRZLq3x1k7GxfAqBMzmpHkDGzjAtnUL8y4y5N15rIFIg5IJgwr211jInl3cipag=="], + + "rc-mentions": ["rc-mentions@2.20.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-input": "1.8.0", "rc-menu": "9.16.1", "rc-textarea": "1.10.2", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-w8HCMZEh3f0nR8ZEd466ATqmXFCMGMN5UFCzEUL0bM/nGw/wOS2GgRzKBcm19K++jDyuWCOJOdgcKGXU3fXfbQ=="], + + "rc-menu": ["rc-menu@9.16.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-overflow": "1.5.0", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ghHx6/6Dvp+fw8CJhDUHFHDJ84hJE3BXNCzSgLdmNiFErWSOaZNsihDAsKq9ByTALo/xkNIwtDFGIl6r+RPXBg=="], + + "rc-motion": ["rc-motion@2.9.5", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-w+XTUrfh7ArbYEd2582uDrEhmBHwK1ZENJiSJVb7uRxdE7qJSYjbO2eksRXmndqyKqKoYPc9ClpPh5242mV1vA=="], + + "rc-notification": ["rc-notification@5.6.4", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-KcS4O6B4qzM3KH7lkwOB7ooLPZ4b6J+VMmQgT51VZCeEcmghdeR4IrMcFq0LG+RPdnbe/ArT086tGM8Snimgiw=="], + + "rc-overflow": ["rc-overflow@1.5.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Lm/v9h0LymeUYJf0x39OveU52InkdRXqnn2aYXfWmo8WdOonIKB2kfau+GF0fWq6jPgtdO9yMqveGcK6aIhJmg=="], + + "rc-pagination": ["rc-pagination@5.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-8416Yip/+eclTFdHXLKTxZvn70duYVGTvUUWbckCCZoIl3jagqke3GLsFrMs0bsQBikiYpZLD9206Ej4SOdOXQ=="], + + "rc-picker": ["rc-picker@4.11.3", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-overflow": "1.5.0", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "optionalDependencies": { "dayjs": "1.11.19" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-MJ5teb7FlNE0NFHTncxXQ62Y5lytq6sh5nUw0iH8OkHL/TjARSEvSHpr940pWgjGANpjCwyMdvsEV55l5tYNSg=="], + + "rc-progress": ["rc-progress@4.0.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-oofVMMafOCokIUIBnZLNcOZFsABaUw8PPrf1/y0ZBvKZNpOiu5h4AO9vv11Sw0p4Hb3D0yGWuEattcQGtNJ/aw=="], + + "rc-rate": ["rc-rate@2.13.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-QUhQ9ivQ8Gy7mtMZPAjLbxBt5y9GRp65VcUyGUMF3N3fhiftivPHdpuDIaWIMOTEprAjZPC08bls1dQB+I1F2Q=="], + + "rc-resize-observer": ["rc-resize-observer@1.4.3", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4", "resize-observer-polyfill": "1.5.1" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-YZLjUbyIWox8E9i9C3Tm7ia+W7euPItNWSPX5sCcQTYbnwDb5uNpnLHQCG1f22oZWUhLw4Mv2tFmeWe68CDQRQ=="], + + "rc-segmented": ["rc-segmented@2.7.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-izj1Nw/Dw2Vb7EVr+D/E9lUTkBe+kKC+SAFSU9zqr7WV2W5Ktaa9Gc7cB2jTqgk8GROJayltaec+DBlYKc6d+g=="], + + "rc-select": ["rc-select@14.16.8", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-overflow": "1.5.0", "rc-util": "5.44.4", "rc-virtual-list": "3.19.2" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-NOV5BZa1wZrsdkKaiK7LHRuo5ZjZYMDxPP6/1+09+FB4KoNi8jcG1ZqLE3AVCxEsYMBe65OBx71wFoHRTP3LRg=="], + + "rc-slider": ["rc-slider@11.1.9", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-h8IknhzSh3FEM9u8ivkskh+Ef4Yo4JRIY2nj7MrH6GQmrwV6mcpJf5/4KgH5JaVI1H3E52yCdpOlVyGZIeph5A=="], + + "rc-steps": ["rc-steps@6.0.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-lKHL+Sny0SeHkQKKDJlAjV5oZ8DwCdS2hFhAkIjuQt1/pB81M0cA0ErVFdHq9+jmPmFw1vJB2F5NBzFXLJxV+g=="], + + "rc-switch": ["rc-switch@4.1.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-TI8ufP2Az9oEbvyCeVE4+90PDSljGyuwix3fV58p7HV2o4wBnVToEyomJRVyTaZeqNPAp+vqeo4Wnj5u0ZZQBg=="], + + "rc-table": ["rc-table@7.54.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/context": "1.4.0", "classnames": "2.5.1", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4", "rc-virtual-list": "3.19.2" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-/wDTkki6wBTjwylwAGjpLKYklKo9YgjZwAU77+7ME5mBoS32Q4nAwoqhA2lSge6fobLW3Tap6uc5xfwaL2p0Sw=="], + + "rc-tabs": ["rc-tabs@15.7.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-dropdown": "4.2.1", "rc-menu": "9.16.1", "rc-motion": "2.9.5", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ZepiE+6fmozYdWf/9gVp7k56PKHB1YYoDsKeQA1CBlJ/POIhjkcYiv0AGP0w2Jhzftd3AVvZP/K+V+Lpi2ankA=="], + + "rc-textarea": ["rc-textarea@1.10.2", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-input": "1.8.0", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-HfaeXiaSlpiSp0I/pvWpecFEHpVysZ9tpDLNkxQbMvMz6gsr7aVZ7FpWP9kt4t7DB+jJXesYS0us1uPZnlRnwQ=="], + + "rc-tooltip": ["rc-tooltip@6.4.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "@rc-component/trigger": "2.3.1", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-kqyivim5cp8I5RkHmpsp1Nn/Wk+1oeloMv9c7LXNgDxUpGm+RbXJGL+OPvDlcRnx9DBeOe4wyOIl4OKUERyH1g=="], + + "rc-tree": ["rc-tree@5.13.1", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-motion": "2.9.5", "rc-util": "5.44.4", "rc-virtual-list": "3.19.2" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-FNhIefhftobCdUJshO7M8uZTA9F4OPGVXqGfZkkD/5soDeOhwO06T/aKTrg0WD8gRg/pyfq+ql3aMymLHCTC4A=="], + + "rc-tree-select": ["rc-tree-select@5.27.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-select": "14.16.8", "rc-tree": "5.13.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-2qTBTzwIT7LRI1o7zLyrCzmo5tQanmyGbSaGTIf7sYimCklAToVVfpMC6OAldSKolcnjorBYPNSKQqJmN3TCww=="], + + "rc-upload": ["rc-upload@4.11.0", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-ZUyT//2JAehfHzjWowqROcwYJKnZkIUGWaTE/VogVrepSl7AFNbQf4+zGfX4zl9Vrj/Jm8scLO0R6UlPDKK4wA=="], + + "rc-util": ["rc-util@5.44.4", "", { "dependencies": { "@babel/runtime": "7.28.6", "react-is": "18.3.1" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-resueRJzmHG9Q6rI/DfK6Kdv9/Lfls05vzMs1Sk3M2P+3cJa+MakaZyWY8IPfehVuhPJFKrIY1IK4GqbiaiY5w=="], + + "rc-virtual-list": ["rc-virtual-list@3.19.2", "", { "dependencies": { "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-resize-observer": "1.4.3", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-Ys6NcjwGkuwkeaWBDqfI3xWuZ7rDiQXlH1o2zLfFzATfEgXcqpk8CkgMfbJD81McqjcJVez25a3kPxCR807evA=="], + + "rcedit": ["rcedit@4.0.1", "", { "dependencies": { "cross-spawn-windows-exe": "^1.1.0" } }, "sha512-bZdaQi34krFWhrDn+O53ccBDw0MkAT2Vhu75SqhtvhQu4OPyFM4RoVheyYiVQYdjhUi6EJMVWQ0tR6bCIYVkUg=="], + + "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="], + + "react-country-flag": ["react-country-flag@3.1.0", "", { "peerDependencies": { "react": "19.2.4" } }, "sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g=="], + + "react-dom": ["react-dom@19.2.4", "", { "dependencies": { "scheduler": "0.27.0" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ=="], + + "react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + + "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "devlop": "1.1.0", "hast-util-to-jsx-runtime": "2.3.6", "html-url-attributes": "3.0.1", "mdast-util-to-hast": "13.2.1", "remark-parse": "11.0.0", "remark-rehype": "11.1.2", "unified": "11.0.5", "unist-util-visit": "5.1.0", "vfile": "6.0.3" }, "peerDependencies": { "@types/react": "19.2.10", "react": "19.2.4" } }, "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ=="], + + "react-redux": ["react-redux@9.3.0", "", { "dependencies": { "@types/use-sync-external-store": "0.0.6", "use-sync-external-store": "1.6.0" }, "optionalDependencies": { "@types/react": "19.2.10", "redux": "5.0.1" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g=="], + + "react-refresh": ["react-refresh@0.18.0", "", {}, "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw=="], + + "react-responsive": ["react-responsive@10.0.1", "", { "dependencies": { "hyphenate-style-name": "1.1.0", "matchmediaquery": "0.4.2", "prop-types": "15.8.1", "shallow-equal": "3.1.0" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-OM5/cRvbtUWEX8le8RCT8scA8y2OPtb0Q/IViEyCEM5FBN8lRrkUOZnu87I88A6njxDldvxG+rLBxWiA7/UM9g=="], + + "react-router": ["react-router@7.13.0", "", { "dependencies": { "cookie": "1.1.1", "set-cookie-parser": "2.7.2" }, "optionalDependencies": { "react-dom": "19.2.4" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-PZgus8ETambRT17BUm/LL8lX3Of+oiLaPuVTRH3l1eLvSPpKO3AvhAEb5N7ihAFZQrYDqkvvWfFh9p0z9VsjLw=="], + + "react-router-dom": ["react-router-dom@7.13.0", "", { "dependencies": { "react-router": "7.13.0" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-5CO/l5Yahi2SKC6rGZ+HDEjpjkGaG/ncEP7eWFTvFxbHP8yeeI0PxTDjimtpXYlR3b3i9/WIL4VJttPrESIf2g=="], + + "read-binary-file-arch": ["read-binary-file-arch@1.0.6", "", { "dependencies": { "debug": "^4.3.4" }, "bin": { "read-binary-file-arch": "cli.js" } }, "sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg=="], + + "read-pkg": ["read-pkg@2.0.0", "", { "dependencies": { "load-json-file": "^2.0.0", "normalize-package-data": "^2.3.2", "path-type": "^2.0.0" } }, "sha512-eFIBOPW7FGjzBuk3hdXEuNSiTZS/xEMlH49HxMyzb0hyPfu4EhVjT2DH32K1hSSmVq4sebAWnZuuY5auISUTGA=="], + + "read-pkg-up": ["read-pkg-up@2.0.0", "", { "dependencies": { "find-up": "^2.0.0", "read-pkg": "^2.0.0" } }, "sha512-1orxQfbWGUiTn9XsPlChs6rLie/AV9jwZTGmu2NZw/CUDJQchXJFYE0Fq5j7+n558T1JhDWLdhyd1Zj+wLY//w=="], + + "readable-stream": ["readable-stream@2.3.8", "", { "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", "isarray": "~1.0.0", "process-nextick-args": "~2.0.0", "safe-buffer": "~5.1.1", "string_decoder": "~1.1.1", "util-deprecate": "~1.0.1" } }, "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA=="], + + "recharts": ["recharts@3.8.1", "", { "dependencies": { "@reduxjs/toolkit": "2.12.0", "clsx": "2.1.1", "decimal.js-light": "2.5.1", "es-toolkit": "1.47.1", "eventemitter3": "5.0.4", "immer": "10.2.0", "react-redux": "9.3.0", "reselect": "5.1.1", "tiny-invariant": "1.3.3", "use-sync-external-store": "1.6.0", "victory-vendor": "37.3.6" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4", "react-is": "18.3.1" } }, "sha512-mwzmO1s9sFL0TduUpwndxCUNoXsBw3u3E/0+A+cLcrSfQitSG62L32N69GhqUrrT5qKcAE3pCGVINC6pqkBBQg=="], + + "redux": ["redux@5.0.1", "", {}, "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w=="], + + "redux-thunk": ["redux-thunk@3.1.0", "", { "peerDependencies": { "redux": "5.0.1" } }, "sha512-NW2r5T6ksUKXCabzhL9z+h206HQw/NJkcLm1GPImRQ8IzfXwRGqjVhKJGauHirT0DAuyy6hjdnMZaRoAcy0Klw=="], + + "reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "get-proto": "1.0.1", "which-builtin-type": "1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="], + + "regexp.prototype.flags": ["regexp.prototype.flags@1.5.4", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-errors": "1.3.0", "get-proto": "1.0.1", "gopd": "1.2.0", "set-function-name": "2.0.2" } }, "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA=="], + + "regexpp": ["regexpp@3.2.0", "", {}, "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="], + + "registry-auth-token": ["registry-auth-token@3.3.2", "", { "dependencies": { "rc": "1.2.8", "safe-buffer": "5.2.1" } }, "sha512-JL39c60XlzCVgNrO+qq68FoNb56w/m7JYvGR2jT5iR1xBrUA3Mfx5Twk5rqTThPmQKMWydGmq8oFtDlxfrmxnQ=="], + + "registry-url": ["registry-url@3.1.0", "", { "dependencies": { "rc": "1.2.8" } }, "sha512-ZbgR5aZEdf4UKZVBPYIgaglBmSF2Hi94s2PcIHhRGFjKYu+chjJdYfHn4rt3hB6eCKLJ8giVIIfgMa1ehDfZKA=="], + + "remark-gfm": ["remark-gfm@4.0.1", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-gfm": "3.1.0", "micromark-extension-gfm": "3.0.0", "remark-parse": "11.0.0", "remark-stringify": "11.0.0", "unified": "11.0.5" } }, "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg=="], + + "remark-parse": ["remark-parse@11.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-from-markdown": "2.0.2", "micromark-util-types": "2.0.2", "unified": "11.0.5" } }, "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA=="], + + "remark-rehype": ["remark-rehype@11.1.2", "", { "dependencies": { "@types/hast": "3.0.4", "@types/mdast": "4.0.4", "mdast-util-to-hast": "13.2.1", "unified": "11.0.5", "vfile": "6.0.3" } }, "sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw=="], + + "remark-stringify": ["remark-stringify@11.0.0", "", { "dependencies": { "@types/mdast": "4.0.4", "mdast-util-to-markdown": "2.1.2", "unified": "11.0.5" } }, "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw=="], + + "require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + + "require-relative": ["require-relative@0.8.7", "", {}, "sha512-AKGr4qvHiryxRb19m3PsLRGuKVAbJLUD7E6eOaHkfKhwc+vSgVOCY5xNvm9EkolBKTOf0GrQAZKLimOCz81Khg=="], + + "resedit": ["resedit@1.7.2", "", { "dependencies": { "pe-library": "^0.4.1" } }, "sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA=="], + + "reselect": ["reselect@5.1.1", "", {}, "sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w=="], + + "resize-observer-polyfill": ["resize-observer-polyfill@1.5.1", "", {}, "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="], + + "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "2.16.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="], + + "resolve-alpn": ["resolve-alpn@1.2.1", "", {}, "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g=="], + + "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + + "responselike": ["responselike@2.0.1", "", { "dependencies": { "lowercase-keys": "^2.0.0" } }, "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw=="], + + "retry": ["retry@0.12.0", "", {}, "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow=="], + + "reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="], + + "rimraf": ["rimraf@3.0.2", "", { "dependencies": { "glob": "7.2.3" }, "bin": { "rimraf": "bin.js" } }, "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="], + + "roarr": ["roarr@2.15.4", "", { "dependencies": { "boolean": "^3.0.1", "detect-node": "^2.0.4", "globalthis": "^1.0.1", "json-stringify-safe": "^5.0.1", "semver-compare": "^1.0.0", "sprintf-js": "^1.1.2" } }, "sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A=="], + + "rollup": ["rollup@4.57.1", "", { "dependencies": { "@types/estree": "1.0.8" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.57.1", "@rollup/rollup-android-arm64": "4.57.1", "@rollup/rollup-darwin-arm64": "4.57.1", "@rollup/rollup-darwin-x64": "4.57.1", "@rollup/rollup-freebsd-arm64": "4.57.1", "@rollup/rollup-freebsd-x64": "4.57.1", "@rollup/rollup-linux-arm-gnueabihf": "4.57.1", "@rollup/rollup-linux-arm-musleabihf": "4.57.1", "@rollup/rollup-linux-arm64-gnu": "4.57.1", "@rollup/rollup-linux-arm64-musl": "4.57.1", "@rollup/rollup-linux-loong64-gnu": "4.57.1", "@rollup/rollup-linux-loong64-musl": "4.57.1", "@rollup/rollup-linux-ppc64-gnu": "4.57.1", "@rollup/rollup-linux-ppc64-musl": "4.57.1", "@rollup/rollup-linux-riscv64-gnu": "4.57.1", "@rollup/rollup-linux-riscv64-musl": "4.57.1", "@rollup/rollup-linux-s390x-gnu": "4.57.1", "@rollup/rollup-linux-x64-gnu": "4.57.1", "@rollup/rollup-linux-x64-musl": "4.57.1", "@rollup/rollup-openbsd-x64": "4.57.1", "@rollup/rollup-openharmony-arm64": "4.57.1", "@rollup/rollup-win32-arm64-msvc": "4.57.1", "@rollup/rollup-win32-ia32-msvc": "4.57.1", "@rollup/rollup-win32-x64-gnu": "4.57.1", "@rollup/rollup-win32-x64-msvc": "4.57.1", "fsevents": "2.3.3" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-oQL6lgK3e2QZeQ7gcgIkS2YZPg5slw37hYufJ3edKlfQSGGm8ICoxswK15ntSzF/a8+h7ekRy7k7oWc3BQ7y8A=="], + + "rollup-plugin-inject": ["rollup-plugin-inject@3.0.2", "", { "dependencies": { "estree-walker": "0.6.1", "magic-string": "0.25.9", "rollup-pluginutils": "2.8.2" } }, "sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w=="], + + "rollup-plugin-node-polyfills": ["rollup-plugin-node-polyfills@0.2.1", "", { "dependencies": { "rollup-plugin-inject": "3.0.2" } }, "sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA=="], + + "rollup-plugin-visualizer": ["rollup-plugin-visualizer@6.0.5", "", { "dependencies": { "open": "8.4.2", "picomatch": "4.0.3", "source-map": "0.7.6", "yargs": "17.7.2" }, "optionalDependencies": { "rollup": "4.57.1" }, "bin": { "rollup-plugin-visualizer": "dist/bin/cli.js" } }, "sha512-9+HlNgKCVbJDs8tVtjQ43US12eqaiHyyiLMdBwQ7vSZPiHMysGNo2E88TAp1si5wx8NAoYriI2A5kuKfIakmJg=="], + + "rollup-pluginutils": ["rollup-pluginutils@2.8.2", "", { "dependencies": { "estree-walker": "0.6.1" } }, "sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ=="], + + "rope-sequence": ["rope-sequence@1.3.4", "", {}, "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "4.4.3", "depd": "2.0.0", "is-promise": "4.0.0", "parseurl": "1.3.3", "path-to-regexp": "8.3.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "1.2.3" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="], + + "rxjs": ["rxjs@7.8.2", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA=="], + + "safe-array-concat": ["safe-array-concat@1.1.3", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "get-intrinsic": "1.3.0", "has-symbols": "1.1.0", "isarray": "2.0.5" } }, "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safe-push-apply": ["safe-push-apply@1.0.0", "", { "dependencies": { "es-errors": "1.3.0", "isarray": "2.0.5" } }, "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA=="], + + "safe-regex-test": ["safe-regex-test@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-regex": "1.2.1" } }, "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "sanitize-filename": ["sanitize-filename@1.6.4", "", { "dependencies": { "truncate-utf8-bytes": "^1.0.0" } }, "sha512-9ZyI08PsvdQl2r/bBIGubpVdR3RR9sY6RDiWFPreA21C/EFlQhmgo20UZlNjZMMZNubusLhAQozkA0Od5J21Eg=="], + + "sax": ["sax@1.4.4", "", {}, "sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw=="], + + "scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="], + + "scroll-into-view-if-needed": ["scroll-into-view-if-needed@3.1.0", "", { "dependencies": { "compute-scroll-into-view": "3.1.1" } }, "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ=="], + + "semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], + + "semver-compare": ["semver-compare@1.0.0", "", {}, "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow=="], + + "send": ["send@1.2.1", "", { "dependencies": { "debug": "4.4.3", "encodeurl": "2.0.0", "escape-html": "1.0.3", "etag": "1.8.1", "fresh": "2.0.0", "http-errors": "2.0.1", "mime-types": "3.0.2", "ms": "2.1.3", "on-finished": "2.4.1", "range-parser": "1.2.1", "statuses": "2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="], + + "serialize-error": ["serialize-error@7.0.1", "", { "dependencies": { "type-fest": "^0.13.1" } }, "sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw=="], + + "serve": ["serve@14.2.5", "", { "dependencies": { "@zeit/schemas": "2.36.0", "ajv": "8.12.0", "arg": "5.0.2", "boxen": "7.0.0", "chalk": "5.0.1", "chalk-template": "0.4.0", "clipboardy": "3.0.0", "compression": "1.8.1", "is-port-reachable": "4.0.0", "serve-handler": "6.1.6", "update-check": "1.5.4" }, "bin": { "serve": "build/main.js" } }, "sha512-Qn/qMkzCcMFVPb60E/hQy+iRLpiU8PamOfOSYoAHmmF+fFFmpPpqa6Oci2iWYpTdOUM3VF+TINud7CfbQnsZbA=="], + + "serve-handler": ["serve-handler@6.1.6", "", { "dependencies": { "bytes": "3.0.0", "content-disposition": "0.5.2", "mime-types": "2.1.18", "minimatch": "3.1.2", "path-is-inside": "1.0.2", "path-to-regexp": "3.3.0", "range-parser": "1.2.0" } }, "sha512-x5RL9Y2p5+Sh3D38Fh9i/iQ5ZK+e4xuXRd/pGbM4D13tgo/MGwbttUk8emytcr1YYzBYs+apnUngBDFYfpjPuQ=="], + + "serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "2.0.0", "escape-html": "1.0.3", "parseurl": "1.3.3", "send": "1.2.1" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="], + + "set-cookie-parser": ["set-cookie-parser@2.7.2", "", {}, "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw=="], + + "set-function-length": ["set-function-length@1.2.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "function-bind": "1.1.2", "get-intrinsic": "1.3.0", "gopd": "1.2.0", "has-property-descriptors": "1.0.2" } }, "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg=="], + + "set-function-name": ["set-function-name@2.0.2", "", { "dependencies": { "define-data-property": "1.1.4", "es-errors": "1.3.0", "functions-have-names": "1.2.3", "has-property-descriptors": "1.0.2" } }, "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ=="], + + "set-proto": ["set-proto@1.0.0", "", { "dependencies": { "dunder-proto": "1.0.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1" } }, "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shallow-equal": ["shallow-equal@3.1.0", "", {}, "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg=="], + + "shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="], + + "sharp": ["sharp@0.33.5", "", { "dependencies": { "color": "4.2.3", "detect-libc": "2.1.2", "semver": "7.7.3" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.33.5", "@img/sharp-darwin-x64": "0.33.5", "@img/sharp-libvips-darwin-arm64": "1.0.4", "@img/sharp-libvips-darwin-x64": "1.0.4", "@img/sharp-libvips-linux-arm": "1.0.5", "@img/sharp-libvips-linux-arm64": "1.0.4", "@img/sharp-libvips-linux-s390x": "1.0.4", "@img/sharp-libvips-linux-x64": "1.0.4", "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", "@img/sharp-libvips-linuxmusl-x64": "1.0.4", "@img/sharp-linux-arm": "0.33.5", "@img/sharp-linux-arm64": "0.33.5", "@img/sharp-linux-s390x": "0.33.5", "@img/sharp-linux-x64": "0.33.5", "@img/sharp-linuxmusl-arm64": "0.33.5", "@img/sharp-linuxmusl-x64": "0.33.5", "@img/sharp-wasm32": "0.33.5", "@img/sharp-win32-ia32": "0.33.5", "@img/sharp-win32-x64": "0.33.5" } }, "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "shell-quote": ["shell-quote@1.8.3", "", {}, "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4", "side-channel-list": "1.0.0", "side-channel-map": "1.0.1", "side-channel-weakmap": "1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "get-intrinsic": "1.3.0", "object-inspect": "1.13.4", "side-channel-map": "1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="], + + "simple-swizzle": ["simple-swizzle@0.2.4", "", { "dependencies": { "is-arrayish": "0.3.4" } }, "sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw=="], + + "simple-update-notifier": ["simple-update-notifier@2.0.0", "", { "dependencies": { "semver": "^7.5.3" } }, "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w=="], + + "simple-xml-to-json": ["simple-xml-to-json@1.2.7", "", {}, "sha512-mz9VXphOxQWX3eQ/uXCtm6upltoN0DLx8Zb5T4TFC4FHB7S9FDPGre8CfLWqPWQQH/GrQYd2AXhhVM5LDpYx6Q=="], + + "simplebar-core": ["simplebar-core@1.3.2", "", { "dependencies": { "lodash": "4.17.23", "lodash-es": "4.17.23" } }, "sha512-qKgTTuTqapjsFGkNhCjyPhysnbZGpQqNmjk0nOYjFN5ordC/Wjvg+RbYCyMSnW60l/Z0ZS82GbNltly6PMUH1w=="], + + "simplebar-react": ["simplebar-react@3.3.2", "", { "dependencies": { "simplebar-core": "1.3.2" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-ZsgcQhKLtt5ra0BRIJeApfkTBQCa1vUPA/WXI4HcYReFt+oCEOvdVz6rR/XsGJcKxTlCRPmdGx1uJIUChupo+A=="], + + "slash": ["slash@3.0.0", "", {}, "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="], + + "smart-buffer": ["smart-buffer@4.2.0", "", {}, "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="], + + "snake-case": ["snake-case@3.0.4", "", { "dependencies": { "dot-case": "3.0.4", "tslib": "2.8.1" } }, "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg=="], + + "socket.io-client": ["socket.io-client@4.8.3", "", { "dependencies": { "@socket.io/component-emitter": "3.1.2", "debug": "4.4.3", "engine.io-client": "6.6.4", "socket.io-parser": "4.2.5" } }, "sha512-uP0bpjWrjQmUt5DTHq9RuoCBdFJF10cdX9X+a368j/Ft0wmaVgxlrjvK3kjvgCODOMMOz9lcaRzxmso0bTWZ/g=="], + + "socket.io-parser": ["socket.io-parser@4.2.5", "", { "dependencies": { "@socket.io/component-emitter": "3.1.2", "debug": "4.4.3" } }, "sha512-bPMmpy/5WWKHea5Y/jYAP6k74A+hvmRCQaJuJB6I/ML5JZq/KfNieUVo/3Mh7SAqn7TyFdIo6wqYHInG1MU1bQ=="], + + "socks": ["socks@2.8.7", "", { "dependencies": { "ip-address": "10.1.0", "smart-buffer": "4.2.0" } }, "sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A=="], + + "socks-proxy-agent": ["socks-proxy-agent@8.0.5", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3", "socks": "2.8.7" } }, "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw=="], + + "source-map": ["source-map@0.7.6", "", {}, "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ=="], + + "source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="], + + "source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "1.1.2", "source-map": "0.6.1" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="], + + "sourcemap-codec": ["sourcemap-codec@1.4.8", "", {}, "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="], + + "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + + "spdx-correct": ["spdx-correct@3.2.0", "", { "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" } }, "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA=="], + + "spdx-exceptions": ["spdx-exceptions@2.5.0", "", {}, "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w=="], + + "spdx-expression-parse": ["spdx-expression-parse@3.0.1", "", { "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" } }, "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="], + + "spdx-license-ids": ["spdx-license-ids@3.0.23", "", {}, "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw=="], + + "sprintf-js": ["sprintf-js@1.1.3", "", {}, "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA=="], + + "stacktracey": ["stacktracey@2.1.8", "", { "dependencies": { "as-table": "1.0.55", "get-source": "2.0.12" } }, "sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw=="], + + "standard": ["standard@17.1.2", "", { "dependencies": { "eslint": "8.57.1", "eslint-config-standard": "17.1.0", "eslint-config-standard-jsx": "11.0.0", "eslint-plugin-import": "2.32.0", "eslint-plugin-n": "15.7.0", "eslint-plugin-promise": "6.6.0", "eslint-plugin-react": "7.37.5", "standard-engine": "15.1.0", "version-guard": "1.1.3" }, "bin": { "standard": "bin/cmd.cjs" } }, "sha512-WLm12WoXveKkvnPnPnaFUUHuOB2cUdAsJ4AiGHL2G0UNMrcRAWY2WriQaV8IQ3oRmYr0AWUbLNr94ekYFAHOrA=="], + + "standard-engine": ["standard-engine@15.1.0", "", { "dependencies": { "get-stdin": "8.0.0", "minimist": "1.2.8", "pkg-conf": "3.1.0", "xdg-basedir": "4.0.0" } }, "sha512-VHysfoyxFu/ukT+9v49d4BRXIokFRZuH3z1VRxzFArZdjSCFpro6rEIU3ji7e4AoAtuSfKBkiOmsrDqKW5ZSRw=="], + + "stat-mode": ["stat-mode@1.0.0", "", {}, "sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "1.3.0", "internal-slot": "1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], + + "stoppable": ["stoppable@1.1.0", "", {}, "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw=="], + + "string-convert": ["string-convert@0.2.1", "", {}, "sha512-u/1tdPl4yQnPBjnVrmdLo9gtuLvELKsAoRapekWggdiQNvvvum+jYF329d84NAa660KQw7pB2n36KrIKVoXa3A=="], + + "string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="], + + "string.prototype.matchall": ["string.prototype.matchall@4.0.12", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-errors": "1.3.0", "es-object-atoms": "1.1.1", "get-intrinsic": "1.3.0", "gopd": "1.2.0", "has-symbols": "1.1.0", "internal-slot": "1.1.0", "regexp.prototype.flags": "1.5.4", "set-function-name": "2.0.2", "side-channel": "1.1.0" } }, "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA=="], + + "string.prototype.repeat": ["string.prototype.repeat@1.0.0", "", { "dependencies": { "define-properties": "1.2.1", "es-abstract": "1.24.1" } }, "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w=="], + + "string.prototype.trim": ["string.prototype.trim@1.2.10", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-data-property": "1.1.4", "define-properties": "1.2.1", "es-abstract": "1.24.1", "es-object-atoms": "1.1.1", "has-property-descriptors": "1.0.2" } }, "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA=="], + + "string.prototype.trimend": ["string.prototype.trimend@1.0.9", "", { "dependencies": { "call-bind": "1.0.8", "call-bound": "1.0.4", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ=="], + + "string.prototype.trimstart": ["string.prototype.trimstart@1.0.8", "", { "dependencies": { "call-bind": "1.0.8", "define-properties": "1.2.1", "es-object-atoms": "1.1.1" } }, "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg=="], + + "string_decoder": ["string_decoder@1.1.1", "", { "dependencies": { "safe-buffer": "~5.1.0" } }, "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="], + + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "2.1.0", "character-entities-legacy": "3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + + "strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + + "strip-bom": ["strip-bom@3.0.0", "", {}, "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA=="], + + "strip-final-newline": ["strip-final-newline@2.0.0", "", {}, "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="], + + "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], + + "strip-outer": ["strip-outer@1.0.1", "", { "dependencies": { "escape-string-regexp": "^1.0.2" } }, "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg=="], + + "strtok3": ["strtok3@10.3.5", "", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA=="], + + "stubborn-fs": ["stubborn-fs@2.0.0", "", { "dependencies": { "stubborn-utils": "^1.0.1" } }, "sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA=="], + + "stubborn-utils": ["stubborn-utils@1.0.2", "", {}, "sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg=="], + + "style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], + + "style-to-js": ["style-to-js@1.1.21", "", { "dependencies": { "style-to-object": "1.0.14" } }, "sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ=="], + + "style-to-object": ["style-to-object@1.0.14", "", { "dependencies": { "inline-style-parser": "0.2.7" } }, "sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw=="], + + "styled-components": ["styled-components@6.3.8", "", { "dependencies": { "@emotion/is-prop-valid": "1.4.0", "@emotion/unitless": "0.10.0", "@types/stylis": "4.2.7", "css-to-react-native": "3.2.0", "csstype": "3.2.3", "postcss": "8.4.49", "shallowequal": "1.1.0", "stylis": "4.3.6", "tslib": "2.8.1" }, "optionalDependencies": { "react-dom": "19.2.4" }, "peerDependencies": { "react": "19.2.4" } }, "sha512-Kq/W41AKQloOqKM39zfaMdJ4BcYDw/N5CIq4/GTI0YjU6pKcZ1KKhk6b4du0a+6RA9pIfOP/eu94Ge7cu+PDCA=="], + + "stylis": ["stylis@4.3.6", "", {}, "sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ=="], + + "sumchecker": ["sumchecker@3.0.1", "", { "dependencies": { "debug": "^4.1.0" } }, "sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg=="], + + "supports-color": ["supports-color@8.1.1", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="], + + "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], + + "svg-parser": ["svg-parser@2.0.4", "", {}, "sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ=="], + + "svgo": ["svgo@4.0.0", "", { "dependencies": { "commander": "11.1.0", "css-select": "5.2.2", "css-tree": "3.1.0", "css-what": "6.2.2", "csso": "5.0.5", "picocolors": "1.1.1", "sax": "1.4.4" }, "bin": "./bin/svgo.js" }, "sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw=="], + + "svgo-loader": ["svgo-loader@4.0.0", "", { "dependencies": { "svgo": "3.3.2" } }, "sha512-bdk2H73AHP8Vo9zgMuA8piEzi5pjFzllK4EwfebDF3hDjmHQpmmqXMoDd6abDtVFrlKTJuveepmnc2kuTdt/WA=="], + + "synckit": ["synckit@0.11.12", "", { "dependencies": { "@pkgr/core": "0.2.9" } }, "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ=="], + + "tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="], + + "tar": ["tar@7.5.22", "", { "dependencies": { "@isaacs/fs-minipass": "^4.0.0", "chownr": "^3.0.0", "minipass": "^7.1.2", "minizlib": "^3.1.0", "yallist": "^5.0.0" } }, "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA=="], + + "temp": ["temp@0.9.4", "", { "dependencies": { "mkdirp": "^0.5.1", "rimraf": "~2.6.2" } }, "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA=="], + + "temp-file": ["temp-file@3.4.0", "", { "dependencies": { "async-exit-hook": "^2.0.1", "fs-extra": "^10.0.0" } }, "sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg=="], + + "terser": ["terser@5.46.0", "", { "dependencies": { "@jridgewell/source-map": "0.3.11", "acorn": "8.17.0", "commander": "2.20.3", "source-map-support": "0.5.21" }, "bin": { "terser": "bin/terser" } }, "sha512-jTwoImyr/QbOWFFso3YoU3ik0jBBDJ6JTOQiy/J2YxVJdZCc+5u7skhNwiOR3FQIygFqVUPHl7qbbxtjW2K3Qg=="], + + "text-table": ["text-table@0.2.0", "", {}, "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw=="], + + "three": ["three@0.179.1", "", {}, "sha512-5y/elSIQbrvKOISxpwXCR4sQqHtGiOI+MKLc3SsBdDXA2hz3Mdp3X59aUp8DyybMa34aeBwbFTpdoLJaUDEWSw=="], + + "throttle-debounce": ["throttle-debounce@5.0.2", "", {}, "sha512-B71/4oyj61iNH0KeCamLuE2rmKuTO5byTOSVwECM5FA7TiAiAW+UqTKZ9ERueC4qvgSttUhdmq1mXC3kJqGX7A=="], + + "tiny-async-pool": ["tiny-async-pool@1.3.0", "", { "dependencies": { "semver": "^5.5.0" } }, "sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA=="], + + "tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="], + + "tinycolor2": ["tinycolor2@1.6.0", "", {}, "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw=="], + + "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "6.5.0", "picomatch": "4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], + + "tmp": ["tmp@0.2.7", "", {}, "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw=="], + + "tmp-promise": ["tmp-promise@3.0.3", "", { "dependencies": { "tmp": "^0.2.0" } }, "sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ=="], + + "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], + + "toggle-selection": ["toggle-selection@1.0.6", "", {}, "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "token-types": ["token-types@6.1.2", "", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="], + + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + + "trim-lines": ["trim-lines@3.0.1", "", {}, "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg=="], + + "trim-repeated": ["trim-repeated@1.0.0", "", { "dependencies": { "escape-string-regexp": "^1.0.2" } }, "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg=="], + + "trough": ["trough@2.2.0", "", {}, "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw=="], + + "truncate-utf8-bytes": ["truncate-utf8-bytes@1.0.2", "", { "dependencies": { "utf8-byte-length": "^1.0.1" } }, "sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ=="], + + "ts-api-utils": ["ts-api-utils@1.4.3", "", { "peerDependencies": { "typescript": "5.9.3" } }, "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw=="], + + "tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "0.0.29", "json5": "1.0.2", "minimist": "1.2.8", "strip-bom": "3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="], + + "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + + "tsparticles": ["tsparticles@3.9.1", "", { "dependencies": { "@tsparticles/engine": "3.9.1", "@tsparticles/interaction-external-trail": "3.9.1", "@tsparticles/plugin-absorbers": "3.9.1", "@tsparticles/plugin-emitters": "3.9.1", "@tsparticles/plugin-emitters-shape-circle": "3.9.1", "@tsparticles/plugin-emitters-shape-square": "3.9.1", "@tsparticles/shape-text": "3.9.1", "@tsparticles/slim": "3.9.1", "@tsparticles/updater-destroy": "3.9.1", "@tsparticles/updater-roll": "3.9.1", "@tsparticles/updater-tilt": "3.9.1", "@tsparticles/updater-twinkle": "3.9.1", "@tsparticles/updater-wobble": "3.9.1" } }, "sha512-Y780IGSL4qjkZj7+fI92PV/cziHqLR/s6nnYri4K6vH3NQRmDK5D6pfskDO8T4Y96ChCWHY3uxPtOb/hKQ83Qg=="], + + "type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="], + + "type-fest": ["type-fest@5.8.0", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA=="], + + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "1.0.5", "media-typer": "1.1.0", "mime-types": "3.0.2" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + + "typed-array-buffer": ["typed-array-buffer@1.0.3", "", { "dependencies": { "call-bound": "1.0.4", "es-errors": "1.3.0", "is-typed-array": "1.1.15" } }, "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw=="], + + "typed-array-byte-length": ["typed-array-byte-length@1.0.3", "", { "dependencies": { "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15" } }, "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg=="], + + "typed-array-byte-offset": ["typed-array-byte-offset@1.0.4", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "has-proto": "1.2.0", "is-typed-array": "1.1.15", "reflect.getprototypeof": "1.0.10" } }, "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ=="], + + "typed-array-length": ["typed-array-length@1.0.7", "", { "dependencies": { "call-bind": "1.0.8", "for-each": "0.3.5", "gopd": "1.2.0", "is-typed-array": "1.1.15", "possible-typed-array-names": "1.1.0", "reflect.getprototypeof": "1.0.10" } }, "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg=="], + + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + + "uc.micro": ["uc.micro@2.1.0", "", {}, "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A=="], + + "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + + "uint8array-extras": ["uint8array-extras@1.5.0", "", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + + "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "1.0.4", "has-bigints": "1.1.0", "has-symbols": "1.1.0", "which-boxed-primitive": "1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], + + "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "2.1.1" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], + + "unenv": ["unenv@2.0.0-rc.14", "", { "dependencies": { "defu": "6.1.4", "exsolve": "1.0.8", "ohash": "2.0.11", "pathe": "2.0.3", "ufo": "1.6.3" } }, "sha512-od496pShMen7nOy5VmVJCnq8rptd45vh6Nx/r2iPbrba6pa6p+tS2ywuIHRZ/OBvSbQZB0kWvpO9XBNVFXHD3Q=="], + + "unified": ["unified@11.0.5", "", { "dependencies": { "@types/unist": "3.0.3", "bail": "2.0.2", "devlop": "1.1.0", "extend": "3.0.2", "is-plain-obj": "4.1.0", "trough": "2.2.0", "vfile": "6.0.3" } }, "sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA=="], + + "unist-util-is": ["unist-util-is@6.0.1", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g=="], + + "unist-util-position": ["unist-util-position@5.0.0", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA=="], + + "unist-util-stringify-position": ["unist-util-stringify-position@4.0.0", "", { "dependencies": { "@types/unist": "3.0.3" } }, "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ=="], + + "unist-util-visit": ["unist-util-visit@5.1.0", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-is": "6.0.1", "unist-util-visit-parents": "6.0.2" } }, "sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg=="], + + "unist-util-visit-parents": ["unist-util-visit-parents@6.0.2", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-is": "6.0.1" } }, "sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ=="], + + "universalify": ["universalify@2.0.1", "", {}, "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "unzipper": ["unzipper@0.12.5", "", { "dependencies": { "bluebird": "~3.7.2", "duplexer2": "~0.1.4", "fs-extra": "11.3.1", "graceful-fs": "^4.2.2", "node-int64": "^0.4.0" } }, "sha512-tXYOi9R57Uj/2Z25SOs5RRSzq886MBQj2gY8dPL+xl/kv6s6SvByoKfAtvfVeEuhntWDgjd2o9p2lb4TVPAz0A=="], + + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "3.2.0", "picocolors": "1.1.1" }, "peerDependencies": { "browserslist": "4.28.1" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], + + "update-check": ["update-check@1.5.4", "", { "dependencies": { "registry-auth-token": "3.3.2", "registry-url": "3.1.0" } }, "sha512-5YHsflzHP4t1G+8WGPlvKbJEbAJGCgw+Em+dGR1KmBUbr1J36SJBqlHLjR7oob7sco5hWHGQVcr9B2poIVDDTQ=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "2.3.1" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "use-merge-value": ["use-merge-value@1.2.0", "", { "peerDependencies": { "react": "19.2.4" } }, "sha512-DXgG0kkgJN45TcyoXL49vJnn55LehnrmoHc7MbKi+QDBvr8dsesqws8UlyIWGHMR+JXgxc1nvY+jDGMlycsUcw=="], + + "use-sync-external-store": ["use-sync-external-store@1.6.0", "", { "peerDependencies": { "react": "19.2.4" } }, "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w=="], + + "utf8-byte-length": ["utf8-byte-length@1.0.5", "", {}, "sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA=="], + + "utif2": ["utif2@4.1.0", "", { "dependencies": { "pako": "^1.0.11" } }, "sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w=="], + + "util-deprecate": ["util-deprecate@1.0.2", "", {}, "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="], + + "validate-npm-package-license": ["validate-npm-package-license@3.0.4", "", { "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" } }, "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "version-guard": ["version-guard@1.1.3", "", {}, "sha512-JwPr6erhX53EWH/HCSzfy1tTFrtPXUe927wdM1jqBBeYp1OM+qPHjWbsvv6pIBduqdgxxS+ScfG7S28pzyr2DQ=="], + + "vfile": ["vfile@6.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "vfile-message": "4.0.3" } }, "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q=="], + + "vfile-message": ["vfile-message@4.0.3", "", { "dependencies": { "@types/unist": "3.0.3", "unist-util-stringify-position": "4.0.0" } }, "sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw=="], + + "victory-vendor": ["victory-vendor@37.3.6", "", { "dependencies": { "@types/d3-array": "3.2.2", "@types/d3-ease": "3.0.2", "@types/d3-interpolate": "3.0.4", "@types/d3-scale": "4.0.9", "@types/d3-shape": "3.1.8", "@types/d3-time": "3.0.4", "@types/d3-timer": "3.0.2", "d3-array": "3.2.4", "d3-ease": "3.0.1", "d3-interpolate": "3.0.1", "d3-scale": "4.0.2", "d3-shape": "3.2.0", "d3-time": "3.1.0", "d3-timer": "3.0.1" } }, "sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ=="], + + "vite": ["vite@7.3.1", "", { "dependencies": { "esbuild": "0.27.2", "fdir": "6.5.0", "picomatch": "4.0.3", "postcss": "8.5.6", "rollup": "4.57.1", "tinyglobby": "0.2.15" }, "optionalDependencies": { "@types/node": "25.2.0", "fsevents": "2.3.3", "jiti": "2.6.1", "terser": "5.46.0" }, "bin": { "vite": "bin/vite.js" } }, "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA=="], + + "vite-plugin-eslint": ["vite-plugin-eslint@1.8.1", "", { "dependencies": { "@rollup/pluginutils": "4.2.1", "@types/eslint": "8.56.12", "rollup": "2.79.2" }, "peerDependencies": { "eslint": "9.39.2", "vite": "7.3.1" } }, "sha512-PqdMf3Y2fLO9FsNPmMX+//2BF5SF8nEWspZdgl4kSt7UvHDRHVVfHvxsD7ULYzZrJDGRxR81Nq7TOFgwMnUang=="], + + "vite-plugin-svgo": ["vite-plugin-svgo@2.0.0", "", { "dependencies": { "svgo": "3.3.2" }, "peerDependencies": { "typescript": "5.9.3", "vite": "7.3.1" } }, "sha512-WaiOUlmt1fKw1w/WWJnx9gVk42D1BASKZmGCPpy6iTLE5iIemN2lim3MwI7Rffyt3aQnPrLfLSLnI8ZUJ9s49g=="], + + "vite-plugin-svgr": ["vite-plugin-svgr@4.5.0", "", { "dependencies": { "@rollup/pluginutils": "5.3.0", "@svgr/core": "8.1.0", "@svgr/plugin-jsx": "8.1.0" }, "peerDependencies": { "vite": "7.3.1" } }, "sha512-W+uoSpmVkSmNOGPSsDCWVW/DDAyv+9fap9AZXBvWiQqrboJ08j2vh0tFxTD/LjwqwAd3yYSVJgm54S/1GhbdnA=="], + + "vue-eslint-parser": ["vue-eslint-parser@9.4.3", "", { "dependencies": { "debug": "4.4.3", "eslint-scope": "7.2.2", "eslint-visitor-keys": "3.4.3", "espree": "9.6.1", "esquery": "1.7.0", "lodash": "4.17.23", "semver": "7.7.3" }, "peerDependencies": { "eslint": "8.57.1" } }, "sha512-2rYRLWlIpaiN8xbPiDyXZXRgLGOtWxERV7ND5fFAv5qo1D2N9Fu9MNajBNc6o13lZ+24DAWCkQCvj4klgmcITg=="], + + "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], + + "web-vitals": ["web-vitals@5.1.0", "", {}, "sha512-ArI3kx5jI0atlTtmV0fWU3fjpLmq/nD3Zr1iFFlJLaqa5wLBkUSzINwBPySCX/8jRyjlmy1Volw1kz1g9XE4Jg=="], + + "webcrypto-core": ["webcrypto-core@1.9.2", "", { "dependencies": { "@peculiar/asn1-schema": "^2.7.0", "@peculiar/json-schema": "^1.1.12", "@peculiar/utils": "^2.0.2", "asn1js": "^3.0.10", "tslib": "^2.8.1" } }, "sha512-gsXecm82UQNlTBURJGuqOWy1Ww08S3kZUcr3aOJS02Pk0xLtkfeUAVC0u0xhgdonFme80edSJUIJyuvL/7250Q=="], + + "when-exit": ["when-exit@2.1.5", "", {}, "sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg=="], + + "which": ["which@5.0.0", "", { "dependencies": { "isexe": "^3.1.1" }, "bin": { "node-which": "bin/which.js" } }, "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ=="], + + "which-boxed-primitive": ["which-boxed-primitive@1.1.1", "", { "dependencies": { "is-bigint": "1.1.0", "is-boolean-object": "1.2.2", "is-number-object": "1.1.1", "is-string": "1.1.1", "is-symbol": "1.1.1" } }, "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA=="], + + "which-builtin-type": ["which-builtin-type@1.2.1", "", { "dependencies": { "call-bound": "1.0.4", "function.prototype.name": "1.1.8", "has-tostringtag": "1.0.2", "is-async-function": "2.1.1", "is-date-object": "1.1.0", "is-finalizationregistry": "1.1.1", "is-generator-function": "1.1.2", "is-regex": "1.2.1", "is-weakref": "1.1.1", "isarray": "2.0.5", "which-boxed-primitive": "1.1.1", "which-collection": "1.0.2", "which-typed-array": "1.1.20" } }, "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q=="], + + "which-collection": ["which-collection@1.0.2", "", { "dependencies": { "is-map": "2.0.3", "is-set": "2.0.3", "is-weakmap": "2.0.2", "is-weakset": "2.0.4" } }, "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw=="], + + "which-typed-array": ["which-typed-array@1.1.20", "", { "dependencies": { "available-typed-arrays": "1.0.7", "call-bind": "1.0.8", "call-bound": "1.0.4", "for-each": "0.3.5", "get-proto": "1.0.1", "gopd": "1.2.0", "has-tostringtag": "1.0.2" } }, "sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg=="], + + "widest-line": ["widest-line@4.0.1", "", { "dependencies": { "string-width": "5.1.2" } }, "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig=="], + + "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], + + "workerd": ["workerd@1.20250718.0", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20250718.0", "@cloudflare/workerd-darwin-arm64": "1.20250718.0", "@cloudflare/workerd-linux-64": "1.20250718.0", "@cloudflare/workerd-linux-arm64": "1.20250718.0", "@cloudflare/workerd-windows-64": "1.20250718.0" }, "bin": { "workerd": "bin/workerd" } }, "sha512-kqkIJP/eOfDlUyBzU7joBg+tl8aB25gEAGqDap+nFWb+WHhnooxjGHgxPBy3ipw2hnShPFNOQt5lFRxbwALirg=="], + + "wrangler": ["wrangler@3.114.17", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", "@cloudflare/unenv-preset": "2.0.2", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@esbuild-plugins/node-modules-polyfill": "0.2.2", "blake3-wasm": "2.1.5", "esbuild": "0.17.19", "miniflare": "3.20250718.3", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.14", "workerd": "1.20250718.0" }, "optionalDependencies": { "fsevents": "2.3.3", "sharp": "0.33.5" }, "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js" } }, "sha512-tAvf7ly+tB+zwwrmjsCyJ2pJnnc7SZhbnNwXbH+OIdVas3zTSmjcZOjmLKcGGptssAA3RyTKhcF9BvKZzMUycA=="], + + "wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "6.2.3", "string-width": "5.1.2", "strip-ansi": "7.1.2" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "ws": ["ws@8.18.0", "", {}, "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw=="], + + "xdg-basedir": ["xdg-basedir@4.0.0", "", {}, "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q=="], + + "xml-parse-from-string": ["xml-parse-from-string@1.0.1", "", {}, "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g=="], + + "xml2js": ["xml2js@0.5.0", "", { "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" } }, "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA=="], + + "xmlbuilder": ["xmlbuilder@15.1.1", "", {}, "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg=="], + + "xmlhttprequest-ssl": ["xmlhttprequest-ssl@2.1.2", "", {}, "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ=="], + + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + + "yallist": ["yallist@5.0.0", "", {}, "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw=="], + + "yaml": ["yaml@1.10.2", "", {}, "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="], + + "yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "8.0.1", "escalade": "3.2.0", "get-caller-file": "2.0.5", "require-directory": "2.1.1", "string-width": "4.2.3", "y18n": "5.0.8", "yargs-parser": "21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="], + + "yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="], + + "yauzl": ["yauzl@2.10.0", "", { "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" } }, "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g=="], + + "yocto-queue": ["yocto-queue@0.1.0", "", {}, "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="], + + "youch": ["youch@3.3.4", "", { "dependencies": { "cookie": "0.7.2", "mustache": "4.2.0", "stacktracey": "2.1.8" } }, "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg=="], + + "zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + + "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + + "@ant-design/colors/@ant-design/fast-color": ["@ant-design/fast-color@3.0.1", "", {}, "sha512-esKJegpW4nckh0o6kV3Tkb7NPIZYbPnnFxmQDUmL08ukXZAvV85TZBr70eGuke/CIArLaP6aw8lt9KILjnWuOw=="], + + "@ant-design/cssinjs/@emotion/unitless": ["@emotion/unitless@0.7.5", "", {}, "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg=="], + + "@babel/core/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-compilation-targets/lru-cache": ["lru-cache@5.1.1", "", { "dependencies": { "yallist": "3.1.1" } }, "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w=="], + + "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@babel/helper-create-class-features-plugin/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@codemirror/autocomplete/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-css/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-go/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-html/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-javascript/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-markdown/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-php/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-python/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-sql/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-xml/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lang-yaml/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@codemirror/lint/crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="], + + "@cspotcode/source-map-support/@jridgewell/trace-mapping": ["@jridgewell/trace-mapping@0.3.9", "", { "dependencies": { "@jridgewell/resolve-uri": "3.1.2", "@jridgewell/sourcemap-codec": "1.5.5" } }, "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ=="], + + "@electron/asar/commander": ["commander@5.1.0", "", {}, "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg=="], + + "@electron/fuses/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@electron/osx-sign/isbinaryfile": ["isbinaryfile@4.0.10", "", {}, "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw=="], + + "@electron/rebuild/@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg=="], + + "@electron/universal/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@electron/windows-sign/fs-extra": ["fs-extra@11.4.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA=="], + + "@emotion/babel-plugin/@emotion/hash": ["@emotion/hash@0.9.2", "", {}, "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="], + + "@emotion/babel-plugin/convert-source-map": ["convert-source-map@1.9.0", "", {}, "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A=="], + + "@emotion/babel-plugin/source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="], + + "@emotion/babel-plugin/stylis": ["stylis@4.2.0", "", {}, "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="], + + "@emotion/cache/stylis": ["stylis@4.2.0", "", {}, "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw=="], + + "@emotion/serialize/@emotion/hash": ["@emotion/hash@0.9.2", "", {}, "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="], + + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], + + "@jimp/js-png/pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="], + + "@lezer/cpp/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/css/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/go/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/highlight/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/html/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/java/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/javascript/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/json/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/lr/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/markdown/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/php/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/python/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/rust/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@lezer/xml/@lezer/common": ["@lezer/common@1.5.0", "", {}, "sha512-PNGcolp9hr4PJdXR4ix7XtixDrClScvtSCYW3rQG106oVMOOI+jFb+0+J3mbeL/53g1Zd6s0kJzaw6Ri68GmAA=="], + + "@malept/flatpak-bundler/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "@rc-component/util/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "@reduxjs/toolkit/immer": ["immer@11.1.8", "", {}, "sha512-/tbkHMW7y10Lx6i1crLjD4/OhNkRG+Fo7byZHtah0547nIeXYcpIXaUh0IAQY6gO5459qpGGYapcEOHtFXkIuA=="], + + "@rollup/pluginutils/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "@svgr/core/camelcase": ["camelcase@6.3.0", "", {}, "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="], + + "@types/cacheable-request/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "@types/eslint/@types/estree": ["@types/estree@1.0.9", "", {}, "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg=="], + + "@types/fs-extra/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "@types/keyv/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "@types/responselike/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "@types/yauzl/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "2.0.2" } }, "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg=="], + + "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "ajv/json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "ajv-formats/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "antd/@ant-design/colors": ["@ant-design/colors@7.2.1", "", { "dependencies": { "@ant-design/fast-color": "2.0.6" } }, "sha512-lCHDcEzieu4GA3n8ELeZ5VQ8pKQAWcGGLRTQ50aQM2iqPpq2evTxER84jfdPvsPAtEcZ7m44NI45edFMo8oOYQ=="], + + "antd/@ant-design/icons": ["@ant-design/icons@5.6.1", "", { "dependencies": { "@ant-design/colors": "7.2.1", "@ant-design/icons-svg": "4.4.2", "@babel/runtime": "7.28.6", "classnames": "2.5.1", "rc-util": "5.44.4" }, "peerDependencies": { "react": "19.2.4", "react-dom": "19.2.4" } }, "sha512-0/xS39c91WjPAZOWsvi1//zjx6kAp4kxWwctR6kuU6p133w8RU0D2dSCvZC19uQyharg/sAvYxGYWl01BbZZfg=="], + + "app-builder-lib/@electron/get": ["@electron/get@3.1.0", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-F+nKc0xW+kVbBRhFzaMgPy3KwmuNTYX1fx6+FxxoSnNgwYX6LD7AKBTWkU0MQ6IBoe7dz069CNkR673sPAgkCQ=="], + + "app-builder-lib/@electron/notarize": ["@electron/notarize@2.5.0", "", { "dependencies": { "debug": "^4.1.1", "fs-extra": "^9.0.1", "promise-retry": "^2.0.1" } }, "sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A=="], + + "app-builder-lib/@electron/universal": ["@electron/universal@2.0.3", "", { "dependencies": { "@electron/asar": "^3.3.1", "@malept/cross-spawn-promise": "^2.0.0", "debug": "^4.3.1", "dir-compare": "^4.2.0", "fs-extra": "^11.1.1", "minimatch": "^9.0.3", "plist": "^3.1.0" } }, "sha512-Wn9sPYIVFRFl5HmwMJkARCCf7rqK/EurkfQ/rJZ14mHP3iYTjZSIOSVonEAnhWeAXwtw7zOekGRlc6yTtZ0t+g=="], + + "app-builder-lib/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "app-builder-lib/ci-info": ["ci-info@4.3.1", "", {}, "sha512-Wdy2Igu8OcBpI2pZePZ5oWjPC38tmDVx5WKUXKwlLYkA0ozo85sLsLvkBbBn/sZaSCMFOGZJ14fvW9t5/d7kdA=="], + + "app-builder-lib/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "app-builder-lib/minimatch": ["minimatch@10.2.6", "", { "dependencies": { "brace-expansion": "^5.0.8" } }, "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A=="], + + "babel-plugin-macros/cosmiconfig": ["cosmiconfig@7.1.0", "", { "dependencies": { "@types/parse-json": "4.0.2", "import-fresh": "3.3.1", "parse-json": "5.2.0", "path-type": "4.0.0", "yaml": "1.10.2" } }, "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA=="], + + "boxen/chalk": ["chalk@5.0.1", "", {}, "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w=="], + + "boxen/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "boxen/type-fest": ["type-fest@2.19.0", "", {}, "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA=="], + + "bun-types/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "chalk/supports-color": ["supports-color@7.2.0", "", { "dependencies": { "has-flag": "4.0.0" } }, "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="], + + "cliui/wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "4.3.0", "string-width": "4.2.3", "strip-ansi": "6.0.1" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="], + + "clone-response/mimic-response": ["mimic-response@1.0.1", "", {}, "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="], + + "compression/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "compression/negotiator": ["negotiator@0.6.4", "", {}, "sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w=="], + + "conf/ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "conf/env-paths": ["env-paths@3.0.0", "", {}, "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A=="], + + "cross-spawn/which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "cross-spawn-windows-exe/which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "1.2.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], + + "dotenv-expand/dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], + + "electrobun/three": ["three@0.165.0", "", {}, "sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA=="], + + "electron-packager/fs-extra": ["fs-extra@11.4.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA=="], + + "electron-packager/rcedit": ["rcedit@3.1.0", "", { "dependencies": { "cross-spawn-windows-exe": "^1.1.0" } }, "sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA=="], + + "electron-publish/mime": ["mime@2.6.0", "", { "bin": { "mime": "cli.js" } }, "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg=="], + + "electron-winstaller/fs-extra": ["fs-extra@7.0.1", "", { "dependencies": { "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw=="], + + "engine.io-client/ws": ["ws@8.18.3", "", {}, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "escodegen/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "eslint-import-resolver-node/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-module-utils/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-es/eslint-utils": ["eslint-utils@2.1.0", "", { "dependencies": { "eslint-visitor-keys": "1.3.0" } }, "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg=="], + + "eslint-plugin-import/debug": ["debug@3.2.7", "", { "dependencies": { "ms": "2.1.3" } }, "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="], + + "eslint-plugin-import/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-plugin-react/resolve": ["resolve@2.0.0-next.5", "", { "dependencies": { "is-core-module": "2.16.1", "path-parse": "1.0.7", "supports-preserve-symlinks-flag": "1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA=="], + + "eslint-plugin-react/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@2.1.0", "", {}, "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="], + + "execa/get-stream": ["get-stream@6.0.1", "", {}, "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="], + + "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "4.0.3" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], + + "filelist/minimatch": ["minimatch@5.1.9", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw=="], + + "form-data/mime-types": ["mime-types@2.1.35", "", { "dependencies": { "mime-db": "1.52.0" } }, "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw=="], + + "gcode-preview/three": ["three@0.159.0", "", {}, "sha512-eCmhlLGbBgucuo4VEA9IO3Qpc7dh8Bd4VKzr7WfW4+8hMcIfoAVi1ev0pJYN9PTTsCslbcKgBwr2wNZ1EvLInA=="], + + "get-package-info/debug": ["debug@2.6.9", "", { "dependencies": { "ms": "2.0.0" } }, "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="], + + "get-source/data-uri-to-buffer": ["data-uri-to-buffer@2.0.2", "", {}, "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA=="], + + "get-source/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "has-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], + + "hosted-git-info/lru-cache": ["lru-cache@6.0.0", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="], + + "image-q/@types/node": ["@types/node@16.9.1", "", {}, "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g=="], + + "load-json-file/parse-json": ["parse-json@4.0.0", "", { "dependencies": { "error-ex": "1.3.4", "json-parse-better-errors": "1.0.2" } }, "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw=="], + + "load-json-file/type-fest": ["type-fest@0.3.1", "", {}, "sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ=="], + + "loglevel-colored-level-prefix/chalk": ["chalk@1.1.3", "", { "dependencies": { "ansi-styles": "2.2.1", "escape-string-regexp": "1.0.5", "has-ansi": "2.0.0", "strip-ansi": "3.0.1", "supports-color": "2.0.0" } }, "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A=="], + + "mdast-util-find-and-replace/escape-string-regexp": ["escape-string-regexp@5.0.0", "", {}, "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw=="], + + "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], + + "miniflare/acorn": ["acorn@8.14.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA=="], + + "miniflare/zod": ["zod@3.22.3", "", {}, "sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug=="], + + "node-gyp/undici": ["undici@6.28.0", "", {}, "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA=="], + + "node-gyp/which": ["which@6.0.1", "", { "dependencies": { "isexe": "^4.0.0" }, "bin": { "node-which": "bin/which.js" } }, "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg=="], + + "normalize-package-data/hosted-git-info": ["hosted-git-info@2.8.9", "", {}, "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="], + + "normalize-package-data/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "online-3d-viewer/three": ["three@0.176.0", "", {}, "sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA=="], + + "parse-entities/@types/unist": ["@types/unist@2.0.11", "", {}, "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="], + + "pkg-conf/find-up": ["find-up@3.0.0", "", { "dependencies": { "locate-path": "3.0.0" } }, "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg=="], + + "pkijs/@noble/hashes": ["@noble/hashes@1.4.0", "", {}, "sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg=="], + + "png-to-ico/@types/node": ["@types/node@17.0.45", "", {}, "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw=="], + + "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "postject/commander": ["commander@9.5.0", "", {}, "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ=="], + + "prettier-eslint/eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/eslintrc": "2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "0.13.0", "@humanwhocodes/module-importer": "1.0.1", "@nodelib/fs.walk": "1.2.8", "@ungap/structured-clone": "1.3.0", "ajv": "6.12.6", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "doctrine": "3.0.0", "escape-string-regexp": "4.0.0", "eslint-scope": "7.2.2", "eslint-visitor-keys": "3.4.3", "espree": "9.6.1", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "6.0.1", "find-up": "5.0.0", "glob-parent": "6.0.2", "globals": "13.24.0", "graphemer": "1.4.0", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "is-path-inside": "3.0.3", "js-yaml": "4.1.1", "json-stable-stringify-without-jsonify": "1.0.1", "levn": "0.4.1", "lodash.merge": "4.6.2", "minimatch": "3.1.2", "natural-compare": "1.4.0", "optionator": "0.9.4", "strip-ansi": "6.0.1", "text-table": "0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="], + + "pretty-format/ansi-styles": ["ansi-styles@5.2.0", "", {}, "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="], + + "pretty-format/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "prosemirror-menu/crelt": ["crelt@1.0.6", "", {}, "sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g=="], + + "rc/strip-json-comments": ["strip-json-comments@2.0.1", "", {}, "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ=="], + + "rc-util/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "react-router/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + + "read-pkg/load-json-file": ["load-json-file@2.0.0", "", { "dependencies": { "graceful-fs": "^4.1.2", "parse-json": "^2.2.0", "pify": "^2.0.0", "strip-bom": "^3.0.0" } }, "sha512-3p6ZOGNbiX4CdvEd1VcE6yi78UrGNpjHO33noGwHCnT/o2fyllJDepsm8+mFFv/DvtwFHht5HIHSyOy5a+ChVQ=="], + + "read-pkg/path-type": ["path-type@2.0.0", "", { "dependencies": { "pify": "^2.0.0" } }, "sha512-dUnb5dXUf+kzhC/W/F4e5/SkluXIFf5VUHolW1Eg1irn1hGWjPGdsRcvYJ1nD6lhk8Ir7VM0bHJKsYTx8Jx9OQ=="], + + "read-pkg-up/find-up": ["find-up@2.1.0", "", { "dependencies": { "locate-path": "^2.0.0" } }, "sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ=="], + + "readable-stream/isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="], + + "readable-stream/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "recharts/react-is": ["react-is@18.3.1", "", {}, "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg=="], + + "rollup-plugin-inject/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="], + + "rollup-pluginutils/estree-walker": ["estree-walker@0.6.1", "", {}, "sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w=="], + + "router/path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="], + + "serialize-error/type-fest": ["type-fest@0.13.1", "", {}, "sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg=="], + + "serve/ajv": ["ajv@8.12.0", "", { "dependencies": { "fast-deep-equal": "3.1.3", "json-schema-traverse": "1.0.0", "require-from-string": "2.0.2", "uri-js": "4.4.1" } }, "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA=="], + + "serve/chalk": ["chalk@5.0.1", "", {}, "sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w=="], + + "serve-handler/bytes": ["bytes@3.0.0", "", {}, "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw=="], + + "serve-handler/content-disposition": ["content-disposition@0.5.2", "", {}, "sha512-kRGRZw3bLlFISDBgwTSA1TMBFN6J6GWDeubmDE3AF+3+yXL8hTWv8r5rkLbqYXY4RjPk/EzHnClI3zQf1cFmHA=="], + + "serve-handler/mime-types": ["mime-types@2.1.18", "", { "dependencies": { "mime-db": "1.33.0" } }, "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ=="], + + "serve-handler/path-to-regexp": ["path-to-regexp@3.3.0", "", {}, "sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw=="], + + "serve-handler/range-parser": ["range-parser@1.2.0", "", {}, "sha512-kA5WQoNVo4t9lNx2kQNFCxKeBl5IbbSNBl1M/tLkw9WCn+hxNBAW5Qh8gdhs63CJnhjJ2zQWFoqPJP2sK1AV5A=="], + + "simple-swizzle/is-arrayish": ["is-arrayish@0.3.4", "", {}, "sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA=="], + + "source-map-support/source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="], + + "standard/eslint": ["eslint@8.57.1", "", { "dependencies": { "@eslint-community/eslint-utils": "4.9.1", "@eslint-community/regexpp": "4.12.2", "@eslint/eslintrc": "2.1.4", "@eslint/js": "8.57.1", "@humanwhocodes/config-array": "0.13.0", "@humanwhocodes/module-importer": "1.0.1", "@nodelib/fs.walk": "1.2.8", "@ungap/structured-clone": "1.3.0", "ajv": "6.12.6", "chalk": "4.1.2", "cross-spawn": "7.0.6", "debug": "4.4.3", "doctrine": "3.0.0", "escape-string-regexp": "4.0.0", "eslint-scope": "7.2.2", "eslint-visitor-keys": "3.4.3", "espree": "9.6.1", "esquery": "1.7.0", "esutils": "2.0.3", "fast-deep-equal": "3.1.3", "file-entry-cache": "6.0.1", "find-up": "5.0.0", "glob-parent": "6.0.2", "globals": "13.24.0", "graphemer": "1.4.0", "ignore": "5.3.2", "imurmurhash": "0.1.4", "is-glob": "4.0.3", "is-path-inside": "3.0.3", "js-yaml": "4.1.1", "json-stable-stringify-without-jsonify": "1.0.1", "levn": "0.4.1", "lodash.merge": "4.6.2", "minimatch": "3.1.2", "natural-compare": "1.4.0", "optionator": "0.9.4", "strip-ansi": "6.0.1", "text-table": "0.2.0" }, "bin": { "eslint": "bin/eslint.js" } }, "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA=="], + + "string_decoder/safe-buffer": ["safe-buffer@5.1.2", "", {}, "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="], + + "strip-outer/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "styled-components/postcss": ["postcss@8.4.49", "", { "dependencies": { "nanoid": "3.3.11", "picocolors": "1.1.1", "source-map-js": "1.2.1" } }, "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA=="], + + "svgo-loader/svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "7.2.0", "css-select": "5.2.2", "css-tree": "2.3.1", "css-what": "6.2.2", "csso": "5.0.5", "picocolors": "1.1.1" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="], + + "temp/rimraf": ["rimraf@2.6.3", "", { "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "./bin.js" } }, "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA=="], + + "terser/acorn": ["acorn@8.17.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg=="], + + "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], + + "tiny-async-pool/semver": ["semver@5.7.2", "", { "bin": { "semver": "bin/semver" } }, "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g=="], + + "trim-repeated/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "tsconfig-paths/json5": ["json5@1.0.2", "", { "dependencies": { "minimist": "1.2.8" }, "bin": { "json5": "lib/cli.js" } }, "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA=="], + + "unzipper/fs-extra": ["fs-extra@11.3.1", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g=="], + + "vite/@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], + + "vite-plugin-eslint/@types/eslint": ["@types/eslint@8.56.12", "", { "dependencies": { "@types/estree": "1.0.8", "@types/json-schema": "7.0.15" } }, "sha512-03ruubjWyOHlmljCVoxSuNDdmfZDzsrrz0P2LeJsOXr+ZwFQ+0yQIwNCwt/GYhV7Z31fgtXJTAEs+FYlEL851g=="], + + "vite-plugin-eslint/rollup": ["rollup@2.79.2", "", { "optionalDependencies": { "fsevents": "2.3.3" }, "bin": { "rollup": "dist/bin/rollup" } }, "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ=="], + + "vite-plugin-svgo/svgo": ["svgo@3.3.2", "", { "dependencies": { "@trysound/sax": "0.2.0", "commander": "7.2.0", "css-select": "5.2.2", "css-tree": "2.3.1", "css-what": "6.2.2", "csso": "5.0.5", "picocolors": "1.1.1" }, "bin": "./bin/svgo" }, "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw=="], + + "vite-plugin-svgr/@rollup/pluginutils": ["@rollup/pluginutils@5.3.0", "", { "dependencies": { "@types/estree": "1.0.8", "estree-walker": "2.0.2", "picomatch": "4.0.3" }, "optionalDependencies": { "rollup": "4.57.1" } }, "sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q=="], + + "vue-eslint-parser/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], + + "vue-eslint-parser/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "vue-eslint-parser/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "8.15.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "3.4.3" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], + + "widest-line/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "wrangler/esbuild": ["esbuild@0.17.19", "", { "optionalDependencies": { "@esbuild/android-arm": "0.17.19", "@esbuild/android-arm64": "0.17.19", "@esbuild/android-x64": "0.17.19", "@esbuild/darwin-arm64": "0.17.19", "@esbuild/darwin-x64": "0.17.19", "@esbuild/freebsd-arm64": "0.17.19", "@esbuild/freebsd-x64": "0.17.19", "@esbuild/linux-arm": "0.17.19", "@esbuild/linux-arm64": "0.17.19", "@esbuild/linux-ia32": "0.17.19", "@esbuild/linux-loong64": "0.17.19", "@esbuild/linux-mips64el": "0.17.19", "@esbuild/linux-ppc64": "0.17.19", "@esbuild/linux-riscv64": "0.17.19", "@esbuild/linux-s390x": "0.17.19", "@esbuild/linux-x64": "0.17.19", "@esbuild/netbsd-x64": "0.17.19", "@esbuild/openbsd-x64": "0.17.19", "@esbuild/sunos-x64": "0.17.19", "@esbuild/win32-arm64": "0.17.19", "@esbuild/win32-ia32": "0.17.19", "@esbuild/win32-x64": "0.17.19" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw=="], + + "wrap-ansi/ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + + "wrap-ansi/string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="], + + "wrap-ansi/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "6.2.2" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "xml2js/xmlbuilder": ["xmlbuilder@11.0.1", "", {}, "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA=="], + + "@babel/helper-compilation-targets/lru-cache/yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], + + "@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="], + + "@esbuild-plugins/node-globals-polyfill/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="], + + "@esbuild-plugins/node-modules-polyfill/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="], + + "@types/cacheable-request/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@types/fs-extra/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@types/keyv/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@types/responselike/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@types/yauzl/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "app-builder-lib/@electron/get/fs-extra": ["fs-extra@8.1.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", "universalify": "^0.1.0" } }, "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g=="], + + "app-builder-lib/@electron/get/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + + "app-builder-lib/@electron/notarize/fs-extra": ["fs-extra@9.1.0", "", { "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="], + + "app-builder-lib/@electron/universal/@malept/cross-spawn-promise": ["@malept/cross-spawn-promise@2.0.0", "", { "dependencies": { "cross-spawn": "^7.0.1" } }, "sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg=="], + + "app-builder-lib/@electron/universal/dir-compare": ["dir-compare@4.2.0", "", { "dependencies": { "minimatch": "^3.0.5", "p-limit": "^3.1.0 " } }, "sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ=="], + + "app-builder-lib/@electron/universal/fs-extra": ["fs-extra@11.4.0", "", { "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" } }, "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA=="], + + "app-builder-lib/@electron/universal/minimatch": ["minimatch@9.0.3", "", { "dependencies": { "brace-expansion": "2.0.2" } }, "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg=="], + + "app-builder-lib/minimatch/brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], + + "boxen/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "boxen/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "6.2.2" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "bun-types/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "compression/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "cross-spawn-windows-exe/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "cross-spawn/which/isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "csso/css-tree/mdn-data": ["mdn-data@2.0.28", "", {}, "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g=="], + + "electron-winstaller/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "electron-winstaller/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "eslint-plugin-es/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@1.3.0", "", {}, "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="], + + "filelist/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "form-data/mime-types/mime-db": ["mime-db@1.52.0", "", {}, "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="], + + "get-package-info/debug/ms": ["ms@2.0.0", "", {}, "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="], + + "hosted-git-info/lru-cache/yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="], + + "loglevel-colored-level-prefix/chalk/ansi-styles": ["ansi-styles@2.2.1", "", {}, "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA=="], + + "loglevel-colored-level-prefix/chalk/escape-string-regexp": ["escape-string-regexp@1.0.5", "", {}, "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="], + + "loglevel-colored-level-prefix/chalk/strip-ansi": ["strip-ansi@3.0.1", "", { "dependencies": { "ansi-regex": "2.1.1" } }, "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg=="], + + "loglevel-colored-level-prefix/chalk/supports-color": ["supports-color@2.0.0", "", {}, "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g=="], + + "node-gyp/which/isexe": ["isexe@4.0.0", "", {}, "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw=="], + + "pkg-conf/find-up/locate-path": ["locate-path@3.0.0", "", { "dependencies": { "p-locate": "3.0.0", "path-exists": "3.0.0" } }, "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A=="], + + "prettier-eslint/eslint/@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "6.12.6", "debug": "4.4.3", "espree": "9.6.1", "globals": "13.24.0", "ignore": "5.3.2", "import-fresh": "3.3.1", "js-yaml": "4.1.1", "minimatch": "3.1.2", "strip-json-comments": "3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], + + "prettier-eslint/eslint/@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], + + "prettier-eslint/eslint/doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="], + + "prettier-eslint/eslint/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], + + "prettier-eslint/eslint/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "prettier-eslint/eslint/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "8.15.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "3.4.3" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], + + "prettier-eslint/eslint/file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "3.2.0" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="], + + "prettier-eslint/eslint/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="], + + "read-pkg-up/find-up/locate-path": ["locate-path@2.0.0", "", { "dependencies": { "p-locate": "^2.0.0", "path-exists": "^3.0.0" } }, "sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA=="], + + "read-pkg/load-json-file/parse-json": ["parse-json@2.2.0", "", { "dependencies": { "error-ex": "^1.2.0" } }, "sha512-QR/GGaKCkhwk1ePQNYDRKYZ3mwU9ypsKhB0XyFnLQdomyEqk3e8wpW3V5Jp88zbxK4n5ST1nqo+g9juTpownhQ=="], + + "read-pkg/load-json-file/pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + + "read-pkg/path-type/pify": ["pify@2.3.0", "", {}, "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog=="], + + "serve-handler/mime-types/mime-db": ["mime-db@1.33.0", "", {}, "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="], + + "standard/eslint/@eslint/eslintrc": ["@eslint/eslintrc@2.1.4", "", { "dependencies": { "ajv": "6.12.6", "debug": "4.4.3", "espree": "9.6.1", "globals": "13.24.0", "ignore": "5.3.2", "import-fresh": "3.3.1", "js-yaml": "4.1.1", "minimatch": "3.1.2", "strip-json-comments": "3.1.1" } }, "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ=="], + + "standard/eslint/@eslint/js": ["@eslint/js@8.57.1", "", {}, "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q=="], + + "standard/eslint/doctrine": ["doctrine@3.0.0", "", { "dependencies": { "esutils": "2.0.3" } }, "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="], + + "standard/eslint/eslint-scope": ["eslint-scope@7.2.2", "", { "dependencies": { "esrecurse": "4.3.0", "estraverse": "5.3.0" } }, "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg=="], + + "standard/eslint/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], + + "standard/eslint/espree": ["espree@9.6.1", "", { "dependencies": { "acorn": "8.15.0", "acorn-jsx": "5.3.2", "eslint-visitor-keys": "3.4.3" } }, "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ=="], + + "standard/eslint/file-entry-cache": ["file-entry-cache@6.0.1", "", { "dependencies": { "flat-cache": "3.2.0" } }, "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="], + + "standard/eslint/globals": ["globals@13.24.0", "", { "dependencies": { "type-fest": "0.20.2" } }, "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ=="], + + "styled-components/postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], + + "svgo-loader/svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "svgo-loader/svgo/css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "1.2.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], + + "vite-plugin-svgo/svgo/commander": ["commander@7.2.0", "", {}, "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="], + + "vite-plugin-svgo/svgo/css-tree": ["css-tree@2.3.1", "", { "dependencies": { "mdn-data": "2.0.30", "source-map-js": "1.2.1" } }, "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw=="], + + "vite/@types/node/undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + + "widest-line/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "widest-line/string-width/strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "6.2.2" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="], + + "wrangler/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.17.19", "", { "os": "android", "cpu": "arm" }, "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A=="], + + "wrangler/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.17.19", "", { "os": "android", "cpu": "arm64" }, "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA=="], + + "wrangler/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.17.19", "", { "os": "android", "cpu": "x64" }, "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww=="], + + "wrangler/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.17.19", "", { "os": "darwin", "cpu": "arm64" }, "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg=="], + + "wrangler/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.17.19", "", { "os": "darwin", "cpu": "x64" }, "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw=="], + + "wrangler/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.17.19", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ=="], + + "wrangler/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.17.19", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ=="], + + "wrangler/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.17.19", "", { "os": "linux", "cpu": "arm" }, "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA=="], + + "wrangler/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.17.19", "", { "os": "linux", "cpu": "arm64" }, "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg=="], + + "wrangler/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.17.19", "", { "os": "linux", "cpu": "ia32" }, "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ=="], + + "wrangler/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ=="], + + "wrangler/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A=="], + + "wrangler/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.17.19", "", { "os": "linux", "cpu": "ppc64" }, "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg=="], + + "wrangler/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.17.19", "", { "os": "linux", "cpu": "none" }, "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA=="], + + "wrangler/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.17.19", "", { "os": "linux", "cpu": "s390x" }, "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q=="], + + "wrangler/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.17.19", "", { "os": "linux", "cpu": "x64" }, "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw=="], + + "wrangler/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.17.19", "", { "os": "none", "cpu": "x64" }, "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q=="], + + "wrangler/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.17.19", "", { "os": "openbsd", "cpu": "x64" }, "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g=="], + + "wrangler/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.17.19", "", { "os": "sunos", "cpu": "x64" }, "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg=="], + + "wrangler/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.17.19", "", { "os": "win32", "cpu": "arm64" }, "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag=="], + + "wrangler/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.17.19", "", { "os": "win32", "cpu": "ia32" }, "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw=="], + + "wrangler/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.17.19", "", { "os": "win32", "cpu": "x64" }, "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA=="], + + "wrap-ansi/string-width/emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="], + + "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "app-builder-lib/@electron/get/fs-extra/jsonfile": ["jsonfile@4.0.0", "", { "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg=="], + + "app-builder-lib/@electron/get/fs-extra/universalify": ["universalify@0.1.2", "", {}, "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="], + + "app-builder-lib/@electron/universal/dir-compare/minimatch": ["minimatch@3.1.2", "", { "dependencies": { "brace-expansion": "1.1.12" } }, "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw=="], + + "app-builder-lib/@electron/universal/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "1.0.2" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], + + "app-builder-lib/minimatch/brace-expansion/balanced-match": ["balanced-match@4.0.4", "", {}, "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA=="], + + "boxen/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "loglevel-colored-level-prefix/chalk/strip-ansi/ansi-regex": ["ansi-regex@2.1.1", "", {}, "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="], + + "pkg-conf/find-up/locate-path/p-locate": ["p-locate@3.0.0", "", { "dependencies": { "p-limit": "2.3.0" } }, "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ=="], + + "pkg-conf/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + + "prettier-eslint/eslint/file-entry-cache/flat-cache": ["flat-cache@3.2.0", "", { "dependencies": { "flatted": "3.3.3", "keyv": "4.5.4", "rimraf": "3.0.2" } }, "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw=="], + + "prettier-eslint/eslint/globals/type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], + + "read-pkg-up/find-up/locate-path/p-locate": ["p-locate@2.0.0", "", { "dependencies": { "p-limit": "^1.1.0" } }, "sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg=="], + + "read-pkg-up/find-up/locate-path/path-exists": ["path-exists@3.0.0", "", {}, "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ=="], + + "standard/eslint/file-entry-cache/flat-cache": ["flat-cache@3.2.0", "", { "dependencies": { "flatted": "3.3.3", "keyv": "4.5.4", "rimraf": "3.0.2" } }, "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw=="], + + "standard/eslint/globals/type-fest": ["type-fest@0.20.2", "", {}, "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="], + + "svgo-loader/svgo/css-tree/mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], + + "vite-plugin-svgo/svgo/css-tree/mdn-data": ["mdn-data@2.0.30", "", {}, "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="], + + "widest-line/string-width/strip-ansi/ansi-regex": ["ansi-regex@6.2.2", "", {}, "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg=="], + + "pkg-conf/find-up/locate-path/p-locate/p-limit": ["p-limit@2.3.0", "", { "dependencies": { "p-try": "2.2.0" } }, "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="], + + "read-pkg-up/find-up/locate-path/p-locate/p-limit": ["p-limit@1.3.0", "", { "dependencies": { "p-try": "^1.0.0" } }, "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="], + + "pkg-conf/find-up/locate-path/p-locate/p-limit/p-try": ["p-try@2.2.0", "", {}, "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="], + } +} diff --git a/electrobun.config.ts b/electrobun.config.ts new file mode 100644 index 0000000..89e9a27 --- /dev/null +++ b/electrobun.config.ts @@ -0,0 +1,88 @@ +import type { ElectrobunConfig } from "electrobun"; +import { readFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.dirname(fileURLToPath(import.meta.url)); +const packageJson = JSON.parse( + readFileSync(path.join(rootDir, "package.json"), "utf8"), +); +const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "dev"; +const isStable = buildEnv === "stable"; +const canCodesign = Boolean(process.env.ELECTROBUN_DEVELOPER_ID); +const bundleCEF = ["1", "true", "yes"].includes( + String(process.env.ELECTROBUN_BUNDLE_CEF || "").toLowerCase(), +); +const defaultRenderer = bundleCEF ? "cef" : "native"; +const targetOs = + process.env.ELECTROBUN_OS || + (process.platform === "darwin" + ? "macos" + : process.platform === "win32" + ? "win" + : "linux"); + +export default { + app: { + name: "Farm Control", + identifier: "com.tombutcher.farmcontrol", + version: packageJson.version, + description: "3D Printer ERP and Control Software.", + urlSchemes: ["farmcontrol"], + }, + runtime: { + exitOnLastWindowClosed: true, + }, + build: { + buildFolder: "build", + artifactFolder: "app_dist", + // macOS WebKit loads views:// assets reliably from a flat app folder; + // ASAR-packed views can fail to load module scripts on first launch. + useAsar: isStable && targetOs !== "macos", + asarUnpack: [ + "*.node", + "*.dll", + "*.dylib", + "*.so", + "views/**", + ], + bun: { + entrypoint: "src/bun/index.js", + }, + copy: { + "dist/mainview": "views/mainview", + "src/bun/libMacWindowEffects.dylib": "bun/libMacWindowEffects.dylib", + }, + watch: ["scripts", "src"], + watchIgnore: ["dist/**", "build/**", "app_dist/**"], + mac: { + bundleCEF, + defaultRenderer, + icons: "assets/icon.iconset", + createDmg: false, + codesign: isStable && canCodesign, + notarize: isStable && canCodesign, + }, + linux: { + bundleCEF: false, + defaultRenderer: "native", + icon: "assets/icon.png", + }, + win: { + bundleCEF, + defaultRenderer, + icon: "assets/icon.iconset/icon_256x256.png", + }, + }, + scripts: { + preBuild: "scripts/pre-build.mjs", + postWrap: "scripts/expand-macos-bundle.mjs", + postPackage: "scripts/finalize-desktop-artifacts.mjs", + }, + release: { + baseUrl: + process.env.ELECTROBUN_RELEASE_BASE_URL || + process.env.RELEASE_BASE_URL || + "", + }, +} satisfies ElectrobunConfig; diff --git a/native/macos/window-effects.mm b/native/macos/window-effects.mm new file mode 100644 index 0000000..04ddaac --- /dev/null +++ b/native/macos/window-effects.mm @@ -0,0 +1,515 @@ +#import +#import + +static NSString *const kElectrobunVibrancyViewIdentifier = + @"ElectrobunVibrancyView"; +static NSString *const kElectrobunNativeDragViewIdentifier = + @"ElectrobunNativeDragView"; +static NSString *const kElectrobunWindowBorderViewIdentifier = + @"ElectrobunWindowBorderView"; + +static CGFloat gWindowCornerRadius = 15.0; +static CGFloat gTrafficLightsX = 16.0; +static CGFloat gTrafficLightsY = 12.0; + +static const void *kElectrobunChromeObserverKey = &kElectrobunChromeObserverKey; + +@interface ElectrobunWindowBorderView : NSView +@property(nonatomic) CGFloat cornerRadius; +@end + +@implementation ElectrobunWindowBorderView +@synthesize cornerRadius = _cornerRadius; + +- (instancetype)initWithFrame:(NSRect)frameRect { + self = [super initWithFrame:frameRect]; + if (self) { + _cornerRadius = gWindowCornerRadius; + } + return self; +} + +- (BOOL)isOpaque { + return NO; +} + +- (BOOL)acceptsFirstMouse:(NSEvent *)event { + (void)event; + return NO; +} + +- (NSView *)hitTest:(NSPoint)point { + (void)point; + return nil; +} + +- (void)setFrame:(NSRect)frame { + [super setFrame:frame]; + [self setNeedsDisplay:YES]; +} + +- (void)drawRect:(NSRect)dirtyRect { + (void)dirtyRect; + + NSRect bounds = [self bounds]; + CGFloat radius = MAX(0.0, self.cornerRadius); + NSBezierPath *borderPath = [NSBezierPath + bezierPathWithRoundedRect:NSInsetRect(bounds, 0.5, 0.5) + xRadius:radius + yRadius:radius]; + + if (@available(macOS 10.14, *)) { + NSAppearance *appearance = [self effectiveAppearance]; + BOOL isDark = + [[appearance bestMatchFromAppearancesWithNames:@[ + NSAppearanceNameAqua, NSAppearanceNameDarkAqua + ]] isEqualToString:NSAppearanceNameDarkAqua]; + + if (isDark) { + [[NSColor colorWithWhite:1.0 alpha:0.18] setStroke]; + } else { + [[NSColor colorWithWhite:1.0 alpha:0.72] setStroke]; + } + } else { + [[NSColor colorWithWhite:1.0 alpha:0.72] setStroke]; + } + + borderPath.lineWidth = 1.0; + [borderPath stroke]; +} +@end + +@interface ElectrobunNativeDragView : NSView +@end + +@implementation ElectrobunNativeDragView +- (BOOL)isOpaque { + return NO; +} + +- (void)drawRect:(NSRect)dirtyRect { + (void)dirtyRect; +} + +- (void)mouseDown:(NSEvent *)event { + NSWindow *window = [self window]; + if (window != nil && event != nil) { + [window performWindowDragWithEvent:event]; + } +} +@end + +@interface ElectrobunWindowChromeObserver : NSObject +@property(nonatomic, weak) NSWindow *window; +@end + +static bool applyTrafficLightsPosition(NSWindow *window, CGFloat x, + CGFloat yFromTop); +static void refreshWindowChrome(NSWindow *window); +static BOOL isWindowFullScreen(NSWindow *window); + +@implementation ElectrobunWindowChromeObserver + +- (instancetype)initWithWindow:(NSWindow *)window { + self = [super init]; + if (self) { + _window = window; + NSNotificationCenter *center = [NSNotificationCenter defaultCenter]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowDidResizeNotification + object:window]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowDidEndLiveResizeNotification + object:window]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowDidEnterFullScreenNotification + object:window]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowDidExitFullScreenNotification + object:window]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowDidBecomeKeyNotification + object:window]; + [center addObserver:self + selector:@selector(refreshChrome) + name:NSWindowWillEnterFullScreenNotification + object:window]; + } + return self; +} + +- (void)refreshChrome { + if (self.window != nil) { + refreshWindowChrome(self.window); + applyTrafficLightsPosition(self.window, gTrafficLightsX, gTrafficLightsY); + } +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +@end + +static NSVisualEffectView *findVibrancyView(NSView *contentView) { + for (NSView *subview in [contentView subviews]) { + if ([subview isKindOfClass:[NSVisualEffectView class]] && + [[subview identifier] + isEqualToString:kElectrobunVibrancyViewIdentifier]) { + return (NSVisualEffectView *)subview; + } + } + + return nil; +} + +static ElectrobunNativeDragView *findNativeDragView(NSView *contentView) { + for (NSView *subview in [contentView subviews]) { + if ([subview isKindOfClass:[ElectrobunNativeDragView class]] && + [[subview identifier] + isEqualToString:kElectrobunNativeDragViewIdentifier]) { + return (ElectrobunNativeDragView *)subview; + } + } + + return nil; +} + +static ElectrobunWindowBorderView *findWindowBorderView(NSView *contentView) { + for (NSView *subview in [contentView subviews]) { + if ([subview isKindOfClass:[ElectrobunWindowBorderView class]] && + [[subview identifier] + isEqualToString:kElectrobunWindowBorderViewIdentifier]) { + return (ElectrobunWindowBorderView *)subview; + } + } + + return nil; +} + +static BOOL isWindowFullScreen(NSWindow *window) { + return (window.styleMask & NSWindowStyleMaskFullScreen) != 0; +} + +static void refreshWindowChrome(NSWindow *window) { + BOOL fullScreen = isWindowFullScreen(window); + CGFloat radius = fullScreen ? 0.0 : gWindowCornerRadius; + + NSView *contentView = [window contentView]; + if (contentView == nil) { + return; + } + + contentView.wantsLayer = YES; + contentView.layer.cornerRadius = radius; + contentView.layer.masksToBounds = YES; + + NSVisualEffectView *effectView = findVibrancyView(contentView); + if (effectView != nil) { + effectView.wantsLayer = YES; + effectView.layer.cornerRadius = radius; + effectView.layer.masksToBounds = YES; + } + + ElectrobunWindowBorderView *borderView = findWindowBorderView(contentView); + if (borderView != nil) { + borderView.hidden = fullScreen; + if (!fullScreen) { + borderView.cornerRadius = gWindowCornerRadius; + [borderView setNeedsDisplay:YES]; + } + } +} + +static void applyWindowCornerRadius(NSWindow *window, CGFloat radius) { + gWindowCornerRadius = MAX(0.0, radius); + refreshWindowChrome(window); +} + +static void ensureWindowBorder(NSWindow *window) { + NSView *contentView = [window contentView]; + if (contentView == nil) { + return; + } + + ElectrobunWindowBorderView *borderView = findWindowBorderView(contentView); + if (borderView == nil) { + borderView = [[ElectrobunWindowBorderView alloc] + initWithFrame:[contentView bounds]]; + [borderView setIdentifier:kElectrobunWindowBorderViewIdentifier]; + [borderView + setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + } + + [borderView setFrame:[contentView bounds]]; + + if ([borderView superview] == nil) { + [contentView addSubview:borderView + positioned:NSWindowAbove + relativeTo:nil]; + } else { + [borderView removeFromSuperview]; + [contentView addSubview:borderView + positioned:NSWindowAbove + relativeTo:nil]; + } + + refreshWindowChrome(window); +} + +static bool applyTrafficLightsPosition(NSWindow *window, CGFloat x, + CGFloat yFromTop) { + NSButton *closeButton = [window standardWindowButton:NSWindowCloseButton]; + NSButton *minimizeButton = + [window standardWindowButton:NSWindowMiniaturizeButton]; + NSButton *zoomButton = [window standardWindowButton:NSWindowZoomButton]; + + if (closeButton == nil || minimizeButton == nil || zoomButton == nil) { + return false; + } + + NSView *buttonContainer = [closeButton superview]; + if (buttonContainer == nil) { + return false; + } + + CGFloat spacing = NSMinX(minimizeButton.frame) - NSMinX(closeButton.frame); + if (spacing <= 0) { + spacing = closeButton.frame.size.width + 6.0; + } + + BOOL flipped = [buttonContainer isFlipped]; + CGFloat targetY = yFromTop; + if (!flipped) { + targetY = buttonContainer.frame.size.height - yFromTop - + closeButton.frame.size.height; + } + targetY = MAX(0.0, targetY); + + CGFloat currentX = x; + NSArray *buttons = @[ closeButton, minimizeButton, zoomButton ]; + for (NSButton *button in buttons) { + [button setAutoresizingMask:NSViewNotSizable]; + [button setFrameOrigin:NSMakePoint(currentX, targetY)]; + currentX += spacing; + } + + return true; +} + +static void ensureTrafficLightsObserver(NSWindow *window) { + ElectrobunWindowChromeObserver *existingObserver = + objc_getAssociatedObject(window, kElectrobunChromeObserverKey); + if (existingObserver != nil) { + return; + } + + ElectrobunWindowChromeObserver *observer = + [[ElectrobunWindowChromeObserver alloc] initWithWindow:window]; + objc_setAssociatedObject(window, kElectrobunChromeObserverKey, observer, + OBJC_ASSOCIATION_RETAIN_NONATOMIC); +} + +static void scheduleTrafficLightsPosition(NSWindow *window, NSInteger attempt) { + if (applyTrafficLightsPosition(window, gTrafficLightsX, gTrafficLightsY)) { + return; + } + + if (attempt >= 10) { + return; + } + + dispatch_after( + dispatch_time(DISPATCH_TIME_NOW, (int64_t)(50 * NSEC_PER_MSEC)), + dispatch_get_main_queue(), ^{ + scheduleTrafficLightsPosition(window, attempt + 1); + }); +} + +extern "C" bool enableWindowVibrancy(void *windowPtr, double cornerRadius) { + if (windowPtr == nullptr) { + return false; + } + + __block BOOL success = NO; + dispatch_sync(dispatch_get_main_queue(), ^{ + NSWindow *window = (__bridge NSWindow *)windowPtr; + if (![window isKindOfClass:[NSWindow class]]) { + return; + } + + applyWindowCornerRadius(window, (CGFloat)cornerRadius); + + [window setOpaque:NO]; + [window setBackgroundColor:[NSColor clearColor]]; + [window setTitlebarAppearsTransparent:YES]; + [window setHasShadow:YES]; + + NSView *contentView = [window contentView]; + if (contentView == nil) { + return; + } + + NSVisualEffectView *effectView = findVibrancyView(contentView); + + if (effectView == nil) { + effectView = [[NSVisualEffectView alloc] + initWithFrame:[contentView bounds]]; + [effectView setIdentifier:kElectrobunVibrancyViewIdentifier]; + [effectView + setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; + } + + if (@available(macOS 10.14, *)) { + [effectView setMaterial:NSVisualEffectMaterialHUDWindow]; + } else { + [effectView setMaterial:NSVisualEffectMaterialSidebar]; + } + [effectView setBlendingMode:NSVisualEffectBlendingModeBehindWindow]; + [effectView setState:NSVisualEffectStateActive]; + + if ([effectView superview] == nil) { + NSView *relativeView = [[contentView subviews] firstObject]; + if (relativeView != nil) { + [contentView addSubview:effectView + positioned:NSWindowBelow + relativeTo:relativeView]; + } else { + [contentView addSubview:effectView]; + } + } + + ensureWindowBorder(window); + applyWindowCornerRadius(window, gWindowCornerRadius); + ensureTrafficLightsObserver(window); + scheduleTrafficLightsPosition(window, 0); + + [window invalidateShadow]; + success = YES; + }); + + return success; +} + +extern "C" bool setWindowCornerRadius(void *windowPtr, double cornerRadius) { + if (windowPtr == nullptr) { + return false; + } + + __block BOOL success = NO; + dispatch_sync(dispatch_get_main_queue(), ^{ + NSWindow *window = (__bridge NSWindow *)windowPtr; + if (![window isKindOfClass:[NSWindow class]]) { + return; + } + + applyWindowCornerRadius(window, (CGFloat)cornerRadius); + ensureWindowBorder(window); + [window invalidateShadow]; + success = YES; + }); + + return success; +} + +extern "C" bool ensureWindowShadow(void *windowPtr) { + if (windowPtr == nullptr) { + return false; + } + + __block BOOL success = NO; + dispatch_sync(dispatch_get_main_queue(), ^{ + NSWindow *window = (__bridge NSWindow *)windowPtr; + if (![window isKindOfClass:[NSWindow class]]) { + return; + } + + [window setHasShadow:YES]; + [window invalidateShadow]; + ensureWindowBorder(window); + applyWindowCornerRadius(window, gWindowCornerRadius); + success = YES; + }); + + return success; +} + +extern "C" bool setWindowTrafficLightsPosition(void *windowPtr, double x, + double yFromTop) { + if (windowPtr == nullptr) { + return false; + } + + __block BOOL success = NO; + dispatch_sync(dispatch_get_main_queue(), ^{ + NSWindow *window = (__bridge NSWindow *)windowPtr; + if (![window isKindOfClass:[NSWindow class]]) { + return; + } + + gTrafficLightsX = (CGFloat)x; + gTrafficLightsY = (CGFloat)yFromTop; + ensureTrafficLightsObserver(window); + success = applyTrafficLightsPosition(window, gTrafficLightsX, gTrafficLightsY); + if (success) { + [window invalidateShadow]; + } + }); + + return success; +} + +extern "C" bool setNativeWindowDragRegion(void *windowPtr, double x, + double height) { + if (windowPtr == nullptr) { + return false; + } + + __block BOOL success = NO; + dispatch_sync(dispatch_get_main_queue(), ^{ + NSWindow *window = (__bridge NSWindow *)windowPtr; + if (![window isKindOfClass:[NSWindow class]]) { + return; + } + + NSView *contentView = [window contentView]; + if (contentView == nil) { + return; + } + + CGFloat dragX = MAX(0.0, x); + CGFloat dragHeight = MAX(0.0, height); + CGFloat dragWidth = MAX(0.0, contentView.bounds.size.width - dragX); + if (dragHeight <= 0.0 || dragWidth <= 0.0) { + return; + } + + BOOL flipped = [contentView isFlipped]; + CGFloat dragY = flipped ? 0.0 : contentView.bounds.size.height - dragHeight; + dragY = MAX(0.0, dragY); + + ElectrobunNativeDragView *dragView = findNativeDragView(contentView); + if (dragView == nil) { + dragView = [[ElectrobunNativeDragView alloc] initWithFrame:NSZeroRect]; + [dragView setIdentifier:kElectrobunNativeDragViewIdentifier]; + } + + [dragView setFrame:NSMakeRect(dragX, dragY, dragWidth, dragHeight)]; + [dragView setAutoresizingMask:NSViewWidthSizable]; + + if ([dragView superview] == nil) { + [contentView addSubview:dragView + positioned:NSWindowAbove + relativeTo:nil]; + } + + success = YES; + }); + + return success; +} diff --git a/package.json b/package.json index cfc4550..24442c1 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "name": "Tom Butcher", "email": "tom@tombutcher.work" }, - "version": "0.1.0", + "version": "0.1.1", "type": "module", "private": true, "homepage": "./", @@ -71,10 +71,7 @@ "remark-gfm": "^4.0.1", "simplebar-react": "^3.3.2", "socket.io-client": "*", - "standard": "^17.1.2", "styled-components": "^6.1.19", - "svgo": "^4.0.0", - "svgo-loader": "^4.0.0", "three": "^0.179.1", "tsparticles": "^3.9.1", "web-vitals": "^5.1.0" @@ -83,13 +80,21 @@ "description": "3D Printer ERP and Control Software.", "scripts": { "dev": "cross-env NODE_ENV=development vite", + "dev:app": "concurrently \"cross-env NODE_ENV=development bun run dev:renderer\" \"cross-env NODE_ENV=development electrobun dev\"", + "dev:renderer": "vite --port 5780 --no-open", "electron": "cross-env ELECTRON_START_URL=http://0.0.0.0:5780 && cross-env NODE_ENV=development && electron .", "start": "serve -s build", "build": "vite build", + "build:app": "electrobun build --env=stable", + "build:app:mac": "bun scripts/build-macos.mjs", "dev:electron": "concurrently \"cross-env NODE_ENV=development vite --port 5780 --no-open\" \"cross-env ELECTRON_START_URL=http://localhost:5780 NODE_ENV=development electron public/electron.js\"", "build:electron": "vite build && electron-builder", "build:cloudflare": "cross-env VITE_DEPLOY_TARGET=cloudflare vite build", - "deploy": "npm run build:cloudflare && wrangler pages deploy --branch main" + "deploy": "npm run build:cloudflare && wrangler pages deploy --branch main", + "postinstall": "bun scripts/patch-electrobun-src.mjs && bun scripts/build-macos-effects.mjs", + "generate-app-icons": "bun scripts/generate-app-icons.mjs", + "build:macos-effects": "bun scripts/build-macos-effects.mjs", + "clean": "bun scripts/clean-build.mjs" }, "eslintConfig": { "extends": [ @@ -113,7 +118,10 @@ "@eslint/js": "^9.39.2", "@vitejs/plugin-react": "^5.0.2", "concurrently": "^9.2.1", + "electrobun": "1.18.1", "electron": "^38.7.1", + "jimp": "^1.6.1", + "png-to-ico": "^2.1.8", "electron-builder": "^26.0.12", "electron-packager": "^17.1.2", "eslint": "^9.34.0", @@ -126,6 +134,7 @@ "globals": "^15.12.0", "prettier": "^3.6.2", "prettier-eslint": "^16.4.2", + "rcedit": "^4.0.1", "rollup-plugin-visualizer": "^6.0.5", "serve": "^14.2.4", "standard": "^17.1.2", @@ -237,13 +246,13 @@ "oneClick": false, "allowToChangeInstallationDirectory": true, "include": "scripts/installer.nsh", - "perMachine": true + "perMachine": false }, "msiWrapped": { "upgradeCode": "{735812DB-E33B-57A0-8FBC-5FC3155925AA}", - "perMachine": true, - "impersonate": false, - "wrappedInstallerArgs": "/S" + "perMachine": false, + "impersonate": true, + "wrappedInstallerArgs": "/S /UPDATE /RESTARTFC" } } } diff --git a/packaging/macos/dmg/volicon.icns b/packaging/macos/dmg/volicon.icns new file mode 100644 index 0000000..f3f5cfa Binary files /dev/null and b/packaging/macos/dmg/volicon.icns differ diff --git a/packaging/windows/farmcontrol.nsi b/packaging/windows/farmcontrol.nsi new file mode 100644 index 0000000..2b8d1f6 --- /dev/null +++ b/packaging/windows/farmcontrol.nsi @@ -0,0 +1,148 @@ +!include "MUI2.nsh" +!include "LogicLib.nsh" +!include "installer.nsh" + +!ifndef OUTFILE + !define OUTFILE "farmcontrol-installer.exe" +!endif + +!ifndef VERSION + !define VERSION "0.1.0" +!endif + +!ifndef BUILD_NUMBER + !define BUILD_NUMBER "dev" +!endif + +!ifndef APP_SOURCE_DIR + !define APP_SOURCE_DIR "app" +!endif + +!ifndef APP_FILE_LIST_GENERATOR + !define APP_FILE_LIST_GENERATOR "..\..\scripts\generate-nsis-file-list.ps1" +!endif + +; Enumerate APP_SOURCE_DIR now, while compiling, so the generated installer +; knows the exact unpacked byte total and can log each extracted file. +!insertmacro compileProgressFileCopy "${APP_SOURCE_DIR}" "${APP_FILE_LIST_GENERATOR}" + +Name "Farm Control" +OutFile "${OUTFILE}" +InstallDir "$LOCALAPPDATA\Programs\Farm Control" +InstallDirRegKey HKCU "Software\Tom Butcher\Farm Control" "InstallDir" +RequestExecutionLevel user +SilentInstall normal + +!define MUI_ABORTWARNING + +!ifndef INSTALLER_ICON + !define INSTALLER_ICON "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico" +!endif + +!ifndef UNINSTALLER_ICON + !define UNINSTALLER_ICON "${INSTALLER_ICON}" +!endif + +!define MUI_ICON "${INSTALLER_ICON}" +!define MUI_UNICON "${UNINSTALLER_ICON}" + +Icon "${INSTALLER_ICON}" +UninstallIcon "${UNINSTALLER_ICON}" + +BrandingText "Farm Control v${VERSION}-b${BUILD_NUMBER} Installer" + +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_LANGUAGE "English" + +Function .onInit + !insertmacro initProgressLog + + ${If} ${Silent} + SetAutoClose true + ${EndIf} + + !insertmacro progressPhase "Starting installation" + !insertmacro progressStatus "Starting Farm Control installation..." + !insertmacro progressCopyTotal "${APP_COPY_TOTAL_BYTES}" + !insertmacro progressStart + + ; In-app updates install into Farm Control.new while the running process + ; keeps using Farm Control; the folders are swapped after exit (/RESTARTFC). + ; Interactive / silent fresh installs still remove the previous version first. + ${If} $IsInAppUpdate == "1" + !insertmacro prepareSideBySideUpdate + ${Else} + StrCpy $FinalInstDir $INSTDIR + !insertmacro uninstallPreviousFarmControl + ${EndIf} + + !insertmacro progressPrepare +FunctionEnd + +Function .onInstFailed + !insertmacro progressFailure "Installation failed." +FunctionEnd + +Function .onInstSuccess + Call restartFarmControlAfterUpdate +FunctionEnd + +Section "Farm Control" SecMain + SectionIn RO + + !insertmacro progressPhase "Copying application files" + !insertmacro progressStatus "Copying application files..." + !insertmacro progressCopyStart + + SetOverwrite try + !insertmacro copyApplicationFilesWithProgress + + !insertmacro progressCopyComplete + !insertmacro customInstall + + !insertmacro progressFinalizeInstall + !insertmacro progressPhase "Finalizing installation" + !insertmacro progressStatus "Writing installation registry entries..." + + WriteRegStr HKCU "Software\Tom Butcher\Farm Control" "InstallDir" $FinalInstDir + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "DisplayName" "Farm Control" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "DisplayVersion" "${VERSION}" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "Publisher" "Tom Butcher" + WriteRegStr HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "UninstallString" "$FinalInstDir\Uninstall.exe" + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "NoModify" 1 + WriteRegDWORD HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" \ + "NoRepair" 1 + + !insertmacro progressWriteUninstaller + !insertmacro progressStatus "Writing uninstall information..." + + WriteUninstaller "$INSTDIR\Uninstall.exe" + + !insertmacro progressFinalize + + + ; For in-app updates (/RESTARTFC) the success signal is emitted from + ; restartFarmControlAfterUpdate, right before the install directory swap, + ; so the running app quits while this installer stays alive. + ${If} $RestartAfterInstall != "1" + !insertmacro progressSuccess + ${EndIf} +SectionEnd + +Section "Uninstall" + !insertmacro customUnInstall + + Delete "$INSTDIR\Uninstall.exe" + RMDir /r "$INSTDIR" + + DeleteRegKey HKCU "Software\Tom Butcher\Farm Control" + DeleteRegKey HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" +SectionEnd diff --git a/packaging/windows/installer.nsh b/packaging/windows/installer.nsh new file mode 100644 index 0000000..4e273ea --- /dev/null +++ b/packaging/windows/installer.nsh @@ -0,0 +1,460 @@ +!include "FileFunc.nsh" +!insertmacro GetParameters +!insertmacro GetOptions + +Var ProgressLogFile +Var IsInAppUpdate +Var RestartAfterInstall +Var FinalInstDir +Var UpdateParentPid + +; Generate an include at compile time that defines APP_COPY_TOTAL_BYTES and +; copyApplicationFilesWithProgress. The generated macro contains one File +; command and one byte-progress log entry for every file in the source tree. +!macro compileProgressFileCopy sourceDir generator + !tempfile GENERATED_FILE_COPY_INCLUDE + !system 'powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "${generator}" -SourceDir "${sourceDir}" -OutputPath "${GENERATED_FILE_COPY_INCLUDE}"' = 0 + !include "${GENERATED_FILE_COPY_INCLUDE}" + !delfile "${GENERATED_FILE_COPY_INCLUDE}" + !undef GENERATED_FILE_COPY_INCLUDE +!macroend + +!macro initProgressLog + StrCpy $ProgressLogFile "" + StrCpy $IsInAppUpdate "0" + StrCpy $RestartAfterInstall "0" + StrCpy $FinalInstDir "" + StrCpy $UpdateParentPid "0" + + ${GetParameters} $R9 + + ClearErrors + ${GetOptions} $R9 "/UPDATE" $R8 + ${IfNot} ${Errors} + StrCpy $IsInAppUpdate "1" + ${EndIf} + + ClearErrors + ${GetOptions} $R9 "/RESTARTFC" $R8 + ${IfNot} ${Errors} + StrCpy $RestartAfterInstall "1" + ${EndIf} + + ClearErrors + ${GetOptions} $R9 "/PARENTPID=" $R8 + ${IfNot} ${Errors} + ; Convert to an integer before it is used in Win32 calls or taskkill. + IntOp $UpdateParentPid $R8 + 0 + ${EndIf} + + ; Prefer env var so paths with spaces are reliable; /LOG= remains supported. + ReadEnvStr $ProgressLogFile "FARMCONTROL_INSTALL_LOG" + ${If} $ProgressLogFile == "" + ClearErrors + ${GetOptions} $R9 "/LOG=" $ProgressLogFile + ${If} ${Errors} + StrCpy $ProgressLogFile "" + ${EndIf} + ${EndIf} + + ${If} $ProgressLogFile != "" + ; Strip surrounding quotes from /LOG="C:\path with spaces\log.log" + StrCpy $R8 $ProgressLogFile 1 + ${If} $R8 == '"' + StrCpy $ProgressLogFile $ProgressLogFile "" 1 + StrLen $R8 $ProgressLogFile + IntOp $R8 $R8 - 1 + ${If} $R8 > 0 + StrCpy $ProgressLogFile $ProgressLogFile $R8 + ${EndIf} + ${EndIf} + + ; Truncate any previous log so progress starts clean. + Push $0 + FileOpen $0 "$ProgressLogFile" w + ${If} $0 != "" + FileClose $0 + ${EndIf} + Pop $0 + ${EndIf} +!macroend + +; Open/append/close each line so the updater can read the log concurrently +; (avoids an exclusive lock for the whole install; LogEx SHARE_READ is an alternative). +!macro progressLog line + DetailPrint "${line}" + ${If} $ProgressLogFile != "" + Push $0 + FileOpen $0 "$ProgressLogFile" a + ${If} $0 != "" + FileSeek $0 0 END + FileWrite $0 "${line}$\r$\n" + FileClose $0 + ${EndIf} + Pop $0 + ${EndIf} +!macroend + +!define PROGRESS_START 1 +!define PREPARE_PROGRESS 3 +!define COPY_PROGRESS_START 5 +!define COPY_PROGRESS_END 90 +!define CONFIGURE_PROGRESS 91 +!define SHORTCUTS_PROGRESS 93 +!define FINALIZE_PROGRESS 95 +!define UNINSTALLER_PROGRESS 97 +!define COMPLETE_PROGRESS 99 + +!macro progressPercent percent + !insertmacro progressLog "installer:%${percent}" +!macroend + +!macro progressStart + !insertmacro progressPercent "${PROGRESS_START}" +!macroend + +!macro progressPrepare + !insertmacro progressPercent "${PREPARE_PROGRESS}" +!macroend + +!macro progressCopyStart + !insertmacro progressPercent "${COPY_PROGRESS_START}" +!macroend + +!macro progressCopyComplete + !insertmacro progressPercent "${COPY_PROGRESS_END}" +!macroend + +!macro progressConfigure + !insertmacro progressPercent "${CONFIGURE_PROGRESS}" +!macroend + +!macro progressShortcuts + !insertmacro progressPercent "${SHORTCUTS_PROGRESS}" +!macroend + +!macro progressFinalizeInstall + !insertmacro progressPercent "${FINALIZE_PROGRESS}" +!macroend + +!macro progressWriteUninstaller + !insertmacro progressPercent "${UNINSTALLER_PROGRESS}" +!macroend + +!macro progressFinalize + !insertmacro progressPercent "${COMPLETE_PROGRESS}" +!macroend + +!macro progressPhase phase + !insertmacro progressLog "installer:PHASE:${phase}" +!macroend + +!macro progressStatus status + !insertmacro progressLog "installer:STATUS:${status}" +!macroend + +!macro progressCopyTotal bytes + !insertmacro progressLog "installer:COPY_TOTAL:${bytes}" +!macroend + +!macro progressCopyFile bytes relativePath + !insertmacro progressLog "installer:COPY_FILE:${bytes}:${relativePath}" +!macroend + +!macro progressSuccess + !insertmacro progressPercent 100 + !insertmacro progressStatus "Installation complete. Restarting Farm Control..." + !insertmacro progressLog "installer: The install was successful." +!macroend + +!macro progressFailure message + !insertmacro progressLog "installer:STATUS:${message}" + !insertmacro progressLog "installer: The install failed." +!macroend + +!macro quitFarmControl + !insertmacro progressPhase "Stopping Farm Control" + !insertmacro progressStatus "Stopping running Farm Control processes..." + DetailPrint "Stopping running Farm Control processes..." + ExecWait 'taskkill /F /IM FarmControl.exe /T' $R0 + ExecWait 'taskkill /F /IM launcher.exe /T' $R0 +!macroend + +; Side-by-side update: install into Farm Control.new while the running app +; keeps using Farm Control, then swap folders after the process exits. +!macro prepareSideBySideUpdate + !insertmacro progressPhase "Preparing update" + !insertmacro progressStatus "Preparing staging folder for update..." + + StrCpy $FinalInstDir $INSTDIR + StrCpy $INSTDIR "$FinalInstDir.new" + + ${If} ${FileExists} "$INSTDIR" + DetailPrint "Removing leftover staging folder..." + RMDir /r "$INSTDIR" + ${EndIf} +!macroend + +; Swap order: Farm Control -> .old, Farm Control.new -> Farm Control, delete .old. +!macro swapUpdateStaging + !insertmacro progressPhase "Applying update" + !insertmacro progressStatus "Replacing Farm Control with the new version..." + DetailPrint "Replacing Farm Control with staged update..." + + ; The install section ran SetOutPath into the install tree; a directory that + ; is any process's working directory cannot be renamed, so move out first. + SetOutPath "$TEMP" + + Sleep 3000 + + ; Clear a leftover .old from a previous interrupted update. + ${If} ${FileExists} "$FinalInstDir.old" + DetailPrint "Removing leftover Farm Control.old..." + RMDir /r "$FinalInstDir.old" + ${EndIf} + + ${If} ${FileExists} "$FinalInstDir" + !insertmacro progressStatus "Waiting for Farm Control to release install files..." + DetailPrint "Waiting to rename install directory to Farm Control.old..." + + ; Retry every 500ms; success is verified on disk rather than via the + ; error flag, which Rename does not set reliably. + StrCpy $R7 0 + swap_rename_old_retry: + Rename "$FinalInstDir" "$FinalInstDir.old" + ${IfNot} ${FileExists} "$FinalInstDir" + Goto swap_rename_old_done + ${EndIf} + IntOp $R7 $R7 + 1 + ${If} $R7 < 120 + Sleep 500 + Goto swap_rename_old_retry + ${EndIf} + !insertmacro progressFailure "Could not move the previous Farm Control installation aside." + Abort + swap_rename_old_done: + DetailPrint "Install directory renamed to Farm Control.old" + ${EndIf} + + !insertmacro progressStatus "Activating new Farm Control installation..." + DetailPrint "Renaming Farm Control.new to Farm Control..." + + StrCpy $R7 0 + swap_rename_new_retry: + Rename "$INSTDIR" "$FinalInstDir" + ${If} ${FileExists} "$FinalInstDir" + Goto swap_rename_new_done + ${EndIf} + IntOp $R7 $R7 + 1 + ${If} $R7 < 20 + Sleep 500 + Goto swap_rename_new_retry + ${EndIf} + ; Best-effort rollback so the previous install is usable again. + ${If} ${FileExists} "$FinalInstDir.old" + Rename "$FinalInstDir.old" "$FinalInstDir" + ${EndIf} + !insertmacro progressFailure "Could not activate the new Farm Control installation." + Abort + swap_rename_new_done: + + StrCpy $INSTDIR $FinalInstDir + !insertmacro progressLog "installer:STATUS:Update files activated" + + ${If} ${FileExists} "$FinalInstDir.old" + !insertmacro progressStatus "Removing previous Farm Control installation..." + DetailPrint "Removing Farm Control.old..." + + StrCpy $R7 0 + swap_delete_old_retry: + RMDir /r "$FinalInstDir.old" + ${If} ${FileExists} "$FinalInstDir.old" + IntOp $R7 $R7 + 1 + ${If} $R7 < 20 + Sleep 500 + Goto swap_delete_old_retry + ${EndIf} + ; New version is already active; leftover .old is non-fatal. + DetailPrint "Warning: could not fully remove Farm Control.old" + !insertmacro progressLog "installer:STATUS:Warning: could not fully remove previous installation" + ${EndIf} + ${EndIf} +!macroend + +!macro uninstallPreviousFarmControl + ClearErrors + ReadRegStr $R0 HKCU "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString" + StrCmp $R0 "" check_install_dir run_uninstall + + check_install_dir: + ReadRegStr $R0 HKCU "Software\Tom Butcher\Farm Control" "InstallDir" + StrCmp $R0 "" check_legacy_uninstall + StrCpy $R0 "$R0\Uninstall.exe" + Goto run_uninstall + + check_legacy_uninstall: + ReadRegStr $R0 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Farm Control" "UninstallString" + StrCmp $R0 "" check_legacy_install_dir run_uninstall + + check_legacy_install_dir: + ReadRegStr $R0 HKLM "Software\Tom Butcher\Farm Control" "InstallDir" + StrCmp $R0 "" check_default_dir + StrCpy $R0 "$R0\Uninstall.exe" + Goto run_uninstall + + check_default_dir: + StrCpy $R0 "$LOCALAPPDATA\Programs\Farm Control\Uninstall.exe" + IfFileExists $R0 run_uninstall check_legacy_default_dir + + check_legacy_default_dir: + StrCpy $R0 "$PROGRAMFILES64\Farm Control\Uninstall.exe" + IfFileExists $R0 run_uninstall done_uninstall + + run_uninstall: + IfFileExists $R0 0 done_uninstall + !insertmacro progressPhase "Removing previous version" + !insertmacro progressStatus "Removing previous Farm Control installation..." + DetailPrint "Removing previous Farm Control installation..." + !insertmacro quitFarmControl + ExecWait '"$R0" /S' $R1 + DetailPrint "Previous installation removed (exit code: $R1)" + !insertmacro progressLog "installer:STATUS:Previous installation removed" + + done_uninstall: +!macroend + +!macro createDesktopShortcut + SetShellVarContext current + SetOutPath "$FinalInstDir\bin" + CreateShortCut "$DESKTOP\Farm Control.lnk" "$FinalInstDir\bin\FarmControl.exe" "" "$FinalInstDir\bin\FarmControl.exe" 0 SW_SHOWNORMAL "" "Farm Control" +!macroend + +!macro createStartMenuShortcut + SetShellVarContext current + CreateDirectory "$SMPROGRAMS\Farm Control" + SetOutPath "$FinalInstDir\bin" + CreateShortCut "$SMPROGRAMS\Farm Control\Farm Control.lnk" "$FinalInstDir\bin\FarmControl.exe" "" "$FinalInstDir\bin\FarmControl.exe" 0 SW_SHOWNORMAL "" "Farm Control" +!macroend + +!macro removeDesktopShortcut + SetShellVarContext current + Delete "$DESKTOP\Farm Control.lnk" +!macroend + +!macro removeStartMenuShortcut + SetShellVarContext current + Delete "$SMPROGRAMS\Farm Control\Farm Control.lnk" + RMDir "$SMPROGRAMS\Farm Control" +!macroend + +!macro customInstall + !insertmacro progressConfigure + !insertmacro progressPhase "Configuring Farm Control" + !insertmacro progressStatus "Registering farmcontrol URI handler..." + DetailPrint "Register farmcontrol URI Handler" + DeleteRegKey HKCU "Software\Classes\farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "" "URL:farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\DefaultIcon" "" "$FinalInstDir\bin\FarmControl.exe" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open\command" "" '"$FinalInstDir\bin\bun.exe" "$FinalInstDir\bin\deeplink.js" "%1"' + + !insertmacro progressShortcuts + !insertmacro progressStatus "Creating shortcuts..." + DetailPrint "Creating shortcuts" + !insertmacro createDesktopShortcut + !insertmacro createStartMenuShortcut +!macroend + +!macro customUnInstall + !insertmacro removeDesktopShortcut + !insertmacro removeStartMenuShortcut + DeleteRegKey HKCU "Software\Classes\farmcontrol" +!macroend + +; Wait for the running app to exit, swap staged update into place, then relaunch. +; Only used when /RESTARTFC is passed. +Function restartFarmControlAfterUpdate + ${If} $RestartAfterInstall != "1" + Return + ${EndIf} + + ; All files are copied and we are about to rename the install directory. + ; Emit the success line (matched by isWindowsInstallSuccessful in + ; winappupdate.js) so the app knows to quit and restart; this installer + ; stays alive to swap the folders and relaunch Farm Control. + !insertmacro progressSuccess + + !insertmacro progressStatus "Waiting for Farm Control to close..." + + ${If} $UpdateParentPid > 0 + ; Wait for the exact updater process rather than an executable name. CEF + ; builds can keep bun/renderer processes alive after the launcher exits. + System::Call 'kernel32::OpenProcess(i 0x00100000, i 0, i $UpdateParentPid) p .r0' + ${If} $0 != 0 + ; Allow two seconds for a graceful exit, then terminate the process. + System::Call 'kernel32::WaitForSingleObject(p r0, i 2000) i .r1' + ${If} $1 == 258 + !insertmacro progressStatus "Stopping Farm Control..." + DetailPrint "Farm Control process $UpdateParentPid did not exit; terminating it..." + ; Never use taskkill /T here: this installer is a direct child of the + ; updater process, so a tree kill would terminate the installer itself + ; before the folder swap (CEF builds hung at "Stopping Farm Control..."). + ExecWait 'taskkill /F /PID $UpdateParentPid' $R0 + + ; Verify that taskkill actually terminated the process before swapping. + System::Call 'kernel32::WaitForSingleObject(p r0, i 10000) i .r1' + ${EndIf} + + System::Call 'kernel32::CloseHandle(p r0)' + ${If} $1 != 0 + !insertmacro progressFailure "Could not stop the running Farm Control process." + Abort + ${EndIf} + ${EndIf} + ${Else} + ; Compatibility fallback for manually launched older installers. + Sleep 2000 + !insertmacro quitFarmControl + + ; Confirm both known launcher names have stopped before continuing. + StrCpy $R7 0 + restart_verify_loop: + ExecWait 'cmd.exe /c tasklist /FI "IMAGENAME eq FarmControl.exe" 2>nul | find /I "FarmControl.exe"' $R0 + ${If} $R0 != 0 + ExecWait 'cmd.exe /c tasklist /FI "IMAGENAME eq launcher.exe" 2>nul | find /I "launcher.exe"' $R0 + ${EndIf} + ${If} $R0 != 0 + Goto restart_wait_done + ${EndIf} + + IntOp $R7 $R7 + 1 + ${If} $R7 < 20 + Sleep 500 + Goto restart_verify_loop + ${EndIf} + + !insertmacro progressFailure "Could not stop the running Farm Control process." + Abort + ${EndIf} + + restart_wait_done: + ; CEF helper processes normally exit on their own once the main process is + ; gone, but sweep up any stragglers still running from the install + ; directory so the rename cannot be blocked. Matching on executable path + ; (not a tree kill) guarantees this installer, which runs from the Updates + ; folder, is never terminated. + ExecWait `powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "Get-CimInstance Win32_Process | Where-Object { $$_.ExecutablePath -like '$FinalInstDir\*' } | ForEach-Object { Stop-Process -Id $$_.ProcessId -Force -ErrorAction SilentlyContinue }"` $R0 + + ; Give CEF descendants a moment to release DLLs before renaming the tree. + Sleep 3000 + + ${If} $IsInAppUpdate == "1" + !insertmacro swapUpdateStaging + ${EndIf} + + !insertmacro progressStatus "Starting Farm Control..." + SetOutPath "$FinalInstDir\bin" + Exec "$FinalInstDir\bin\FarmControl.exe" +FunctionEnd diff --git a/packaging/windows/msi-wrapped.wxs b/packaging/windows/msi-wrapped.wxs new file mode 100644 index 0000000..75e301e --- /dev/null +++ b/packaging/windows/msi-wrapped.wxs @@ -0,0 +1,94 @@ + + + + + + + = 601]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NOT Installed + + + diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 267bc74..1c9e943 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -202,18 +202,9 @@ importers: socket.io-client: specifier: '*' version: 4.8.3 - standard: - specifier: ^17.1.2 - version: 17.1.2 styled-components: specifier: ^6.1.19 version: 6.3.8(react-dom@19.2.4(react@19.2.4))(react@19.2.4) - svgo: - specifier: ^4.0.0 - version: 4.0.0 - svgo-loader: - specifier: ^4.0.0 - version: 4.0.0 three: specifier: ^0.179.1 version: 0.179.1 @@ -236,6 +227,9 @@ importers: concurrently: specifier: ^9.2.1 version: 9.2.1 + electrobun: + specifier: 1.18.1 + version: 1.18.1 electron: specifier: ^38.7.1 version: 38.8.0 @@ -269,18 +263,36 @@ importers: globals: specifier: ^15.12.0 version: 15.15.0 + jimp: + specifier: ^1.6.1 + version: 1.6.1 + png-to-ico: + specifier: ^2.1.8 + version: 2.1.8 prettier: specifier: ^3.6.2 version: 3.8.1 prettier-eslint: specifier: ^16.4.2 version: 16.4.2(typescript@5.9.3) + rcedit: + specifier: ^4.0.1 + version: 4.0.1 rollup-plugin-visualizer: specifier: ^6.0.5 version: 6.0.5(rollup@4.57.1) serve: specifier: ^14.2.4 version: 14.2.5 + standard: + specifier: ^17.1.2 + version: 17.1.2 + svgo: + specifier: ^4.0.0 + version: 4.0.0 + svgo-loader: + specifier: ^4.0.0 + version: 4.0.0 vite: specifier: ^7.1.3 version: 7.3.1(@types/node@25.2.0)(jiti@2.6.1)(terser@5.46.0) @@ -484,6 +496,12 @@ packages: resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} engines: {node: '>=6.9.0'} + '@babylonjs/core@7.54.3': + resolution: {integrity: sha512-P5ncXVd8GEUJLhwloP9V0oVwQYIrvZztguVeLlvd5Rx+9aQnenKjpV8auJ6SRsUlAmNZU4pFTKzwF6o2EUfhAw==} + + '@borewit/text-codec@0.2.2': + resolution: {integrity: sha512-DDaRehssg1aNrH4+2hnj1B7vnUGEjU6OIlyRdkMd0aUdIUvKXrJfXsy8LVtXAy7DRvYVluWbMspsRhz2lcW0mQ==} + '@cloudflare/kv-asset-handler@0.3.4': resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} engines: {node: '>=16.13'} @@ -1116,67 +1134,79 @@ packages: resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.0.5': resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.0.4': resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.0.4': resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.0.4': resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.0.4': resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.33.5': resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.33.5': resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.33.5': resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.33.5': resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.33.5': resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.33.5': resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.33.5': resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} @@ -1215,6 +1245,118 @@ packages: resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jimp/core@1.6.1': + resolution: {integrity: sha512-+BoKC5G6hkrSy501zcJ2EpfnllP+avPevcBfRcZe/CW+EwEfY6X1EZ8QWyT7NpDIvEEJb1fdJnMMfUnFkxmw9A==} + engines: {node: '>=18'} + + '@jimp/diff@1.6.1': + resolution: {integrity: sha512-YkKDPdHjLgo1Api3+Bhc0GLAygldlpt97NfOKoNg1U6IUNXA6X2MgosCjPfSBiSvJvrrz1fsIR+/4cfYXBI/HQ==} + engines: {node: '>=18'} + + '@jimp/file-ops@1.6.1': + resolution: {integrity: sha512-T+gX6osHjprbDRad0/B71Evyre7ZdVY1z/gFGEG9Z8KOtZPKboWvPeP2UjbZYWQLy9UKCPQX1FNAnDiOPkJL7w==} + engines: {node: '>=18'} + + '@jimp/js-bmp@1.6.1': + resolution: {integrity: sha512-xzWzNT4/u5zGrTT3Tme9sGU7YzIKxi13+BCQwLqACbt5DXf9SAfdzRkopZQnmDko+6In5nqaT89Gjs43/WdnYQ==} + engines: {node: '>=18'} + + '@jimp/js-gif@1.6.1': + resolution: {integrity: sha512-YjY2W26rQa05XhanYhRZ7dingCiNN+T2Ymb1JiigIbABY0B28wHE3v3Cf1/HZPWGu0hOg36ylaKgV5KxF2M58w==} + engines: {node: '>=18'} + + '@jimp/js-jpeg@1.6.1': + resolution: {integrity: sha512-HT9H3yOmlOFzYmdI15IYdfy6ggQhSRIaHeA+OTJSEORXBqEo97sUZu/DsgHIcX5NJ7TkJBTgZ9BZXsV6UbsyMg==} + engines: {node: '>=18'} + + '@jimp/js-png@1.6.1': + resolution: {integrity: sha512-SZ/KVhI5UjcSzzlXsXdIi/LhJ7UShf2NkMOtVrbZQcGzsqNtynAelrOXeoTxcanfVqmNhAoVHg8yR2cYoqrYjA==} + engines: {node: '>=18'} + + '@jimp/js-tiff@1.6.1': + resolution: {integrity: sha512-jDG/eJquID1M4MBlKMmDRBmz2TpXMv7TUyu2nIRUxhlUc2ogC82T+VQUkca9GJH1BBJ9dx5sSE5dGkWNjIbZxw==} + engines: {node: '>=18'} + + '@jimp/plugin-blit@1.6.1': + resolution: {integrity: sha512-MwnI7C7K81uWddY9FLw1fCOIy6SsPIUftUz36Spt7jisCn8/40DhQMlSxpxTNelnZb/2SnloFimQfRZAmHLOqQ==} + engines: {node: '>=18'} + + '@jimp/plugin-blur@1.6.1': + resolution: {integrity: sha512-lIo7Tzp5jQu30EFFSK/phXANK3citKVEjepDjQ6ljHoIFtuMRrnybnmI2Md24ulvWlDaz+hh3n6qrMb8ydwhZQ==} + engines: {node: '>=18'} + + '@jimp/plugin-circle@1.6.1': + resolution: {integrity: sha512-kK1PavY6cKHNNKce37vdV4Tmpc1/zDKngGoeOV3j+EMatoHFZUinV3s6F9aWryPs3A0xhCLZgdJ6Zeea1d5LCQ==} + engines: {node: '>=18'} + + '@jimp/plugin-color@1.6.1': + resolution: {integrity: sha512-LtUN1vAP+LRlZAtTNVhDRSiXx+26Kbz3zJaG6a5k59gQ95jgT5mknnF8lxkHcqJthM4MEk3/tPxkdJpEybyF/A==} + engines: {node: '>=18'} + + '@jimp/plugin-contain@1.6.1': + resolution: {integrity: sha512-m0qhrfA8jkTqretGv4w+T/ADFR4GwBpE0sCOC2uJ0dzr44/ddOMsIdrpi89kabqYiPYIrxkgdCVCLm3zn1Vkkg==} + engines: {node: '>=18'} + + '@jimp/plugin-cover@1.6.1': + resolution: {integrity: sha512-hZytnsth0zoll6cPf434BrT+p/v569Wr5tyO6Dp0dH1IDPhzhB5F38sZGMLDo7bzQiN9JFVB3fxkcJ/WYCJ3Mg==} + engines: {node: '>=18'} + + '@jimp/plugin-crop@1.6.1': + resolution: {integrity: sha512-EerRSLlclXyKDnYc/H9w/1amZW7b7v3OGi/VlerPd2M/pAu5X8TkyYWtfqYCXnNp1Ixtd8oCo9zGfY9zoXT4rg==} + engines: {node: '>=18'} + + '@jimp/plugin-displace@1.6.1': + resolution: {integrity: sha512-K07QVl7xQwIfD6KfxRV/c3E9e7ZBXxUXdWuvoTWcKHL2qV48MOF5Nqbz/aJW4ThnQARIsxvYlZjPFiqkCjlU+g==} + engines: {node: '>=18'} + + '@jimp/plugin-dither@1.6.1': + resolution: {integrity: sha512-+2V+GCV2WycMoX1/z977TkZ8Zq/4MVSKElHYatgUqtwXMi2fDK2gKYU2g9V39IqFvTJsTIsK0+58VFz/ROBVew==} + engines: {node: '>=18'} + + '@jimp/plugin-fisheye@1.6.1': + resolution: {integrity: sha512-XtS5ZyoZ0vxZxJ6gkqI63SivhtI58vX95foMPM+cyzYkRsJXMOYCr8DScxF5bp4Xr003NjYm/P+7+08tibwzHA==} + engines: {node: '>=18'} + + '@jimp/plugin-flip@1.6.1': + resolution: {integrity: sha512-ws38W/sGj7LobNRayQ83garxiktOyWxM5vO/y4a/2cy9v65SLEUzVkrj+oeAaUSSObdz4HcCEla7XtGlnAGAaA==} + engines: {node: '>=18'} + + '@jimp/plugin-hash@1.6.1': + resolution: {integrity: sha512-sZt6ZcMX6i8vFWb4GYnw0pR/o9++ef0dTVcboTB5B/g7nrxCODIB4wfEkJ/YqZM5wUvol77K1qeS0/rVO6z21A==} + engines: {node: '>=18'} + + '@jimp/plugin-mask@1.6.1': + resolution: {integrity: sha512-SIG0/FcmEj3tkwFxc7fAGLO8o4uNzMpSOdQOhbCgxefQKq5wOVMk9BQx/sdMPBwtMLr9WLq0GzLA/rk6t2v20A==} + engines: {node: '>=18'} + + '@jimp/plugin-print@1.6.1': + resolution: {integrity: sha512-BYVz/X3Xzv8XYilVeDy11NOp0h7BTDjlOtu0BekIFHP1yHVd24AXNzbOy52XlzYZWQ0Dl36HOHEpl/nSNrzc6w==} + engines: {node: '>=18'} + + '@jimp/plugin-quantize@1.6.1': + resolution: {integrity: sha512-J2En9PLURfP+vwYDtuZ9T8yBW6BWYZBScydAjRiPBmJfEhTcNQqiiQODrZf7EqbbX/Sy5H6dAeRiqkgoV9N6Ww==} + engines: {node: '>=18'} + + '@jimp/plugin-resize@1.6.1': + resolution: {integrity: sha512-CLkrtJoIz2HdWnpYiN6p8KYcPc00rCH/SUu6o+lfZL05Q4uhecJlnvXuj9x+U6mDn3ldPmJj6aZqMHuUJzdVqg==} + engines: {node: '>=18'} + + '@jimp/plugin-rotate@1.6.1': + resolution: {integrity: sha512-nOjVjbbj705B02ksysKnh0POAwEBXZtJ9zQ5qC+X7Tavl3JNn+P3BzQovbBxLPSbUSld6XID9z5ijin4PtOAUg==} + engines: {node: '>=18'} + + '@jimp/plugin-threshold@1.6.1': + resolution: {integrity: sha512-JOKv9F8s6tnVLf4sB/2fF0F339EFnHvgEdFYugO6VhowKLsap0pEZmLyE/DlRnYtIj2RddHZVxVMp/eKJ04l2Q==} + engines: {node: '>=18'} + + '@jimp/types@1.6.1': + resolution: {integrity: sha512-leI7YbveTNi565m910XgIOwXyuu074H5qazAD1357HImJSv2hqxnWXpwxQbadGWZ7goZRYBDZy5lpqud0p7q5w==} + engines: {node: '>=18'} + + '@jimp/utils@1.6.1': + resolution: {integrity: sha512-veFPRd93FCnS7AgmCkPgARVGoDRrJ9cm1ujuNyA+UfQ5VKbED2002sm5XfFLFwTsKC8j04heTrwe+tU1dluXOw==} + engines: {node: '>=18'} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -1456,66 +1598,79 @@ packages: resolution: {integrity: sha512-F8sWbhZ7tyuEfsmOxwc2giKDQzN3+kuBLPwwZGyVkLlKGdV1nvnNwYD0fKQ8+XS6hp9nY7B+ZeK01EBUE7aHaw==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.57.1': resolution: {integrity: sha512-rGfNUfn0GIeXtBP1wL5MnzSj98+PZe/AXaGBCRmT0ts80lU5CATYGxXukeTX39XBKsxzFpEeK+Mrp9faXOlmrw==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.57.1': resolution: {integrity: sha512-MMtej3YHWeg/0klK2Qodf3yrNzz6CGjo2UntLvk2RSPlhzgLvYEB3frRvbEF2wRKh1Z2fDIg9KRPe1fawv7C+g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.57.1': resolution: {integrity: sha512-1a/qhaaOXhqXGpMFMET9VqwZakkljWHLmZOX48R0I/YLbhdxr1m4gtG1Hq7++VhVUmf+L3sTAf9op4JlhQ5u1Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.57.1': resolution: {integrity: sha512-QWO6RQTZ/cqYtJMtxhkRkidoNGXc7ERPbZN7dVW5SdURuLeVU7lwKMpo18XdcmpWYd0qsP1bwKPf7DNSUinhvA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-loong64-musl@4.57.1': resolution: {integrity: sha512-xpObYIf+8gprgWaPP32xiN5RVTi/s5FCR+XMXSKmhfoJjrpRAjCuuqQXyxUa/eJTdAE6eJ+KDKaoEqjZQxh3Gw==} cpu: [loong64] os: [linux] + libc: [musl] '@rollup/rollup-linux-ppc64-gnu@4.57.1': resolution: {integrity: sha512-4BrCgrpZo4hvzMDKRqEaW1zeecScDCR+2nZ86ATLhAoJ5FQ+lbHVD3ttKe74/c7tNT9c6F2viwB3ufwp01Oh2w==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-musl@4.57.1': resolution: {integrity: sha512-NOlUuzesGauESAyEYFSe3QTUguL+lvrN1HtwEEsU2rOwdUDeTMJdO5dUYl/2hKf9jWydJrO9OL/XSSf65R5+Xw==} cpu: [ppc64] os: [linux] + libc: [musl] '@rollup/rollup-linux-riscv64-gnu@4.57.1': resolution: {integrity: sha512-ptA88htVp0AwUUqhVghwDIKlvJMD/fmL/wrQj99PRHFRAG6Z5nbWoWG4o81Nt9FT+IuqUQi+L31ZKAFeJ5Is+A==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.57.1': resolution: {integrity: sha512-S51t7aMMTNdmAMPpBg7OOsTdn4tySRQvklmL3RpDRyknk87+Sp3xaumlatU+ppQ+5raY7sSTcC2beGgvhENfuw==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.57.1': resolution: {integrity: sha512-Bl00OFnVFkL82FHbEqy3k5CUCKH6OEJL54KCyx2oqsmZnFTR8IoNqBF+mjQVcRCT5sB6yOvK8A37LNm/kPJiZg==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.57.1': resolution: {integrity: sha512-ABca4ceT4N+Tv/GtotnWAeXZUZuM/9AQyCyKYyKnpk4yoA7QIAuBt6Hkgpw8kActYlew2mvckXkvx0FfoInnLg==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.57.1': resolution: {integrity: sha512-HFps0JeGtuOR2convgRRkHCekD7j+gdAuXM+/i6kGzQtFhlCtQkpwtNzkNj6QhCDp7DRJ7+qC/1Vg2jt5iSOFw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openbsd-x64@4.57.1': resolution: {integrity: sha512-H+hXEv9gdVQuDTgnqD+SQffoWoc0Of59AStSzTEj/feWTBAnSfSD3+Dql1ZruJQxmykT/JVY0dE8Ka7z0DH1hw==} @@ -1812,69 +1967,99 @@ packages: '@tiptap/starter-kit@3.20.1': resolution: {integrity: sha512-opqWxL/4OTEiqmVC0wsU4o3JhAf6LycJ2G/gRIZVAIFLljI9uHfpPMTFGxZ5w9IVVJaP5PJysfwW/635kKqkrw==} + '@tokenizer/inflate@0.4.1': + resolution: {integrity: sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA==} + engines: {node: '>=18'} + + '@tokenizer/token@0.3.0': + resolution: {integrity: sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==} + + '@tootallnate/quickjs-emscripten@0.23.0': + resolution: {integrity: sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} '@tsparticles/basic@3.9.1': resolution: {integrity: sha512-ijr2dHMx0IQHqhKW3qA8tfwrR2XYbbWYdaJMQuBo2CkwBVIhZ76U+H20Y492j/NXpd1FUnt2aC0l4CEVGVGdeQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/engine@3.9.1': resolution: {integrity: sha512-DpdgAhWMZ3Eh2gyxik8FXS6BKZ8vyea+Eu5BC4epsahqTGY9V3JGGJcXC6lRJx6cPMAx1A0FaQAojPF3v6rkmQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-attract@3.9.1': resolution: {integrity: sha512-5AJGmhzM9o4AVFV24WH5vSqMBzOXEOzIdGLIr+QJf4fRh9ZK62snsusv/ozKgs2KteRYQx+L7c5V3TqcDy2upg==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-bounce@3.9.1': resolution: {integrity: sha512-bv05+h70UIHOTWeTsTI1AeAmX6R3s8nnY74Ea6p6AbQjERzPYIa0XY19nq/hA7+Nrg+EissP5zgoYYeSphr85A==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-bubble@3.9.1': resolution: {integrity: sha512-tbd8ox/1GPl+zr+KyHQVV1bW88GE7OM6i4zql801YIlCDrl9wgTDdDFGIy9X7/cwTvTrCePhrfvdkUamXIribQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-connect@3.9.1': resolution: {integrity: sha512-sq8YfUNsIORjXHzzW7/AJQtfi/qDqLnYG2qOSE1WOsog39MD30RzmiOloejOkfNeUdcGUcfsDgpUuL3UhzFUOA==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-grab@3.9.1': resolution: {integrity: sha512-QwXza+sMMWDaMiFxd8y2tJwUK6c+nNw554+/9+tEZeTTk2fCbB0IJ7p/TH6ZGWDL0vo2muK54Njv2fEey191ow==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-pause@3.9.1': resolution: {integrity: sha512-Gzv4/FeNir0U/tVM9zQCqV1k+IAgaFjDU3T30M1AeAsNGh/rCITV2wnT7TOGFkbcla27m4Yxa+Fuab8+8pzm+g==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-push@3.9.1': resolution: {integrity: sha512-GvnWF9Qy4YkZdx+WJL2iy9IcgLvzOIu3K7aLYJFsQPaxT8d9TF8WlpoMlWKnJID6H5q4JqQuMRKRyWH8aAKyQw==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-remove@3.9.1': resolution: {integrity: sha512-yPThm4UDWejDOWW5Qc8KnnS2EfSo5VFcJUQDWc1+Wcj17xe7vdSoiwwOORM0PmNBzdDpSKQrte/gUnoqaUMwOA==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-repulse@3.9.1': resolution: {integrity: sha512-/LBppXkrMdvLHlEKWC7IykFhzrz+9nebT2fwSSFXK4plEBxDlIwnkDxd3FbVOAbnBvx4+L8+fbrEx+RvC8diAw==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-slow@3.9.1': resolution: {integrity: sha512-1ZYIR/udBwA9MdSCfgADsbDXKSFS0FMWuPWz7bm79g3sUxcYkihn+/hDhc6GXvNNR46V1ocJjrj0u6pAynS1KQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-external-trail@3.9.1': resolution: {integrity: sha512-Au0v2oiqfKTemI/4bzjD4dUXzIngB5Q2T4nJcMCYpP24uZfwZh5xTjUMH7gyJyyaRTdMl9IJrp8ySjyYbLfeGg==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-particles-attract@3.9.1': resolution: {integrity: sha512-CYYYowJuGwRLUixQcSU/48PTKM8fCUYThe0hXwQ+yRMLAn053VHzL7NNZzKqEIeEyt5oJoy9KcvubjKWbzMBLQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-particles-collisions@3.9.1': resolution: {integrity: sha512-ggGyjW/3v1yxvYW1IF1EMT15M6w31y5zfNNUPkqd/IXRNPYvm0Z0ayhp+FKmz70M5p0UxxPIQHTvAv9Jqnuj8w==} + deprecated: Please update to version 4.1.1 '@tsparticles/interaction-particles-links@3.9.1': resolution: {integrity: sha512-MsLbMjy1vY5M5/hu/oa5OSRZAUz49H3+9EBMTIOThiX+a+vpl3sxc9AqNd9gMsPbM4WJlub8T6VBZdyvzez1Vg==} + deprecated: Please update to version 4.1.1 '@tsparticles/move-base@3.9.1': resolution: {integrity: sha512-X4huBS27d8srpxwOxliWPUt+NtCwY+8q/cx1DvQxyqmTA8VFCGpcHNwtqiN+9JicgzOvSuaORVqUgwlsc7h4pQ==} + deprecated: this package was deprecated in tsparticles v4, replaced by @tsparticles/plugin-move '@tsparticles/move-parallax@3.9.1': resolution: {integrity: sha512-whlOR0bVeyh6J/hvxf/QM3DqvNnITMiAQ0kro6saqSDItAVqg4pYxBfEsSOKq7EhjxNvfhhqR+pFMhp06zoCVA==} + deprecated: this package was deprecated in tsparticles v4, replaced by @tsparticles/interaction-external-parallax '@tsparticles/plugin-absorbers@3.9.1': resolution: {integrity: sha512-q9SQllpbPPgw1+euxHPYCFawOVUazQkkwnleiIgpYSiimlCyjIdwGnFPSNe1Sypzqmr2h6oOyX2vkK5ZVNEu8A==} + deprecated: Please update to version 4.1.1 '@tsparticles/plugin-easing-quad@3.9.1': resolution: {integrity: sha512-C2UJOca5MTDXKUTBXj30Kiqr5UyID+xrY/LxicVWWZPczQW2bBxbIbfq9ULvzGDwBTxE2rdvIB8YFKmDYO45qw==} + deprecated: Please update to version 4.1.1 '@tsparticles/plugin-emitters-shape-circle@3.9.1': resolution: {integrity: sha512-z+9MsAPWr++sNz6N6303rRDjusW0BIPhHY51E5eXGDcRdOqrESDs6y99AJ/6Kdb/PpibCIYjFY9jVi2JJADPRA==} @@ -1890,12 +2075,15 @@ packages: '@tsparticles/plugin-hsl-color@3.9.1': resolution: {integrity: sha512-jJd1iGgRwX6eeNjc1zUXiJivaqC5UE+SC2A3/NtHwwoQrkfxGWmRHOsVyLnOBRcCPgBp/FpdDe6DIDjCMO715w==} + deprecated: Please update to version 4.1.1 '@tsparticles/plugin-rgb-color@3.9.1': resolution: {integrity: sha512-SBxk7f1KBfXeTnnklbE2Hx4jBgh6I6HOtxb+Os1gTp0oaghZOkWcCD2dP4QbUu7fVNCMOcApPoMNC8RTFcy9wQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/react@3.0.0': resolution: {integrity: sha512-hjGEtTT1cwv6BcjL+GcVgH++KYs52bIuQGW3PWv7z3tMa8g0bd6RI/vWSLj7p//NZ3uTjEIeilYIUPBh7Jfq/Q==} + deprecated: Please update to version 4.1.1 peerDependencies: '@tsparticles/engine': ^3.0.2 react: '>=16.8.0' @@ -1903,66 +2091,87 @@ packages: '@tsparticles/shape-circle@3.9.1': resolution: {integrity: sha512-DqZFLjbuhVn99WJ+A9ajz9YON72RtCcvubzq6qfjFmtwAK7frvQeb6iDTp6Ze9FUipluxVZWVRG4vWTxi2B+/g==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-emoji@3.9.1': resolution: {integrity: sha512-ifvY63usuT+hipgVHb8gelBHSeF6ryPnMxAAEC1RGHhhXfpSRWMtE6ybr+pSsYU52M3G9+TF84v91pSwNrb9ZQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-image@3.9.1': resolution: {integrity: sha512-fCA5eme8VF3oX8yNVUA0l2SLDKuiZObkijb0z3Ky0qj1HUEVlAuEMhhNDNB9E2iELTrWEix9z7BFMePp2CC7AA==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-line@3.9.1': resolution: {integrity: sha512-wT8NSp0N9HURyV05f371cHKcNTNqr0/cwUu6WhBzbshkYGy1KZUP9CpRIh5FCrBpTev34mEQfOXDycgfG0KiLQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-polygon@3.9.1': resolution: {integrity: sha512-dA77PgZdoLwxnliH6XQM/zF0r4jhT01pw5y7XTeTqws++hg4rTLV9255k6R6eUqKq0FPSW1/WBsBIl7q/MmrqQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-square@3.9.1': resolution: {integrity: sha512-DKGkDnRyZrAm7T2ipqNezJahSWs6xd9O5LQLe5vjrYm1qGwrFxJiQaAdlb00UNrexz1/SA7bEoIg4XKaFa7qhQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-star@3.9.1': resolution: {integrity: sha512-kdMJpi8cdeb6vGrZVSxTG0JIjCwIenggqk0EYeKAwtOGZFBgL7eHhF2F6uu1oq8cJAbXPujEoabnLsz6mW8XaA==} + deprecated: Please update to version 4.1.1 '@tsparticles/shape-text@3.9.1': resolution: {integrity: sha512-oNsLHI0lGkIXoUw3W598iwd7dtoHCDrwpwJRGnQzgfk6T5a9dCpSD5vDeQN89lr3BUbVui4lhxq+/TyC64oAqA==} + deprecated: Please update to version 4.1.1 '@tsparticles/slim@3.9.1': resolution: {integrity: sha512-CL5cDmADU7sDjRli0So+hY61VMbdroqbArmR9Av+c1Fisa5ytr6QD7Jv62iwU2S6rvgicEe9OyRmSy5GIefwZw==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-color@3.9.1': resolution: {integrity: sha512-XGWdscrgEMA8L5E7exsE0f8/2zHKIqnTrZymcyuFBw2DCB6BIV+5z6qaNStpxrhq3DbIxxhqqcybqeOo7+Alpg==} + deprecated: this package was deprecated in tsparticles v4, replaced by @tsparticles/updater-paint '@tsparticles/updater-destroy@3.9.1': resolution: {integrity: sha512-MjMzEhZwCQIbxO6ZRM0eXsHVwmlXuUqwC43WCPZCpjhK3AJrMu3KR4xsJieFTWIbVNguAvbgoTB10FfJOUU5VA==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-life@3.9.1': resolution: {integrity: sha512-Oi8aF2RIwMMsjssUkCB6t3PRpENHjdZf6cX92WNfAuqXtQphr3OMAkYFJFWkvyPFK22AVy3p/cFt6KE5zXxwAA==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-opacity@3.9.1': resolution: {integrity: sha512-w778LQuRZJ+IoWzeRdrGykPYSSaTeWfBvLZ2XwYEkh/Ss961InOxZKIpcS6i5Kp/Zfw0fS1ZAuqeHwuj///Osw==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-out-modes@3.9.1': resolution: {integrity: sha512-cKQEkAwbru+hhKF+GTsfbOvuBbx2DSB25CxOdhtW2wRvDBoCnngNdLw91rs+0Cex4tgEeibkebrIKFDDE6kELg==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-roll@3.9.1': resolution: {integrity: sha512-zl4JeM3gUBJ0uttmIsond3lrZ3f3AkItFeS0Lhj/7jiCKfUoRyyOMrcBk8R1AhW7lI+7ko1iBs3jhO0jnxz9vg==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-rotate@3.9.1': resolution: {integrity: sha512-9BfKaGfp28JN82MF2qs6Ae/lJr9EColMfMTHqSKljblwbpVDHte4umuwKl3VjbRt87WD9MGtla66NTUYl+WxuQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-size@3.9.1': resolution: {integrity: sha512-3NSVs0O2ApNKZXfd+y/zNhTXSFeG1Pw4peI8e6z/q5+XLbmue9oiEwoPy/tQLaark3oNj3JU7Q903ZijPyXSzw==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-stroke-color@3.9.1': resolution: {integrity: sha512-3x14+C2is9pZYTg9T2TiA/aM1YMq4wLdYaZDcHm3qO30DZu5oeQq0rm/6w+QOGKYY1Z3Htg9rlSUZkhTHn7eDA==} + deprecated: this package was deprecated in tsparticles v4, replaced by @tsparticles/updater-paint '@tsparticles/updater-tilt@3.9.1': resolution: {integrity: sha512-PB2yaoyXRmSk4iIVgjtRrzOxXMK9mjeAQHIJGtT4faq46Z8cbIIEFgjTwqrUV8qOrNg/h4sm5NE/s0qsTYjp1Q==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-twinkle@3.9.1': resolution: {integrity: sha512-xgTcYr6LmP44IPIBeQmEExN2Y5Nfl3ikmC08eOh5nZy/ta6ORP+JTsprrnfuv/O2DwTyoqFLkZ16hZfkdc1yOQ==} + deprecated: Please update to version 4.1.1 '@tsparticles/updater-wobble@3.9.1': resolution: {integrity: sha512-c99Ogy9q4QWO+zsDXol0UnpUwZiY2UucFb8ltuDv9AlbGUeprygoub8jhgT5pEDv+GdzWOJGSgq7rfgv9cHBrg==} + deprecated: Please update to version 4.1.1 '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -1976,6 +2185,9 @@ packages: '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@types/bun@1.3.14': + resolution: {integrity: sha512-h1hFqFVcvAvD9j9K7ZW7vd82aSA+rTdznZa+5bwvCwqSB1jmmfLcbIWhOLx1/+boy/xmjgCs/OMUL8hRJSmnPw==} + '@types/cacheable-request@6.0.3': resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} @@ -2057,6 +2269,12 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@types/node@16.9.1': + resolution: {integrity: sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==} + + '@types/node@17.0.45': + resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} + '@types/node@22.19.7': resolution: {integrity: sha512-MciR4AKGHWl7xwxkBa6xUGxQJ4VBOmPTF7sL+iGzuahOFaO0jHCsuEfS80pan1ef4gWId1oWOweIhrDEYLuaOw==} @@ -2153,6 +2371,7 @@ packages: '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@vitejs/plugin-react@5.1.2': resolution: {integrity: sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==} @@ -2166,6 +2385,7 @@ packages: '@xmldom/xmldom@0.8.11': resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} engines: {node: '>=10.0.0'} + deprecated: this version has critical issues, please update to the latest version '@zeit/schemas@2.36.0': resolution: {integrity: sha512-7kjMwcChYEzMKjeex9ZFXkt1AyNov9R5HZtjBKVsmVpw7pa7ZtlCGvCBC2vnnXctaYN+aRI61HjIqeetZW5ROg==} @@ -2271,6 +2491,9 @@ packages: react: '>=16.9.0' react-dom: '>=16.9.0' + any-base@1.1.0: + resolution: {integrity: sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==} + app-builder-bin@5.0.0-alpha.12: resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} @@ -2333,6 +2556,10 @@ packages: resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} engines: {node: '>=0.8'} + ast-types@0.13.4: + resolution: {integrity: sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==} + engines: {node: '>=4'} + astral-regex@2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -2366,6 +2593,10 @@ packages: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} + await-to-js@3.0.0: + resolution: {integrity: sha512-zJAaP9zxTcvTHRlejau3ZOY4V7SRpiByf3/dxx2uyKxxor19tpmpV2QRsTKikckwhaPmr2dVpxxMr7jOCYVp5g==} + engines: {node: '>=6.0.0'} + axios@1.13.4: resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} @@ -2387,6 +2618,10 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + basic-ftp@5.3.1: + resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} + engines: {node: '>=10.0.0'} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2399,6 +2634,9 @@ packages: blurhash@2.0.5: resolution: {integrity: sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==} + bmp-ts@1.0.9: + resolution: {integrity: sha512-cTEHk2jLrPyi+12M3dhpEbnnPOsaZuq7C45ylbbQIiWgDFZq4UVYPEY5mlqjvsj/6gJv9qX5sa+ebDzLXT28Vw==} + body-parser@2.2.2: resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} engines: {node: '>=18'} @@ -2452,6 +2690,9 @@ packages: builtins@5.1.0: resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} + bun-types@1.3.14: + resolution: {integrity: sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==} + bytes@3.0.0: resolution: {integrity: sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==} engines: {node: '>= 0.8'} @@ -2823,6 +3064,10 @@ packages: data-uri-to-buffer@2.0.2: resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} + data-uri-to-buffer@6.0.2: + resolution: {integrity: sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==} + engines: {node: '>= 14'} + data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -2906,6 +3151,10 @@ packages: defu@6.1.4: resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + degenerator@5.0.1: + resolution: {integrity: sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==} + engines: {node: '>= 14'} + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -3005,6 +3254,10 @@ packages: engines: {node: '>=0.10.0'} hasBin: true + electrobun@1.18.1: + resolution: {integrity: sha512-tgZ+WKGskn/1/Y5i1mpVCCkgRa1O31Tz7MIArBTK44GfPzT43uOq9c/HvxdQGrLeZV8ZvjK1lQrwqSXCgh6tvA==} + hasBin: true + electron-builder-squirrel-windows@26.7.0: resolution: {integrity: sha512-3EqkQK+q0kGshdPSKEPb2p5F75TENMKu6Fe5aTdeaPfdzFK4Yjp5L0d6S7K8iyvqIsGQ/ei4bnpyX9wt+kVCKQ==} @@ -3146,6 +3399,11 @@ packages: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} + escodegen@2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + eslint-config-prettier@10.1.8: resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} hasBin: true @@ -3308,6 +3566,11 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + esquery@1.7.0: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} @@ -3344,6 +3607,9 @@ packages: resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} engines: {node: '>=10'} + exif-parser@0.1.12: + resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} + exit-hook@2.2.1: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} @@ -3419,6 +3685,10 @@ packages: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} + file-type@21.3.4: + resolution: {integrity: sha512-Ievi/yy8DS3ygGvT47PjSfdFoX+2isQueoYP1cntFW1JLYAuS4GD7NUPGg4zv2iZfV52uDyk5w5Z0TdpRS6Q1g==} + engines: {node: '>=20'} + filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -3593,6 +3863,13 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} + get-uri@6.0.5: + resolution: {integrity: sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==} + engines: {node: '>= 14'} + + gifwrap@0.10.1: + resolution: {integrity: sha512-2760b1vpJHNmLzZ/ubTtNnEx5WApN/PYWJvXvgS+tL1egTTthayFYIQQNi136FLEDcN/IyEY2EcGpIITD6eYUw==} + glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -3606,11 +3883,12 @@ packages: glob@10.5.0: resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} @@ -3746,6 +4024,9 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + image-q@4.0.0: + resolution: {integrity: sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==} + immer@10.2.0: resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} @@ -3984,10 +4265,17 @@ packages: engines: {node: '>=10'} hasBin: true + jimp@1.6.1: + resolution: {integrity: sha512-hNQh6rZtWfSVWSNVmvq87N5BPJsNH7k7I7qyrXf9DOma9xATQk3fsyHazCQe51nCjdkoWdTmh0vD7bjVSLoxxw==} + engines: {node: '>=18'} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jpeg-js@0.4.4: + resolution: {integrity: sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4149,6 +4437,10 @@ packages: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} + lru-cache@7.18.3: + resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} + engines: {node: '>=12'} + magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} @@ -4486,6 +4778,10 @@ packages: resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} engines: {node: '>= 0.6'} + netmask@2.1.1: + resolution: {integrity: sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==} + engines: {node: '>= 0.4.0'} + no-case@3.0.4: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} @@ -4561,6 +4857,9 @@ packages: ohash@2.0.11: resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==} + omggif@1.0.10: + resolution: {integrity: sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -4638,9 +4937,20 @@ packages: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} + pac-proxy-agent@7.2.0: + resolution: {integrity: sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==} + engines: {node: '>= 14'} + + pac-resolver@7.0.1: + resolution: {integrity: sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==} + engines: {node: '>= 14'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + pako@1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4649,6 +4959,15 @@ packages: resolution: {integrity: sha512-yx5DfvkN8JsHL2xk2Os9oTia467qnvRgey4ahSm2X8epehBLx/gWLcy5KI+Y36ful5DzGbCS6RazqZGgy1gHNw==} engines: {node: '>=0.10.0'} + parse-bmfont-ascii@1.0.6: + resolution: {integrity: sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==} + + parse-bmfont-binary@1.0.6: + resolution: {integrity: sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==} + + parse-bmfont-xml@1.1.6: + resolution: {integrity: sha512-0cEliVMZEhrFDwMh4SxIyVJpqYoOWDJ9P895tFuS+XuNzI5UBmBk5U5O4KuJdTnZpSBI4LFA2+ZiJaiwfSwlMA==} + parse-entities@4.0.2: resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} @@ -4740,6 +5059,10 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} + pixelmatch@5.3.0: + resolution: {integrity: sha512-o8mkY4E/+LNUf6LzX96ht6k6CEDi65k9G2rjMtBe9Oo+VPKSvl+0GKHuH/AlG+GA5LPG/i5hrekkxUc3s2HU+Q==} + hasBin: true + pkg-conf@3.1.0: resolution: {integrity: sha512-m0OTbR/5VPNPqO1ph6Fqbj7Hv6QU7gR/tQW40ZqrL1rjgCU85W6C1bJn0BItuJqnR98PWzw7Z8hHeChD1WrgdQ==} engines: {node: '>=6'} @@ -4748,6 +5071,19 @@ packages: resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} engines: {node: '>=10.4.0'} + png-to-ico@2.1.8: + resolution: {integrity: sha512-Nf+IIn/cZ/DIZVdGveJp86NG5uNib1ZXMiDd/8x32HCTeKSvgpyg6D/6tUBn1QO/zybzoMK0/mc3QRgAyXdv9w==} + engines: {node: '>=8'} + hasBin: true + + pngjs@6.0.0: + resolution: {integrity: sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==} + engines: {node: '>=12.13.0'} + + pngjs@7.0.0: + resolution: {integrity: sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==} + engines: {node: '>=14.19.0'} + possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} @@ -4883,6 +5219,10 @@ packages: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} + proxy-agent@6.5.0: + resolution: {integrity: sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==} + engines: {node: '>= 14'} + proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} @@ -5155,6 +5495,12 @@ packages: rcedit@3.1.0: resolution: {integrity: sha512-WRlRdY1qZbu1L11DklT07KuHfRk42l0NFFJdaExELEu4fEQ982bP5Z6OWGPj/wLLIuKRQDCxZJGAwoFsxhZhNA==} engines: {node: '>= 10.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + + rcedit@4.0.1: + resolution: {integrity: sha512-bZdaQi34krFWhrDn+O53ccBDw0MkAT2Vhu75SqhtvhQu4OPyFM4RoVheyYiVQYdjhUi6EJMVWQ0tR6bCIYVkUg==} + engines: {node: '>= 14.0.0'} + deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. react-country-flag@3.1.0: resolution: {integrity: sha512-JWQFw1efdv9sTC+TGQvTKXQg1NKbDU2mBiAiRWcKM9F1sK+/zjhP2yGmm8YDddWyZdXVkR8Md47rPMJmo4YO5g==} @@ -5534,6 +5880,10 @@ packages: resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} engines: {node: '>=10'} + simple-xml-to-json@1.2.7: + resolution: {integrity: sha512-mz9VXphOxQWX3eQ/uXCtm6upltoN0DLx8Zb5T4TFC4FHB7S9FDPGre8CfLWqPWQQH/GrQYd2AXhhVM5LDpYx6Q==} + engines: {node: '>=20.12.2'} + simplebar-core@1.3.2: resolution: {integrity: sha512-qKgTTuTqapjsFGkNhCjyPhysnbZGpQqNmjk0nOYjFN5ordC/Wjvg+RbYCyMSnW60l/Z0ZS82GbNltly6PMUH1w==} @@ -5714,6 +6064,10 @@ packages: resolution: {integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==} engines: {node: '>=0.10.0'} + strtok3@10.3.5: + resolution: {integrity: sha512-ki4hZQfh5rX0QDLLkOCj+h+CVNkqmp/CMf8v8kZpkNVK6jGQooMytqzLZYUVYIZcFZ6yDB70EfD8POcFXiF5oA==} + engines: {node: '>=18'} + stubborn-fs@2.0.0: resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} @@ -5792,6 +6146,7 @@ packages: tar@7.5.7: resolution: {integrity: sha512-fov56fJiRuThVFXD6o6/Q354S7pnWMJIVlDBYijsTNx6jKSE4pvrDTs6lUnmGvNyfJwFQQwWy3owKz1ucIhveQ==} engines: {node: '>=18'} + deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me temp-file@3.4.0: resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} @@ -5811,6 +6166,9 @@ packages: three@0.159.0: resolution: {integrity: sha512-eCmhlLGbBgucuo4VEA9IO3Qpc7dh8Bd4VKzr7WfW4+8hMcIfoAVi1ev0pJYN9PTTsCslbcKgBwr2wNZ1EvLInA==} + three@0.165.0: + resolution: {integrity: sha512-cc96IlVYGydeceu0e5xq70H8/yoVT/tXBxV/W8A/U6uOq7DXc4/s1Mkmnu6SqoYGhSRWWYFOhVwvq6V0VtbplA==} + three@0.176.0: resolution: {integrity: sha512-PWRKYWQo23ojf9oZSlRGH8K09q7nRSWx6LY/HF/UUrMdYgN9i1e2OwJYHoQjwc6HF/4lvvYLC5YC1X8UJL2ZpA==} @@ -5827,6 +6185,9 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} + tinycolor2@1.6.0: + resolution: {integrity: sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==} + tinyglobby@0.2.15: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} @@ -5849,6 +6210,10 @@ packages: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + token-types@6.1.2: + resolution: {integrity: sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww==} + engines: {node: '>=14.16'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -5880,6 +6245,7 @@ packages: tsparticles@3.9.1: resolution: {integrity: sha512-Y780IGSL4qjkZj7+fI92PV/cziHqLR/s6nnYri4K6vH3NQRmDK5D6pfskDO8T4Y96ChCWHY3uxPtOb/hKQ83Qg==} + deprecated: Please update to version 4.1.1 type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} @@ -6020,6 +6386,9 @@ packages: utf8-byte-length@1.0.5: resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + utif2@4.1.0: + resolution: {integrity: sha512-+oknB9FHrJ7oW7A2WZYajOcv4FcDR4CfoGB0dPNfxbi4GO05RRnFmt5oa23+9w32EanrYcSJWspUiJkLMs+37w==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -6210,6 +6579,17 @@ packages: resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==} engines: {node: '>=8'} + xml-parse-from-string@1.0.1: + resolution: {integrity: sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==} + + xml2js@0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + + xmlbuilder@11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + xmlbuilder@15.1.1: resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} engines: {node: '>=8.0'} @@ -6257,6 +6637,9 @@ packages: zod@3.22.3: resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -6510,6 +6893,10 @@ snapshots: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.28.5 + '@babylonjs/core@7.54.3': {} + + '@borewit/text-codec@0.2.2': {} + '@cloudflare/kv-asset-handler@0.3.4': dependencies: mime: 3.0.0 @@ -7273,6 +7660,229 @@ snapshots: dependencies: '@sinclair/typebox': 0.27.8 + '@jimp/core@1.6.1': + dependencies: + '@jimp/file-ops': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + await-to-js: 3.0.0 + exif-parser: 0.1.12 + file-type: 21.3.4 + mime: 3.0.0 + transitivePeerDependencies: + - supports-color + + '@jimp/diff@1.6.1': + dependencies: + '@jimp/plugin-resize': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + pixelmatch: 5.3.0 + transitivePeerDependencies: + - supports-color + + '@jimp/file-ops@1.6.1': {} + + '@jimp/js-bmp@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + bmp-ts: 1.0.9 + transitivePeerDependencies: + - supports-color + + '@jimp/js-gif@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + gifwrap: 0.10.1 + omggif: 1.0.10 + transitivePeerDependencies: + - supports-color + + '@jimp/js-jpeg@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + jpeg-js: 0.4.4 + transitivePeerDependencies: + - supports-color + + '@jimp/js-png@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + pngjs: 7.0.0 + transitivePeerDependencies: + - supports-color + + '@jimp/js-tiff@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + utif2: 4.1.0 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-blit@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-blur@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/utils': 1.6.1 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-circle@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-color@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + tinycolor2: 1.6.0 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-contain@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/plugin-blit': 1.6.1 + '@jimp/plugin-resize': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-cover@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/plugin-crop': 1.6.1 + '@jimp/plugin-resize': 1.6.1 + '@jimp/types': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-crop@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-displace@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-dither@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + + '@jimp/plugin-fisheye@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-flip@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-hash@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/js-bmp': 1.6.1 + '@jimp/js-jpeg': 1.6.1 + '@jimp/js-png': 1.6.1 + '@jimp/js-tiff': 1.6.1 + '@jimp/plugin-color': 1.6.1 + '@jimp/plugin-resize': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + any-base: 1.1.0 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-mask@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + zod: 3.25.76 + + '@jimp/plugin-print@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/js-jpeg': 1.6.1 + '@jimp/js-png': 1.6.1 + '@jimp/plugin-blit': 1.6.1 + '@jimp/types': 1.6.1 + parse-bmfont-ascii: 1.0.6 + parse-bmfont-binary: 1.0.6 + parse-bmfont-xml: 1.1.6 + simple-xml-to-json: 1.2.7 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-quantize@1.6.1': + dependencies: + image-q: 4.0.0 + zod: 3.25.76 + + '@jimp/plugin-resize@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/types': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-rotate@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/plugin-crop': 1.6.1 + '@jimp/plugin-resize': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/plugin-threshold@1.6.1': + dependencies: + '@jimp/core': 1.6.1 + '@jimp/plugin-color': 1.6.1 + '@jimp/plugin-hash': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + zod: 3.25.76 + transitivePeerDependencies: + - supports-color + + '@jimp/types@1.6.1': + dependencies: + zod: 3.25.76 + + '@jimp/utils@1.6.1': + dependencies: + '@jimp/types': 1.6.1 + tinycolor2: 1.6.0 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -7907,6 +8517,17 @@ snapshots: '@tiptap/extensions': 3.20.1(@tiptap/core@3.20.1(@tiptap/pm@3.20.1))(@tiptap/pm@3.20.1) '@tiptap/pm': 3.20.1 + '@tokenizer/inflate@0.4.1': + dependencies: + debug: 4.4.3 + token-types: 6.1.2 + transitivePeerDependencies: + - supports-color + + '@tokenizer/token@0.3.0': {} + + '@tootallnate/quickjs-emscripten@0.23.0': {} + '@trysound/sax@0.2.0': {} '@tsparticles/basic@3.9.1': @@ -8158,6 +8779,10 @@ snapshots: dependencies: '@babel/types': 7.29.0 + '@types/bun@1.3.14': + dependencies: + bun-types: 1.3.14 + '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 @@ -8229,7 +8854,7 @@ snapshots: '@types/keyv@3.1.4': dependencies: - '@types/node': 22.19.7 + '@types/node': 25.2.0 '@types/linkify-it@5.0.0': {} @@ -8246,6 +8871,10 @@ snapshots: '@types/ms@2.1.0': {} + '@types/node@16.9.1': {} + + '@types/node@17.0.45': {} + '@types/node@22.19.7': dependencies: undici-types: 6.21.0 @@ -8523,6 +9152,8 @@ snapshots: - luxon - moment + any-base@1.1.0: {} + app-builder-bin@5.0.0-alpha.12: {} app-builder-lib@26.7.0(dmg-builder@26.7.0)(electron-builder-squirrel-windows@26.7.0): @@ -8650,6 +9281,10 @@ snapshots: assert-plus@1.0.0: optional: true + ast-types@0.13.4: + dependencies: + tslib: 2.8.1 + astral-regex@2.0.0: optional: true @@ -8674,6 +9309,8 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 + await-to-js@3.0.0: {} + axios@1.13.4: dependencies: follow-redirects: 1.15.11 @@ -8696,6 +9333,8 @@ snapshots: baseline-browser-mapping@2.11.4: {} + basic-ftp@5.3.1: {} + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -8708,6 +9347,8 @@ snapshots: blurhash@2.0.5: {} + bmp-ts@1.0.9: {} + body-parser@2.2.2: dependencies: bytes: 3.1.2 @@ -8802,6 +9443,10 @@ snapshots: dependencies: semver: 7.7.3 + bun-types@1.3.14: + dependencies: + '@types/node': 25.2.0 + bytes@3.0.0: {} bytes@3.1.2: {} @@ -9178,6 +9823,8 @@ snapshots: data-uri-to-buffer@2.0.2: {} + data-uri-to-buffer@6.0.2: {} + data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -9250,6 +9897,12 @@ snapshots: defu@6.1.4: {} + degenerator@5.0.1: + dependencies: + ast-types: 0.13.4 + escodegen: 2.1.0 + esprima: 4.0.1 + delayed-stream@1.0.0: {} depd@2.0.0: {} @@ -9363,6 +10016,17 @@ snapshots: dependencies: jake: 10.9.4 + electrobun@1.18.1: + dependencies: + '@babylonjs/core': 7.54.3 + '@types/bun': 1.3.14 + png-to-ico: 2.1.8 + proxy-agent: 6.5.0 + rcedit: 4.0.1 + three: 0.165.0 + transitivePeerDependencies: + - supports-color + electron-builder-squirrel-windows@26.7.0(dmg-builder@26.7.0): dependencies: app-builder-lib: 26.7.0(dmg-builder@26.7.0)(electron-builder-squirrel-windows@26.7.0) @@ -9663,21 +10327,29 @@ snapshots: escape-string-regexp@5.0.0: {} + escodegen@2.1.0: + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + eslint-config-prettier@10.1.8(eslint@9.39.2(jiti@2.6.1)): dependencies: eslint: 9.39.2(jiti@2.6.1) - eslint-config-standard-jsx@11.0.0(eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)))(eslint@8.57.1): + eslint-config-standard-jsx@11.0.0(eslint-plugin-react@7.37.5(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-react: 7.37.5(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-react: 7.37.5(eslint@8.57.1) eslint-config-standard@17.1.0(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1): dependencies: eslint: 8.57.1 - eslint-plugin-import: 2.32.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-n: 15.7.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-promise: 6.6.0(eslint@9.39.2(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(eslint@8.57.1) + eslint-plugin-n: 15.7.0(eslint@8.57.1) + eslint-plugin-promise: 6.6.0(eslint@8.57.1) eslint-import-resolver-node@0.3.9: dependencies: @@ -9687,22 +10359,22 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)): + eslint-module-utils@2.12.1(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-plugin-es@4.1.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-es@4.1.0(eslint@8.57.1): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 8.57.1 eslint-utils: 2.1.0 regexpp: 3.2.0 - eslint-plugin-import@2.32.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-import@2.32.0(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -9711,9 +10383,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 9.39.2(jiti@2.6.1) + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@9.39.2(jiti@2.6.1)) + eslint-module-utils: 2.12.1(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -9729,12 +10401,12 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@15.7.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-n@15.7.0(eslint@8.57.1): dependencies: builtins: 5.1.0 - eslint: 9.39.2(jiti@2.6.1) - eslint-plugin-es: 4.1.0(eslint@9.39.2(jiti@2.6.1)) - eslint-utils: 3.0.0(eslint@9.39.2(jiti@2.6.1)) + eslint: 8.57.1 + eslint-plugin-es: 4.1.0(eslint@8.57.1) + eslint-utils: 3.0.0(eslint@8.57.1) ignore: 5.3.2 is-core-module: 2.16.1 minimatch: 3.1.2 @@ -9751,9 +10423,9 @@ snapshots: '@types/eslint': 9.6.1 eslint-config-prettier: 10.1.8(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-promise@6.6.0(eslint@9.39.2(jiti@2.6.1)): + eslint-plugin-promise@6.6.0(eslint@8.57.1): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 8.57.1 eslint-plugin-react-hooks@5.2.0(eslint@9.39.2(jiti@2.6.1)): dependencies: @@ -9821,9 +10493,9 @@ snapshots: dependencies: eslint-visitor-keys: 1.3.0 - eslint-utils@3.0.0(eslint@9.39.2(jiti@2.6.1)): + eslint-utils@3.0.0(eslint@8.57.1): dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 8.57.1 eslint-visitor-keys: 2.1.0 eslint-visitor-keys@1.3.0: {} @@ -9930,6 +10602,8 @@ snapshots: acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 + esprima@4.0.1: {} + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -9964,6 +10638,8 @@ snapshots: signal-exit: 3.0.7 strip-final-newline: 2.0.0 + exif-parser@0.1.12: {} + exit-hook@2.2.1: {} exponential-backoff@3.1.3: {} @@ -10060,6 +10736,15 @@ snapshots: dependencies: flat-cache: 4.0.1 + file-type@21.3.4: + dependencies: + '@tokenizer/inflate': 0.4.1 + strtok3: 10.3.5 + token-types: 6.1.2 + uint8array-extras: 1.5.0 + transitivePeerDependencies: + - supports-color + filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -10270,6 +10955,19 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 + get-uri@6.0.5: + dependencies: + basic-ftp: 5.3.1 + data-uri-to-buffer: 6.0.2 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + gifwrap@0.10.1: + dependencies: + image-q: 4.0.0 + omggif: 1.0.10 + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -10463,6 +11161,10 @@ snapshots: ignore@5.3.2: {} + image-q@4.0.0: + dependencies: + '@types/node': 16.9.1 + immer@10.2.0: {} immer@11.1.8: {} @@ -10678,8 +11380,42 @@ snapshots: filelist: 1.0.4 picocolors: 1.1.1 + jimp@1.6.1: + dependencies: + '@jimp/core': 1.6.1 + '@jimp/diff': 1.6.1 + '@jimp/js-bmp': 1.6.1 + '@jimp/js-gif': 1.6.1 + '@jimp/js-jpeg': 1.6.1 + '@jimp/js-png': 1.6.1 + '@jimp/js-tiff': 1.6.1 + '@jimp/plugin-blit': 1.6.1 + '@jimp/plugin-blur': 1.6.1 + '@jimp/plugin-circle': 1.6.1 + '@jimp/plugin-color': 1.6.1 + '@jimp/plugin-contain': 1.6.1 + '@jimp/plugin-cover': 1.6.1 + '@jimp/plugin-crop': 1.6.1 + '@jimp/plugin-displace': 1.6.1 + '@jimp/plugin-dither': 1.6.1 + '@jimp/plugin-fisheye': 1.6.1 + '@jimp/plugin-flip': 1.6.1 + '@jimp/plugin-hash': 1.6.1 + '@jimp/plugin-mask': 1.6.1 + '@jimp/plugin-print': 1.6.1 + '@jimp/plugin-quantize': 1.6.1 + '@jimp/plugin-resize': 1.6.1 + '@jimp/plugin-rotate': 1.6.1 + '@jimp/plugin-threshold': 1.6.1 + '@jimp/types': 1.6.1 + '@jimp/utils': 1.6.1 + transitivePeerDependencies: + - supports-color + jiti@2.6.1: {} + jpeg-js@0.4.4: {} + js-tokens@4.0.0: {} js-yaml@4.1.1: @@ -10837,6 +11573,8 @@ snapshots: dependencies: yallist: 4.0.0 + lru-cache@7.18.3: {} + magic-string@0.25.9: dependencies: sourcemap-codec: 1.4.8 @@ -11371,6 +12109,8 @@ snapshots: negotiator@1.0.0: {} + netmask@2.1.1: {} + no-case@3.0.4: dependencies: lower-case: 2.0.2 @@ -11469,6 +12209,8 @@ snapshots: ohash@2.0.11: {} + omggif@1.0.10: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -11556,8 +12298,28 @@ snapshots: p-try@2.2.0: {} + pac-proxy-agent@7.2.0: + dependencies: + '@tootallnate/quickjs-emscripten': 0.23.0 + agent-base: 7.1.4 + debug: 4.4.3 + get-uri: 6.0.5 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + pac-resolver: 7.0.1 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + + pac-resolver@7.0.1: + dependencies: + degenerator: 5.0.1 + netmask: 2.1.1 + package-json-from-dist@1.0.1: {} + pako@1.0.11: {} + parent-module@1.0.1: dependencies: callsites: 3.1.0 @@ -11566,6 +12328,15 @@ snapshots: dependencies: author-regex: 1.0.0 + parse-bmfont-ascii@1.0.6: {} + + parse-bmfont-binary@1.0.6: {} + + parse-bmfont-xml@1.1.6: + dependencies: + xml-parse-from-string: 1.0.1 + xml2js: 0.5.0 + parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 @@ -11639,6 +12410,10 @@ snapshots: pify@4.0.1: {} + pixelmatch@5.3.0: + dependencies: + pngjs: 6.0.0 + pkg-conf@3.1.0: dependencies: find-up: 3.0.0 @@ -11650,6 +12425,16 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 15.1.1 + png-to-ico@2.1.8: + dependencies: + '@types/node': 17.0.45 + minimist: 1.2.8 + pngjs: 6.0.0 + + pngjs@6.0.0: {} + + pngjs@7.0.0: {} + possible-typed-array-names@1.1.0: {} postcss-value-parser@4.2.0: {} @@ -11836,6 +12621,19 @@ snapshots: forwarded: 0.2.0 ipaddr.js: 1.9.1 + proxy-agent@6.5.0: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + lru-cache: 7.18.3 + pac-proxy-agent: 7.2.0 + proxy-from-env: 1.1.0 + socks-proxy-agent: 8.0.5 + transitivePeerDependencies: + - supports-color + proxy-from-env@1.1.0: {} pump@3.0.3: @@ -12196,6 +12994,10 @@ snapshots: dependencies: cross-spawn-windows-exe: 1.2.0 + rcedit@4.0.1: + dependencies: + cross-spawn-windows-exe: 1.2.0 + react-country-flag@3.1.0(react@19.2.4): dependencies: react: 19.2.4 @@ -12721,6 +13523,8 @@ snapshots: dependencies: semver: 7.7.3 + simple-xml-to-json@1.2.7: {} + simplebar-core@1.3.2: dependencies: lodash: 4.17.23 @@ -12832,10 +13636,10 @@ snapshots: dependencies: eslint: 8.57.1 eslint-config-standard: 17.1.0(eslint-plugin-import@2.32.0(eslint@8.57.1))(eslint-plugin-n@15.7.0(eslint@8.57.1))(eslint-plugin-promise@6.6.0(eslint@8.57.1))(eslint@8.57.1) - eslint-config-standard-jsx: 11.0.0(eslint-plugin-react@7.37.5(eslint@9.39.2(jiti@2.6.1)))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-n: 15.7.0(eslint@9.39.2(jiti@2.6.1)) - eslint-plugin-promise: 6.6.0(eslint@9.39.2(jiti@2.6.1)) + eslint-config-standard-jsx: 11.0.0(eslint-plugin-react@7.37.5(eslint@8.57.1))(eslint@8.57.1) + eslint-plugin-import: 2.32.0(eslint@8.57.1) + eslint-plugin-n: 15.7.0(eslint@8.57.1) + eslint-plugin-promise: 6.6.0(eslint@8.57.1) eslint-plugin-react: 7.37.5(eslint@8.57.1) standard-engine: 15.1.0 version-guard: 1.1.3 @@ -12947,6 +13751,10 @@ snapshots: dependencies: escape-string-regexp: 1.0.5 + strtok3@10.3.5: + dependencies: + '@tokenizer/token': 0.3.0 + stubborn-fs@2.0.0: dependencies: stubborn-utils: 1.0.2 @@ -13062,6 +13870,8 @@ snapshots: three@0.159.0: {} + three@0.165.0: {} + three@0.176.0: {} three@0.179.1: {} @@ -13074,6 +13884,8 @@ snapshots: tiny-invariant@1.3.3: {} + tinycolor2@1.6.0: {} + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -13093,6 +13905,12 @@ snapshots: toidentifier@1.0.1: {} + token-types@6.1.2: + dependencies: + '@borewit/text-codec': 0.2.2 + '@tokenizer/token': 0.3.0 + ieee754: 1.2.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -13295,6 +14113,10 @@ snapshots: utf8-byte-length@1.0.5: {} + utif2@4.1.0: + dependencies: + pako: 1.0.11 + util-deprecate@1.0.2: {} validate-npm-package-license@3.0.4: @@ -13504,6 +14326,15 @@ snapshots: xdg-basedir@4.0.0: {} + xml-parse-from-string@1.0.1: {} + + xml2js@0.5.0: + dependencies: + sax: 1.4.4 + xmlbuilder: 11.0.1 + + xmlbuilder@11.0.1: {} + xmlbuilder@15.1.1: {} xmlhttprequest-ssl@2.1.2: {} @@ -13545,4 +14376,6 @@ snapshots: zod@3.22.3: {} + zod@3.25.76: {} + zwitch@2.0.4: {} diff --git a/public/appupdate.js b/public/appupdate.js index 4c6dada..214115b 100644 --- a/public/appupdate.js +++ b/public/appupdate.js @@ -1,270 +1,260 @@ -import { ipcMain } from 'electron' -import { createWriteStream, promises as fs } from 'fs' -import http from 'http' -import https from 'https' -import os from 'os' -import path from 'path' -import process from 'process' -import { launchMacInstaller } from './macappupdate.js' -import { launchWindowsInstaller } from './winappupdate.js' +import { createWriteStream, promises as fs } from "node:fs"; +import http from "node:http"; +import https from "node:https"; +import os from "node:os"; +import path from "node:path"; +import process from "node:process"; +import { Utils } from "electrobun/bun"; +import { launchMacInstaller } from "./macappupdate.js"; +import { launchWindowsInstaller } from "./winappupdate.js"; +import { scheduleAppRestart } from "./updater-runner.js"; -const UPDATE_PROGRESS_CHANNEL = 'app-update-progress' const SUPPORTED_TARGETS = { darwin: { - extension: '.pkg', - osMatchers: ['darwin', 'mac', 'macos', 'osx'] + extension: ".pkg", + osMatchers: ["darwin", "mac", "macos", "osx"], }, win32: { - extension: '.msi', - osMatchers: ['win32', 'win', 'windows'] - } -} + extension: ".msi", + osMatchers: ["win32", "win", "windows"], + }, +}; -let runningUpdate = null +let runningUpdate = null; const getArtifactName = (artifact) => - String(artifact?.fileName || artifact?.relativePath || artifact?.url || '') - -const isCefInstallerArtifact = (artifact) => { - const name = getArtifactName(artifact).toLowerCase() - // CEF builds are named like farmcontrol-0.1.1-x64-cef.msi / -cef.pkg / -cef.exe - return /-cef\.[a-z0-9]+$/.test(name) -} + String(artifact?.fileName || artifact?.relativePath || artifact?.url || ""); const normalizeArch = (arch) => { - if (arch === 'x64' || arch === 'amd64') return 'x64' - if (arch === 'arm64' || arch === 'aarch64') return 'arm64' - return arch -} + if (arch === "x64" || arch === "amd64") return "x64"; + if (arch === "arm64" || arch === "aarch64") return "arm64"; + return arch; +}; const artifactMatchesPlatform = (artifact, target, platform, arch) => { - const name = getArtifactName(artifact).toLowerCase() - const normalizedArch = normalizeArch(arch) - const artifactArch = normalizeArch(String(artifact?.arch || '').toLowerCase()) + const name = getArtifactName(artifact).toLowerCase(); + const normalizedArch = normalizeArch(arch); + const artifactArch = normalizeArch(String(artifact?.arch || "").toLowerCase()); const artifactPlatform = String( - artifact?.platform || artifact?.os || artifact?.target || '' - ).toLowerCase() + artifact?.platform || artifact?.os || artifact?.target || "", + ).toLowerCase(); - if (!name.endsWith(target.extension)) return false - if (!artifact?.url) return false + if (!name.endsWith(target.extension)) return false; + if (!artifact?.url) return false; const matchesArch = artifactArch === normalizedArch || name.includes(`-${normalizedArch}`) || name.includes(`_${normalizedArch}`) || name.includes(`.${normalizedArch}.`) || - name.includes(normalizedArch) + name.includes(normalizedArch); const matchesOs = !artifactPlatform || target.osMatchers.includes(artifactPlatform) || target.osMatchers.some((matcher) => name.includes(matcher)) || - (platform === 'darwin' && name.includes('mac')) || - (platform === 'win32' && name.includes('win')) + (platform === "darwin" && name.includes("mac")) || + (platform === "win32" && name.includes("win")); - return matchesArch && matchesOs -} + return matchesArch && matchesOs; +}; const selectUpdateArtifact = ( update, platform = process.platform, - arch = process.arch + arch = process.arch, ) => { - const target = SUPPORTED_TARGETS[platform] + const target = SUPPORTED_TARGETS[platform]; if (!target) { - throw new Error(`App updates are not supported on ${platform}.`) + throw new Error(`App updates are not supported on ${platform}.`); } - const artifacts = (Array.isArray(update?.artifacts) ? update.artifacts : []).filter( - (artifact) => !isCefInstallerArtifact(artifact) - ) + const artifacts = Array.isArray(update?.artifacts) ? update.artifacts : []; const matchingArtifact = artifacts.find((artifact) => - artifactMatchesPlatform(artifact, target, platform, arch) - ) + artifactMatchesPlatform(artifact, target, platform, arch), + ); const fallbackArtifact = artifacts.find((artifact) => { - const name = getArtifactName(artifact).toLowerCase() - return artifact?.url && name.endsWith(target.extension) - }) + const name = getArtifactName(artifact).toLowerCase(); + return artifact?.url && name.endsWith(target.extension); + }); if (!matchingArtifact && !fallbackArtifact) { throw new Error( - `No ${target.extension} update artifact found for ${platform}/${arch}.` - ) + `No ${target.extension} update artifact found for ${platform}/${arch}.`, + ); } - return matchingArtifact || fallbackArtifact -} + return matchingArtifact || fallbackArtifact; +}; -const sendProgress = (webContents, payload) => { - if (!webContents || webContents.isDestroyed()) return - webContents.send(UPDATE_PROGRESS_CHANNEL, { - timestamp: new Date().toISOString(), - ...payload - }) -} - -const getInstallErrorMessage = (error, output = '') => { - const combined = `${output}\n${error?.message || ''}`.trim() +const getInstallErrorMessage = (error, output = "") => { + const combined = `${output}\n${error?.message || ""}`.trim(); if ( /cancel/i.test(combined) || /did not grant permission/i.test(combined) || /user canceled/i.test(combined) ) { - return 'Update installation was cancelled.' + return "Update installation was cancelled."; } if (/incorrect/i.test(combined)) { - return 'The administrator password was incorrect.' + return "The administrator password was incorrect."; } - return combined || 'Failed to install update.' -} + if ( + /1625/.test(combined) || + /forbidden by system policy/i.test(combined) || + /Non-assigned apps are disabled/i.test(combined) + ) { + return "Update installation was blocked by Windows Installer policy."; + } -const installerHelpers = { sendProgress, getInstallErrorMessage } + return combined || "Failed to install update."; +}; const getDownloadUrl = (url, redirectCount = 0) => new Promise((resolve, reject) => { if (redirectCount > 5) { - reject(new Error('Too many redirects while downloading update.')) - return + reject(new Error("Too many redirects while downloading update.")); + return; } - const parsedUrl = new URL(url) - const client = parsedUrl.protocol === 'https:' ? https : http + const parsedUrl = new URL(url); + const client = parsedUrl.protocol === "https:" ? https : http; const request = client.get(parsedUrl, (response) => { - const location = response.headers.location + const location = response.headers.location; if (response.statusCode >= 300 && response.statusCode < 400 && location) { - response.resume() + response.resume(); resolve( getDownloadUrl( new URL(location, parsedUrl).toString(), - redirectCount + 1 - ) - ) - return + redirectCount + 1, + ), + ); + return; } - resolve({ response, url: parsedUrl.toString() }) - }) + resolve({ response, url: parsedUrl.toString() }); + }); - request.on('error', reject) - }) + request.on("error", reject); + }); -const downloadArtifact = async (artifact, destinationPath, webContents) => { - const { response } = await getDownloadUrl(artifact.url) +const downloadArtifact = async (artifact, destinationPath, sendProgress) => { + const { response } = await getDownloadUrl(artifact.url); if (response.statusCode < 200 || response.statusCode >= 300) { - response.resume() - throw new Error(`Update download failed with HTTP ${response.statusCode}.`) + response.resume(); + throw new Error(`Update download failed with HTTP ${response.statusCode}.`); } const totalBytes = - Number.parseInt(response.headers['content-length'], 10) || 0 - let downloadedBytes = 0 + Number.parseInt(response.headers["content-length"], 10) || 0; + let downloadedBytes = 0; await new Promise((resolve, reject) => { - const output = createWriteStream(destinationPath) + const output = createWriteStream(destinationPath); - response.on('data', (chunk) => { - downloadedBytes += chunk.length + response.on("data", (chunk) => { + downloadedBytes += chunk.length; const percent = totalBytes ? Math.round((downloadedBytes / totalBytes) * 100) - : null + : null; - sendProgress(webContents, { - phase: 'downloading', + sendProgress({ + phase: "downloading", percent, downloadedBytes, totalBytes, message: totalBytes ? `Downloading update (${percent}%)` - : 'Downloading update' - }) - }) + : "Downloading update", + }); + }); - response.on('error', reject) - output.on('error', reject) - output.on('finish', resolve) - response.pipe(output) - }) -} + response.on("error", reject); + output.on("error", reject); + output.on("finish", resolve); + response.pipe(output); + }); +}; -const restartApp = (app) => { - app.relaunch() - app.exit(0) -} +const launchInstallerAndRestart = async ( + mainWindow, + installerPath, + sendProgress, +) => { + const installerHelpers = { sendProgress, getInstallErrorMessage }; -const launchInstallerAndQuit = async (app, installerPath, webContents) => { - if (process.platform === 'darwin') { - await launchMacInstaller(app, installerPath, webContents, installerHelpers) - restartApp(app) - return - } - - if (process.platform === 'win32') { - await launchWindowsInstaller( - app, + if (process.platform === "darwin") { + await launchMacInstaller( + mainWindow, installerPath, - webContents, - installerHelpers - ) - restartApp(app) - return + sendProgress, + installerHelpers, + ); + } else if (process.platform === "win32") { + await launchWindowsInstaller( + mainWindow, + installerPath, + sendProgress, + installerHelpers, + ); + } else { + throw new Error(`App updates are not supported on ${process.platform}.`); } - throw new Error(`App updates are not supported on ${process.platform}.`) -} + scheduleAppRestart(); + Utils.quit(); +}; -const runAppUpdate = async (app, update, webContents) => { - const artifact = selectUpdateArtifact(update) +const runAppUpdate = async (mainWindow, update, sendProgress) => { + const artifact = selectUpdateArtifact(update); const tempDirectory = await fs.mkdtemp( - path.join(os.tmpdir(), 'farmcontrol-update-') - ) - const artifactName = path.basename(getArtifactName(artifact)) - const installerPath = path.join(tempDirectory, artifactName) + path.join(os.tmpdir(), "farmcontrol-update-"), + ); + const artifactName = path.basename(getArtifactName(artifact)); + const installerPath = path.join(tempDirectory, artifactName); - sendProgress(webContents, { - phase: 'preparing', + sendProgress({ + phase: "preparing", percent: 0, artifact, - message: 'Preparing update download' - }) + message: "Preparing update download", + }); - await downloadArtifact(artifact, installerPath, webContents) + await downloadArtifact(artifact, installerPath, sendProgress); - sendProgress(webContents, { - phase: 'downloaded', + sendProgress({ + phase: "downloaded", percent: 100, downloadedBytes: null, totalBytes: null, artifact, - message: 'Update downloaded' - }) + message: "Update downloaded", + }); - await launchInstallerAndQuit(app, installerPath, webContents) -} - -export function setupAppUpdateIPC(app) { - ipcMain.handle('app-update-start', async (event, update) => { - if (runningUpdate) return runningUpdate - - const webContents = event.sender - runningUpdate = runAppUpdate(app, update, webContents) - .then(() => ({ ok: true })) - .catch((error) => { - sendProgress(webContents, { - phase: 'error', - percent: null, - message: error?.message || 'Failed to update app.' - }) - throw error - }) - .finally(() => { - runningUpdate = null - }) - - return runningUpdate - }) + await launchInstallerAndRestart(mainWindow, installerPath, sendProgress); +}; + +export function startAppUpdate(mainWindow, update, sendProgress) { + if (runningUpdate) return runningUpdate; + + runningUpdate = runAppUpdate(mainWindow, update, sendProgress) + .then(() => ({ ok: true })) + .catch((error) => { + sendProgress({ + phase: "error", + percent: null, + message: error?.message || "Failed to update app.", + }); + throw error; + }) + .finally(() => { + runningUpdate = null; + }); + + return runningUpdate; } diff --git a/public/mainWindow.js b/public/mainWindow.js index 0dd67d2..cddec0d 100644 --- a/public/mainWindow.js +++ b/public/mainWindow.js @@ -1,4 +1,4 @@ -import { BrowserWindow, ipcMain, Menu } from 'electron' +import { app, BrowserWindow, ipcMain, Menu } from 'electron' import path, { dirname } from 'path' import { fileURLToPath } from 'url' @@ -227,6 +227,12 @@ export function createWindow() { setupWindowEvents() attachKeyboardShortcuts(win) setupNavigationGestures(win) + + if (process.platform === 'darwin') { + win.maximize() + } else if (process.platform === 'win32') { + win.maximize() + } } export function getWindow() { @@ -250,7 +256,7 @@ export function setupMainWindowIPC() { // IPC handlers for window controls ipcMain.on('window-control', (event, action) => { - if (!win) return + if (!win && action !== 'quit') return switch (action) { case 'minimize': win.minimize() @@ -265,6 +271,17 @@ export function setupMainWindowIPC() { case 'close': win.close() break + case 'fullscreen': + win.setFullScreen(!win.isFullScreen()) + break + case 'quit': + app.quit() + break + case 'toggle-devtools': + if (win && !win.isDestroyed()) { + win.webContents.toggleDevTools() + } + break default: break } diff --git a/public/preload.css b/public/preload.css index 96288a7..b4fedfa 100644 --- a/public/preload.css +++ b/public/preload.css @@ -6,18 +6,6 @@ align-items: center; } -@media (prefers-color-scheme: dark) { - body { - background-color: black; - } -} - -@media (prefers-color-scheme: light) { - body { - background-color: white; - } -} - /* HTML:
*/ .fc-loader { width: 35px; diff --git a/public/winappupdate.js b/public/winappupdate.js index ba9fd36..8b7e908 100644 --- a/public/winappupdate.js +++ b/public/winappupdate.js @@ -144,10 +144,12 @@ const isValidMsiPackage = async (filePath) => { } } -const prepareInstallerPath = async (installerPath) => { +export const prepareInstallerPath = async (installerPath) => { const fileName = path.basename(installerPath) const updateDir = path.join( - process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), + os.homedir(), + 'AppData', + 'Local', 'FarmControl', 'Updates' ) @@ -173,11 +175,7 @@ const prepareInstallerPath = async (installerPath) => { return resolvedPath } -const startWindowsInstallerProgressWatch = ( - logPath, - webContents, - sendProgress -) => { +const startWindowsInstallerProgressWatch = (logPath, sendProgress) => { let installerOutput = '' let lastLogSize = 0 let lastPercent = null @@ -239,7 +237,7 @@ const startWindowsInstallerProgressWatch = ( lastPercent = resolvedPercent lastMessage = resolvedMessage - sendProgress(webContents, { + sendProgress( { phase: 'installing', percent: resolvedPercent, message: resolvedMessage @@ -280,7 +278,7 @@ const startWindowsInstallerProgressWatch = ( } export const launchWindowsInstaller = async ( - app, + mainWindow, installerPath, webContents, { sendProgress, getInstallErrorMessage } @@ -294,7 +292,7 @@ export const launchWindowsInstaller = async ( logPath }) - sendProgress(webContents, { + sendProgress( { phase: 'installing', percent: 0, message: 'Installing update...' @@ -307,7 +305,6 @@ export const launchWindowsInstaller = async ( const stopProgressWatch = startWindowsInstallerProgressWatch( logPath, - webContents, sendProgress ) @@ -320,6 +317,9 @@ export const launchWindowsInstaller = async ( resolvedPath, '/qn', '/norestart', + 'ALLUSERS=2', + 'MSIINSTALLPERUSER=1', + 'REBOOT=ReallySuppress', '/L*v!', logPath ] @@ -369,7 +369,7 @@ export const launchWindowsInstaller = async ( }) const message = error?.message || 'Failed to start update installer.' - sendProgress(webContents, { + sendProgress( { phase: 'error', percent: null, message @@ -396,7 +396,7 @@ export const launchWindowsInstaller = async ( if (code !== 0) { const message = getInstallErrorMessage(null, output) - sendProgress(webContents, { + sendProgress( { phase: 'error', percent: null, message @@ -418,7 +418,7 @@ export const launchWindowsInstaller = async ( if (!succeeded) { const message = getInstallErrorMessage(null, output) - sendProgress(webContents, { + sendProgress( { phase: 'error', percent: null, message @@ -429,7 +429,7 @@ export const launchWindowsInstaller = async ( const { percent, message } = finalParse - sendProgress(webContents, { + sendProgress( { phase: 'installing', percent: percent ?? 100, message: message || 'Installation complete. Restarting Farm Control...' diff --git a/scripts/build-macos-effects.mjs b/scripts/build-macos-effects.mjs new file mode 100644 index 0000000..0e8377e --- /dev/null +++ b/scripts/build-macos-effects.mjs @@ -0,0 +1,121 @@ +import { existsSync, mkdirSync, statSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const srcFile = path.join(rootDir, "native/macos/window-effects.mm"); +export const outFile = path.join(rootDir, "src/bun/libMacWindowEffects.dylib"); +const minDylibBytes = 10_000; + +function normalizeArch(value) { + if (value === "x64" || value === "amd64" || value === "x86_64") { + return "x86_64"; + } + if (value === "arm64" || value === "aarch64") { + return "arm64"; + } + return null; +} + +export function resolveTargetArch() { + return ( + normalizeArch(process.env.ELECTROBUN_TARGET_ARCH) || + normalizeArch(process.env.ELECTROBUN_ARCH) || + normalizeArch(process.arch) || + "arm64" + ); +} + +function createPlaceholder() { + mkdirSync(path.dirname(outFile), { recursive: true }); + writeFileSync(outFile, ""); + console.log(`build-macos-effects: created placeholder dylib at ${outFile}`); +} + +function readDylibArch(dylibPath) { + const lipo = spawnSync("lipo", ["-info", dylibPath], { encoding: "utf8" }); + if (lipo.status === 0) { + return lipo.stdout; + } + + const file = spawnSync("file", ["-b", dylibPath], { encoding: "utf8" }); + return file.stdout || ""; +} + +export function validateMacosEffectsDylib({ + dylibPath = outFile, + expectedArch = resolveTargetArch(), + required = process.platform === "darwin", +} = {}) { + if (!required) { + return true; + } + + if (!existsSync(dylibPath)) { + console.error(`build-macos-effects: missing dylib at ${dylibPath}`); + return false; + } + + const { size } = statSync(dylibPath); + if (size < minDylibBytes) { + console.error( + `build-macos-effects: dylib at ${dylibPath} is too small (${size} bytes)`, + ); + return false; + } + + const archInfo = readDylibArch(dylibPath); + if (!archInfo.includes(expectedArch)) { + console.error( + `build-macos-effects: dylib architecture mismatch (expected ${expectedArch}): ${archInfo.trim()}`, + ); + return false; + } + + return true; +} + +if (process.platform !== "darwin") { + createPlaceholder(); + process.exit(0); +} + +if (!existsSync(srcFile)) { + console.error(`build-macos-effects: missing source file ${srcFile}`); + process.exit(1); +} + +mkdirSync(path.dirname(outFile), { recursive: true }); + +const targetArch = resolveTargetArch(); +const result = spawnSync( + "xcrun", + [ + "clang++", + "-dynamiclib", + "-fobjc-arc", + "-arch", + targetArch, + "-mmacosx-version-min=11.0", + "-framework", + "Cocoa", + srcFile, + "-o", + outFile, + ], + { cwd: rootDir, stdio: "inherit" }, +); + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} + +if (!validateMacosEffectsDylib({ dylibPath: outFile, expectedArch: targetArch })) { + process.exit(1); +} + +const { size } = statSync(outFile); +console.log( + `build-macos-effects: built ${outFile} (${size} bytes, arch=${targetArch})`, +); diff --git a/scripts/build-macos.mjs b/scripts/build-macos.mjs new file mode 100644 index 0000000..bacf15a --- /dev/null +++ b/scripts/build-macos.mjs @@ -0,0 +1,111 @@ +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import path from "node:path"; +import { getReleaseArch, isBundleCefEnabled } from "./release-artifact-utils.mjs"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const hostArch = getReleaseArch(process.arch); +const targetArchs = process.env.ELECTROBUN_TARGET_ARCH + ? [getReleaseArch(process.env.ELECTROBUN_TARGET_ARCH)] + : ["arm64", "x64"]; +const bundleCef = isBundleCefEnabled(); + +function canRunUnderArch(archFlag) { + const result = spawnSync("arch", [archFlag, "true"], { + encoding: "utf8", + stdio: ["ignore", "pipe", "pipe"], + }); + return result.status === 0; +} + +function run(command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: rootDir, + stdio: "inherit", + env: process.env, + ...options, + }); + + if (result.status !== 0) { + process.exit(result.status ?? 1); + } +} + +function buildElectrobunEnv(targetArch) { + return { + ...process.env, + ELECTROBUN_BUILD_ENV: "stable", + ELECTROBUN_OS: "macos", + ELECTROBUN_ARCH: targetArch, + ELECTROBUN_FORCE_ARCH: targetArch, + ELECTROBUN_TARGET_ARCH: targetArch, + NODE_ENV: "production", + }; +} + +function getInvocation(targetArch) { + const env = buildElectrobunEnv(targetArch); + const runScript = path.join(rootDir, "scripts/run-electrobun-build.mjs"); + + if (targetArch === hostArch) { + return { command: "bun", args: [runScript], env }; + } + + if (targetArch === "x64" && hostArch === "arm64" && canRunUnderArch("-x86_64")) { + return { + command: "arch", + args: ["-x86_64", "bun", runScript], + env, + }; + } + + if (targetArch === "arm64" && hostArch === "x64") { + return { command: "bun", args: [runScript], env }; + } + + return null; +} + +const orderedTargets = [...targetArchs].sort((a, b) => { + if (a === hostArch) return -1; + if (b === hostArch) return 1; + return 0; +}); + +console.log(`Host architecture: ${hostArch}`); +console.log(`CEF bundling: ${bundleCef ? "enabled" : "disabled"}`); +console.log(`Build order: ${orderedTargets.join(", ")}`); + +let builtCount = 0; + +for (const targetArch of orderedTargets) { + const invocation = getInvocation(targetArch); + if (!invocation) { + console.error( + `Cannot build macOS ${targetArch} from host ${hostArch}.`, + ); + continue; + } + + console.log(`\n=== Building macOS ${targetArch} (host ${hostArch}, cef=${bundleCef}) ===`); + console.log( + `ELECTROBUN_BUILD_ENV=stable ELECTROBUN_OS=macos ELECTROBUN_ARCH=${targetArch} ELECTROBUN_BUNDLE_CEF=${bundleCef}\n`, + ); + + run(invocation.command, invocation.args, { env: invocation.env }); + builtCount += 1; +} + +if (builtCount === 0) { + console.error("No macOS architectures were built."); + process.exit(1); +} + +if (builtCount < targetArchs.length) { + console.error( + `Built ${builtCount}/${targetArchs.length} macOS architectures.`, + ); + process.exit(1); +} + +console.log(`\nBuilt macOS architectures: ${orderedTargets.join(", ")}`); diff --git a/scripts/build-renderer.mjs b/scripts/build-renderer.mjs new file mode 100644 index 0000000..4a463e0 --- /dev/null +++ b/scripts/build-renderer.mjs @@ -0,0 +1,36 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +const result = spawnSync("bun", ["x", "vite", "build"], { + cwd: rootDir, + stdio: "inherit", + env: { + ...process.env, + NODE_ENV: process.env.NODE_ENV || "production", + }, +}); + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} + +const syncResult = spawnSync( + "bun", + [path.join(rootDir, "scripts/sync-electrobun-views.mjs")], + { + cwd: rootDir, + stdio: "inherit", + env: process.env, + }, +); + +if (syncResult.status !== 0) { + process.exit(syncResult.status ?? 1); +} + +console.log( + `build-renderer: output at ${path.join(rootDir, "dist/mainview")}`, +); diff --git a/scripts/build-windows-deeplink.mjs b/scripts/build-windows-deeplink.mjs new file mode 100644 index 0000000..5a1b05f --- /dev/null +++ b/scripts/build-windows-deeplink.mjs @@ -0,0 +1,56 @@ +import { existsSync, mkdirSync } from 'node:fs' +import path from 'node:path' +import { spawnSync } from 'node:child_process' +import { fileURLToPath } from 'node:url' + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const entrypoint = path.join(rootDir, 'src/bun/deeplink.js') + +export function stageWindowsDeeplink(appDir) { + if (!existsSync(entrypoint)) { + throw new Error(`stage-windows-deeplink: entrypoint not found: ${entrypoint}`) + } + + const outputPath = path.join(appDir, 'bin', 'deeplink.js') + mkdirSync(path.dirname(outputPath), { recursive: true }) + + const result = spawnSync( + 'bun', + [ + 'build', + '--minify', + '--target=bun', + entrypoint, + '--outfile', + outputPath + ], + { + cwd: rootDir, + stdio: 'inherit', + env: process.env + } + ) + + if (result.status !== 0) { + throw new Error( + `stage-windows-deeplink: bun build failed with exit code ${result.status ?? 1}` + ) + } + + if (!existsSync(outputPath)) { + throw new Error(`stage-windows-deeplink: output not created: ${outputPath}`) + } + + console.log(`stage-windows-deeplink: created ${outputPath}`) + return outputPath +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const appDirArg = process.argv[2] + if (!appDirArg) { + console.error('Usage: bun scripts/build-windows-deeplink.mjs ') + process.exit(1) + } + + stageWindowsDeeplink(path.resolve(appDirArg)) +} diff --git a/scripts/build-windows-msi.ps1 b/scripts/build-windows-msi.ps1 new file mode 100644 index 0000000..f986c76 --- /dev/null +++ b/scripts/build-windows-msi.ps1 @@ -0,0 +1,130 @@ +param( + [Parameter(Mandatory = $true)] + [string]$SetupExe, + + [Parameter(Mandatory = $true)] + [string]$OutputMsi, + + [Parameter(Mandatory = $true)] + [string]$Version, + + [string]$UpgradeCode = "735812DB-E33B-57A0-8FBC-5FC3155925AA" +) + +$ErrorActionPreference = "Stop" + +function Get-MsiVersion { + param([string]$InputVersion) + + $parts = $InputVersion.Split(".") + while ($parts.Count -lt 4) { + $parts += "0" + } + + return ($parts[0..3] -join ".") +} + +function Find-WixToolset { + $searchRoots = @( + $env:WIX, + $env:WIX_TOOLSET_PATH, + "${env:ProgramFiles(x86)}\WiX Toolset v3.14\bin", + "${env:ProgramFiles}\WiX Toolset v3.14\bin", + "${env:ProgramFiles(x86)}\WiX Toolset v3.11\bin", + "${env:ProgramFiles}\WiX Toolset v3.11\bin" + ) + + foreach ($root in $searchRoots) { + if (-not $root) { + continue + } + + $candle = Join-Path $root "candle.exe" + $light = Join-Path $root "light.exe" + if ((Test-Path $candle) -and (Test-Path $light)) { + return @{ + Candle = $candle + Light = $light + } + } + } + + $candleCommand = Get-Command candle.exe -ErrorAction SilentlyContinue + $lightCommand = Get-Command light.exe -ErrorAction SilentlyContinue + if ($candleCommand -and $lightCommand) { + return @{ + Candle = $candleCommand.Source + Light = $lightCommand.Source + } + } + + throw @" +WiX Toolset not found. Install WiX Toolset 3.11+ on the Windows build agent and ensure candle.exe and light.exe are on PATH. +Example: choco install wixtoolset --version=3.14.0.4118 +"@ +} + +function Escape-WixSourcePath { + param([string]$Path) + + return $Path.Replace("\", "\\") +} + +$rootDir = Split-Path -Parent $PSScriptRoot +$templatePath = Join-Path $rootDir "packaging/windows/msi-wrapped.wxs" +$workDir = Join-Path $env:TEMP "farmcontrol-wix" +$wix = Find-WixToolset + +if (Test-Path $workDir) { + Remove-Item $workDir -Recurse -Force +} +New-Item -ItemType Directory -Path $workDir | Out-Null + +$setupExePath = (Resolve-Path -LiteralPath $SetupExe).Path +$outputMsiPath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputMsi) +$outputDir = Split-Path $outputMsiPath -Parent +if ($outputDir -and -not (Test-Path $outputDir)) { + New-Item -ItemType Directory -Path $outputDir -Force | Out-Null +} + +$installerIconPath = Join-Path $rootDir "assets\installer.ico" +if (-not (Test-Path $installerIconPath)) { + throw "Installer icon not found at $installerIconPath. Run 'bun run generate-app-icons' first." +} + +$installerIconWorkPath = Join-Path $workDir "installer.ico" +Copy-Item -LiteralPath $installerIconPath -Destination $installerIconWorkPath -Force + +$msiVersion = Get-MsiVersion $Version +$wxsContent = Get-Content -LiteralPath $templatePath -Raw +$wxsContent = $wxsContent.Replace("__UPGRADE_CODE__", $UpgradeCode) +$wxsContent = $wxsContent.Replace("__VERSION__", $msiVersion) +$wxsContent = $wxsContent.Replace("__SETUP_EXE__", (Escape-WixSourcePath $setupExePath)) +$wxsContent = $wxsContent.Replace("__INSTALLER_ICON__", (Escape-WixSourcePath $installerIconWorkPath)) + +$projectWxs = Join-Path $workDir "project.wxs" +Set-Content -LiteralPath $projectWxs -Value $wxsContent -Encoding UTF8 + +$wixObj = Join-Path $workDir "project.wixobj" + +Push-Location $workDir +try { + & $wix.Candle "-arch" "x64" $projectWxs + if ($LASTEXITCODE -ne 0) { + throw "candle.exe failed with exit code $LASTEXITCODE" + } + + & $wix.Light "-out" $outputMsiPath "-spdb" "-sw1076" $wixObj + if ($LASTEXITCODE -ne 0) { + throw "light.exe failed with exit code $LASTEXITCODE" + } +} finally { + Pop-Location + Remove-Item $workDir -Recurse -Force +} + +if (-not (Test-Path $outputMsiPath)) { + throw "MSI installer was not created at $outputMsiPath" +} + +Write-Host "Created MSI installer at $outputMsiPath" diff --git a/scripts/build-windows-nsis.ps1 b/scripts/build-windows-nsis.ps1 new file mode 100644 index 0000000..05abc1d --- /dev/null +++ b/scripts/build-windows-nsis.ps1 @@ -0,0 +1,149 @@ +param( + [Parameter(Mandatory = $true)] + [string]$AppDir, + + [Parameter(Mandatory = $true)] + [string]$OutputExe, + + [Parameter(Mandatory = $true)] + [string]$Version, + + [string]$BuildNumber = "dev", + + [long]$MinInstallerBytes = 10485760 +) + +$ErrorActionPreference = "Stop" + +function Find-Makensis() { + $command = Get-Command makensis -ErrorAction SilentlyContinue + if ($command) { + return $command.Source + } + + $searchRoots = @( + "${env:ProgramFiles(x86)}\NSIS\makensis.exe", + "${env:ProgramFiles}\NSIS\makensis.exe" + ) + + foreach ($candidate in $searchRoots) { + if (Test-Path $candidate) { + return $candidate + } + } + + throw "Could not find makensis. Install NSIS 3.x on the Windows build agent." +} + +function Get-DirectoryBytes { + param([string]$Path) + + $total = 0 + foreach ($item in Get-ChildItem -LiteralPath $Path -Recurse -File -Force) { + $total += $item.Length + } + return $total +} + +$rootDir = Split-Path -Parent $PSScriptRoot +$nsiPath = Join-Path $rootDir "packaging/windows/farmcontrol.nsi" +$installerInclude = Join-Path $rootDir "packaging/windows/installer.nsh" +$fileListGenerator = Join-Path $rootDir "scripts/generate-nsis-file-list.ps1" +$workDir = Join-Path $env:TEMP "farmcontrol-nsis" +$localInstallerName = "farmcontrol-installer.exe" + +if (Test-Path $workDir) { + Remove-Item $workDir -Recurse -Force +} +New-Item -ItemType Directory -Path $workDir | Out-Null + +$appDirPath = (Resolve-Path -LiteralPath $AppDir).Path +$stagingAppDir = Join-Path $workDir "app" + +Write-Host "Staging application files for NSIS from $appDirPath" +Copy-Item -LiteralPath $appDirPath -Destination $stagingAppDir -Recurse -Force + +$stagedAppBytes = Get-DirectoryBytes $stagingAppDir +Write-Host "Staged application size: $([math]::Round($stagedAppBytes / 1MB, 2)) MB" + +if ($stagedAppBytes -lt 5242880) { + throw "Staged application is only $([math]::Round($stagedAppBytes / 1KB, 1)) KiB. Expected a full Electrobun app bundle before building the installer." +} + +$requiredExe = Join-Path $stagingAppDir "bin\FarmControl.exe" +$requiredDeeplinkScript = Join-Path $stagingAppDir "bin\deeplink.js" +if (-not (Test-Path $requiredExe)) { + throw "Staged application is missing bin\FarmControl.exe" +} +if (-not (Test-Path $requiredDeeplinkScript)) { + throw "Staged application is missing bin\deeplink.js" +} + +Copy-Item -LiteralPath $nsiPath -Destination (Join-Path $workDir "farmcontrol.nsi") +Copy-Item -LiteralPath $installerInclude -Destination (Join-Path $workDir "installer.nsh") +Copy-Item -LiteralPath $fileListGenerator -Destination (Join-Path $workDir "generate-nsis-file-list.ps1") + +$iconPath = Join-Path $rootDir "assets\installer.ico" +if (Test-Path $iconPath) { + Copy-Item -LiteralPath $iconPath -Destination (Join-Path $workDir "icon.ico") -Force + Write-Host "Using installer icon from $iconPath" +} + +$uninstallerIconPath = Join-Path $rootDir "assets\uninstaller.ico" +if (Test-Path $uninstallerIconPath) { + Copy-Item -LiteralPath $uninstallerIconPath -Destination (Join-Path $workDir "uninstaller.ico") -Force + Write-Host "Using uninstaller icon from $uninstallerIconPath" +} + +$makensis = Find-Makensis +$outputExePath = $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($OutputExe) +$outputDir = Split-Path $outputExePath -Parent +if (-not (Test-Path $outputDir)) { + New-Item -ItemType Directory -Path $outputDir | Out-Null +} + +$makensisArgs = @( + "/V3" + "/NOCD" + "/DOUTFILE=$localInstallerName" + "/DVERSION=$Version" + "/DBUILD_NUMBER=$BuildNumber" + "/DAPP_SOURCE_DIR=app" + "/DAPP_FILE_LIST_GENERATOR=generate-nsis-file-list.ps1" +) + +if (Test-Path (Join-Path $workDir "icon.ico")) { + $makensisArgs += "/DINSTALLER_ICON=icon.ico" +} + +if (Test-Path (Join-Path $workDir "uninstaller.ico")) { + $makensisArgs += "/DUNINSTALLER_ICON=uninstaller.ico" +} + +$makensisArgs += (Join-Path $workDir "farmcontrol.nsi") + +Push-Location $workDir +try { + & $makensis @makensisArgs + if ($LASTEXITCODE -ne 0) { + throw "makensis failed with exit code $LASTEXITCODE" + } +} finally { + Pop-Location +} + +$localInstallerPath = Join-Path $workDir $localInstallerName +if (-not (Test-Path $localInstallerPath)) { + throw "NSIS installer was not created at $localInstallerPath" +} + +$installerBytes = (Get-Item -LiteralPath $localInstallerPath).Length +Write-Host "NSIS installer size: $([math]::Round($installerBytes / 1MB, 2)) MB" + +if ($installerBytes -lt $MinInstallerBytes) { + throw "NSIS installer is only $([math]::Round($installerBytes / 1KB, 1)) KiB at $localInstallerPath. The application files were not packaged. Check NSIS logs above." +} + +Move-Item -LiteralPath $localInstallerPath -Destination $outputExePath -Force + +Write-Host "Created NSIS installer at $outputExePath" diff --git a/scripts/clean-build.mjs b/scripts/clean-build.mjs new file mode 100644 index 0000000..519a6ca --- /dev/null +++ b/scripts/clean-build.mjs @@ -0,0 +1,11 @@ +import { rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +for (const dir of ["build", "dist", "app_dist", "artifacts"]) { + rmSync(path.join(rootDir, dir), { recursive: true, force: true }); +} + +console.log("clean: removed build, dist, app_dist, and artifacts"); diff --git a/scripts/codesign-macos-app.mjs b/scripts/codesign-macos-app.mjs new file mode 100644 index 0000000..ae2e8c7 --- /dev/null +++ b/scripts/codesign-macos-app.mjs @@ -0,0 +1,89 @@ +import { existsSync } from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +function getCodesignArgs() { + const identity = process.env.ELECTROBUN_DEVELOPER_ID || "-"; + const args = ["--force", "--deep"]; + + if (identity !== "-") { + args.push("--options", "runtime", "--timestamp"); + } + + args.push("--sign", identity); + return { identity, args }; +} + +export function codesignMacAppBundle(appBundlePath) { + if (process.platform !== "darwin") { + console.log("codesign-macos-app: skipping (not macOS)"); + return; + } + + if (!appBundlePath || !existsSync(appBundlePath)) { + throw new Error(`codesign-macos-app: app bundle not found: ${appBundlePath}`); + } + + const contentsPath = path.join(appBundlePath, "Contents"); + if (!existsSync(contentsPath)) { + throw new Error(`codesign-macos-app: invalid app bundle: ${appBundlePath}`); + } + + const { identity, args } = getCodesignArgs(); + const result = spawnSync("codesign", [...args, appBundlePath], { + stdio: "inherit", + }); + + if (result.status !== 0) { + throw new Error( + `codesign failed with exit code ${result.status ?? 1}`, + ); + } + + const verify = spawnSync( + "codesign", + ["--verify", "--deep", "--strict", "--verbose=2", appBundlePath], + { encoding: "utf8" }, + ); + + if (verify.status !== 0) { + throw new Error( + `codesign verify failed: ${verify.stderr || verify.stdout || "unknown error"}`, + ); + } + + const label = identity === "-" ? "ad-hoc" : identity; + console.log(`codesign-macos-app: signed ${appBundlePath} (${label})`); +} + +function resolveAppBundlePath() { + const fromEnv = process.env.ELECTROBUN_WRAPPER_BUNDLE_PATH; + if (fromEnv && existsSync(fromEnv)) { + return path.resolve(fromEnv); + } + + const fromArgv = process.argv[2]; + if (fromArgv && existsSync(fromArgv)) { + return path.resolve(fromArgv); + } + + return null; +} + +const invokedPath = process.argv[1] + ? path.resolve(process.argv[1]) + : null; +const modulePath = fileURLToPath(import.meta.url); + +if (invokedPath === modulePath) { + const appBundlePath = resolveAppBundlePath(); + if (!appBundlePath) { + console.error( + "codesign-macos-app: set ELECTROBUN_WRAPPER_BUNDLE_PATH or pass app bundle path", + ); + process.exit(1); + } + + codesignMacAppBundle(appBundlePath); +} diff --git a/scripts/ensure-electrobun-core.mjs b/scripts/ensure-electrobun-core.mjs new file mode 100644 index 0000000..1881010 --- /dev/null +++ b/scripts/ensure-electrobun-core.mjs @@ -0,0 +1,131 @@ +import { + createWriteStream, + existsSync, + mkdirSync, + readdirSync, + unlinkSync, +} from "node:fs"; +import { spawnSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { getReleaseArch } from "./release-artifact-utils.mjs"; +import { fixMacosHeaderpad } from "./fix-macos-headerpad.mjs"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const electrobunDir = path.join(rootDir, "node_modules/electrobun"); +const electrobunVersion = JSON.parse( + await Bun.file(path.join(electrobunDir, "package.json")).text(), +).version; + +function getPlatformPaths(targetOS, targetArch) { + const binExt = targetOS === "win" ? ".exe" : ""; + const platformDistDir = path.join( + electrobunDir, + `dist-${targetOS}-${targetArch}`, + ); + + return { + platformDistDir, + bunBinary: path.join(platformDistDir, "bun") + binExt, + bsdiff: path.join(platformDistDir, "bsdiff") + binExt, + bspatch: path.join(platformDistDir, "bspatch") + binExt, + launcher: path.join(platformDistDir, "launcher") + binExt, + nativeWrapperMacos: path.join(platformDistDir, "libNativeWrapper.dylib"), + }; +} + +async function downloadFile(url, destination) { + const response = await fetch(url); + if (!response.ok) { + throw new Error(`Failed to download ${url}: ${response.status} ${response.statusText}`); + } + + mkdirSync(path.dirname(destination), { recursive: true }); + const fileStream = createWriteStream(destination); + const reader = response.body?.getReader(); + if (!reader) { + throw new Error(`No response body for ${url}`); + } + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + fileStream.write(Buffer.from(value)); + } + + await new Promise((resolve, reject) => { + fileStream.end((error) => (error ? reject(error) : resolve())); + }); +} + +function extractTarGz(tarPath, destination) { + mkdirSync(destination, { recursive: true }); + const result = spawnSync("tar", ["-xzf", tarPath, "-C", destination], { + stdio: "inherit", + }); + if (result.status !== 0) { + throw new Error(`tar extraction failed for ${tarPath}`); + } +} + +async function ensureCoreDependencies(targetOS, targetArch) { + const paths = getPlatformPaths(targetOS, targetArch); + const required = [ + paths.bunBinary, + paths.bsdiff, + paths.bspatch, + paths.launcher, + paths.nativeWrapperMacos, + ]; + + if (required.every((filePath) => existsSync(filePath))) { + console.log(`ensure-electrobun-core: ${targetOS}-${targetArch} already present`); + return; + } + + const platformName = + targetOS === "macos" ? "darwin" : targetOS === "win" ? "win" : "linux"; + const url = `https://github.com/blackboardsh/electrobun/releases/download/v${electrobunVersion}/electrobun-core-${platformName}-${targetArch}.tar.gz`; + const tempFile = path.join( + electrobunDir, + `core-${targetOS}-${targetArch}-temp.tar.gz`, + ); + + console.log(`ensure-electrobun-core: downloading ${targetOS}-${targetArch}`); + console.log(url); + + await downloadFile(url, tempFile); + extractTarGz(tempFile, paths.platformDistDir); + + if (existsSync(tempFile)) { + unlinkSync(tempFile); + } + + const missing = required.filter((filePath) => !existsSync(filePath)); + if (missing.length > 0) { + const extracted = existsSync(paths.platformDistDir) + ? readdirSync(paths.platformDistDir) + : []; + throw new Error( + `Missing ${targetOS}-${targetArch} binaries after extract: ${missing.join(", ")}; extracted=${extracted.join(", ")}`, + ); + } + + console.log(`ensure-electrobun-core: ${targetOS}-${targetArch} ready`); +} + +const targetOS = "macos"; +const hostArch = getReleaseArch(process.arch); +const targetArch = getReleaseArch( + process.env.ELECTROBUN_TARGET_ARCH || + process.env.ELECTROBUN_FORCE_ARCH || + process.arch, +); + +const archesToEnsure = new Set([hostArch, targetArch]); +for (const arch of archesToEnsure) { + await ensureCoreDependencies(targetOS, arch); + // electrobun#485: x64 core binaries lack Mach-O headerpad and get corrupted + // by codesign; free a load-command slot before anything copies or signs them. + fixMacosHeaderpad(getPlatformPaths(targetOS, arch).platformDistDir); +} diff --git a/scripts/expand-macos-bundle.mjs b/scripts/expand-macos-bundle.mjs new file mode 100644 index 0000000..6559f8c --- /dev/null +++ b/scripts/expand-macos-bundle.mjs @@ -0,0 +1,152 @@ +import { + existsSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, +} from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { tmpdir } from "node:os"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "dev"; +const targetOs = process.env.ELECTROBUN_OS || "macos"; +const wrapperPath = process.env.ELECTROBUN_WRAPPER_BUNDLE_PATH; + +if (buildEnv === "dev" || targetOs !== "macos") { + console.log("expand-macos-bundle: skipping (dev or non-macOS build)"); + process.exit(0); +} + +if (!wrapperPath || !existsSync(wrapperPath)) { + console.error("expand-macos-bundle: ELECTROBUN_WRAPPER_BUNDLE_PATH not set or missing"); + process.exit(1); +} + +const resolvedWrapperPath = path.resolve(wrapperPath); +const contentsPath = path.join(resolvedWrapperPath, "Contents"); +const resourcesPath = path.join(contentsPath, "Resources"); +const metadataPath = path.join(resourcesPath, "metadata.json"); + +if (!existsSync(metadataPath)) { + console.log("expand-macos-bundle: no extractor metadata, assuming already expanded"); + process.exit(0); +} + +const metadata = JSON.parse(readFileSync(metadataPath, "utf8")); +const hash = metadata.hash; +const appName = metadata.name || "Farm Control"; +const tarZstPath = path.resolve(resourcesPath, `${hash}.tar.zst`); + +if (!existsSync(tarZstPath)) { + console.log(`expand-macos-bundle: ${hash}.tar.zst not found, skipping`); + process.exit(0); +} + +function decompressTarZst(inputPath, outputPath) { + const systemZstd = spawnSync("zstd", ["--version"], { encoding: "utf8" }); + if (systemZstd.status === 0) { + return spawnSync("zstd", ["-d", "-f", "-o", outputPath, inputPath], { + stdio: "inherit", + }); + } + + const hostArch = process.arch === "arm64" ? "arm64" : "x64"; + const zigZstd = path.join( + rootDir, + "node_modules/electrobun/dist-macos-" + hostArch, + "zig-zstd", + ); + if (existsSync(zigZstd)) { + return spawnSync( + zigZstd, + ["decompress", "-i", inputPath, "-o", outputPath, "--no-timing"], + { stdio: "inherit" }, + ); + } + + console.error( + "expand-macos-bundle: zstd not found (install zstd or use electrobun dist binaries)", + ); + process.exit(1); +} + +const workDir = path.join(tmpdir(), `farmcontrol-expand-${hash}`); +const tarPath = path.join(workDir, `${hash}.tar`); +rmSync(workDir, { recursive: true, force: true }); +mkdirSync(workDir, { recursive: true }); + +const decompress = decompressTarZst(tarZstPath, tarPath); + +if (decompress.status !== 0) { + console.error("expand-macos-bundle: zstd decompression failed"); + process.exit(decompress.status ?? 1); +} + +const extractTar = spawnSync("tar", ["-xf", tarPath, "-C", workDir], { + stdio: "inherit", +}); + +if (extractTar.status !== 0) { + console.error("expand-macos-bundle: tar extraction failed"); + process.exit(extractTar.status ?? 1); +} + +const innerAppPath = path.join(workDir, `${appName}.app`); +if (!existsSync(innerAppPath)) { + const appBundle = readdirSync(workDir).find((entry) => entry.endsWith(".app")); + if (!appBundle) { + console.error("expand-macos-bundle: extracted app bundle not found"); + process.exit(1); + } +} + +const resolvedInnerApp = existsSync(innerAppPath) + ? innerAppPath + : path.join(workDir, readdirSync(workDir).find((e) => e.endsWith(".app"))); +const innerContentsPath = path.join(resolvedInnerApp, "Contents"); + +function replaceDirectory(sourceDir, destinationDir) { + rmSync(destinationDir, { recursive: true, force: true }); + const result = spawnSync("ditto", [sourceDir, destinationDir], { + stdio: "inherit", + }); + if (result.status !== 0) { + console.error("expand-macos-bundle: ditto copy failed"); + process.exit(result.status ?? 1); + } +} + +replaceDirectory( + path.join(innerContentsPath, "MacOS"), + path.join(contentsPath, "MacOS"), +); + +rmSync(resourcesPath, { recursive: true, force: true }); +replaceDirectory(path.join(innerContentsPath, "Resources"), resourcesPath); + +const innerFrameworks = path.join(innerContentsPath, "Frameworks"); +const wrapperFrameworks = path.join(contentsPath, "Frameworks"); +if (existsSync(innerFrameworks)) { + replaceDirectory(innerFrameworks, wrapperFrameworks); +} + +const infoPlistResult = spawnSync( + "ditto", + [path.join(innerContentsPath, "Info.plist"), path.join(contentsPath, "Info.plist")], + { stdio: "inherit" }, +); +if (infoPlistResult.status !== 0) { + console.error("expand-macos-bundle: Info.plist copy failed"); + process.exit(infoPlistResult.status ?? 1); +} + +rmSync(workDir, { recursive: true, force: true }); + +if (process.platform === "darwin") { + spawnSync("xattr", ["-cr", resolvedWrapperPath], { stdio: "inherit" }); +} + +console.log(`expand-macos-bundle: pre-expanded ${resolvedWrapperPath}`); diff --git a/scripts/expand-windows-installer.mjs b/scripts/expand-windows-installer.mjs new file mode 100644 index 0000000..1061c9b --- /dev/null +++ b/scripts/expand-windows-installer.mjs @@ -0,0 +1,144 @@ +import { + cpSync, + existsSync, + mkdirSync, + readdirSync, + rmSync, + statSync, +} from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const electrobunDir = path.join(rootDir, "node_modules/electrobun"); + +function findZstdDecompressCommand() { + const hostArch = process.arch === "arm64" ? "arm64" : "x64"; + const zigCandidates = [ + path.join(electrobunDir, `dist-win-${hostArch}`, "zig-zstd.exe"), + path.join(electrobunDir, "dist-win-x64", "zig-zstd.exe"), + path.join(electrobunDir, `dist-macos-${hostArch}`, "zig-zstd"), + path.join(electrobunDir, "dist-macos-x64", "zig-zstd"), + path.join(electrobunDir, "dist-win-x64", "zig-zstd", "x64", "zig-zstd.exe"), + path.join(electrobunDir, "dist-win-x64", "zig-zstd", "arm64", "zig-zstd.exe"), + path.join(electrobunDir, "vendors", "zig-zstd", "x64", "zig-zstd.exe"), + path.join(electrobunDir, "vendors", "zig-zstd", "arm64", "zig-zstd.exe"), + ]; + + for (const candidate of zigCandidates) { + if (!existsSync(candidate)) { + continue; + } + + return { + kind: "zig-zstd", + command: candidate, + args: (inputPath, outputPath) => [ + "decompress", + "-i", + inputPath, + "-o", + outputPath, + "--no-timing", + ], + }; + } + + const systemZstd = spawnSync("zstd", ["--version"], { + encoding: "utf8", + shell: process.platform === "win32", + }); + if (systemZstd.status === 0) { + return { + kind: "system-zstd", + command: "zstd", + args: (inputPath, outputPath) => [ + "-d", + "-f", + "-o", + outputPath, + inputPath, + ], + }; + } + + return null; +} + +function decompressTarZst(inputPath, outputPath) { + const zstd = findZstdDecompressCommand(); + if (!zstd) { + throw new Error( + "expand-windows-installer: zstd not found (install zstd or use electrobun dist binaries)", + ); + } + + const resolvedInput = path.resolve(inputPath); + const resolvedOutput = path.resolve(outputPath); + const args = zstd.args(resolvedInput, resolvedOutput); + + console.log( + `expand-windows-installer: decompressing with ${zstd.command} (${zstd.kind})`, + ); + + const result = spawnSync(zstd.command, args, { + stdio: "inherit", + shell: false, + windowsHide: true, + }); + + if (result.status !== 0) { + throw new Error( + `expand-windows-installer: decompression failed (exit ${result.status ?? 1}) using ${zstd.command} ${args.join(" ")}`, + ); + } +} + +export function expandWindowsAppFromArchive(setupArchivePath, parentDir) { + const resolvedArchive = path.resolve(setupArchivePath); + if (!existsSync(resolvedArchive)) { + throw new Error(`expand-windows-installer: archive not found: ${resolvedArchive}`); + } + + const workDir = path.join(path.resolve(parentDir), ".expanded-app"); + const tarPath = path.join(workDir, "app.tar"); + + rmSync(workDir, { recursive: true, force: true }); + mkdirSync(workDir, { recursive: true }); + + const archiveForDecompress = path.join(workDir, "setup.tar.zst"); + cpSync(resolvedArchive, archiveForDecompress); + decompressTarZst(archiveForDecompress, tarPath); + + const extractTar = spawnSync("tar", ["-xf", tarPath, "-C", workDir], { + stdio: "inherit", + shell: false, + windowsHide: true, + }); + + if (extractTar.status !== 0) { + rmSync(workDir, { recursive: true, force: true }); + throw new Error( + `expand-windows-installer: tar extraction failed (exit ${extractTar.status ?? 1})`, + ); + } + + const appDir = readdirSync(workDir) + .filter((entry) => entry !== "app.tar" && entry !== "__MACOSX") + .map((entry) => path.join(workDir, entry)) + .find((entryPath) => statSync(entryPath).isDirectory()); + + if (!appDir) { + rmSync(workDir, { recursive: true, force: true }); + throw new Error("expand-windows-installer: app folder not found in archive"); + } + + console.log(`expand-windows-installer: expanded ${appDir}`); + return appDir; +} + +export function cleanExpandedWindowsApp(parentDir) { + const workDir = path.join(path.resolve(parentDir), ".expanded-app"); + rmSync(workDir, { recursive: true, force: true }); +} diff --git a/scripts/finalize-desktop-artifacts.mjs b/scripts/finalize-desktop-artifacts.mjs new file mode 100644 index 0000000..6b8db20 --- /dev/null +++ b/scripts/finalize-desktop-artifacts.mjs @@ -0,0 +1,681 @@ +import { + cpSync, + existsSync, + mkdirSync, + readdirSync, + readFileSync, + rmSync, + statSync +} from 'node:fs' +import path from 'node:path' +import { spawnSync } from 'node:child_process' +import { fileURLToPath } from 'node:url' +import { + getReleaseArch, + getReleaseArtifactName, + getReleaseVersion, + isBundleCefEnabled +} from './release-artifact-utils.mjs' +import { + cleanExpandedWindowsApp, + expandWindowsAppFromArchive +} from './expand-windows-installer.mjs' +import { stageWindowsDeeplink } from './build-windows-deeplink.mjs' +import { patchWindowsBinaries } from './patch-windows-binaries.mjs' +import { codesignMacAppBundle } from './codesign-macos-app.mjs' + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const packageJson = JSON.parse( + readFileSync(path.join(rootDir, 'package.json'), 'utf8') +) +const buildEnv = process.env.ELECTROBUN_BUILD_ENV || 'stable' +const targetOs = + process.env.ELECTROBUN_OS || + (process.platform === 'darwin' + ? 'macos' + : process.platform === 'win32' + ? 'win' + : process.platform === 'linux' + ? 'linux' + : null) +const buildArch = getReleaseArch(process.env.ELECTROBUN_ARCH || process.arch) +const version = + process.env.ELECTROBUN_APP_VERSION || getReleaseVersion(packageJson) +const bundleCef = isBundleCefEnabled() +const artifactDir = + process.env.ELECTROBUN_ARTIFACT_DIR || path.join(rootDir, 'app_dist') +const identifier = + process.env.ELECTROBUN_APP_IDENTIFIER || 'com.tombutcher.farmcontrol' +const artifactPrefix = `farmcontrol-${version}-` + +function artifactName(arch, ext) { + return getReleaseArtifactName(version, arch, ext, { cef: bundleCef }) +} + +function getBuildRoot() { + const electrobunBuildDir = process.env.ELECTROBUN_BUILD_DIR + if (!electrobunBuildDir) { + return path.join(rootDir, 'build') + } + + const baseName = path.basename(electrobunBuildDir) + if (baseName.startsWith('stable-')) { + return path.dirname(electrobunBuildDir) + } + + return electrobunBuildDir +} + +function walkFiles(dir) { + const files = [] + if (!existsSync(dir)) { + return files + } + + for (const entry of readdirSync(dir)) { + const fullPath = path.join(dir, entry) + const stats = statSync(fullPath) + if (stats.isDirectory()) { + files.push(...walkFiles(fullPath)) + } else { + files.push(fullPath) + } + } + + return files +} + +function findByExtension(root, extension) { + return walkFiles(root).find((filePath) => + filePath.toLowerCase().endsWith(extension.toLowerCase()) + ) +} + +function findMacAppBundle(arch) { + const platformDir = path.join(getBuildRoot(), `stable-macos-${arch}`) + if (!existsSync(platformDir)) { + return null + } + + for (const child of readdirSync(platformDir)) { + if (child.endsWith('.app')) { + return path.join(platformDir, child) + } + } + + return null +} + +function findMacDmgSource(arch) { + const prefixedArtifact = walkFiles(artifactDir).find( + (filePath) => + filePath.includes(`stable-macos-${arch}`) && + filePath.toLowerCase().endsWith('.dmg') + ) + if (prefixedArtifact) { + return prefixedArtifact + } + + const buildDmg = findByExtension( + path.join(getBuildRoot(), `stable-macos-${arch}`), + '.dmg' + ) + if (buildDmg) { + return buildDmg + } + + return findByExtension(artifactDir, '.dmg') +} + +function findWindowsInstallerFiles() { + const buildRoot = getBuildRoot() + if (!existsSync(buildRoot)) { + return null + } + + for (const entry of readdirSync(buildRoot)) { + if (!entry.startsWith('stable-win-')) { + continue + } + + const platformDir = path.join(buildRoot, entry) + const files = walkFiles(platformDir) + const setupExe = files.find((filePath) => /-setup\.exe$/i.test(filePath)) + const setupArchive = files.find((filePath) => + /-setup\.tar\.zst$/i.test(filePath) + ) + const setupMetadata = files.find((filePath) => + /-setup\.metadata\.json$/i.test(filePath) + ) + const setupZip = files.find((filePath) => /-setup\.zip$/i.test(filePath)) + + if (setupExe && setupArchive && setupMetadata) { + return { setupExe, setupArchive, setupMetadata, setupZip } + } + } + + return null +} + +function publishArtifact(sourcePath, arch, ext) { + if (!sourcePath || !existsSync(sourcePath)) { + throw new Error( + `Missing source artifact for ${arch}.${ext}: ${sourcePath ?? 'not found'}` + ) + } + + mkdirSync(artifactDir, { recursive: true }) + const destination = path.join(artifactDir, artifactName(arch, ext)) + cpSync(sourcePath, destination) + console.log(`Published ${destination}`) + return destination +} + +function cleanStagingArtifacts(keepNames) { + if (!existsSync(artifactDir)) { + return + } + + for (const entry of readdirSync(artifactDir)) { + if (keepNames.includes(entry) || entry.startsWith(artifactPrefix)) { + continue + } + + if ( + entry.includes('stable-macos-') || + entry.includes('stable-win-') || + entry.endsWith('-update.json') || + entry.endsWith('.tar.gz') + ) { + rmSync(path.join(artifactDir, entry), { recursive: true, force: true }) + } + } +} + +const MAC_DMG_ASSETS_DIR = path.join(rootDir, 'packaging/macos/dmg') +const MAC_INSTALLER_ICONSET_PATH = path.join(rootDir, 'assets/installer.iconset') +const MAC_DMG_BACKGROUND_PATH = path.join(rootDir, 'assets/dmg/background.png') +const MAC_DMG_BACKGROUND_RETINA_PATH = path.join( + rootDir, + 'assets/dmg/background@2x.png' +) +const MAC_DMG_APP_NAME = 'Farm Control.app' +const MAC_DMG_WINDOW_WIDTH = 540 +const MAC_DMG_WINDOW_HEIGHT = 380 + +function findCommand(command) { + const which = spawnSync('which', [command], { encoding: 'utf8' }) + if (which.status === 0 && which.stdout.trim()) { + return which.stdout.trim() + } + + return null +} + +function buildInstallerIcns(destinationPath) { + if (!existsSync(MAC_INSTALLER_ICONSET_PATH)) { + throw new Error( + `Installer iconset not found at ${MAC_INSTALLER_ICONSET_PATH}. Run \`bun run generate-app-icons\` first.` + ) + } + + mkdirSync(path.dirname(destinationPath), { recursive: true }) + rmSync(destinationPath, { force: true }) + + const iconutil = spawnSync( + 'iconutil', + ['-c', 'icns', '-o', destinationPath, MAC_INSTALLER_ICONSET_PATH], + { stdio: 'inherit' } + ) + + if (iconutil.status !== 0) { + throw new Error( + `iconutil failed to create installer icns with exit code ${iconutil.status ?? 1}` + ) + } + + return destinationPath +} + +function applyMacInstallerFileIcon(targetPath, icnsPath) { + if (!existsSync(icnsPath)) { + console.warn( + `finalize-desktop-artifacts: installer icns not found at ${icnsPath}, skipping custom icon` + ) + return false + } + + const fileicon = findCommand('fileicon') + if (fileicon) { + const result = spawnSync(fileicon, ['set', targetPath, icnsPath], { + stdio: 'inherit' + }) + + if (result.status === 0) { + return true + } + } + + const escapedTarget = targetPath.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + const escapedIcon = icnsPath.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + const result = spawnSync( + 'osascript', + [ + '-e', + `tell application "Finder" to set icon of (POSIX file "${escapedTarget}") to (read (POSIX file "${escapedIcon}") as picture)` + ], + { stdio: 'inherit' } + ) + + if (result.status === 0) { + return true + } + + console.warn( + 'finalize-desktop-artifacts: could not apply installer icon; install fileicon or run on macOS with Finder access' + ) + return false +} + +function ensureMacDmgAssets() { + mkdirSync(MAC_DMG_ASSETS_DIR, { recursive: true }) + + const voliconPath = path.join(MAC_DMG_ASSETS_DIR, 'volicon.icns') + buildInstallerIcns(voliconPath) + + if (!existsSync(MAC_DMG_BACKGROUND_PATH)) { + throw new Error(`DMG background not found at ${MAC_DMG_BACKGROUND_PATH}`) + } + + if (!existsSync(MAC_DMG_BACKGROUND_RETINA_PATH)) { + console.warn( + `finalize-desktop-artifacts: retina DMG background not found at ${MAC_DMG_BACKGROUND_RETINA_PATH}` + ) + } + + return { + volicon: voliconPath, + background: MAC_DMG_BACKGROUND_PATH + } +} + +function findCreateDmgCommand() { + const which = spawnSync('which', ['create-dmg'], { encoding: 'utf8' }) + if (which.status === 0 && which.stdout.trim()) { + return which.stdout.trim() + } + + for (const candidate of [ + '/opt/homebrew/bin/create-dmg', + '/usr/local/bin/create-dmg' + ]) { + if (existsSync(candidate)) { + return candidate + } + } + + return null +} + +function buildMacDmgWithCreateDmg( + createDmg, + dmgPath, + sourceFolder, + appBundleName, + dmgAssets +) { + rmSync(dmgPath, { force: true }) + + const args = [ + '--volname', + 'Farm Control', + '--window-pos', + '200', + '120', + '--window-size', + String(MAC_DMG_WINDOW_WIDTH), + String(MAC_DMG_WINDOW_HEIGHT), + '--icon-size', + '100', + '--icon', + appBundleName, + '130', + '212', + '--hide-extension', + appBundleName, + '--app-drop-link', + '410', + '212', + '--format', + 'UDZO' + ] + + if (dmgAssets.volicon) { + args.push('--volicon', dmgAssets.volicon) + } + + if (dmgAssets.background) { + args.push('--background', dmgAssets.background) + } + + args.push(dmgPath, sourceFolder) + + const result = spawnSync(createDmg, args, { stdio: 'inherit' }) + + if (result.status !== 0) { + throw new Error(`create-dmg failed with exit code ${result.status ?? 1}`) + } + + if (!existsSync(dmgPath)) { + throw new Error(`create-dmg did not produce ${dmgPath}`) + } + + return dmgPath +} + +function copyMacAppBundle(sourcePath, destinationPath) { + rmSync(destinationPath, { recursive: true, force: true }) + mkdirSync(path.dirname(destinationPath), { recursive: true }) + + const result = spawnSync('ditto', [sourcePath, destinationPath], { + stdio: 'inherit' + }) + + if (result.status !== 0) { + throw new Error(`ditto failed with exit code ${result.status ?? 1}`) + } +} + +function canUseDirectDmgSourceFolder(appBundlePath) { + const platformDir = path.dirname(appBundlePath) + const appName = path.basename(appBundlePath) + const entries = readdirSync(platformDir).filter( + (entry) => !entry.startsWith('.') && entry !== '.finalize-dmg-staging' + ) + + return entries.length === 1 && entries[0] === appName +} + +async function buildMacDmg(appBundlePath, arch) { + const createDmg = findCreateDmgCommand() + if (!createDmg) { + throw new Error( + 'create-dmg not found. Install with: brew install create-dmg' + ) + } + + const appBundleName = path.basename(appBundlePath) + if (appBundleName !== MAC_DMG_APP_NAME) { + console.warn( + `finalize-desktop-artifacts: expected ${MAC_DMG_APP_NAME}, found ${appBundleName}` + ) + } + + const dmgPath = path.join(artifactDir, artifactName(arch, 'dmg')) + + mkdirSync(artifactDir, { recursive: true }) + + const stagingDir = path.join( + path.dirname(appBundlePath), + '.finalize-dmg-staging' + ) + const useDirectSource = canUseDirectDmgSourceFolder(appBundlePath) + const sourceFolder = useDirectSource + ? path.dirname(appBundlePath) + : stagingDir + + if (!useDirectSource) { + rmSync(stagingDir, { recursive: true, force: true }) + mkdirSync(stagingDir, { recursive: true }) + const stagedAppPath = path.join(stagingDir, path.basename(appBundlePath)) + copyMacAppBundle(appBundlePath, stagedAppPath) + codesignMacAppBundle(stagedAppPath) + } + + let builtDmgPath + const dmgAssets = ensureMacDmgAssets() + + try { + builtDmgPath = buildMacDmgWithCreateDmg( + createDmg, + dmgPath, + sourceFolder, + appBundleName, + dmgAssets + ) + applyMacInstallerFileIcon(builtDmgPath, dmgAssets.volicon) + } finally { + if (!useDirectSource) { + rmSync(stagingDir, { recursive: true, force: true }) + } + } + + console.log(`Published ${builtDmgPath}`) + return builtDmgPath +} + +function cleanMacBuildDir(arch) { + const platformDir = path.join(getBuildRoot(), `stable-macos-${arch}`) + if (existsSync(platformDir)) { + rmSync(platformDir, { recursive: true, force: true }) + console.log(`Removed build output ${platformDir}`) + } +} + +function buildMacPkg(appBundlePath, arch) { + const pkgPath = path.join(artifactDir, artifactName(arch, 'pkg')) + + const result = spawnSync( + 'pkgbuild', + [ + '--component', + appBundlePath, + '--install-location', + '/Applications', + '--identifier', + identifier, + '--version', + version, + pkgPath + ], + { stdio: 'inherit' } + ) + + if (result.status !== 0) { + throw new Error(`pkgbuild failed with exit code ${result.status ?? 1}`) + } + + console.log(`Published ${pkgPath}`) + return pkgPath +} + +function stageWindowsDeeplinkScript(appDir) { + return stageWindowsDeeplink(appDir) +} + +function cleanWinBuildDir(arch) { + const platformDir = path.join(getBuildRoot(), `stable-win-${arch}`) + if (existsSync(platformDir)) { + rmSync(platformDir, { recursive: true, force: true }) + console.log(`Removed build output ${platformDir}`) + } +} + +function buildWindowsNsis(appDir, arch) { + const scriptPath = path.join(rootDir, 'scripts/build-windows-nsis.ps1') + const exePath = path.join(artifactDir, artifactName(arch, 'exe')) + const buildInfoPath = path.join(rootDir, 'src/buildInfo.json') + const buildInfo = existsSync(buildInfoPath) + ? JSON.parse(readFileSync(buildInfoPath, 'utf8')) + : {} + const buildNumber = + process.env.BUILD_NUMBER || + process.env.VITE_BUILD_NUMBER || + buildInfo.buildNumber || + 'dev' + const powershell = process.env.SystemRoot + ? path.join( + process.env.SystemRoot, + 'System32', + 'WindowsPowerShell', + 'v1.0', + 'powershell.exe' + ) + : 'powershell.exe' + + const result = spawnSync( + powershell, + [ + '-NoProfile', + '-ExecutionPolicy', + 'Bypass', + '-File', + scriptPath, + '-AppDir', + appDir, + '-OutputExe', + exePath, + '-Version', + version, + '-BuildNumber', + buildNumber + ], + { stdio: 'inherit' } + ) + + if (result.status !== 0) { + throw new Error( + `build-windows-nsis.ps1 failed with exit code ${result.status ?? 1}` + ) + } + + const minInstallerBytes = 10 * 1024 * 1024 + const installerSize = statSync(exePath).size + if (installerSize < minInstallerBytes) { + throw new Error( + `Windows installer ${path.basename(exePath)} is only ${(installerSize / 1024).toFixed(1)} KiB; expected at least ${minInstallerBytes / (1024 * 1024)} MiB` + ) + } + + console.log(`Published ${exePath}`) + return exePath +} + +function buildWindowsMsi(setupExePath, arch) { + const scriptPath = path.join(rootDir, 'scripts/build-windows-msi.ps1') + const msiPath = path.join(artifactDir, artifactName(arch, 'msi')) + const powershell = process.env.SystemRoot + ? path.join( + process.env.SystemRoot, + 'System32', + 'WindowsPowerShell', + 'v1.0', + 'powershell.exe' + ) + : 'powershell.exe' + + const result = spawnSync( + powershell, + [ + '-NoProfile', + '-ExecutionPolicy', + 'Bypass', + '-File', + scriptPath, + '-SetupExe', + setupExePath, + '-OutputMsi', + msiPath, + '-Version', + version + ], + { stdio: 'inherit' } + ) + + if (result.status !== 0) { + throw new Error( + `build-windows-msi.ps1 failed with exit code ${result.status ?? 1}` + ) + } + + console.log(`Published ${msiPath}`) + return msiPath +} + +if (buildEnv === 'dev') { + console.log('finalize-desktop-artifacts: skipping dev build') + process.exit(0) +} + +async function main() { + console.log( + `finalize-desktop-artifacts: os=${targetOs} arch=${buildArch} cef=${bundleCef} version=${version}` + ) + + if (targetOs === 'macos') { + const appBundle = findMacAppBundle(buildArch) + + if (!appBundle) { + console.log( + `finalize-desktop-artifacts: no macOS ${buildArch} app bundle found, skipping` + ) + process.exit(0) + } + + codesignMacAppBundle(appBundle) + + const existingDmg = findMacDmgSource(buildArch) + const dmgPath = existingDmg + ? publishArtifact(existingDmg, buildArch, 'dmg') + : await buildMacDmg(appBundle, buildArch) + + const published = [dmgPath, buildMacPkg(appBundle, buildArch)] + + cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))) + cleanMacBuildDir(buildArch) + return + } + + if (targetOs === 'win') { + const arch = getReleaseArch(process.env.ELECTROBUN_ARCH || 'x64') + const installerFiles = findWindowsInstallerFiles() + + if (!installerFiles?.setupArchive) { + throw new Error( + 'Could not find the Windows setup archive (.tar.zst) to expand' + ) + } + + const platformDir = path.dirname(installerFiles.setupArchive) + const appDir = expandWindowsAppFromArchive( + installerFiles.setupArchive, + platformDir + ) + stageWindowsDeeplinkScript(appDir) + patchWindowsBinaries(appDir) + + let published + try { + const setupExe = buildWindowsNsis(appDir, arch) + published = [setupExe, buildWindowsMsi(setupExe, arch)] + + if (installerFiles.setupZip) { + published.push(publishArtifact(installerFiles.setupZip, arch, 'zip')) + } + } finally { + cleanExpandedWindowsApp(platformDir) + } + + cleanStagingArtifacts(published.map((filePath) => path.basename(filePath))) + cleanWinBuildDir(arch) + return + } + + console.log( + 'finalize-desktop-artifacts: no desktop packaging configured for', + targetOs ?? 'unknown target' + ) + process.exit(0) +} + +await main() diff --git a/scripts/fix-macos-headerpad.mjs b/scripts/fix-macos-headerpad.mjs new file mode 100644 index 0000000..cc673c3 --- /dev/null +++ b/scripts/fix-macos-headerpad.mjs @@ -0,0 +1,152 @@ +// Workaround for https://github.com/blackboardsh/electrobun/issues/485 +// +// Electrobun's darwin-x64 core binaries (launcher, extractor, libasar.dylib, +// bsdiff, zig-asar in v1.18.1) are Zig-built with zero/near-zero Mach-O +// headerpad and no code signature. When codesign adds the 16-byte +// LC_CODE_SIGNATURE load command it silently overwrites the first bytes of +// __text, and the signed binary segfaults on launch (Intel Macs only; +// arm64 binaries always ship with a signature slot that is re-signed in +// place). +// +// This script frees room in the load-command area by dropping the 16-byte +// LC_SOURCE_VERSION command (LC_UUID as a fallback) from any thin x86_64 +// Mach-O that has less than 16 bytes of headerpad and no existing code +// signature. It is idempotent and a no-op once upstream ships rebuilt +// binaries with headerpad_size set. + +import { readdirSync, readFileSync, statSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const MH_MAGIC_64 = 0xfeedfacf; +const CPU_TYPE_X86_64 = 0x01000007; +const LC_SEGMENT_64 = 0x19; +const LC_UUID = 0x1b; +const LC_CODE_SIGNATURE = 0x1d; +const LC_SOURCE_VERSION = 0x2a; +const HEADER_SIZE = 32; +const CODE_SIGNATURE_CMD_SIZE = 16; + +function analyzeMachO(buffer) { + if (buffer.length < HEADER_SIZE || buffer.readUInt32LE(0) !== MH_MAGIC_64) { + return null; + } + + const cputype = buffer.readInt32LE(4); + const ncmds = buffer.readUInt32LE(16); + const sizeofcmds = buffer.readUInt32LE(20); + + let offset = HEADER_SIZE; + let firstSectionOffset = null; + let hasCodeSignature = false; + let sourceVersionCmd = null; + let uuidCmd = null; + + for (let i = 0; i < ncmds; i += 1) { + const cmd = buffer.readUInt32LE(offset); + const cmdsize = buffer.readUInt32LE(offset + 4); + + if (cmd === LC_CODE_SIGNATURE) { + hasCodeSignature = true; + } else if (cmd === LC_SOURCE_VERSION) { + sourceVersionCmd = { offset, cmdsize }; + } else if (cmd === LC_UUID) { + uuidCmd = { offset, cmdsize }; + } else if (cmd === LC_SEGMENT_64) { + const nsects = buffer.readUInt32LE(offset + 64); + let sectionOffset = offset + 72; + for (let s = 0; s < nsects; s += 1) { + const size = Number(buffer.readBigUInt64LE(sectionOffset + 40)); + const fileOffset = buffer.readUInt32LE(sectionOffset + 48); + if (fileOffset > 0 && size > 0) { + firstSectionOffset = + firstSectionOffset === null + ? fileOffset + : Math.min(firstSectionOffset, fileOffset); + } + sectionOffset += 80; + } + } + + offset += cmdsize; + } + + return { + cputype, + ncmds, + sizeofcmds, + headerpad: + firstSectionOffset === null + ? Infinity + : firstSectionOffset - (HEADER_SIZE + sizeofcmds), + hasCodeSignature, + removableCmd: sourceVersionCmd ?? uuidCmd, + }; +} + +function fixFile(filePath) { + const buffer = readFileSync(filePath); + const info = analyzeMachO(buffer); + const name = path.basename(filePath); + + if (!info || info.cputype !== CPU_TYPE_X86_64) { + return; + } + + if (info.hasCodeSignature || info.headerpad >= CODE_SIGNATURE_CMD_SIZE) { + return; + } + + if (!info.removableCmd) { + console.warn( + `fix-macos-headerpad: ${name} has headerpad ${info.headerpad} but no removable load command; signing may corrupt it`, + ); + return; + } + + const { offset, cmdsize } = info.removableCmd; + const loadCommandsEnd = HEADER_SIZE + info.sizeofcmds; + + // Shift the remaining load commands over the removed one, then zero the + // freed tail so codesign finds clean padding. + buffer.copyWithin(offset, offset + cmdsize, loadCommandsEnd); + buffer.fill(0, loadCommandsEnd - cmdsize, loadCommandsEnd); + buffer.writeUInt32LE(info.ncmds - 1, 16); + buffer.writeUInt32LE(info.sizeofcmds - cmdsize, 20); + + writeFileSync(filePath, buffer); + console.log( + `fix-macos-headerpad: ${name} freed ${cmdsize} bytes for LC_CODE_SIGNATURE (headerpad was ${info.headerpad})`, + ); +} + +export function fixMacosHeaderpad(directory) { + if (process.platform !== "darwin") { + return; + } + + let entries; + try { + entries = readdirSync(directory); + } catch { + return; + } + + for (const entry of entries) { + const filePath = path.join(directory, entry); + if (statSync(filePath).isFile()) { + fixFile(filePath); + } + } +} + +const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : null; +const modulePath = fileURLToPath(import.meta.url); + +if (invokedPath === modulePath) { + const rootDir = path.resolve(path.dirname(modulePath), ".."); + const target = + process.argv[2] || + path.join(rootDir, "node_modules/electrobun/dist-macos-x64"); + fixMacosHeaderpad(path.resolve(target)); +} diff --git a/scripts/generate-app-icons.mjs b/scripts/generate-app-icons.mjs new file mode 100644 index 0000000..8c77107 --- /dev/null +++ b/scripts/generate-app-icons.mjs @@ -0,0 +1,27 @@ +import path from 'node:path' +import { spawnSync } from 'node:child_process' +import { fileURLToPath } from 'node:url' + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') + +const steps = [ + [ + path.join(rootDir, 'scripts/prepare-app-icons.mjs'), + 'assets/logos/farmcontrolicon.png' + ], + [path.join(rootDir, 'scripts/prepare-installer-icons.mjs')] +] + +for (const args of steps) { + const result = spawnSync('bun', args, { + cwd: rootDir, + stdio: 'inherit', + env: process.env + }) + + if (result.status !== 0) { + process.exit(result.status ?? 1) + } +} + +console.log('generate-app-icons: done') diff --git a/scripts/generate-nsis-file-list.ps1 b/scripts/generate-nsis-file-list.ps1 new file mode 100644 index 0000000..2128cec --- /dev/null +++ b/scripts/generate-nsis-file-list.ps1 @@ -0,0 +1,62 @@ +param( + [Parameter(Mandatory = $true)] + [string]$SourceDir, + + [Parameter(Mandatory = $true)] + [string]$OutputPath +) + +$ErrorActionPreference = "Stop" + +function ConvertTo-NsisString { + param([string]$Value) + + return $Value.Replace('$', '$$').Replace('"', '$\"') +} + +$sourceRoot = (Resolve-Path -LiteralPath $SourceDir).Path.TrimEnd('\') +$sourcePrefix = "$sourceRoot\" +$files = @( + Get-ChildItem -LiteralPath $sourceRoot -Recurse -File -Force | + Sort-Object FullName +) + +if ($files.Count -eq 0) { + throw "No files were found in NSIS application source directory: $sourceRoot" +} + +[long]$totalBytes = ($files | Measure-Object -Property Length -Sum).Sum +$lines = [System.Collections.Generic.List[string]]::new() +$lines.Add("!define APP_COPY_TOTAL_BYTES `"$totalBytes`"") +$lines.Add("!macro copyApplicationFilesWithProgress") + +$lastRelativeDirectory = $null +foreach ($file in $files) { + $relativePath = $file.FullName.Substring($sourcePrefix.Length) + $relativeDirectory = Split-Path -Parent $relativePath + $escapedRelativePath = ConvertTo-NsisString $relativePath + $escapedSourcePath = ConvertTo-NsisString $file.FullName + $escapedFileName = ConvertTo-NsisString $file.Name + + if ($relativeDirectory -ne $lastRelativeDirectory) { + if ([string]::IsNullOrEmpty($relativeDirectory)) { + $lines.Add(' SetOutPath "$INSTDIR"') + } else { + $escapedDirectory = ConvertTo-NsisString $relativeDirectory + $lines.Add(" SetOutPath `"`$INSTDIR\$escapedDirectory`"") + } + $lastRelativeDirectory = $relativeDirectory + } + + $lines.Add(" File `"/oname=$escapedFileName`" `"$escapedSourcePath`"") + $lines.Add( + " !insertmacro progressCopyFile `"$($file.Length)`" `"$escapedRelativePath`"" + ) +} + +$lines.Add("!macroend") + +$encoding = [System.Text.UTF8Encoding]::new($false) +[System.IO.File]::WriteAllLines($OutputPath, $lines, $encoding) + +Write-Host "Generated NSIS commands for $($files.Count) files ($totalBytes bytes)." diff --git a/scripts/installer.nsh b/scripts/installer.nsh index a3217b2..d999278 100644 --- a/scripts/installer.nsh +++ b/scripts/installer.nsh @@ -1,10 +1,10 @@ -!macro customInstall +!macro customInstall DetailPrint "Register farmcontrol URI Handler" - DeleteRegKey HKCR "farmcontrol" - WriteRegStr HKCR "farmcontrol" "" "URL:farmcontrol" - WriteRegStr HKCR "farmcontrol" "URL Protocol" "" - WriteRegStr HKCR "farmcontrol\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" - WriteRegStr HKCR "farmcontrol\shell" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open" "" "" - WriteRegStr HKCR "farmcontrol\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1" -!macroend \ No newline at end of file + DeleteRegKey HKCU "Software\Classes\farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "" "URL:farmcontrol" + WriteRegStr HKCU "Software\Classes\farmcontrol" "URL Protocol" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\DefaultIcon" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME}" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open" "" "" + WriteRegStr HKCU "Software\Classes\farmcontrol\shell\Open\command" "" "$INSTDIR\${APP_EXECUTABLE_FILENAME} %1" +!macroend diff --git a/scripts/patch-electrobun-src.mjs b/scripts/patch-electrobun-src.mjs new file mode 100644 index 0000000..0656823 --- /dev/null +++ b/scripts/patch-electrobun-src.mjs @@ -0,0 +1,350 @@ +import { + cpSync, + existsSync, + mkdirSync, + readFileSync, + writeFileSync +} from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const electrobunDir = path.join(rootDir, 'node_modules/electrobun') +const sharedSrcDir = path.join(electrobunDir, 'src/shared') +const sharedDistDir = path.join(electrobunDir, 'dist/api/shared') + +if (!existsSync(sharedDistDir)) { + console.error('patch-electrobun-src: electrobun dist/api/shared not found') + process.exit(1) +} + +mkdirSync(sharedSrcDir, { recursive: true }) + +for (const fileName of [ + 'cef-version.ts', + 'bun-version.ts', + 'electrobun-version.ts', + 'naming.ts', + 'rpc.ts' +]) { + const source = path.join(sharedDistDir, fileName) + const destination = path.join(sharedSrcDir, fileName) + if (existsSync(source)) { + cpSync(source, destination) + } +} + +const platformPatch = `import { platform, arch } from "os"; + +export type SupportedOS = "macos" | "win" | "linux"; +export type SupportedArch = "arm64" | "x64"; + +const platformName = platform(); +const archName = arch(); + +export const OS: SupportedOS = (() => { + switch (platformName) { + case "win32": + return "win"; + case "darwin": + return "macos"; + case "linux": + return "linux"; + default: + throw new Error(\`Unsupported platform: \${platformName}\`); + } +})(); + +function normalizeForcedArch(value) { + if (value === "arm64" || value === "aarch64") { + return "arm64"; + } + if (value === "x64" || value === "amd64") { + return "x64"; + } + return null; +} + +export const ARCH: SupportedArch = (() => { + const forcedArch = normalizeForcedArch( + process.env.ELECTROBUN_FORCE_ARCH || process.env.ELECTROBUN_TARGET_ARCH, + ); + if (forcedArch) { + return forcedArch; + } + + if (OS === "win") { + return "x64"; + } + + switch (archName) { + case "arm64": + return "arm64"; + case "x64": + return "x64"; + default: + throw new Error(\`Unsupported architecture: \${archName}\`); + } +})(); + +export const HOST_ARCH: SupportedArch = (() => { + if (OS === "win") { + return "x64"; + } + + switch (archName) { + case "arm64": + return "arm64"; + case "x64": + return "x64"; + default: + throw new Error(\`Unsupported architecture: \${archName}\`); + } +})(); + +export function getPlatformOS(): SupportedOS { + return OS; +} + +export function getPlatformArch(): SupportedArch { + return ARCH; +} +` + +writeFileSync(path.join(sharedSrcDir, 'platform.ts'), platformPatch) + +const templatesDir = path.join(electrobunDir, 'src/cli/templates') +mkdirSync(templatesDir, { recursive: true }) +writeFileSync( + path.join(templatesDir, 'embedded.ts'), + `export function getTemplateNames() { + return []; +} + +export function getTemplate(name: string) { + throw new Error(\`Template not available in patched electrobun CLI: \${name}\`); +} +` +) + +const RCEDIT_RESOLVER_FN = `function resolveProjectRceditPkgPath(projectRoot) { + const candidates = [ + join(projectRoot, "node_modules/rcedit/package.json"), + join(projectRoot, "node_modules/electrobun/node_modules/rcedit/package.json"), + ]; + for (const candidate of candidates) { + if (existsSync(candidate)) { + return candidate; + } + } + throw new Error( + "rcedit not found under " + projectRoot + ". Install rcedit in the project (bun add -d rcedit).", + ); +}` + +const cliPath = path.join(electrobunDir, 'src/cli/index.ts') +let cliSource = readFileSync(cliPath, 'utf8') +if (!cliSource.includes('HOST_ARCH')) { + cliSource = cliSource.replace( + 'import { OS, ARCH } from "../shared/platform";', + 'import { OS, ARCH, HOST_ARCH } from "../shared/platform";' + ) + cliSource = cliSource.replace( + 'const hostPaths = getPlatformPaths(OS, ARCH);', + 'const hostPaths = getPlatformPaths(OS, HOST_ARCH);' + ) +} +if (!cliSource.includes('toolPaths')) { + cliSource = cliSource.replace( + 'const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);', + 'const targetPaths = getPlatformPaths(currentTarget.os, currentTarget.arch);\n\t\tconst toolPaths = getPlatformPaths(currentTarget.os, ARCH !== HOST_ARCH ? HOST_ARCH : ARCH);' + ) + cliSource = cliSource.replaceAll( + 'const zstdPath = targetPaths.ZSTD;', + 'const zstdPath = toolPaths.ZSTD;' + ) + cliSource = cliSource.replaceAll( + 'const bsdiffpath = targetPaths.BSDIFF;', + 'const bsdiffpath = toolPaths.BSDIFF;' + ) + cliSource = cliSource.replace( + 'zigAsarCli = join(targetPaths.BSPATCH).replace("bspatch", "zig-asar");', + 'zigAsarCli = join(toolPaths.BSPATCH).replace("bspatch", "zig-asar");' + ) + writeFileSync(cliPath, cliSource) + cliSource = readFileSync(cliPath, 'utf8') +} +if (!cliSource.includes('hookBunBinary')) { + cliSource = cliSource.replace( + `const hostPaths = getPlatformPaths(OS, HOST_ARCH); + + const result = Bun.spawnSync([hostPaths.BUN_BINARY, hookScript],`, + `const hostPaths = getPlatformPaths(OS, HOST_ARCH); + const hookBunBinary = existsSync(hostPaths.BUN_BINARY) + ? hostPaths.BUN_BINARY + : process.execPath; + + const result = Bun.spawnSync([hookBunBinary, hookScript],` + ) + cliSource = cliSource.replace( + 'console.error("Tried to run with bun at:", hostPaths.BUN_BINARY);', + 'console.error("Tried to run with bun at:", hookBunBinary);' + ) + writeFileSync(cliPath, cliSource) + cliSource = readFileSync(cliPath, 'utf8') +} + +if (!cliSource.includes('resolveProjectRceditPkgPath')) { + cliSource = cliSource.replaceAll( + 'const rceditPkgPath = require.resolve("rcedit/package.json");', + 'const rceditPkgPath = resolveProjectRceditPkgPath(projectRoot);' + ) + cliSource = cliSource.replace( + 'function getPlatformPaths(', + `${RCEDIT_RESOLVER_FN} + +function getPlatformPaths(` + ) + writeFileSync(cliPath, cliSource) + cliSource = readFileSync(cliPath, 'utf8') +} else { + cliSource = cliSource.replace( + /function resolveProjectRceditPkgPath\(projectRoot\) \{[\s\S]*?\n\}/m, + RCEDIT_RESOLVER_FN + ) + writeFileSync(cliPath, cliSource) +} + +const electrobunCjsPath = path.join(electrobunDir, 'bin/electrobun.cjs') +let electrobunCjs = readFileSync(electrobunCjsPath, 'utf8') + +if (!electrobunCjs.includes('farmcontrol-use-patched-cli')) { + electrobunCjs = electrobunCjs.replace( + `async function main() { + try { + const args = process.argv.slice(2); + const cliPath = await ensureCliBinary(); + + // Replace this process with the actual CLI + const child = spawn(cliPath, args, { + stdio: 'inherit', + cwd: process.cwd() + });`, + `async function main() { + try { + const args = process.argv.slice(2); + const patchedCliPath = join(electrobunDir, 'src', 'cli', 'index.ts'); + + if (existsSync(patchedCliPath)) { + // farmcontrol-use-patched-cli: bundled electrobun.exe cannot resolve project rcedit + const bunBinary = process.env.BUN_INSTALL + ? join(process.env.BUN_INSTALL, 'bin', 'bun' + binExt) + : 'bun'; + const child = spawn(bunBinary, [patchedCliPath, ...args], { + stdio: 'inherit', + cwd: process.cwd(), + env: process.env, + shell: platform === 'win', + }); + + child.on('exit', (code) => { + process.exit(code || 0); + }); + + child.on('error', (error) => { + console.error('Failed to start electrobun patched CLI:', error.message); + process.exit(1); + }); + + return; + } + + const cliPath = await ensureCliBinary(); + + // Replace this process with the actual CLI + const child = spawn(cliPath, args, { + stdio: 'inherit', + cwd: process.cwd() + });` + ) + writeFileSync(electrobunCjsPath, electrobunCjs) +} + +const rceditSrc = path.join(rootDir, 'node_modules/rcedit') +const rceditDest = path.join(electrobunDir, 'node_modules/rcedit') +if (existsSync(rceditSrc)) { + mkdirSync(path.join(electrobunDir, 'node_modules'), { recursive: true }) + cpSync(rceditSrc, rceditDest, { recursive: true, force: true }) +} + +function patchNativeWrapperPath(nativeTsPath) { + if (!existsSync(nativeTsPath)) { + return + } + + let source = readFileSync(nativeTsPath, 'utf8') + + if (source.includes('function resolveNativeWrapperPath()')) { + return + } + + if (!source.includes('existsSync')) { + if (source.includes('import { dirname, join } from "path";')) { + source = source.replace( + 'import { dirname, join } from "path";', + 'import { existsSync } from "fs";\nimport { dirname, join } from "path";' + ) + } else { + source = source.replace( + 'import { join } from "path";', + 'import { existsSync } from "fs";\nimport { dirname, join } from "path";' + ) + } + } else if (!source.includes('dirname')) { + source = source.replace( + 'import { join } from "path";', + 'import { dirname, join } from "path";' + ) + } + + const helper = ` +function resolveNativeWrapperPath() { +\tconst fileName = \`libNativeWrapper.\${suffix}\`; +\tconst candidates = [ +\t\tjoin(dirname(process.execPath), fileName), +\t\tjoin(process.cwd(), fileName), +\t]; +\tfor (const candidate of candidates) { +\t\tif (existsSync(candidate)) { +\t\t\treturn candidate; +\t\t} +\t} +\treturn candidates[0]!; +} +` + + source = source.replace( + 'export const native = (() => {', + `${helper}\nexport const native = (() => {` + ) + + source = source.replace( + /const nativeWrapperPath = join\((?:dirname\(process\.execPath\)|process\.cwd\(\)), `libNativeWrapper\.\$\{suffix\}`\);/, + 'const nativeWrapperPath = resolveNativeWrapperPath();' + ) + + writeFileSync(nativeTsPath, source) +} + +for (const distDir of ['dist', 'dist-macos-arm64', 'dist-win-x64']) { + patchNativeWrapperPath( + path.join(electrobunDir, distDir, 'api/bun/proc/native.ts') + ) +} + +const markerPath = path.join(electrobunDir, '.farmcontrol-electrobun-patched') +writeFileSync(markerPath, `patched-at=${new Date().toISOString()}\n`) + +console.log( + 'patch-electrobun-src: electrobun src/shared ready for cross-arch builds' +) diff --git a/scripts/patch-windows-binaries.mjs b/scripts/patch-windows-binaries.mjs new file mode 100644 index 0000000..cc24550 --- /dev/null +++ b/scripts/patch-windows-binaries.mjs @@ -0,0 +1,45 @@ +import { existsSync, renameSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +export const WINDOWS_LAUNCHER_EXE = 'FarmControl.exe' +const SOURCE_LAUNCHER_EXE = 'launcher.exe' + +export function patchWindowsBinaries(appDir) { + const binDir = path.join(appDir, 'bin') + if (!existsSync(binDir)) { + throw new Error(`patch-windows-binaries: bin directory not found at ${binDir}`) + } + + const sourcePath = path.join(binDir, SOURCE_LAUNCHER_EXE) + const destPath = path.join(binDir, WINDOWS_LAUNCHER_EXE) + + if (existsSync(destPath) && !existsSync(sourcePath)) { + console.log(`patch-windows-binaries: ${WINDOWS_LAUNCHER_EXE} already present`) + return + } + + if (!existsSync(sourcePath)) { + console.warn(`patch-windows-binaries: skipping missing ${sourcePath}`) + return + } + + if (existsSync(destPath)) { + renameSync(destPath, `${destPath}.old`) + } + + renameSync(sourcePath, destPath) + console.log( + `patch-windows-binaries: renamed ${SOURCE_LAUNCHER_EXE} -> ${WINDOWS_LAUNCHER_EXE}` + ) +} + +if (process.argv[1] === fileURLToPath(import.meta.url)) { + const appDirArg = process.argv[2] + if (!appDirArg) { + console.error('Usage: bun scripts/patch-windows-binaries.mjs ') + process.exit(1) + } + + patchWindowsBinaries(path.resolve(appDirArg)) +} diff --git a/scripts/pre-build.mjs b/scripts/pre-build.mjs new file mode 100644 index 0000000..c756a7a --- /dev/null +++ b/scripts/pre-build.mjs @@ -0,0 +1,145 @@ +import { existsSync, mkdirSync, writeFileSync } from "node:fs"; +import path from "node:path"; +import { spawnSync } from "node:child_process"; +import { fileURLToPath, pathToFileURL } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "dev"; + +const requiredFiles = [ + "src/bun/index.js", + "electrobun.config.ts", + "package.json", +]; + +for (const relativePath of requiredFiles) { + const filePath = path.join(rootDir, relativePath); + if (!existsSync(filePath)) { + console.error(`pre-build: required file not found: ${relativePath}`); + process.exit(1); + } +} + +if (buildEnv === "stable" && process.env.ELECTROBUN_OS === "macos") { + const codesignVars = [ + "ELECTROBUN_DEVELOPER_ID", + "ELECTROBUN_APPLEID", + "ELECTROBUN_APPLEIDPASS", + "ELECTROBUN_TEAMID", + ]; + const missing = codesignVars.filter((name) => !process.env[name]); + + if (missing.length > 0) { + console.warn( + `pre-build: stable macOS build without code signing credentials (${missing.join(", ")}); Electrobun will skip signing.`, + ); + } +} + +const buildMacosEffects = spawnSync( + "bun", + [path.join(rootDir, "scripts/build-macos-effects.mjs")], + { cwd: rootDir, stdio: "inherit", env: process.env }, +); + +if (buildMacosEffects.status !== 0) { + process.exit(buildMacosEffects.status ?? 1); +} + +if (process.platform === "darwin") { + const { validateMacosEffectsDylib, outFile } = await import( + pathToFileURL( + path.join(rootDir, "scripts/build-macos-effects.mjs"), + ).href + ); + + if (!validateMacosEffectsDylib({ dylibPath: outFile })) { + console.error( + "pre-build: macOS window effects dylib is missing or invalid; blur and traffic lights will not work in packaged builds.", + ); + process.exit(1); + } +} + +const requiredIconPaths = [ + path.join(rootDir, "assets/icon.ico"), + path.join(rootDir, "assets/icon.png"), + path.join(rootDir, "assets/icon.iconset/icon_256x256.png"), + path.join(rootDir, "assets/installer.ico"), + path.join(rootDir, "assets/uninstaller.ico"), +]; + +if (buildEnv === "stable") { + const prepareIcons = spawnSync( + "bun", + [path.join(rootDir, "scripts/generate-app-icons.mjs")], + { cwd: rootDir, stdio: "inherit", env: process.env }, + ); + + if (prepareIcons.status !== 0) { + process.exit(prepareIcons.status ?? 1); + } +} + +const missingIcons = requiredIconPaths.filter((filePath) => !existsSync(filePath)); +if (missingIcons.length > 0) { + console.error( + `pre-build: missing generated icons:\n${missingIcons + .map((filePath) => ` - ${path.relative(rootDir, filePath)}`) + .join("\n")}\nRun \`bun run generate-app-icons\` to create them.`, + ); + process.exit(1); +} + +const writeBuildInfo = spawnSync( + "bun", + [path.join(rootDir, "scripts/write-build-info.mjs")], + { cwd: rootDir, stdio: "inherit", env: process.env }, +); + +if (writeBuildInfo.status !== 0) { + process.exit(writeBuildInfo.status ?? 1); +} + +if (buildEnv === "dev") { + console.log( + "pre-build: dev environment — skipping production renderer build (use dev:renderer for Vite)", + ); + + // Electrobun still copies dist/mainview into the app bundle; provide a stub so + // dev builds don't warn when Vite serves the renderer instead. + const stubDir = path.join(rootDir, "dist/mainview"); + mkdirSync(stubDir, { recursive: true }); + writeFileSync( + path.join(stubDir, "index.html"), + "Dev mode — start Vite with bun run dev:renderer.", + ); + + console.log(`pre-build: validation passed (${buildEnv})`); + process.exit(0); +} + +const buildRenderer = spawnSync( + "bun", + [path.join(rootDir, "scripts/build-renderer.mjs")], + { + cwd: rootDir, + stdio: "inherit", + env: { + ...process.env, + NODE_ENV: "production", + }, + }, +); + +if (buildRenderer.status !== 0) { + process.exit(buildRenderer.status ?? 1); +} + +const rendererIndex = path.join(rootDir, "dist/mainview/index.html"); +if (!existsSync(rendererIndex)) { + console.error(`pre-build: renderer output not found: dist/mainview/index.html`); + process.exit(1); +} + +console.log(`pre-build: validation and renderer build passed (${buildEnv})`); diff --git a/scripts/prepare-app-icons.mjs b/scripts/prepare-app-icons.mjs new file mode 100644 index 0000000..6db3159 --- /dev/null +++ b/scripts/prepare-app-icons.mjs @@ -0,0 +1,104 @@ +import { existsSync, mkdirSync, rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; +import { Jimp } from "jimp"; +import pngToIco from "png-to-ico"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); + +const MAC_ICONSET_ENTRIES = [ + { name: "icon_16x16.png", size: 16 }, + { name: "icon_16x16@2x.png", size: 32 }, + { name: "icon_32x32.png", size: 32 }, + { name: "icon_32x32@2x.png", size: 64 }, + { name: "icon_128x128.png", size: 128 }, + { name: "icon_128x128@2x.png", size: 256 }, + { name: "icon_256x256.png", size: 256 }, + { name: "icon_256x256@2x.png", size: 512 }, + { name: "icon_512x512.png", size: 512 }, + { name: "icon_512x512@2x.png", size: 1024 }, +]; + +const WIN_ICO_SIZES = [16, 32, 48, 256]; +const LINUX_ICON_SIZE = 256; + +function resolveSourcePath(arg) { + if (!arg) { + return path.join(rootDir, "assets/farmcontrolhosticon.png"); + } + + const candidate = path.isAbsolute(arg) ? arg : path.resolve(rootDir, arg); + return candidate; +} + +async function resizePng(sourceImage, size) { + return sourceImage + .clone() + .resize({ w: size, h: size }) + .getBuffer("image/png"); +} + +async function writePng(filePath, sourceImage, size) { + const png = await resizePng(sourceImage, size); + await Bun.write(filePath, png); + return png; +} + +function parseArgs(argv) { + const sourceArg = argv.find((arg) => !arg.startsWith("-")); + const outDirArgIndex = argv.indexOf("--out-dir"); + const outDir = + outDirArgIndex >= 0 ? argv[outDirArgIndex + 1] : path.join(rootDir, "assets"); + + return { + sourcePath: resolveSourcePath(sourceArg), + outDir: path.isAbsolute(outDir) ? outDir : path.resolve(rootDir, outDir), + }; +} + +async function main() { + const { sourcePath, outDir } = parseArgs(process.argv.slice(2)); + + if (!existsSync(sourcePath)) { + console.error(`prepare-app-icons: source image not found: ${sourcePath}`); + process.exit(1); + } + + const sourceImage = await Jimp.read(sourcePath); + if (sourceImage.width < 256 || sourceImage.height < 256) { + console.warn( + `prepare-app-icons: source image is ${sourceImage.width}x${sourceImage.height}; Electrobun recommends at least 256x256`, + ); + } + + mkdirSync(outDir, { recursive: true }); + + const iconsetDir = path.join(outDir, "icon.iconset"); + rmSync(iconsetDir, { recursive: true, force: true }); + mkdirSync(iconsetDir, { recursive: true }); + + for (const entry of MAC_ICONSET_ENTRIES) { + const iconPath = path.join(iconsetDir, entry.name); + await writePng(iconPath, sourceImage, entry.size); + } + + const icoPngs = []; + for (const size of WIN_ICO_SIZES) { + icoPngs.push(await resizePng(sourceImage, size)); + } + + const icoPath = path.join(outDir, "icon.ico"); + await Bun.write(icoPath, await pngToIco(icoPngs)); + + const linuxIconPath = path.join(outDir, "icon.png"); + await writePng(linuxIconPath, sourceImage, LINUX_ICON_SIZE); + + console.log(`prepare-app-icons: wrote ${iconsetDir}`); + console.log(`prepare-app-icons: wrote ${icoPath}`); + console.log(`prepare-app-icons: wrote ${linuxIconPath}`); +} + +main().catch((error) => { + console.error(`prepare-app-icons: ${error.message}`); + process.exit(1); +}); diff --git a/scripts/prepare-installer-icons.mjs b/scripts/prepare-installer-icons.mjs new file mode 100644 index 0000000..503481d --- /dev/null +++ b/scripts/prepare-installer-icons.mjs @@ -0,0 +1,110 @@ +import { existsSync, mkdirSync, rmSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { Jimp } from 'jimp' +import pngToIco from 'png-to-ico' + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..') +const INSTALLER_SOURCE = path.join( + rootDir, + 'assets/logos/farmcontrolinstaller.png' +) +const UNINSTALLER_SOURCE = path.join( + rootDir, + 'assets/logos/farmcontroluninstaller.png' +) + +const MAC_ICONSET_ENTRIES = [ + { name: 'icon_16x16.png', size: 16 }, + { name: 'icon_16x16@2x.png', size: 32 }, + { name: 'icon_32x32.png', size: 32 }, + { name: 'icon_32x32@2x.png', size: 64 }, + { name: 'icon_128x128.png', size: 128 }, + { name: 'icon_128x128@2x.png', size: 256 }, + { name: 'icon_256x256.png', size: 256 }, + { name: 'icon_256x256@2x.png', size: 512 }, + { name: 'icon_512x512.png', size: 512 }, + { name: 'icon_512x512@2x.png', size: 1024 } +] + +const WIN_ICO_SIZES = [16, 32, 48, 256] + +async function resizePng(sourceImage, size) { + return sourceImage + .clone() + .resize({ w: size, h: size }) + .getBuffer('image/png') +} + +async function writePng(filePath, sourceImage, size) { + const png = await resizePng(sourceImage, size) + await Bun.write(filePath, png) + return png +} + +async function writeWindowsIco(sourceImage, icoPath) { + const icoPngs = [] + for (const size of WIN_ICO_SIZES) { + icoPngs.push(await resizePng(sourceImage, size)) + } + + await Bun.write(icoPath, await pngToIco(icoPngs)) + console.log(`prepare-installer-icons: wrote ${icoPath}`) +} + +async function main() { + if (!existsSync(INSTALLER_SOURCE)) { + console.error( + `prepare-installer-icons: source image not found: ${INSTALLER_SOURCE}` + ) + process.exit(1) + } + + if (!existsSync(UNINSTALLER_SOURCE)) { + console.error( + `prepare-installer-icons: source image not found: ${UNINSTALLER_SOURCE}` + ) + process.exit(1) + } + + const installerImage = await Jimp.read(INSTALLER_SOURCE) + if (installerImage.width < 256 || installerImage.height < 256) { + console.warn( + `prepare-installer-icons: installer source is ${installerImage.width}x${installerImage.height}; recommend at least 256x256` + ) + } + + const uninstallerImage = await Jimp.read(UNINSTALLER_SOURCE) + if (uninstallerImage.width < 256 || uninstallerImage.height < 256) { + console.warn( + `prepare-installer-icons: uninstaller source is ${uninstallerImage.width}x${uninstallerImage.height}; recommend at least 256x256` + ) + } + + const assetsDir = path.join(rootDir, 'assets') + mkdirSync(assetsDir, { recursive: true }) + + const iconsetDir = path.join(assetsDir, 'installer.iconset') + rmSync(iconsetDir, { recursive: true, force: true }) + mkdirSync(iconsetDir, { recursive: true }) + + for (const entry of MAC_ICONSET_ENTRIES) { + await writePng( + path.join(iconsetDir, entry.name), + installerImage, + entry.size + ) + } + + console.log(`prepare-installer-icons: wrote ${iconsetDir}`) + await writeWindowsIco(installerImage, path.join(assetsDir, 'installer.ico')) + await writeWindowsIco( + uninstallerImage, + path.join(assetsDir, 'uninstaller.ico') + ) +} + +main().catch((error) => { + console.error(`prepare-installer-icons: ${error.message}`) + process.exit(1) +}) diff --git a/scripts/release-artifact-utils.mjs b/scripts/release-artifact-utils.mjs new file mode 100644 index 0000000..83912ed --- /dev/null +++ b/scripts/release-artifact-utils.mjs @@ -0,0 +1,28 @@ +export function getReleaseVersion(packageJson) { + return packageJson.version; +} + +export function getReleaseArch(platformArch = process.arch) { + if (platformArch === "arm64" || platformArch === "aarch64") { + return "arm64"; + } + if (platformArch === "x64" || platformArch === "amd64") { + return "x64"; + } + return platformArch; +} + +export function isBundleCefEnabled( + value = process.env.ELECTROBUN_BUNDLE_CEF, +) { + return ["1", "true", "yes"].includes(String(value || "").toLowerCase()); +} + +export function getReleaseArtifactName(version, arch, ext, options = {}) { + const cef = + typeof options === "boolean" + ? options + : Boolean(options.cef ?? isBundleCefEnabled()); + const cefSuffix = cef ? "-cef" : ""; + return `farmcontrol-${version}-${arch}${cefSuffix}.${ext}`; +} diff --git a/scripts/run-electrobun-build.mjs b/scripts/run-electrobun-build.mjs new file mode 100644 index 0000000..53737d0 --- /dev/null +++ b/scripts/run-electrobun-build.mjs @@ -0,0 +1,101 @@ +import { spawnSync } from "node:child_process"; +import path from "node:path"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { getReleaseArch, isBundleCefEnabled } from "./release-artifact-utils.mjs"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const electrobunCli = path.join( + rootDir, + "node_modules/electrobun/src/cli/index.ts", +); + +const buildEnv = process.env.ELECTROBUN_BUILD_ENV || "stable"; +const targetArch = getReleaseArch( + process.env.ELECTROBUN_TARGET_ARCH || + process.env.ELECTROBUN_FORCE_ARCH || + process.arch, +); +const bundleCef = isBundleCefEnabled(); + +const patchResult = spawnSync("bun", [path.join(rootDir, "scripts/patch-electrobun-src.mjs")], { + cwd: rootDir, + stdio: "inherit", + env: process.env, +}); + +if (patchResult.status !== 0) { + process.exit(patchResult.status ?? 1); +} + +const macosEffectsResult = spawnSync( + "bun", + [path.join(rootDir, "scripts/build-macos-effects.mjs")], + { cwd: rootDir, stdio: "inherit", env: process.env }, +); + +if (macosEffectsResult.status !== 0) { + process.exit(macosEffectsResult.status ?? 1); +} + +if (process.platform === "darwin") { + const { validateMacosEffectsDylib, outFile } = await import( + pathToFileURL( + path.join(rootDir, "scripts/build-macos-effects.mjs"), + ).href + ); + + if (!validateMacosEffectsDylib({ dylibPath: outFile })) { + console.error( + "run-electrobun-build: macOS window effects dylib is missing or invalid.", + ); + process.exit(1); + } +} + +const ensureCoreEnv = { + ...process.env, + ELECTROBUN_TARGET_ARCH: targetArch, + ELECTROBUN_FORCE_ARCH: targetArch, +}; + +const ensureCoreResult = spawnSync( + "bun", + [path.join(rootDir, "scripts/ensure-electrobun-core.mjs")], + { + cwd: rootDir, + stdio: "inherit", + env: ensureCoreEnv, + }, +); + +if (ensureCoreResult.status !== 0) { + process.exit(ensureCoreResult.status ?? 1); +} + +const env = { + ...process.env, + ELECTROBUN_BUILD_ENV: buildEnv, + ELECTROBUN_OS: "macos", + ELECTROBUN_ARCH: targetArch, + ELECTROBUN_FORCE_ARCH: targetArch, + ELECTROBUN_TARGET_ARCH: targetArch, + NODE_ENV: process.env.NODE_ENV || "production", +}; + +console.log( + `run-electrobun-build: env=${buildEnv} os=macos arch=${targetArch} cef=${bundleCef} (host ${getReleaseArch(process.arch)})`, +); + +const result = spawnSync( + "bun", + [electrobunCli, "build", `--env=${buildEnv}`], + { + cwd: rootDir, + stdio: "inherit", + env, + }, +); + +if (result.status !== 0) { + process.exit(result.status ?? 1); +} diff --git a/scripts/sync-electrobun-views.mjs b/scripts/sync-electrobun-views.mjs new file mode 100644 index 0000000..48e77e0 --- /dev/null +++ b/scripts/sync-electrobun-views.mjs @@ -0,0 +1,13 @@ +import { cpSync, mkdirSync, rmSync } from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const buildDir = path.join(rootDir, "build"); +const viewDir = path.join(rootDir, "dist", "mainview"); + +rmSync(viewDir, { recursive: true, force: true }); +mkdirSync(viewDir, { recursive: true }); +cpSync(buildDir, viewDir, { recursive: true }); + +console.log(`Synced renderer build to ${viewDir}`); diff --git a/scripts/write-build-info.mjs b/scripts/write-build-info.mjs new file mode 100644 index 0000000..e013764 --- /dev/null +++ b/scripts/write-build-info.mjs @@ -0,0 +1,15 @@ +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const rootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const buildNumber = + process.env.BUILD_NUMBER || process.env.VITE_BUILD_NUMBER || "dev"; + +const buildInfoPath = path.join(rootDir, "src/buildInfo.json"); + +await Bun.write( + buildInfoPath, + `${JSON.stringify({ buildNumber }, null, 2)}\n`, +); + +console.log(`write-build-info: ${buildInfoPath} (buildNumber=${buildNumber})`); diff --git a/src/buildInfo.json b/src/buildInfo.json new file mode 100644 index 0000000..9287740 --- /dev/null +++ b/src/buildInfo.json @@ -0,0 +1,3 @@ +{ + "buildNumber": "dev" +} diff --git a/src/bun/deeplink.js b/src/bun/deeplink.js new file mode 100644 index 0000000..4a6dad3 --- /dev/null +++ b/src/bun/deeplink.js @@ -0,0 +1,50 @@ +import { spawn } from 'node:child_process' +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' +import { + buildDeeplinkPayload, + findProtocolUrl, + forwardDeeplinkToRunningInstance, + writeDeeplinkSignal +} from '../desktop/deeplink-ipc.js' + +const url = findProtocolUrl(process.argv) + +console.log('[deeplink] argv:', process.argv) +console.log('[deeplink] url:', url ?? null) + +if (!url) { + process.exit(1) +} + +const payload = buildDeeplinkPayload(url, process.argv) +const forwarded = await forwardDeeplinkToRunningInstance(payload) + +if (forwarded) { + console.log('[deeplink] forwarded to running Farm Control instance') + process.exit(0) +} + +console.log('[deeplink] no running instance found, launching Farm Control') + +writeDeeplinkSignal(payload) + +const binDir = dirname(process.execPath) +const launcherPath = ['FarmControl.exe', 'launcher.exe'] + .map((name) => join(binDir, name)) + .find((candidate) => existsSync(candidate)) + +if (!launcherPath) { + console.error('[deeplink] FarmControl.exe not found in', binDir) + process.exit(1) +} + +const child = spawn(launcherPath, [], { + cwd: dirname(launcherPath), + detached: true, + stdio: 'ignore', + windowsHide: true +}) + +child.unref() +process.exit(0) diff --git a/src/bun/index.js b/src/bun/index.js new file mode 100644 index 0000000..847d149 --- /dev/null +++ b/src/bun/index.js @@ -0,0 +1,43 @@ +import { ensureWindowsWorkingDirectory } from '../desktop/windows-app-paths.js' +import { + captureLaunchUrl, + closeSingleInstanceServer, + ensureSingleInstanceLock +} from '../desktop/single-instance.js' + +ensureWindowsWorkingDirectory() + +const launchUrl = captureLaunchUrl() +const gotSingleInstanceLock = await ensureSingleInstanceLock({ launchUrl }) + +if (!gotSingleInstanceLock) { + process.exit(0) +} + +const { createAppRpc } = await import('../desktop/rpc.js') +const { + registerGlobalShortcuts, + unregisterGlobalShortcuts +} = await import('../desktop/spotlight.js') +const { + createMainWindow, + handleDeepLinkFromArgv, + setupDevAuthServer, + setupNavigationGestures, + setupWindowsDeepLinkHandling +} = await import('../desktop/window.js') + +setupWindowsDeepLinkHandling() + +const rpc = createAppRpc() +const mainWindow = await createMainWindow(rpc) + +setupNavigationGestures(mainWindow) +registerGlobalShortcuts(rpc) +setupDevAuthServer() +handleDeepLinkFromArgv(launchUrl) + +process.on('exit', () => { + unregisterGlobalShortcuts() + closeSingleInstanceServer() +}) diff --git a/src/components/Dashboard/Layout.jsx b/src/components/Dashboard/Layout.jsx index 56160aa..596a564 100644 --- a/src/components/Dashboard/Layout.jsx +++ b/src/components/Dashboard/Layout.jsx @@ -30,7 +30,7 @@ const DashboardLayout = ({ children }) => { @@ -49,7 +49,7 @@ const DashboardLayout = ({ children }) => { ) : ( // Default to production sidebar )} - + diff --git a/src/components/Dashboard/Management/About.jsx b/src/components/Dashboard/Management/About.jsx index ce6c0b9..a7022e4 100644 --- a/src/components/Dashboard/Management/About.jsx +++ b/src/components/Dashboard/Management/About.jsx @@ -30,7 +30,7 @@ const About = () => { const { token } = useContext(AuthContext) const { fetchApiServerVersion, fetchWsServerVersion } = useContext(ApiServerContext) - const { isElectron, getElectronVersion } = useContext(ElectronContext) + const { isElectron, getAppEngine } = useContext(ElectronContext) const { checkForUpdates } = useContext(AppUpdateContext) const isMobile = useMediaQuery({ maxWidth: 768 }) @@ -74,18 +74,18 @@ const About = () => { useEffect(() => { if (!isElectron) return - getElectronVersion() - .then((version) => { - setElectronVersion(version || 'unknown') + getAppEngine() + .then((engine) => { + setAppEngine(engine === 'chromium' ? 'Chromium' : 'Native') }) .catch(() => { - setElectronVersion('unknown') + setAppEngine('Unknown') }) - }, [getElectronVersion, isElectron]) + }, [getAppEngine, isElectron]) const [apiServerVersion, setApiServerVersion] = useState(null) const [wsServerVersion, setWsServerVersion] = useState(null) - const [electronVersion, setElectronVersion] = useState(null) + const [appEngine, setAppEngine] = useState(null) const apiServerVersionText = apiServerVersion ? ( @@ -99,8 +99,8 @@ const About = () => { ) : ( ) - const electronVersionText = electronVersion ? ( - {`v${electronVersion}`} + const appEngineText = appEngine ? ( + {appEngine} ) : ( ) @@ -153,9 +153,7 @@ const About = () => { {isElectron && ( - - Electron: {electronVersionText} - + Engine: {appEngineText} )} REST API: {apiServerVersionText} diff --git a/src/components/Dashboard/Management/AppUpdates/AppUpdateProgress.jsx b/src/components/Dashboard/Management/AppUpdates/AppUpdateProgress.jsx index 482c3f8..65b5c3d 100644 --- a/src/components/Dashboard/Management/AppUpdates/AppUpdateProgress.jsx +++ b/src/components/Dashboard/Management/AppUpdates/AppUpdateProgress.jsx @@ -1,10 +1,11 @@ import PropTypes from 'prop-types' -import { useState } from 'react' -import { Button, Flex, Modal, Progress, Typography, theme, Divider } from 'antd' +import { useEffect, useState } from 'react' +import { Button, Flex, Modal, Typography, theme, Divider } from 'antd' import CloudIcon from '../../../Icons/CloudIcon' import HostIcon from '../../../Icons/HostIcon' import ReloadIcon from '../../../Icons/ReloadIcon' +import HProgress from '../../common/HProgress' import CheckCircleIcon from '../../../Icons/CheckCircleIcon' import XMarkCircleIcon from '../../../Icons/XMarkCircleIcon' @@ -65,16 +66,9 @@ const getStageColor = (status, token) => { return token.colorTextQuaternary } -const getDownloadStageStatus = (phase, isError) => { - if (isError && ['preparing', 'downloading'].includes(phase)) return 'error' - if (['downloaded', 'installing'].includes(phase)) return 'complete' - if (['preparing', 'downloading'].includes(phase)) return 'active' - return 'pending' -} - -const isInstallComplete = (phase, message) => { - if (phase !== 'installing') return false +const STAGE_INDEX = { download: 0, install: 1, restart: 2 } +const isCompletionMessage = (message) => { const normalized = String(message || '').toLowerCase() return ( @@ -84,17 +78,33 @@ const isInstallComplete = (phase, message) => { ) } -const getInstallStageStatus = (phase, isError, message) => { - if (isError && ['downloaded', 'installing'].includes(phase)) return 'error' - if (isInstallComplete(phase, message)) return 'complete' - if (phase === 'installing') return 'active' - return 'pending' +// Maps a progress event to the stage that should currently be active. +// Returns null when the event carries no stage information (e.g. errors), +// so the previously reached stage is kept. +const getStageIndexFromProgress = (phase, percent, message) => { + if (phase === 'restarting') return STAGE_INDEX.restart + + if (phase === 'installing') { + return percent >= 100 || isCompletionMessage(message) + ? STAGE_INDEX.restart + : STAGE_INDEX.install + } + + if (phase === 'downloaded') return STAGE_INDEX.install + + if (phase === 'preparing' || phase === 'downloading') { + return phase === 'downloading' && percent >= 100 + ? STAGE_INDEX.install + : STAGE_INDEX.download + } + + return null } -const getRestartStageStatus = (phase, isError, message) => { - if (isError && isInstallComplete(phase, message)) return 'error' - if (isInstallComplete(phase, message)) return 'active' - return 'pending' +const getStageStatus = (stageIndex, activeIndex, isError) => { + if (stageIndex < activeIndex) return 'complete' + if (stageIndex > activeIndex) return 'pending' + return isError ? 'error' : 'active' } const getProgressStatus = (stageStatus) => { @@ -109,15 +119,13 @@ const UpdateStage = ({ stage, status, percent, detail }) => { const StageIcon = config.icon const resolvedPercent = typeof percent === 'number' ? Math.min(percent, 100) : undefined - const resolvedStatus = - status !== 'error' && resolvedPercent === 100 ? 'complete' : status - const color = getStageColor(resolvedStatus, token) - const showProgress = resolvedStatus === 'active' && stage !== 'restart' + const color = getStageColor(status, token) + const showProgress = status === 'active' && stage !== 'restart' const StatusIcon = - resolvedStatus === 'complete' + status === 'complete' ? CheckCircleIcon - : resolvedStatus === 'error' + : status === 'error' ? XMarkCircleIcon : StageIcon @@ -125,16 +133,20 @@ const UpdateStage = ({ stage, status, percent, detail }) => { - {config.labels[resolvedStatus]} + {config.labels[status]} {showProgress && ( - - + - {detail && {detail}} + {detail && ( + + {detail} + + )} )} @@ -163,21 +175,46 @@ const AppUpdateProgress = ({ progress, update, onClose }) => { const [errorModalOpen, setErrorModalOpen] = useState(true) - const downloadStatus = getDownloadStageStatus(phase, isError) - const installStatus = getInstallStageStatus(phase, isError, message) - const restartStatus = getRestartStageStatus(phase, isError, message) + // Track the furthest stage reached so out-of-order or skipped progress + // events can never move the steps backwards. + const [activeStageIndex, setActiveStageIndex] = useState(STAGE_INDEX.download) + + useEffect(() => { + const stageIndex = getStageIndexFromProgress(phase, percent, message) + if (stageIndex !== null) { + setActiveStageIndex((previous) => Math.max(previous, stageIndex)) + } + }, [phase, percent, message]) + + const downloadStatus = getStageStatus( + STAGE_INDEX.download, + activeStageIndex, + isError + ) + const installStatus = getStageStatus( + STAGE_INDEX.install, + activeStageIndex, + isError + ) + const restartStatus = getStageStatus( + STAGE_INDEX.restart, + activeStageIndex, + isError + ) const downloadPercent = - downloadStatus === 'active' ? (phase === 'preparing' ? 0 : percent) : null + downloadStatus === 'active' && phase === 'downloading' ? percent : 0 - const installPercent = installStatus === 'active' ? percent : null + const installPercent = + installStatus === 'active' && phase === 'installing' ? percent : null const downloadDetail = downloadStatus === 'active' && downloaded && total ? `${downloaded} of ${total}` : null - const installDetail = installStatus === 'active' ? message : null + const installDetail = + installStatus === 'active' && phase === 'installing' ? message : null return ( diff --git a/src/components/Dashboard/Management/AppUpdates/NewAppUpdate.jsx b/src/components/Dashboard/Management/AppUpdates/NewAppUpdate.jsx index b2c0835..8cef762 100644 --- a/src/components/Dashboard/Management/AppUpdates/NewAppUpdate.jsx +++ b/src/components/Dashboard/Management/AppUpdates/NewAppUpdate.jsx @@ -88,6 +88,16 @@ const NewAppUpdate = ({ update, onCancel, onUpdate }) => { Branch: {update?.branch || 'Unknown'} + + Engine:{' '} + + {update?.engine === 'chromium' + ? 'Chromium' + : update?.engine === 'native' + ? 'Native' + : 'Unknown'} + + + ) +} + +TrafficLightButton.propTypes = { + action: PropTypes.string.isRequired, + icons: PropTypes.shape({ + colored: PropTypes.elementType.isRequired, + hover: PropTypes.elementType.isRequired, + down: PropTypes.elementType.isRequired, + noFocus: PropTypes.elementType.isRequired + }).isRequired, + isGroupHovered: PropTypes.bool.isRequired, + activeAction: PropTypes.string, + isEnabled: PropTypes.bool.isRequired, + isWindowFocused: PropTypes.bool.isRequired, + onActive: PropTypes.func.isRequired, + onAction: PropTypes.func.isRequired +} + +const MacOSTrafficLights = () => { + const { handleWindowControl, isFullScreen } = useContext(ElectronContext) + const [isGroupHovered, setIsGroupHovered] = useState(false) + const [activeAction, setActiveAction] = useState(null) + const [isWindowFocused, setIsWindowFocused] = useState( + () => document.hasFocus?.() ?? true + ) + + useEffect(() => { + const handleFocus = () => setIsWindowFocused(true) + const handleBlur = () => setIsWindowFocused(false) + + window.addEventListener('focus', handleFocus) + window.addEventListener('blur', handleBlur) + + return () => { + window.removeEventListener('focus', handleFocus) + window.removeEventListener('blur', handleBlur) + } + }, []) + + const fullscreenIcons = isFullScreen + ? { + colored: FullscreenColored, + hover: ExitFullscreenHoverColored, + down: ExitFullscreenDownColored, + noFocus: NoFocus + } + : { + colored: FullscreenColored, + hover: FullscreenHoverColored, + down: FullscreenDownColored, + noFocus: NoFocus + } + + const handleAction = (action) => { + handleWindowControl(action) + } + + return ( + setIsGroupHovered(true)} + onMouseLeave={() => { + setIsGroupHovered(false) + setActiveAction(null) + }} + > + + + + + ) +} + +export default MacOSTrafficLights diff --git a/src/components/Dashboard/common/ObjectTable.jsx b/src/components/Dashboard/common/ObjectTable.jsx index 7b582ac..6d3f666 100644 --- a/src/components/Dashboard/common/ObjectTable.jsx +++ b/src/components/Dashboard/common/ObjectTable.jsx @@ -47,7 +47,10 @@ import { useActions } from '../context/ActionsContext' import ActionsIcon from '../../Icons/ActionsIcon' import FilterIcon from '../../Icons/FilterIcon' import ScrollBox from './ScrollBox' -import { useTableStatePersistence } from '../context/TableStateContext' +import { + getActiveFilterValues, + useTableStatePersistence +} from '../context/TableStateContext' const logger = loglevel.getLogger('DasboardTable') logger.setLevel(config.logLevel) @@ -154,8 +157,7 @@ const ObjectTable = forwardRef( getPersistedSorter, persistFilter, persistTableState, - registerPageFilter, - getActiveFilterValues + registerPageFilter } = useTableStatePersistence({ scope: type, pagePath: location.pathname, diff --git a/src/components/Dashboard/common/ObjectTableNavigationButtons.jsx b/src/components/Dashboard/common/ObjectTableNavigationButtons.jsx index d0171fa..e79eea3 100644 --- a/src/components/Dashboard/common/ObjectTableNavigationButtons.jsx +++ b/src/components/Dashboard/common/ObjectTableNavigationButtons.jsx @@ -6,7 +6,10 @@ import ArrowRightIcon from '../../Icons/ArrowRightIcon.jsx' import PropTypes from 'prop-types' import { ApiServerContext } from '../context/ApiServerContext' import { AuthContext } from '../context/AuthContext' -import { useTableStatePersistence } from '../context/TableStateContext' +import { + getActiveFilterValues, + useTableStatePersistence +} from '../context/TableStateContext' import KeyboardShortcut from './KeyboardShortcut.jsx' const ObjectTableNavigationButtons = ({ @@ -21,8 +24,7 @@ const ObjectTableNavigationButtons = ({ const [neighbors, setNeighbors] = useState({ next: null, previous: null }) const [loading, setLoading] = useState(false) - const { getPersistedFilter, getPersistedSorter, getActiveFilterValues } = - useTableStatePersistence({ + const { getPersistedFilter, getPersistedSorter } = useTableStatePersistence({ scope: objectType, useFilterInSession: true, useSortInSession: true @@ -87,8 +89,25 @@ const ObjectTableNavigationButtons = ({ [searchParams, setSearchParams, objectType] ) - const handlePrevious = () => navigateToNeighbor(neighbors.previous) - const handleNext = () => navigateToNeighbor(neighbors.next) + const handlePrevious = useCallback(() => { + navigateToNeighbor(neighbors.previous) + }, [navigateToNeighbor, neighbors.previous]) + + const handleNext = useCallback(() => { + navigateToNeighbor(neighbors.next) + }, [navigateToNeighbor, neighbors.next]) + + const handlePreviousShortcut = useCallback(() => { + if (!disabled && !loading && neighbors.previous?._id) { + handlePrevious() + } + }, [disabled, loading, neighbors.previous?._id, handlePrevious]) + + const handleNextShortcut = useCallback(() => { + if (!disabled && !loading && neighbors.next?._id) { + handleNext() + } + }, [disabled, loading, neighbors.next?._id, handleNext]) return ( @@ -99,11 +118,7 @@ const ObjectTableNavigationButtons = ({ { - if (!disabled && !loading && neighbors.previous?._id) { - handlePrevious() - } - }, [disabled, loading, neighbors.previous?._id])} + onTrigger={handlePreviousShortcut} > + +) + +MenuButton.propTypes = { + label: PropTypes.oneOfType([PropTypes.string, PropTypes.element]).isRequired, + items: PropTypes.array.isRequired, + logo: PropTypes.bool +} + +const WindowAppMenu = () => { + const navigate = useNavigate() + const { handleWindowControl } = useContext(ElectronContext) + const { checkForUpdates } = useAppUpdateContext() + const includeDev = import.meta.env.DEV + + const viewSections = useMemo( + () => getSidebarMenuSections({ includeDev }), + [includeDev] + ) + + const appMenuItems = useMemo( + () => [ + { + key: 'about', + label: 'About Farm Control', + onClick: () => navigate('/dashboard/management/about') + }, + { type: 'divider' }, + { + key: 'check-for-updates', + label: 'Check For Updates...', + onClick: () => checkForUpdates() + }, + { type: 'divider' }, + { + key: 'quit', + label: 'Quit Farm Control', + onClick: () => handleWindowControl('quit') + } + ], + [checkForUpdates, handleWindowControl, navigate] + ) + + const fileMenuItems = useMemo( + () => [ + { + key: 'close', + label: 'Close Window', + onClick: () => handleWindowControl('close') + } + ], + [handleWindowControl] + ) + + const editMenuItems = useMemo( + () => [ + { + key: 'undo', + label: 'Undo', + onClick: () => runEditCommand('undo') + }, + { + key: 'redo', + label: 'Redo', + onClick: () => runEditCommand('redo') + }, + { type: 'divider' }, + { + key: 'cut', + label: 'Cut', + onClick: () => runEditCommand('cut') + }, + { + key: 'copy', + label: 'Copy', + onClick: () => runEditCommand('copy') + }, + { + key: 'paste', + label: 'Paste', + onClick: () => runEditCommand('paste') + }, + { + key: 'pasteAndMatchStyle', + label: 'Paste and Match Style', + onClick: () => runEditCommand('paste') + }, + { + key: 'delete', + label: 'Delete', + onClick: () => runEditCommand('delete') + }, + { type: 'divider' }, + { + key: 'selectAll', + label: 'Select All', + onClick: () => runEditCommand('selectAll') + } + ], + [] + ) + + const viewMenuItems = useMemo(() => { + const sectionItems = + viewSections.length > 0 + ? viewSections.map((section) => ({ + key: `view-section-${section.key}`, + label: section.label, + children: mapSidebarItemsToMenuItems(section.items || [], navigate) + })) + : [ + { + key: 'no-sidebar-items', + label: 'No sidebar items available', + disabled: true + } + ] + + if (!includeDev) { + return sectionItems + } + + return [ + ...sectionItems, + { type: 'divider' }, + { + key: 'toggle-devtools', + label: 'Toggle Developer Tools', + onClick: () => handleWindowControl('toggle-devtools') + } + ] + }, [handleWindowControl, includeDev, navigate, viewSections]) + + const windowMenuItems = useMemo( + () => [ + { + key: 'minimize', + label: 'Minimize', + onClick: () => handleWindowControl('minimize') + }, + { + key: 'zoom', + label: 'Zoom', + onClick: () => handleWindowControl('maximize') + } + ], + [handleWindowControl] + ) + + const menus = useMemo( + () => [ + { key: 'app', label: 'Farm Control', items: appMenuItems }, + { key: 'file', label: 'File', items: fileMenuItems }, + { key: 'edit', label: 'Edit', items: editMenuItems }, + { key: 'view', label: 'View', items: viewMenuItems }, + { key: 'window', label: 'Window', items: windowMenuItems } + ], + [appMenuItems, editMenuItems, fileMenuItems, viewMenuItems, windowMenuItems] + ) + + return ( + + {menus.map((menu) => { + if (menu.key === 'app') { + return ( + + } + items={menu.items} + /> + ) + } + return ( + + ) + })} + + ) +} + +export default WindowAppMenu diff --git a/src/components/Dashboard/context/AppUpdateContext.jsx b/src/components/Dashboard/context/AppUpdateContext.jsx index dbcea60..bf949d6 100644 --- a/src/components/Dashboard/context/AppUpdateContext.jsx +++ b/src/components/Dashboard/context/AppUpdateContext.jsx @@ -16,14 +16,28 @@ import { ElectronContext } from './ElectronContext' import NewAppUpdate from '../Management/AppUpdates/NewAppUpdate' import AppUpdateProgress from '../Management/AppUpdates/AppUpdateProgress' import SoftwareUpdateIcon from '../../Icons/SoftwareUpdateIcon' +import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon' const { Text } = Typography const UPDATE_CHECK_INTERVAL_MS = 5 * 60 * 1000 +const DEFAULT_MODEL_WIDTH = 710 const DEFAULT_UPDATE_BRANCH = 'main' +const DEFAULT_UPDATE_ENGINE = 'native' const CURRENT_BUILD_NUMBER = import.meta.env.VITE_BUILD_NUMBER const APP_UPDATE_DISMISSED_KEY = 'appUpdateDismissed' +// eslint-disable-next-line react-refresh/only-export-components +export const normalizeAppUpdateEngine = (engine) => { + const value = String(engine || '') + .trim() + .toLowerCase() + + if (value === 'chromium' || value === 'cef') return 'chromium' + if (value === 'native') return 'native' + return null +} + const getDismissedUpdate = () => { try { const stored = sessionStorage.getItem(APP_UPDATE_DISMISSED_KEY) @@ -42,10 +56,30 @@ const isUpdateDismissed = (update) => { return ( dismissed.version === update.version && dismissed.buildNumber === update.buildNumber && - dismissed.branch === update.branch + dismissed.branch === update.branch && + normalizeAppUpdateEngine(dismissed.engine) === + normalizeAppUpdateEngine(update.engine) ) } +const formatFullAppVersion = (version, buildNumber) => { + const normalizedVersion = String(version || '') + .trim() + .replace(/^v/i, '') + + if (!normalizedVersion) return null + + const build = String(buildNumber || '').trim() + const buildSuffix = + !build || build === 'dev' + ? 'dev' + : build.startsWith('b') + ? build + : `b${build}` + + return `v${normalizedVersion}-${buildSuffix}` +} + const saveDismissedUpdate = (update) => { if (!update) return @@ -54,7 +88,8 @@ const saveDismissedUpdate = (update) => { JSON.stringify({ version: update.version, buildNumber: update.buildNumber, - branch: update.branch + branch: update.branch, + engine: normalizeAppUpdateEngine(update.engine) || DEFAULT_UPDATE_ENGINE }) ) } @@ -109,23 +144,41 @@ export const AppUpdateProvider = ({ children }) => { const { fetchAppUpdateBranches, fetchAppUpdateCurrent } = useContext(ApiServerContext) const { token } = useContext(AuthContext) - const { isElectron, getAppSettings, startAppUpdate, onAppUpdateProgress } = - useContext(ElectronContext) + const { + isElectron, + getAppSettings, + setAppSettings, + getAppEngine, + startAppUpdate, + checkAppUpdateResult, + checkDuplicateInstallations, + removeDuplicateInstallations, + onDuplicateInstallationsRemoved, + onAppUpdateProgress, + onCheckForUpdatesRequest + } = useContext(ElectronContext) const [checking, setChecking] = useState(false) const [noUpdateOpen, setNoUpdateOpen] = useState(false) const [availableUpdate, setAvailableUpdate] = useState(null) const [updatePromptOpen, setUpdatePromptOpen] = useState(false) const [installingUpdate, setInstallingUpdate] = useState(null) const [updateProgress, setUpdateProgress] = useState(null) + const [completedUpdate, setCompletedUpdate] = useState(null) + const [duplicateInstall, setDuplicateInstall] = useState(null) + const [duplicatePromptOpen, setDuplicatePromptOpen] = useState(false) + const [removingDuplicate, setRemovingDuplicate] = useState(false) + const [duplicateRemovalResult, setDuplicateRemovalResult] = useState(null) const runningCheckRef = useRef(null) const updateCheckDependenciesRef = useRef({}) - const [modelWidth, setModelWidth] = useState(650) + const [modelWidth, setModelWidth] = useState(DEFAULT_MODEL_WIDTH) updateCheckDependenciesRef.current = { fetchAppUpdateBranches, fetchAppUpdateCurrent, getAppSettings, + setAppSettings, + getAppEngine, isElectron, token } @@ -135,6 +188,8 @@ export const AppUpdateProvider = ({ children }) => { fetchAppUpdateBranches, fetchAppUpdateCurrent, getAppSettings, + setAppSettings, + getAppEngine, isElectron, token } = updateCheckDependenciesRef.current @@ -143,9 +198,10 @@ export const AppUpdateProvider = ({ children }) => { if (runningCheckRef.current) return runningCheckRef.current const checkPromise = (async () => { - const [branches, appSettings] = await Promise.all([ + const [branches, appSettings, runningEngine] = await Promise.all([ fetchAppUpdateBranches(), - getAppSettings() + getAppSettings(), + getAppEngine() ]) const configuredBranch = appSettings?.appUpdateBranch const defaultBranch = branches.includes(DEFAULT_UPDATE_BRANCH) @@ -157,11 +213,52 @@ export const AppUpdateProvider = ({ children }) => { if (!selectedBranch) return null - const update = await fetchAppUpdateCurrent(selectedBranch) + const selectedEngine = + normalizeAppUpdateEngine(appSettings?.appUpdateEngine) || + normalizeAppUpdateEngine(runningEngine) || + DEFAULT_UPDATE_ENGINE + const currentRunningEngine = + normalizeAppUpdateEngine(runningEngine) || DEFAULT_UPDATE_ENGINE - return isAppUpdateAvailable(update, appVersion, CURRENT_BUILD_NUMBER) - ? update - : null + const settingsUpdates = {} + if (!appSettings?.appUpdateRunningBranch) { + settingsUpdates.appUpdateRunningBranch = selectedBranch + } + if (!normalizeAppUpdateEngine(appSettings?.appUpdateEngine)) { + settingsUpdates.appUpdateEngine = selectedEngine + } + if (Object.keys(settingsUpdates).length > 0) { + await setAppSettings({ + ...appSettings, + ...settingsUpdates + }) + } + + const runningBranch = + appSettings?.appUpdateRunningBranch || + settingsUpdates.appUpdateRunningBranch || + selectedBranch + + const update = await fetchAppUpdateCurrent(selectedBranch) + if (!update) return null + + const newerVersionAvailable = isAppUpdateAvailable( + update, + appVersion, + CURRENT_BUILD_NUMBER + ) + const engineMismatch = selectedEngine !== currentRunningEngine + const branchMismatch = selectedBranch !== runningBranch + + if (!newerVersionAvailable && !engineMismatch && !branchMismatch) { + return null + } + + return { + ...update, + branch: update.branch || selectedBranch, + engine: selectedEngine + } })() runningCheckRef.current = checkPromise @@ -181,6 +278,7 @@ export const AppUpdateProvider = ({ children }) => { setNoUpdateOpen(false) setAvailableUpdate(update) if (forcePrompt || !isUpdateDismissed(update)) { + setModelWidth(DEFAULT_MODEL_WIDTH) setUpdatePromptOpen(true) } } @@ -205,6 +303,11 @@ export const AppUpdateProvider = ({ children }) => { } }, [isElectron, showUpdateIfAvailable]) + const recheckForUpdates = useCallback(async () => { + if (!isElectron) return null + return showUpdateIfAvailable({ forcePrompt: true }) + }, [isElectron, showUpdateIfAvailable]) + useEffect(() => { if (!isElectron) return undefined @@ -219,6 +322,54 @@ export const AppUpdateProvider = ({ children }) => { } }, [isElectron, showUpdateIfAvailable]) + useEffect(() => { + if (!isElectron) return undefined + + let cancelled = false + + const runStartupChecks = async () => { + let result = null + + try { + result = await checkAppUpdateResult?.() + if (!cancelled && result?.updated) { + setCompletedUpdate(result) + } + } catch (error) { + console.warn('[AppUpdateContext] Startup update check failed:', error) + } + + try { + const installations = + result?.duplicates || (await checkDuplicateInstallations?.()) + if (!cancelled && installations?.duplicatePath) { + setDuplicateInstall(installations) + setDuplicatePromptOpen(true) + } + } catch (error) { + console.warn( + '[AppUpdateContext] Duplicate installation check failed:', + error + ) + } + } + + void runStartupChecks() + + return () => { + cancelled = true + } + }, [isElectron, checkAppUpdateResult, checkDuplicateInstallations]) + + useEffect(() => { + if (!isElectron || !onDuplicateInstallationsRemoved) return undefined + + return onDuplicateInstallationsRemoved((result) => { + setRemovingDuplicate(false) + setDuplicateRemovalResult(result || { ok: false }) + }) + }, [isElectron, onDuplicateInstallationsRemoved]) + useEffect(() => { if (!isElectron || !onAppUpdateProgress) return undefined @@ -227,6 +378,14 @@ export const AppUpdateProvider = ({ children }) => { }) }, [isElectron, onAppUpdateProgress]) + useEffect(() => { + if (!isElectron || !onCheckForUpdatesRequest) return undefined + + return onCheckForUpdatesRequest(() => { + void checkForUpdates() + }) + }, [isElectron, onCheckForUpdatesRequest, checkForUpdates]) + const dismissUpdatePrompt = () => { if (availableUpdate) { saveDismissedUpdate(availableUpdate) @@ -244,7 +403,7 @@ export const AppUpdateProvider = ({ children }) => { setNoUpdateOpen(false) setUpdatePromptOpen(false) setInstallingUpdate(update) - setModelWidth(550) + setModelWidth(580) setUpdateProgress({ phase: 'preparing', percent: 0, @@ -252,10 +411,20 @@ export const AppUpdateProvider = ({ children }) => { }) try { - const result = await startAppUpdate(update) + const appSettings = await getAppSettings() + const engine = + normalizeAppUpdateEngine(update?.engine) || + normalizeAppUpdateEngine(appSettings?.appUpdateEngine) || + DEFAULT_UPDATE_ENGINE + const result = await startAppUpdate({ + ...update, + engine + }) if (!result) { - throw new Error('App updates are only available in the desktop app.') + throw new Error( + 'Failed to start the app update. Please restart the app and try again.' + ) } } catch (error) { setUpdateProgress({ @@ -266,12 +435,33 @@ export const AppUpdateProvider = ({ children }) => { } } + const handleRemoveDuplicate = async () => { + setRemovingDuplicate(true) + setDuplicateRemovalResult(null) + + const started = await removeDuplicateInstallations?.() + if (!started) { + setRemovingDuplicate(false) + setDuplicateRemovalResult({ + ok: false, + error: 'Failed to start removing the duplicate installation.' + }) + } + } + + const closeDuplicatePrompt = () => { + setDuplicatePromptOpen(false) + setDuplicateRemovalResult(null) + } + const updateModalOpen = Boolean(updatePromptOpen || installingUpdate) const updateModalBusy = Boolean(installingUpdate) && updateProgress?.phase !== 'error' return ( - + {children} { + + Software Update + + } open={noUpdateOpen} okText='OK' style={{ maxWidth: 430 }} centered maskClosable + closable={false} onOk={() => setNoUpdateOpen(false)} onCancel={() => setNoUpdateOpen(false)} footer={[ @@ -344,6 +540,103 @@ export const AppUpdateProvider = ({ children }) => { /> )} + + + Update Installed + + } + open={Boolean(completedUpdate)} + style={{ maxWidth: 430 }} + centered + closable={false} + onCancel={() => setCompletedUpdate(null)} + footer={[ + + ]} + > + + {completedUpdate?.message || + `Farm Control was successfully updated to version ${ + completedUpdate?.current?.version || + formatFullAppVersion(appVersion, CURRENT_BUILD_NUMBER) || + `v${appVersion}` + }.`} + + + + + Duplicate Installation Found + + } + open={Boolean(duplicatePromptOpen && duplicateInstall)} + width={!removingDuplicate && !duplicateRemovalResult ? 560 : 430} + centered + closable={false} + maskClosable={false} + onCancel={removingDuplicate ? undefined : closeDuplicatePrompt} + footer={ + removingDuplicate + ? null + : duplicateRemovalResult + ? [ + + ] + : [ + , + + ] + } + > + {removingDuplicate ? ( + + + + Removing the duplicate installation... You may be asked for an + administrator password. + + + ) : duplicateRemovalResult ? ( + + {duplicateRemovalResult.ok + ? 'The duplicate installation was removed.' + : duplicateRemovalResult.error || + 'Failed to remove the duplicate installation.'} + + ) : ( + + + Farm Control is now installed in your user applications folder, + but an older copy is still installed at:{' '} + {duplicateInstall?.duplicatePath}.{' '} + Do you want to remove the duplicate installation? + + + )} + ) } diff --git a/src/components/Dashboard/context/ElectronContext.jsx b/src/components/Dashboard/context/ElectronContext.jsx index 6f0299a..a2f8518 100644 --- a/src/components/Dashboard/context/ElectronContext.jsx +++ b/src/components/Dashboard/context/ElectronContext.jsx @@ -1,33 +1,14 @@ import { createContext, useCallback, useEffect, useRef, useState } from 'react' import PropTypes from 'prop-types' import { useNavigate } from 'react-router-dom' +import desktopBridge, { + isElectrobunBridgeReady, + isElectrobunDesktop +} from '../../../electrobun-bridge.js' -// Only available in Electron renderer -const electron = window.require ? window.require('electron') : null -const ipcRenderer = electron ? electron.ipcRenderer : null - -// Utility to check if running in Electron // eslint-disable-next-line react-refresh/only-export-components export function isElectron() { - // Renderer process - - if ( - typeof window !== 'undefined' && - window.process && - window.process.type === 'renderer' - ) { - return true - } - - // User agent - if ( - typeof navigator === 'object' && - typeof navigator.userAgent === 'string' && - navigator.userAgent.indexOf('Electron') >= 0 - ) { - return true - } - return false + return isElectrobunBridgeReady() || isElectrobunDesktop() } const ElectronContext = createContext() @@ -70,70 +51,76 @@ const ElectronProvider = ({ children }) => { [navigate] ) - // Function to open external URL via Electron - const openExternalUrl = (url) => { - if (electronAvailable && ipcRenderer) { - ipcRenderer.invoke('open-external-url', url) - return true + const applyWindowState = useCallback((state) => { + if (state && typeof state.isMaximized === 'boolean') { + setIsMaximized(state.isMaximized) } - return false + if (state && typeof state.isFullScreen === 'boolean') { + setIsFullScreen(state.isFullScreen) + } + }, []) + + const openExternalUrl = (url) => { + if (!electronAvailable) return false + void desktopBridge.openExternalUrl(url).catch((error) => { + console.warn('[ElectronContext] Failed to open external url:', error) + }) + return true } - // Function to open internal URL via Electron const openInternalUrl = (url) => { - if (electronAvailable && ipcRenderer) { - ipcRenderer.invoke('open-internal-url', url) - return true - } - return false + if (!electronAvailable) return false + void desktopBridge.openInternalUrl(url).catch((error) => { + console.warn('[ElectronContext] Failed to open internal url:', error) + }) + return true } useEffect(() => { - if (!ipcRenderer) return + if (!electronAvailable) return - // Get initial platform - ipcRenderer.invoke('os-info').then((info) => { - if (info && info.platform) setPlatform(info.platform) - }) - - // Get initial window state - ipcRenderer.invoke('window-state').then((state) => { - if (state && typeof state.isMaximized === 'boolean') { - setIsMaximized(state.isMaximized) - } - if (state && typeof state.isFullScreen === 'boolean') { - setIsFullScreen(state.isFullScreen) - } - }) - - // Listen for window state changes - const windowStateHandler = (event, state) => { - if (state && typeof state.isMaximized === 'boolean') { - setIsMaximized(state.isMaximized) - } - if (state && typeof state.isFullScreen === 'boolean') { - setIsFullScreen(state.isFullScreen) - } + document.body.classList.add('electron-body') + return () => { + document.body.classList.remove('electron-body') } - ipcRenderer.on('window-state', windowStateHandler) + }, [electronAvailable]) - // Listen for navigate - const navigateHandler = (event, url) => { + useEffect(() => { + if (!electronAvailable) return + + desktopBridge.getOsInfo().then((info) => { + if (info?.platform) { + setPlatform(info.platform) + if (info.platform === 'darwin') { + document.documentElement.classList.add('macos-vibrancy') + } + } + }) + + desktopBridge.getWindowState().then(applyWindowState) + + const unsubWindowState = desktopBridge.onMessage( + 'windowState', + applyWindowState + ) + const unsubNavigate = desktopBridge.onMessage('navigate', (url) => { + if (url.toLowerCase() == '/favicon.ico') { + return + } + console.log('[ElectronContext] Navigating to:', url) navigate(url) - } - ipcRenderer.on('navigate', navigateHandler) - - const navigationGestureHandler = (_event, direction) => { - navigateHistory(direction) - } - ipcRenderer.on('navigation-gesture', navigationGestureHandler) + }) + const unsubNavigationGesture = desktopBridge.onMessage( + 'navigationGesture', + navigateHistory + ) return () => { - ipcRenderer.removeListener('navigate', navigateHandler) - ipcRenderer.removeListener('navigation-gesture', navigationGestureHandler) - ipcRenderer.removeListener('window-state', windowStateHandler) + unsubWindowState() + unsubNavigate() + unsubNavigationGesture() } - }, [navigate, navigateHistory]) + }, [applyWindowState, electronAvailable, navigate, navigateHistory]) useEffect(() => { if (!electronAvailable || platform !== 'darwin') return @@ -142,7 +129,8 @@ const ElectronProvider = ({ children }) => { let resetTimer const handleWheel = (event) => { - if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) return + if (event.metaKey || event.ctrlKey || event.altKey || event.shiftKey) + return if (Math.abs(event.deltaX) < Math.abs(event.deltaY)) return if (Math.abs(event.deltaX) < 2) return if (isInHorizontalScrollContainer(event.target)) return @@ -165,69 +153,97 @@ const ElectronProvider = ({ children }) => { } }, [electronAvailable, navigateHistory, platform]) - // Window control handler const handleWindowControl = (action) => { - if (electronAvailable && ipcRenderer) { - ipcRenderer.send('window-control', action) - } + if (!electronAvailable) return + void desktopBridge.windowControl(action) } const getAuthSession = async () => { - if (!electronAvailable || !ipcRenderer) return null - return await ipcRenderer.invoke('auth-session-get') + if (!electronAvailable) return null + return await desktopBridge.getAuthSession() } const setAuthSession = async (session) => { - if (!electronAvailable || !ipcRenderer) return false - return await ipcRenderer.invoke('auth-session-set', session) + if (!electronAvailable) return false + const result = await desktopBridge.setAuthSession(session) + return result?.ok ?? false } const clearAuthSession = async () => { - if (!electronAvailable || !ipcRenderer) return false - return await ipcRenderer.invoke('auth-session-clear') + if (!electronAvailable) return false + const result = await desktopBridge.clearAuthSession() + return result?.ok ?? false } const getAppSettings = useCallback(async () => { - if (!electronAvailable || !ipcRenderer) return {} - return await ipcRenderer.invoke('app-settings-get') + if (!electronAvailable) return {} + return await desktopBridge.getAppSettings() }, [electronAvailable]) const setAppSettings = useCallback( async (settings) => { - if (!electronAvailable || !ipcRenderer) return false - return await ipcRenderer.invoke('app-settings-set', settings) + if (!electronAvailable) return false + const result = await desktopBridge.setAppSettings(settings) + return result?.ok ?? false }, [electronAvailable] ) const startAppUpdate = useCallback( async (update) => { - if (!electronAvailable || !ipcRenderer) return false - return await ipcRenderer.invoke('app-update-start', update) + if (!electronAvailable) return false + const result = await desktopBridge.startAppUpdate(update) + return result?.ok ?? false + }, + [electronAvailable] + ) + + const checkAppUpdateResult = useCallback(async () => { + if (!electronAvailable) return null + return await desktopBridge.checkAppUpdateResult() + }, [electronAvailable]) + + const checkDuplicateInstallations = useCallback(async () => { + if (!electronAvailable) return null + return await desktopBridge.checkDuplicateInstallations() + }, [electronAvailable]) + + const removeDuplicateInstallations = useCallback(async () => { + if (!electronAvailable) return false + const result = await desktopBridge.removeDuplicateInstallations() + return result?.ok ?? false + }, [electronAvailable]) + + const onDuplicateInstallationsRemoved = useCallback( + (handler) => { + if (!electronAvailable || typeof handler !== 'function') { + return () => {} + } + return desktopBridge.onMessage('duplicateInstallationsRemoved', handler) }, [electronAvailable] ) const onAppUpdateProgress = useCallback( (handler) => { - if (!electronAvailable || !ipcRenderer || typeof handler !== 'function') { + if (!electronAvailable || typeof handler !== 'function') { return () => {} } - - const progressHandler = (event, progress) => { - handler(progress) - } - - ipcRenderer.on('app-update-progress', progressHandler) - - return () => { - ipcRenderer.removeListener('app-update-progress', progressHandler) - } + return desktopBridge.onMessage('appUpdateProgress', handler) + }, + [electronAvailable] + ) + + const onCheckForUpdatesRequest = useCallback( + (handler) => { + if (!electronAvailable || typeof handler !== 'function') { + return () => {} + } + return desktopBridge.onMessage('checkForUpdates', handler) }, [electronAvailable] ) - // Backwards-compatible helpers const getToken = async () => { const session = await getAuthSession() return session?.token || null @@ -239,9 +255,10 @@ const ElectronProvider = ({ children }) => { } const resizeSpotlightWindow = async (height) => { - if (!electronAvailable || !ipcRenderer) return false + if (!electronAvailable) return false try { - return await ipcRenderer.invoke('spotlight-window-resize', height) + const result = await desktopBridge.resizeSpotlightWindow(height) + return result?.ok ?? false } catch (error) { console.warn( '[ElectronContext] Failed to resize spotlight window:', @@ -253,15 +270,22 @@ const ElectronProvider = ({ children }) => { const setSidebarViewMenu = useCallback( async (sections) => { - if (!electronAvailable || !ipcRenderer) return false - return await ipcRenderer.invoke('set-sidebar-view-menu', sections) + if (!electronAvailable) return false + const result = await desktopBridge.setSidebarViewMenu(sections) + return result?.ok ?? false }, [electronAvailable] ) const getElectronVersion = useCallback(async () => { - if (!electronAvailable || !ipcRenderer) return null - return await ipcRenderer.invoke('electron-version') + if (!electronAvailable) return null + return await desktopBridge.getAppVersion() + }, [electronAvailable]) + + const getAppEngine = useCallback(async () => { + if (!electronAvailable) return 'native' + const engine = await desktopBridge.getAppEngine() + return engine === 'chromium' ? 'chromium' : 'native' }, [electronAvailable]) return ( @@ -280,12 +304,18 @@ const ElectronProvider = ({ children }) => { getAppSettings, setAppSettings, startAppUpdate, + checkAppUpdateResult, + checkDuplicateInstallations, + removeDuplicateInstallations, + onDuplicateInstallationsRemoved, onAppUpdateProgress, + onCheckForUpdatesRequest, getToken, setToken, resizeSpotlightWindow, setSidebarViewMenu, - getElectronVersion + getElectronVersion, + getAppEngine }} > {children} diff --git a/src/components/Dashboard/context/MessageContext.jsx b/src/components/Dashboard/context/MessageContext.jsx index cdea2c8..1faf25b 100644 --- a/src/components/Dashboard/context/MessageContext.jsx +++ b/src/components/Dashboard/context/MessageContext.jsx @@ -1,11 +1,16 @@ import { createContext, useContext } from 'react' import PropTypes from 'prop-types' import { message } from 'antd' +import { isElectrobunDesktop } from '../../../electrobun-bridge' const MessageContext = createContext() +// antd's default message top is 8px; push messages down an extra 40px in the +// desktop app so they clear the custom title bar / drag region. +const MESSAGE_TOP = isElectrobunDesktop() ? 48 : undefined + export const MessageProvider = ({ children }) => { - const [msgApi, contextHolder] = message.useMessage() + const [msgApi, contextHolder] = message.useMessage({ top: MESSAGE_TOP }) const showMessage = (type, content, options = {}) => { return msgApi.open({ diff --git a/src/components/Dashboard/context/NotificationContext.jsx b/src/components/Dashboard/context/NotificationContext.jsx index 5e15bbb..4e5c472 100644 --- a/src/components/Dashboard/context/NotificationContext.jsx +++ b/src/components/Dashboard/context/NotificationContext.jsx @@ -13,6 +13,7 @@ import { ApiServerContext } from './ApiServerContext' import NotificationCenter from '../common/NotificationCenter' import Notification from '../common/Notification' import { useMediaQuery } from 'react-responsive' +import { ElectronContext } from './ElectronContext' const NotificationContext = createContext() @@ -35,6 +36,8 @@ const NotificationProvider = ({ children }) => { const [notifications, setNotifications] = useState([]) const [notificationsLoading, setNotificationsLoading] = useState(false) + const { isElectron } = useContext(ElectronContext) + const isMobile = useMediaQuery({ maxWidth: 768 }) const fetchNotifications = useCallback(async () => { @@ -180,6 +183,7 @@ const NotificationProvider = ({ children }) => { title='Notifications' placement='right' width={isMobile ? '100%' : 460} + style={{ marginTop: isElectron ? '40px' : '0px' }} onClose={() => setNotificationCenterVisible(false)} open={notificationCenterVisible} > diff --git a/src/components/Dashboard/context/TableStateContext.jsx b/src/components/Dashboard/context/TableStateContext.jsx index 59981db..a9b98d6 100644 --- a/src/components/Dashboard/context/TableStateContext.jsx +++ b/src/components/Dashboard/context/TableStateContext.jsx @@ -16,6 +16,7 @@ export const SORT_URL_PARAM = 'sort' const getSessionFilterKey = (scope) => `tableState:${scope}:filter` const getSessionSortKey = (scope) => `tableState:${scope}:sort` +// eslint-disable-next-line react-refresh/only-export-components export const getActiveFilterValues = (filterState) => { const active = {} Object.entries(filterState || {}).forEach(([k, v]) => { @@ -51,6 +52,7 @@ const readFilterFromSession = (scope) => { } } +// eslint-disable-next-line react-refresh/only-export-components export const hasStoredSessionFilter = (scope) => { if (!scope) return false return Object.keys(getActiveFilterValues(readFilterFromSession(scope) || {})).length > 0 @@ -268,6 +270,7 @@ export const TableStateProvider = ({ children }) => { ) } +// eslint-disable-next-line react-refresh/only-export-components export const useTableState = () => { const context = useContext(TableStateContext) if (!context) { @@ -276,6 +279,7 @@ export const useTableState = () => { return context } +// eslint-disable-next-line react-refresh/only-export-components export const useTableStatePersistence = ({ scope, pagePath, diff --git a/src/desktop/appupdate.js b/src/desktop/appupdate.js new file mode 100644 index 0000000..c37765d --- /dev/null +++ b/src/desktop/appupdate.js @@ -0,0 +1,490 @@ +import { createWriteStream, promises as fs } from 'node:fs' +import http from 'node:http' +import https from 'node:https' +import os from 'node:os' +import path from 'node:path' +import process from 'node:process' +import { Utils } from 'electrobun/bun' +import { launchMacInstaller } from './macappupdate.js' +import { launchWindowsInstaller } from './winappupdate.js' +import { checkForDuplicateInstallations } from './check-duplicate-installations.js' +import { scheduleAppRestart } from './updater-runner.js' +import buildInfo from '../buildInfo.json' +import { version as packageVersion } from '../../package.json' +import { getAppSettings, setAppSettings } from './store.js' + +const SUPPORTED_TARGETS = { + darwin: { + extension: '.pkg', + osMatchers: ['darwin', 'mac', 'macos', 'osx'] + }, + win32: { + extension: '.exe', + osMatchers: ['win32', 'win', 'windows'] + } +} + +const DEFAULT_UPDATE_ENGINE = 'native' + +let runningUpdate = null + +const getArtifactName = (artifact) => + String(artifact?.fileName || artifact?.relativePath || artifact?.url || '') + +const normalizeArch = (arch) => { + if (arch === 'x64' || arch === 'amd64') return 'x64' + if (arch === 'arm64' || arch === 'aarch64') return 'arm64' + return arch +} + +const normalizeEngine = (engine) => { + const value = String(engine || '') + .trim() + .toLowerCase() + + if (value === 'chromium' || value === 'cef') return 'chromium' + if (value === 'native') return 'native' + return null +} + +const artifactIsChromium = (artifact) => { + const explicit = String( + artifact?.engine || artifact?.renderer || '' + ).toLowerCase() + + if (explicit === 'cef' || explicit === 'chromium') return true + if (explicit === 'native') return false + + const name = getArtifactName(artifact).toLowerCase() + return /[-_.]cef(?:[-_.]|$)/.test(name) +} + +const artifactMatchesEngine = (artifact, engine) => { + const wantsChromium = normalizeEngine(engine) === 'chromium' + return artifactIsChromium(artifact) === wantsChromium +} + +const artifactMatchesPlatform = (artifact, target, platform, arch) => { + const name = getArtifactName(artifact).toLowerCase() + const normalizedArch = normalizeArch(arch) + const artifactArch = normalizeArch(String(artifact?.arch || '').toLowerCase()) + const artifactPlatform = String( + artifact?.platform || artifact?.os || artifact?.target || '' + ).toLowerCase() + + if (!name.endsWith(target.extension)) return false + if (!artifact?.url) return false + + const matchesArch = + artifactArch === normalizedArch || + name.includes(`-${normalizedArch}`) || + name.includes(`_${normalizedArch}`) || + name.includes(`.${normalizedArch}.`) || + name.includes(normalizedArch) + + const matchesOs = + !artifactPlatform || + target.osMatchers.includes(artifactPlatform) || + target.osMatchers.some((matcher) => name.includes(matcher)) || + (platform === 'darwin' && name.includes('mac')) || + (platform === 'win32' && name.includes('win')) + + return matchesArch && matchesOs +} + +const selectUpdateArtifact = ( + update, + platform = process.platform, + arch = process.arch +) => { + const target = SUPPORTED_TARGETS[platform] + if (!target) { + throw new Error(`App updates are not supported on ${platform}.`) + } + + const engine = normalizeEngine(update?.engine) || DEFAULT_UPDATE_ENGINE + const artifacts = Array.isArray(update?.artifacts) ? update.artifacts : [] + const matchingArtifact = artifacts.find( + (artifact) => + artifactMatchesPlatform(artifact, target, platform, arch) && + artifactMatchesEngine(artifact, engine) + ) + + if (!matchingArtifact) { + const engineLabel = engine === 'chromium' ? 'Chromium (cef)' : 'Native' + throw new Error( + `No ${target.extension} ${engineLabel} update artifact found for ${platform}/${arch}.` + ) + } + + return matchingArtifact +} + +const getInstallErrorMessage = (error, output = '') => { + const combined = `${output}\n${error?.message || ''}`.trim() + + if ( + /cancel/i.test(combined) || + /did not grant permission/i.test(combined) || + /user canceled/i.test(combined) + ) { + return 'Update installation was cancelled.' + } + + if (/incorrect/i.test(combined)) { + return 'The administrator password was incorrect.' + } + + if ( + /1625/.test(combined) || + /forbidden by system policy/i.test(combined) || + /Non-assigned apps are disabled/i.test(combined) + ) { + return 'Update installation was blocked by system policy.' + } + + return combined || 'Failed to install update.' +} + +const getDownloadUrl = (url, redirectCount = 0) => + new Promise((resolve, reject) => { + if (redirectCount > 5) { + reject(new Error('Too many redirects while downloading update.')) + return + } + + const parsedUrl = new URL(url) + const client = parsedUrl.protocol === 'https:' ? https : http + const request = client.get(parsedUrl, (response) => { + const location = response.headers.location + + if (response.statusCode >= 300 && response.statusCode < 400 && location) { + response.resume() + resolve( + getDownloadUrl( + new URL(location, parsedUrl).toString(), + redirectCount + 1 + ) + ) + return + } + + resolve({ response, url: parsedUrl.toString() }) + }) + + request.on('error', reject) + }) + +const downloadArtifact = async (artifact, destinationPath, sendProgress) => { + const { response } = await getDownloadUrl(artifact.url) + + if (response.statusCode < 200 || response.statusCode >= 300) { + response.resume() + throw new Error(`Update download failed with HTTP ${response.statusCode}.`) + } + + const totalBytes = + Number.parseInt(response.headers['content-length'], 10) || 0 + let downloadedBytes = 0 + + await new Promise((resolve, reject) => { + const output = createWriteStream(destinationPath) + + response.on('data', (chunk) => { + downloadedBytes += chunk.length + const percent = totalBytes + ? Math.round((downloadedBytes / totalBytes) * 100) + : null + + sendProgress({ + phase: 'downloading', + percent, + downloadedBytes, + totalBytes, + message: totalBytes + ? `Downloading update (${percent}%)` + : 'Downloading update' + }) + }) + + response.on('error', reject) + output.on('error', reject) + output.on('finish', resolve) + response.pipe(output) + }) +} + +const getRunningEngine = (mainWindow) => + mainWindow?.renderer === 'cef' ? 'chromium' : 'native' + +const formatFullAppVersion = (version, buildNumber) => { + const normalizedVersion = String(version || '') + .trim() + .replace(/^v/i, '') + + if (!normalizedVersion) return null + + const build = String( + buildNumber || process.env.BUILD_NUMBER || process.env.VITE_BUILD_NUMBER || '' + ).trim() + const buildSuffix = + !build || build === 'dev' ? 'dev' : build.startsWith('b') ? build : `b${build}` + + return `v${normalizedVersion}-${buildSuffix}` +} + +export const getRunningAppVersion = () => + formatFullAppVersion(packageVersion, buildInfo?.buildNumber) + +const getRunningAppState = (mainWindow, settings) => ({ + version: getRunningAppVersion(), + branch: settings?.appUpdateRunningBranch || null, + engine: getRunningEngine(mainWindow) +}) + +// Snapshot the running version/branch/engine so the next launch can tell +// whether an update actually completed. +const persistCurrentAppState = async (mainWindow) => { + try { + const settings = await getAppSettings() + await setAppSettings({ + ...settings, + current: getRunningAppState(mainWindow, settings) + }) + } catch (error) { + console.warn('[app-update] Failed to persist current app state.', error) + } +} + +// Ignore missing values: a field only counts as changed when it was recorded +// both before and after the update. +const stateValueChanged = (previous, next) => + Boolean(previous) && Boolean(next) && previous !== next + +const formatEngineLabel = (engine) => { + const normalized = normalizeEngine(engine) + if (normalized === 'chromium') return 'Chromium' + if (normalized === 'native') return 'Native' + return String(engine || 'Unknown') +} + +export const getUpdateInstalledMessage = ({ changes, current } = {}) => { + if (!current) return 'Farm Control was successfully updated.' + + const versionChanged = Boolean(changes?.version && current.version) + const branchChanged = Boolean(changes?.branch && current.branch) + const engineChanged = Boolean(changes?.engine && current.engine) + + if (!versionChanged && !branchChanged && !engineChanged) { + const version = current.version || getRunningAppVersion() + return version + ? `Farm Control was successfully updated to version ${version}.` + : 'Farm Control was successfully updated.' + } + + const segments = [] + + if (versionChanged) { + segments.push({ type: 'version', text: `version ${current.version}` }) + } + if (branchChanged) { + segments.push({ type: 'branch', text: `the ${current.branch} branch` }) + } + if (engineChanged) { + segments.push({ + type: 'engine', + text: `the ${formatEngineLabel(current.engine)} engine` + }) + } + + if (segments.length === 1) { + const [segment] = segments + if (segment.type === 'engine') { + return `Farm Control was successfully updated to use ${segment.text}.` + } + return `Farm Control was successfully updated to ${segment.text}.` + } + + let message = `Farm Control was successfully updated to ${segments[0].text}` + + for (const segment of segments.slice(1)) { + if (segment.type === 'branch') { + message += ` on ${segment.text}` + } else if (segment.type === 'engine') { + message += ` using ${segment.text}` + } else { + message += ` and ${segment.text}` + } + } + + return `${message}.` +} + +let completedUpdateResult = null + +export const checkForCompletedUpdate = async (mainWindow) => { + // Cache per process so repeated renderer calls (e.g. remounts) get the same + // answer instead of a false negative after `current` has been rewritten. + if (completedUpdateResult) return completedUpdateResult + + try { + const settings = await getAppSettings() + const previous = + settings?.current && typeof settings.current === 'object' + ? settings.current + : null + const current = getRunningAppState(mainWindow, settings) + + await setAppSettings({ ...settings, current }) + + const changes = { + version: stateValueChanged(previous.version, current.version), + branch: stateValueChanged(previous.branch, current.branch), + engine: stateValueChanged( + normalizeEngine(previous.engine), + normalizeEngine(current.engine) + ) + } + + const updated = + Boolean(previous) && + (changes.version || changes.branch || changes.engine) + + const duplicates = checkForDuplicateInstallations() + + completedUpdateResult = { + updated, + previous, + current, + changes, + message: updated + ? getUpdateInstalledMessage({ changes, current }) + : null, + duplicates + } + } catch (error) { + console.warn('[app-update] Failed to check for a completed update.', error) + completedUpdateResult = { + updated: false, + previous: null, + current: null, + duplicates: checkForDuplicateInstallations() + } + } + + return completedUpdateResult +} + +const persistInstalledUpdateSettings = async (update) => { + try { + const settings = await getAppSettings() + const engine = + normalizeEngine(update?.engine) || + normalizeEngine(settings?.appUpdateEngine) || + DEFAULT_UPDATE_ENGINE + + await setAppSettings({ + ...settings, + appUpdateEngine: engine, + ...(update?.branch ? { appUpdateRunningBranch: update.branch } : {}) + }) + } catch (error) { + console.warn( + '[app-update] Failed to persist installed update settings.', + error + ) + } +} + +const launchInstallerAndRestart = async ( + mainWindow, + installerPath, + sendProgress, + update +) => { + const installerHelpers = { sendProgress, getInstallErrorMessage } + + if (process.platform === 'darwin') { + await launchMacInstaller( + mainWindow, + installerPath, + sendProgress, + installerHelpers + ) + } else if (process.platform === 'win32') { + await launchWindowsInstaller( + mainWindow, + installerPath, + sendProgress, + installerHelpers + ) + } else { + throw new Error(`App updates are not supported on ${process.platform}.`) + } + + await persistInstalledUpdateSettings(update) + + if (process.platform === 'darwin') { + scheduleAppRestart() + } + + // Give the UI a moment to show completion before the app exits. + await new Promise((resolve) => setTimeout(resolve, 500)) + Utils.quit() +} + +const runAppUpdate = async (mainWindow, update, sendProgress) => { + await persistCurrentAppState(mainWindow) + + const artifact = selectUpdateArtifact(update) + const tempDirectory = await fs.mkdtemp( + path.join(os.tmpdir(), 'farmcontrol-update-') + ) + const artifactName = path.basename(getArtifactName(artifact)) + const installerPath = path.join(tempDirectory, artifactName) + + sendProgress({ + phase: 'preparing', + percent: 0, + artifact, + message: 'Preparing update download' + }) + + await downloadArtifact(artifact, installerPath, sendProgress) + + sendProgress({ + phase: 'downloaded', + percent: 100, + downloadedBytes: null, + totalBytes: null, + artifact, + message: 'Update downloaded' + }) + + await launchInstallerAndRestart( + mainWindow, + installerPath, + sendProgress, + update + ) +} + +export function startAppUpdate(mainWindow, update, sendProgress) { + if (runningUpdate) return runningUpdate + + runningUpdate = runAppUpdate(mainWindow, update, sendProgress) + .then(() => ({ ok: true })) + .catch((error) => { + sendProgress({ + phase: 'error', + percent: null, + message: error?.message || 'Failed to update app.' + }) + throw error + }) + .finally(() => { + runningUpdate = null + }) + + return runningUpdate +} diff --git a/src/desktop/check-duplicate-installations.js b/src/desktop/check-duplicate-installations.js new file mode 100644 index 0000000..31cf1cd --- /dev/null +++ b/src/desktop/check-duplicate-installations.js @@ -0,0 +1,294 @@ +import { execSync, spawn } from 'node:child_process' +import { existsSync } from 'node:fs' +import { unlink, writeFile } from 'node:fs/promises' +import os from 'node:os' +import path from 'node:path' +import process from 'node:process' +import sudo from '@vscode/sudo-prompt' +import { findMacAppBundle } from './updater-runner.js' + +const MAC_APP_NAME = 'Farm Control.app' +const MAC_SYSTEM_APP_PATH = path.join('/Applications', MAC_APP_NAME) +const MAC_PKG_IDENTIFIER = 'com.tombutcher.farmcontrol' + +const WINDOWS_APP_DIR_NAME = 'Farm Control' +const WINDOWS_LAUNCHER_EXE = 'FarmControl.exe' +const WINDOWS_LEGACY_LAUNCHER_EXE = 'launcher.exe' +const WINDOWS_REGISTRY_APP_KEY = 'Software\\Tom Butcher\\Farm Control' +const WINDOWS_REGISTRY_UNINSTALL_KEY = + 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Farm Control' + +const UNSUPPORTED_RESULT = { + supported: false, + runningInstall: 'unknown', + runningPath: null, + duplicatePath: null, +} + +const quoteShellArg = (value) => `'${String(value).replaceAll("'", "'\\''")}'` + +const isPathInside = (childPath, parentPath) => { + if (!childPath || !parentPath) return false + const relative = path.relative(parentPath, childPath) + return ( + relative === '' || + (!relative.startsWith('..') && !path.isAbsolute(relative)) + ) +} + +const samePath = (left, right) => { + if (!left || !right) return false + if (process.platform === 'win32') { + return path.resolve(left).toLowerCase() === path.resolve(right).toLowerCase() + } + return path.resolve(left) === path.resolve(right) +} + +const checkMacInstallations = () => { + const runningBundle = findMacAppBundle(process.execPath) + const userAppPath = path.join(os.homedir(), 'Applications', MAC_APP_NAME) + + let runningInstall = 'unknown' + if (runningBundle) { + if (isPathInside(runningBundle, path.join(os.homedir(), 'Applications'))) { + runningInstall = 'user' + } else if (isPathInside(runningBundle, '/Applications')) { + runningInstall = 'system' + } + } + + const systemCopyExists = + existsSync(MAC_SYSTEM_APP_PATH) && + !samePath(runningBundle, MAC_SYSTEM_APP_PATH) + + return { + supported: true, + runningInstall, + runningPath: runningBundle, + userPath: userAppPath, + duplicatePath: + runningInstall === 'user' && systemCopyExists + ? MAC_SYSTEM_APP_PATH + : null, + } +} + +const readWindowsInstallDir = (hive) => { + try { + const output = execSync( + `reg query "${hive}\\${WINDOWS_REGISTRY_APP_KEY}" /v InstallDir`, + { encoding: 'utf8', windowsHide: true }, + ) + const match = output.match(/InstallDir\s+REG_\w+\s+(.+)/i) + return match?.[1]?.trim() || null + } catch { + return null + } +} + +const windowsDirLooksLikeInstall = (dir) => + Boolean(dir) && + (existsSync(path.join(dir, 'bin', WINDOWS_LAUNCHER_EXE)) || + existsSync(path.join(dir, 'bin', WINDOWS_LEGACY_LAUNCHER_EXE)) || + existsSync(path.join(dir, WINDOWS_LAUNCHER_EXE)) || + existsSync(path.join(dir, 'Uninstall.exe')) || + existsSync(path.join(dir, `Uninstall ${WINDOWS_APP_DIR_NAME}.exe`))) + +const getWindowsUserInstallDir = () => + readWindowsInstallDir('HKCU') || + path.join( + process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), + 'Programs', + WINDOWS_APP_DIR_NAME, + ) + +const getWindowsSystemInstallCandidates = () => { + const candidates = [ + readWindowsInstallDir('HKLM'), + process.env.ProgramFiles && + path.join(process.env.ProgramFiles, WINDOWS_APP_DIR_NAME), + process.env['ProgramFiles(x86)'] && + path.join(process.env['ProgramFiles(x86)'], WINDOWS_APP_DIR_NAME), + process.env.ProgramW6432 && + path.join(process.env.ProgramW6432, WINDOWS_APP_DIR_NAME), + ].filter(Boolean) + + const unique = [] + for (const candidate of candidates) { + if (!unique.some((existing) => samePath(existing, candidate))) { + unique.push(candidate) + } + } + return unique +} + +const checkWindowsInstallations = () => { + const runningDir = path.dirname(process.execPath) + const userInstallDir = getWindowsUserInstallDir() + const systemCandidates = getWindowsSystemInstallCandidates() + const localAppData = + process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local') + + let runningInstall = 'unknown' + if ( + isPathInside(runningDir, userInstallDir) || + isPathInside(runningDir, localAppData) + ) { + runningInstall = 'user' + } else if ( + systemCandidates.some((candidate) => isPathInside(runningDir, candidate)) + ) { + runningInstall = 'system' + } + + const duplicatePath = + runningInstall === 'user' + ? systemCandidates.find( + (candidate) => + windowsDirLooksLikeInstall(candidate) && + !isPathInside(runningDir, candidate), + ) || null + : null + + return { + supported: true, + runningInstall, + runningPath: runningDir, + userPath: userInstallDir, + duplicatePath, + } +} + +export const checkForDuplicateInstallations = () => { + try { + if (process.platform === 'darwin') return checkMacInstallations() + if (process.platform === 'win32') return checkWindowsInstallations() + } catch (error) { + console.warn( + '[duplicate-install] Failed to check for duplicate installations.', + error, + ) + } + return UNSUPPORTED_RESULT +} + +const removeMacDuplicate = (duplicatePath) => + new Promise((resolve, reject) => { + // Removing from /Applications typically needs admin rights; also forget + // the pkg receipt so future installer runs start clean. + const script = [ + `/bin/rm -rf ${quoteShellArg(duplicatePath)}`, + `/usr/sbin/pkgutil --forget ${quoteShellArg(MAC_PKG_IDENTIFIER)} || true`, + ].join(' && ') + + sudo.exec(script, { name: 'farmcontrol' }, (error, stdout, stderr) => { + if (error) { + const combined = `${stderr || ''}\n${error?.message || ''}` + const message = + /cancel/i.test(combined) || /did not grant permission/i.test(combined) + ? 'Removal was cancelled.' + : 'Failed to remove the duplicate installation.' + reject(new Error(message)) + return + } + resolve() + }) + }) + +const psQuote = (value) => `'${String(value).replaceAll("'", "''")}'` + +// Intentionally does NOT run the old install's Uninstall.exe: it taskkills +// FarmControl.exe, which would terminate the running app. Instead the old +// files, HKLM registry keys and machine-level shortcuts are removed directly. +const buildWindowsRemovalScript = (duplicatePath) => + [ + `$ErrorActionPreference = 'SilentlyContinue'`, + `$installDir = ${psQuote(duplicatePath)}`, + `if (Test-Path -LiteralPath $installDir) {`, + ` Remove-Item -LiteralPath $installDir -Recurse -Force`, + `}`, + `& reg.exe delete ${psQuote(`HKLM\\${WINDOWS_REGISTRY_APP_KEY}`)} /f 2>$null | Out-Null`, + `& reg.exe delete ${psQuote(`HKLM\\${WINDOWS_REGISTRY_UNINSTALL_KEY}`)} /f 2>$null | Out-Null`, + `$commonStartMenu = Join-Path $env:ProgramData 'Microsoft\\Windows\\Start Menu\\Programs\\${WINDOWS_APP_DIR_NAME}'`, + `if (Test-Path -LiteralPath $commonStartMenu) {`, + ` Remove-Item -LiteralPath $commonStartMenu -Recurse -Force`, + `}`, + `$publicDesktopShortcut = 'C:\\Users\\Public\\Desktop\\${WINDOWS_APP_DIR_NAME}.lnk'`, + `if (Test-Path -LiteralPath $publicDesktopShortcut) {`, + ` Remove-Item -LiteralPath $publicDesktopShortcut -Force`, + `}`, + `if (Test-Path -LiteralPath $installDir) { exit 1 }`, + `exit 0`, + ].join('\r\n') + +const removeWindowsDuplicate = async (duplicatePath) => { + const scriptPath = path.join( + os.tmpdir(), + `farmcontrol-remove-duplicate-${Date.now()}.ps1`, + ) + await writeFile(scriptPath, buildWindowsRemovalScript(duplicatePath), 'utf8') + + // Pre-quote the -File argument: PowerShell 5.1's Start-Process does not + // quote ArgumentList entries containing spaces. + const elevateCommand = [ + `$p = Start-Process -FilePath 'powershell.exe'`, + `-ArgumentList @('-NoProfile','-ExecutionPolicy','Bypass','-File','"${scriptPath.replaceAll("'", "''")}"')`, + `-Verb RunAs -Wait -PassThru; exit $p.ExitCode`, + ].join(' ') + + try { + await new Promise((resolve, reject) => { + const child = spawn( + 'powershell.exe', + ['-NoProfile', '-ExecutionPolicy', 'Bypass', '-Command', elevateCommand], + { stdio: 'ignore', windowsHide: true }, + ) + + child.on('error', reject) + child.on('exit', (code) => { + if (code === 0) { + resolve() + return + } + // Start-Process throws when the UAC prompt is declined, which exits + // the outer PowerShell with a non-zero code and no script output. + reject( + new Error( + code === 1 + ? 'Failed to remove the duplicate installation.' + : 'Removal was cancelled.', + ), + ) + }) + }) + } finally { + await unlink(scriptPath).catch(() => {}) + } +} + +export const removeDuplicateInstallations = async () => { + // Re-detect instead of trusting a path from the renderer so this can never + // be used to delete an arbitrary directory. + const check = checkForDuplicateInstallations() + + if (!check.duplicatePath) { + return { ok: false, error: 'No duplicate installation was found.' } + } + + try { + if (process.platform === 'darwin') { + await removeMacDuplicate(check.duplicatePath) + } else if (process.platform === 'win32') { + await removeWindowsDuplicate(check.duplicatePath) + } else { + return { ok: false, error: 'Not supported on this platform.' } + } + } catch (error) { + return { + ok: false, + error: error?.message || 'Failed to remove the duplicate installation.', + } + } + + return { ok: true, removedPath: check.duplicatePath } +} diff --git a/src/desktop/deeplink-ipc.js b/src/desktop/deeplink-ipc.js new file mode 100644 index 0000000..d037192 --- /dev/null +++ b/src/desktop/deeplink-ipc.js @@ -0,0 +1,220 @@ +import { + existsSync, + mkdirSync, + readFileSync, + unlinkSync, + writeFileSync +} from 'node:fs' +import net from 'node:net' +import os from 'node:os' +import { join } from 'node:path' + +export const PROTOCOL_PREFIX = 'farmcontrol://' +export const WINDOWS_PIPE_NAME = '\\\\.\\pipe\\com.tombutcher.farmcontrol.instance' +export const SIGNAL_FILE = 'instance-signal.json' +export const LOCK_FILE = 'primary.lock' +const FORWARD_TIMEOUT_MS = 750 +const PIPE_RETRY_ATTEMPTS = 3 +const PIPE_RETRY_DELAY_MS = 100 + +export function getInstanceDir() { + if (process.platform === 'win32') { + return join( + os.homedir(), + 'AppData', + 'Local', + 'com.tombutcher.farmcontrol', + 'instance' + ) + } + + return join(process.env.TMPDIR || '/tmp', 'com.tombutcher.farmcontrol', 'instance') +} + +export function getSignalPath() { + return join(getInstanceDir(), SIGNAL_FILE) +} + +export function getLockPath() { + return join(getInstanceDir(), LOCK_FILE) +} + +export function isProcessAlive(pid) { + if (!Number.isInteger(pid) || pid <= 0) { + return false + } + + try { + process.kill(pid, 0) + return true + } catch { + return false + } +} + +export function isPrimaryInstanceRunning() { + const lockPath = getLockPath() + if (!existsSync(lockPath)) { + return false + } + + try { + const existingPid = Number.parseInt(readFileSync(lockPath, 'utf8').trim(), 10) + return isProcessAlive(existingPid) + } catch { + return false + } +} + +export function findProtocolUrl(args) { + const directMatch = args.find( + (arg) => typeof arg === 'string' && arg.startsWith(PROTOCOL_PREFIX) + ) + + if (directMatch) { + return directMatch + } + + const sources = args.filter((arg) => typeof arg === 'string') + + for (const arg of sources) { + const trimmed = arg.trim().replace(/^['"]+|['"]+$/g, '') + const match = trimmed.match(/farmcontrol:\/\/\S+/i) + if (match) { + const rawUrl = match[0].replace(/['"]+$/g, '') + try { + return decodeURI(rawUrl) + } catch { + return rawUrl + } + } + } + + const combinedMatch = sources.join(' ').match(/farmcontrol:\/\/\S+/i) + if (combinedMatch) { + const rawUrl = combinedMatch[0].replace(/['"]+$/g, '') + try { + return decodeURI(rawUrl) + } catch { + return rawUrl + } + } + + return undefined +} + +export function buildDeeplinkPayload(url, argv = process.argv) { + const commandLine = [...argv] + + return url + ? { type: 'deeplink', url, argv: commandLine } + : { type: 'focus', argv: commandLine } +} + +function readSignalQueue({ clear = true } = {}) { + const signalPath = getSignalPath() + if (!existsSync(signalPath)) { + return [] + } + + try { + const raw = readFileSync(signalPath, 'utf8') + const parsed = JSON.parse(raw) + + if (clear) { + unlinkSync(signalPath) + } + + if (Array.isArray(parsed)) { + return parsed + } + + return parsed ? [parsed] : [] + } catch { + if (clear) { + try { + unlinkSync(signalPath) + } catch { + // Ignore cleanup failures. + } + } + return [] + } +} + +export function writeDeeplinkSignal(payload) { + const signalPath = getSignalPath() + mkdirSync(getInstanceDir(), { recursive: true }) + + const queue = readSignalQueue({ clear: false }) + queue.push({ ...payload, timestamp: Date.now() }) + + const tempPath = `${signalPath}.${process.pid}.${Date.now()}.tmp` + writeFileSync(tempPath, JSON.stringify(queue), 'utf8') + writeFileSync(signalPath, readFileSync(tempPath)) + unlinkSync(tempPath) +} + +function tryForwardViaPipe(payload) { + return new Promise((resolve) => { + let settled = false + const finish = (forwarded) => { + if (settled) return + settled = true + resolve(forwarded) + } + + const client = net.connect({ path: WINDOWS_PIPE_NAME }) + const message = JSON.stringify(payload) + + client.on('connect', () => { + client.write(message) + client.end() + finish(true) + }) + + client.on('error', () => { + finish(false) + }) + + client.setTimeout(FORWARD_TIMEOUT_MS, () => { + client.destroy() + finish(false) + }) + }) +} + +function delay(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms) + }) +} + +async function tryForwardViaPipeWithRetries(payload) { + for (let attempt = 0; attempt < PIPE_RETRY_ATTEMPTS; attempt += 1) { + if (await tryForwardViaPipe(payload)) { + return true + } + + if (attempt < PIPE_RETRY_ATTEMPTS - 1) { + await delay(PIPE_RETRY_DELAY_MS) + } + } + + return false +} + +export async function forwardDeeplinkToRunningInstance(payload) { + if (process.platform === 'win32') { + if (await tryForwardViaPipeWithRetries(payload)) { + return true + } + } + + if (isPrimaryInstanceRunning()) { + writeDeeplinkSignal(payload) + return true + } + + return false +} diff --git a/src/desktop/macappupdate.js b/src/desktop/macappupdate.js new file mode 100644 index 0000000..b111936 --- /dev/null +++ b/src/desktop/macappupdate.js @@ -0,0 +1,167 @@ +import { promises as fs } from 'fs' +import path from 'path' +import sudo from '@vscode/sudo-prompt' + +const quoteShellArg = (value) => `'${String(value).replaceAll("'", "'\\''")}'` + +const parseMacInstallerProgress = (output) => { + const lines = String(output || '').split('\n') + let percent = null + let message = 'Installing update...' + + for (const line of lines) { + if (line.startsWith('installer:PHASE:')) { + message = line.slice('installer:PHASE:'.length).trim() || message + } else if (line.startsWith('installer:STATUS:')) { + const status = line.slice('installer:STATUS:'.length).trim() + if (status) message = status + } else if (line.startsWith('installer:%')) { + const value = Number.parseFloat(line.slice('installer:%'.length)) + if (Number.isFinite(value)) { + percent = Math.min(100, Math.round(value <= 1 ? value * 100 : value)) + } + } else if ( + line.startsWith('installer: ') && + !line.startsWith('installer:PHASE:') && + !line.startsWith('installer:STATUS:') && + !line.startsWith('installer:%') + ) { + const text = line.slice('installer: '.length).trim() + if (text) message = text + } + } + + return { percent, message } +} + +const isMacInstallSuccessful = (output) => + /installer: The (install|upgrade) was successful\./i.test(output) + +const isMacInstallFailed = (output) => + /installer: The install failed/i.test(output) + +const buildMacInstallScript = (installerPath, logPath) => + `sleep 2 && /usr/sbin/installer -pkg ${quoteShellArg( + installerPath + )} -target / -verboseR 2>&1 | /usr/bin/tee ${quoteShellArg(logPath)}` + +const startMacInstallerProgressWatch = (logPath, sendProgress) => { + let installerOutput = '' + let offset = 0 + let lastPercent = null + let lastMessage = null + + const poll = async () => { + try { + const stat = await fs.stat(logPath) + if (stat.size <= offset) return + + const handle = await fs.open(logPath, 'r') + try { + const buffer = Buffer.alloc(stat.size - offset) + await handle.read(buffer, 0, buffer.length, offset) + offset = stat.size + installerOutput += buffer.toString('utf8') + + const { percent, message } = parseMacInstallerProgress(installerOutput) + const resolvedMessage = message || 'Installing update...' + + if (percent !== lastPercent || resolvedMessage !== lastMessage) { + lastPercent = percent + lastMessage = resolvedMessage + sendProgress( { + phase: 'installing', + percent, + message: resolvedMessage + }) + } + } finally { + await handle.close() + } + } catch (error) { + if (error?.code !== 'ENOENT') { + console.error('[app-update] installer log poll error:', error) + } + } + } + + const intervalId = setInterval(() => { + poll().catch((error) => { + console.error('[app-update] installer log poll error:', error) + }) + }, 300) + + return async () => { + clearInterval(intervalId) + await poll() + return installerOutput + } +} + +export const launchMacInstaller = ( + mainWindow, + installerPath, + webContents, + { sendProgress, getInstallErrorMessage } +) => { + const logPath = path.join(path.dirname(installerPath), 'install.log') + const installScript = buildMacInstallScript(installerPath, logPath) + const promptName = 'farmcontrol' + + sendProgress( { + phase: 'installing', + percent: 0, + message: 'Enter your Mac password when prompted.' + }) + + if (mainWindow && !mainWindow.isDestroyed?.()) { + mainWindow.focus?.(); + mainWindow.show?.(); + } + + const stopProgressWatch = startMacInstallerProgressWatch(logPath, sendProgress) + + return new Promise((resolve, reject) => { + sudo.exec(installScript, { name: promptName }, async (error, stdout, stderr) => { + const watchedOutput = await stopProgressWatch() + const output = `${stdout || ''}${stderr || ''}` || watchedOutput + + await fs.unlink(logPath).catch(() => {}) + + if (stderr) console.error('[app-update] installer stderr:', stderr) + + if (error) { + console.error('[app-update] installer error:', error) + const message = getInstallErrorMessage(error, output) + sendProgress( { + phase: 'error', + percent: null, + message + }) + reject(new Error(message)) + return + } + + if (isMacInstallFailed(output) || !isMacInstallSuccessful(output)) { + const message = getInstallErrorMessage(null, output) + sendProgress( { + phase: 'error', + percent: null, + message + }) + reject(new Error(message)) + return + } + + const { percent, message } = parseMacInstallerProgress(output) + + sendProgress( { + phase: 'installing', + percent: percent ?? 100, + message: message || 'Installation complete. Restarting Farm Control...' + }) + + resolve() + }) + }) +} diff --git a/src/desktop/macos-window-effects.js b/src/desktop/macos-window-effects.js new file mode 100644 index 0000000..aafa3cc --- /dev/null +++ b/src/desktop/macos-window-effects.js @@ -0,0 +1,148 @@ +import { dlopen, FFIType } from 'bun:ffi' +import { existsSync, statSync } from 'node:fs' +import path from 'node:path' +import { fileURLToPath } from 'node:url' + +export const MAC_WINDOW_CORNER_RADIUS = 15 +export const MAC_TRAFFIC_LIGHT_OFFSET = { x: 14, y: 12 } + +const DYLIB_NAME = 'libMacWindowEffects.dylib' +const MIN_DYLIB_BYTES = 10_000 + +function resolveDylibPath() { + const candidates = new Set() + const moduleDir = path.dirname(fileURLToPath(import.meta.url)) + + candidates.add(path.join(moduleDir, DYLIB_NAME)) + candidates.add(path.join(moduleDir, '../bun', DYLIB_NAME)) + candidates.add(path.join(moduleDir, '../../bun', DYLIB_NAME)) + candidates.add(path.join(process.cwd(), 'src/bun', DYLIB_NAME)) + + for (const execPath of [process.execPath, process.argv0].filter(Boolean)) { + const execDir = path.dirname(execPath) + candidates.add( + path.join(execDir, '../Resources/app/bun', DYLIB_NAME) + ) + candidates.add(path.join(execDir, 'Resources/app/bun', DYLIB_NAME)) + candidates.add(path.join(execDir, DYLIB_NAME)) + } + + for (const candidate of candidates) { + const resolved = path.resolve(candidate) + if (!existsSync(resolved)) { + continue + } + + try { + if (statSync(resolved).size >= MIN_DYLIB_BYTES) { + return resolved + } + } catch { + // Ignore unreadable paths and keep searching. + } + } + + return null +} + +function loadMacWindowEffectsLibrary() { + const dylibPath = resolveDylibPath() + if (!dylibPath) { + console.warn( + 'macOS vibrancy: native effects library not found; using transparent window only.' + ) + return null + } + + try { + return { + path: dylibPath, + lib: dlopen(dylibPath, { + enableWindowVibrancy: { + args: [FFIType.ptr, FFIType.f64], + returns: FFIType.bool + }, + ensureWindowShadow: { + args: [FFIType.ptr], + returns: FFIType.bool + }, + setWindowCornerRadius: { + args: [FFIType.ptr, FFIType.f64], + returns: FFIType.bool + }, + setWindowTrafficLightsPosition: { + args: [FFIType.ptr, FFIType.f64, FFIType.f64], + returns: FFIType.bool + }, + setNativeWindowDragRegion: { + args: [FFIType.ptr, FFIType.f64, FFIType.f64], + returns: FFIType.bool + } + }) + } + } catch (error) { + console.warn( + `macOS vibrancy: failed to load native effects library (${dylibPath}):`, + error + ) + return null + } +} + +function applyTrafficLightsPosition(lib, mainWindow, attempt = 0) { + const applied = lib.symbols.setWindowTrafficLightsPosition( + mainWindow.ptr, + MAC_TRAFFIC_LIGHT_OFFSET.x, + MAC_TRAFFIC_LIGHT_OFFSET.y + ) + + if (applied || attempt >= 10) { + return applied + } + + setTimeout(() => applyTrafficLightsPosition(lib, mainWindow, attempt + 1), 50) + return false +} + +export function applyMacOSWindowEffects(mainWindow) { + if (process.platform !== 'darwin' || !mainWindow?.ptr) { + return + } + + const loaded = loadMacWindowEffectsLibrary() + if (!loaded) { + return + } + + const { path: dylibPath, lib } = loaded + + try { + const vibrancyEnabled = lib.symbols.enableWindowVibrancy( + mainWindow.ptr, + MAC_WINDOW_CORNER_RADIUS + ) + const shadowEnabled = lib.symbols.ensureWindowShadow(mainWindow.ptr) + const trafficLightsScheduled = applyTrafficLightsPosition(lib, mainWindow) + + mainWindow.on?.('resize', () => { + lib.symbols.setWindowCornerRadius( + mainWindow.ptr, + MAC_WINDOW_CORNER_RADIUS + ) + lib.symbols.setWindowTrafficLightsPosition( + mainWindow.ptr, + MAC_TRAFFIC_LIGHT_OFFSET.x, + MAC_TRAFFIC_LIGHT_OFFSET.y + ) + }) + + console.log( + `macOS vibrancy applied (dylib=${dylibPath}, vibrancy=${vibrancyEnabled}, shadow=${shadowEnabled}, trafficLights=${trafficLightsScheduled}, cornerRadius=${MAC_WINDOW_CORNER_RADIUS})` + ) + } catch (error) { + console.warn( + 'macOS vibrancy: failed to apply native window effects:', + error + ) + } +} diff --git a/src/desktop/menu.js b/src/desktop/menu.js new file mode 100644 index 0000000..277a714 --- /dev/null +++ b/src/desktop/menu.js @@ -0,0 +1,186 @@ +import { ApplicationMenu } from "electrobun/bun"; + +const SIDEBAR_MENU_ACTION_PREFIX = "sidebar-nav:"; + +let sidebarViewMenuSections = []; +let navigateHandler = null; + +function buildMacAppMenu() { + return { + submenu: [ + { + label: "About Farm Control", + action: `${SIDEBAR_MENU_ACTION_PREFIX}/dashboard/management/about`, + }, + { type: "separator" }, + { + label: "Check For Updates...", + action: "check-for-updates", + }, + { type: "separator" }, + { role: "hide" }, + { role: "hideOthers" }, + { role: "showAll" }, + { type: "separator" }, + { role: "quit" }, + ], + }; +} + +function buildEditMenu() { + return { + label: "Edit", + submenu: [ + { role: "undo" }, + { role: "redo" }, + { type: "separator" }, + { role: "cut" }, + { role: "copy" }, + { role: "paste" }, + { role: "pasteAndMatchStyle" }, + { role: "delete" }, + { type: "separator" }, + { role: "selectAll" }, + { type: "separator" }, + { role: "startSpeaking" }, + { role: "stopSpeaking" }, + ], + }; +} + +function buildFileMenu() { + return { + label: "File", + submenu: [{ role: "close" }], + }; +} + +function buildWindowMenu() { + return { + label: "Window", + submenu: [ + { role: "minimize" }, + { role: "zoom" }, + { type: "separator" }, + { role: "bringAllToFront" }, + ], + }; +} + +function toMenuItems(items = []) { + return items + .map((item) => { + if (item?.type === "divider") { + return { type: "separator" }; + } + + const menuItem = { + label: item.label, + }; + + if ( + item?.children && + Array.isArray(item.children) && + item.children.length + ) { + menuItem.submenu = toMenuItems(item.children); + } else if (item?.path) { + menuItem.action = `${SIDEBAR_MENU_ACTION_PREFIX}${item.path}`; + } else { + menuItem.enabled = false; + } + + return menuItem; + }) + .filter(Boolean); +} + +function buildApplicationMenuTemplate() { + const env = (process.env.NODE_ENV || "development").trim(); + const viewSubmenu = sidebarViewMenuSections.map((section) => ({ + label: section.label, + submenu: toMenuItems(section.items || []), + })); + + if (viewSubmenu.length === 0) { + viewSubmenu.push({ label: "No sidebar items available", enabled: false }); + } + + if (env === "development") { + viewSubmenu.push( + { type: "separator" }, + { + label: "Toggle Developer Tools", + accelerator: "i", + action: "toggle-devtools", + }, + ); + } + + const template = [ + buildFileMenu(), + buildEditMenu(), + { label: "View", submenu: viewSubmenu }, + buildWindowMenu(), + ]; + + if (process.platform === "darwin") { + template.unshift(buildMacAppMenu()); + } + + return template; +} + +export function applyApplicationMenu() { + if (process.platform !== "darwin") { + return; + } + + ApplicationMenu.setApplicationMenu(buildApplicationMenuTemplate()); +} + +export function setSidebarViewMenu(sections) { + if (!Array.isArray(sections)) { + return false; + } + + sidebarViewMenuSections = sections; + applyApplicationMenu(); + return true; +} + +export function setupApplicationMenuEvents({ + onNavigate, + onToggleDevTools, + onCheckForUpdates, +}) { + if (process.platform !== "darwin") { + return; + } + + navigateHandler = onNavigate; + + ApplicationMenu.on("application-menu-clicked", (event) => { + const action = event?.data?.action; + if (!action) return; + + if (action === "toggle-devtools") { + onToggleDevTools?.(); + return; + } + + if (action === "check-for-updates") { + onCheckForUpdates?.(); + return; + } + + if (action.startsWith(SIDEBAR_MENU_ACTION_PREFIX)) { + const path = action.slice(SIDEBAR_MENU_ACTION_PREFIX.length); + navigateHandler?.(path || "/"); + } + }); +} + +export function getSidebarMenuActionPrefix() { + return SIDEBAR_MENU_ACTION_PREFIX; +} diff --git a/src/desktop/notify.js b/src/desktop/notify.js new file mode 100644 index 0000000..f25fa61 --- /dev/null +++ b/src/desktop/notify.js @@ -0,0 +1,9 @@ +let sendMessage = () => false; + +export function setMessageSender(sender) { + sendMessage = sender; +} + +export function sendToRenderer(channel, data) { + return sendMessage(channel, data); +} diff --git a/src/desktop/rpc.js b/src/desktop/rpc.js new file mode 100644 index 0000000..d495cd8 --- /dev/null +++ b/src/desktop/rpc.js @@ -0,0 +1,140 @@ +import { BrowserView } from 'electrobun/bun' +import { + checkForCompletedUpdate, + getRunningAppVersion, + startAppUpdate +} from './appupdate.js' +import { + checkForDuplicateInstallations, + removeDuplicateInstallations +} from './check-duplicate-installations.js' +import { setSidebarViewMenu } from './menu.js' +import { sendToRenderer } from './notify.js' +import { resizeSpotlightWindow } from './spotlight.js' +import { + clearAuthSession, + getAppSettings, + getAuthSession, + setAppSettings, + setAuthSession +} from './store.js' +import { + getMainWindow, + getWindowState, + handleWindowControl, + openExternalUrl, + openInternalUrl +} from './window.js' + +export function createAppRpc() { + const requestHandlers = { + getOsInfo: async () => ({ + platform: process.platform + }), + getWindowState: async () => getWindowState(), + windowControl: async ({ action }) => { + handleWindowControl(action) + return { ok: true } + }, + openExternalUrl: async ({ url }) => { + openExternalUrl(url) + return { ok: true } + }, + openInternalUrl: async ({ url }) => ({ + ok: openInternalUrl(url) + }), + getAuthSession: async () => getAuthSession(), + setAuthSession: async ({ session }) => ({ + ok: await setAuthSession(session) + }), + clearAuthSession: async () => ({ + ok: await clearAuthSession() + }), + getAppSettings: async () => getAppSettings(), + setAppSettings: async ({ settings }) => ({ + ok: await setAppSettings(settings) + }), + startAppUpdate: async ({ update }) => { + const mainWindow = getMainWindow() + const sendProgress = (payload) => { + sendToRenderer('appUpdateProgress', { + timestamp: new Date().toISOString(), + ...payload + }) + } + + // Updates can take several minutes; return immediately and report + // progress via appUpdateProgress messages instead of blocking RPC. + void startAppUpdate(mainWindow, update, sendProgress).catch((error) => { + console.error('App update failed:', error) + }) + return { ok: true } + }, + resizeSpotlightWindow: async ({ height }) => ({ + ok: resizeSpotlightWindow(height) + }), + setSidebarViewMenu: async ({ sections }) => ({ + ok: setSidebarViewMenu(sections) + }), + checkAppUpdateResult: async () => + checkForCompletedUpdate(getMainWindow()), + checkDuplicateInstallations: async () => checkForDuplicateInstallations(), + removeDuplicateInstallations: async () => { + // Removal waits on an admin/UAC prompt which can outlive the RPC + // timeout; report the outcome via a push message instead. + void removeDuplicateInstallations() + .catch((error) => ({ + ok: false, + error: + error?.message || 'Failed to remove the duplicate installation.' + })) + .then((result) => { + sendToRenderer('duplicateInstallationsRemoved', result) + }) + return { ok: true } + }, + getAppVersion: async () => getRunningAppVersion() || 'desktop', + getAppEngine: async () => { + const mainWindow = getMainWindow() + const renderer = mainWindow?.renderer || 'native' + return renderer === 'cef' ? 'chromium' : 'native' + } + } + + return BrowserView.defineRPC({ + maxRequestTime: 30000, + handlers: { + requests: requestHandlers, + messages: { + rendererRequest: ({ id, method, params }) => { + const handler = requestHandlers[method] + if (!handler) { + sendToRenderer('rpcResponse', { + id, + success: false, + error: `Unknown desktop RPC method: ${String(method)}` + }) + return + } + + void Promise.resolve() + .then(() => handler(params || {})) + .then((result) => { + sendToRenderer('rpcResponse', { + id, + success: true, + result + }) + }) + .catch((error) => { + sendToRenderer('rpcResponse', { + id, + success: false, + error: error?.message || String(error) + }) + }) + } + } + } + }) +} diff --git a/src/desktop/single-instance.js b/src/desktop/single-instance.js new file mode 100644 index 0000000..398c0e0 --- /dev/null +++ b/src/desktop/single-instance.js @@ -0,0 +1,307 @@ +import { + closeSync, + existsSync, + mkdirSync, + openSync, + readFileSync, + unlinkSync, + watch, + writeFileSync +} from 'node:fs' +import net from 'node:net' +import { + buildDeeplinkPayload, + findProtocolUrl, + forwardDeeplinkToRunningInstance, + getInstanceDir, + getLockPath, + getSignalPath, + isProcessAlive, + SIGNAL_FILE, + WINDOWS_PIPE_NAME, + writeDeeplinkSignal +} from './deeplink-ipc.js' + +let lockFd = null +let pollInterval = null +let fsWatcher = null +let pipeServer = null +let handlers = { + onDeepLink: null, + onFocus: null +} +const pendingMessages = [] + +function tryAcquirePrimaryLock() { + mkdirSync(getInstanceDir(), { recursive: true }) + const lockPath = getLockPath() + + if (existsSync(lockPath)) { + try { + const existingPid = Number.parseInt(readFileSync(lockPath, 'utf8').trim(), 10) + + if (existingPid === process.pid) { + return true + } + + if (isProcessAlive(existingPid)) { + return false + } + + unlinkSync(lockPath) + } catch { + try { + unlinkSync(lockPath) + } catch { + // Ignore cleanup failures. + } + } + } + + try { + lockFd = openSync(lockPath, 'wx') + writeFileSync(lockFd, String(process.pid)) + return true + } catch { + return false + } +} + +function releasePrimaryLock() { + if (lockFd !== null) { + try { + closeSync(lockFd) + } catch { + // Ignore close failures. + } + lockFd = null + } + + try { + unlinkSync(getLockPath()) + } catch { + // Ignore cleanup failures. + } +} + +export { findProtocolUrl } + +export function captureLaunchUrl() { + return findProtocolUrl(process.argv) +} + +function buildLaunchPayload(launchUrl = captureLaunchUrl()) { + const commandLine = [...process.argv] + const url = launchUrl || findProtocolUrl(commandLine) + + return buildDeeplinkPayload(url, commandLine) +} + +function readSignalQueue({ clear = true } = {}) { + const signalPath = getSignalPath() + if (!existsSync(signalPath)) { + return [] + } + + try { + const raw = readFileSync(signalPath, 'utf8') + const parsed = JSON.parse(raw) + + if (clear) { + unlinkSync(signalPath) + } + + if (Array.isArray(parsed)) { + return parsed + } + + return parsed ? [parsed] : [] + } catch { + if (clear) { + try { + unlinkSync(signalPath) + } catch { + // Ignore cleanup failures. + } + } + return [] + } +} + +function writeInstanceSignal(payload) { + writeDeeplinkSignal(payload) +} + +function resolveIncomingMessage(message) { + if (!message || typeof message !== 'object') { + return null + } + + if (message.type === 'deeplink') { + const url = message.url || findProtocolUrl(message.argv || []) + return url ? { type: 'deeplink', url } : { type: 'focus' } + } + + if (message.type === 'focus') { + return { type: 'focus' } + } + + return null +} + +function dispatchMessage(message) { + const resolved = resolveIncomingMessage(message) + if (!resolved) return + + if (process.platform === 'win32') { + console.log('[deeplink][dispatch]', message) + console.log('[deeplink][dispatch] resolved:', resolved) + } + + if (!handlers.onDeepLink && !handlers.onFocus) { + pendingMessages.push(resolved) + return + } + + if (resolved.type === 'deeplink' && resolved.url) { + handlers.onDeepLink?.(resolved.url) + return + } + + if (resolved.type === 'focus') { + handlers.onFocus?.() + } +} + +function processInstanceSignals() { + for (const message of readSignalQueue({ clear: true })) { + dispatchMessage(message) + } +} + +function startInstanceSignalWatcher() { + if (process.platform === 'darwin' || pollInterval) { + return + } + + mkdirSync(getInstanceDir(), { recursive: true }) + processInstanceSignals() + + try { + fsWatcher = watch(getInstanceDir(), (_event, filename) => { + if (!filename || filename === SIGNAL_FILE) { + setTimeout(processInstanceSignals, 25) + } + }) + } catch { + // Polling below covers filesystems without reliable watch support. + } + + pollInterval = setInterval(processInstanceSignals, 100) +} + +function startWindowsPipeServer() { + if (process.platform !== 'win32' || pipeServer) { + return + } + + const server = net.createServer((socket) => { + let buffer = '' + + socket.on('data', (chunk) => { + buffer += chunk.toString() + }) + + socket.on('end', () => { + if (!buffer) return + + try { + dispatchMessage(JSON.parse(buffer)) + } catch { + // Ignore malformed payloads. + } + }) + }) + + server.on('error', (error) => { + if (error?.code !== 'EADDRINUSE') { + console.warn('[single-instance] pipe server error:', error) + } + }) + + server.listen({ path: WINDOWS_PIPE_NAME }) + pipeServer = server +} + +export async function ensureSingleInstanceLock({ launchUrl } = {}) { + if (process.platform === 'darwin') { + return true + } + + const payload = buildLaunchPayload(launchUrl) + + if (process.platform === 'win32') { + if (await forwardDeeplinkToRunningInstance(payload)) { + console.log('[deeplink] forwarded duplicate launcher instance to running app') + return false + } + + if (!tryAcquirePrimaryLock()) { + if (await forwardDeeplinkToRunningInstance(payload)) { + return false + } + + writeInstanceSignal(payload) + return false + } + + startWindowsPipeServer() + startInstanceSignalWatcher() + return true + } + + if (tryAcquirePrimaryLock()) { + startInstanceSignalWatcher() + return true + } + + writeInstanceSignal(payload) + return false +} + +export function setSingleInstanceHandlers({ onDeepLink, onFocus }) { + handlers = { onDeepLink, onFocus } + + while (pendingMessages.length > 0) { + dispatchMessage(pendingMessages.shift()) + } + + processInstanceSignals() +} + +export function closeSingleInstanceServer() { + if (pipeServer) { + try { + pipeServer.close() + } catch { + // Ignore close failures. + } + pipeServer = null + } + + if (pollInterval) { + clearInterval(pollInterval) + pollInterval = null + } + + if (fsWatcher) { + try { + fsWatcher.close() + } catch { + // Ignore close failures. + } + fsWatcher = null + } + + releasePrimaryLock() +} diff --git a/src/desktop/spotlight.js b/src/desktop/spotlight.js new file mode 100644 index 0000000..106624f --- /dev/null +++ b/src/desktop/spotlight.js @@ -0,0 +1,106 @@ +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { BrowserWindow, GlobalShortcut } from 'electrobun/bun' + +const __filename = fileURLToPath(import.meta.url) +const __dirname = path.dirname(__filename) + +const DEV_SERVER_PORT = 5780 +const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}` +const SPOTLIGHT_ROUTE_PATH = '/dashboard/electron/spotlightcontent' + +let spotlightWindow = null + +function getSpotlightRouteUrl() { + if (process.env.NODE_ENV === 'development') { + return `${DEV_SERVER_URL}${SPOTLIGHT_ROUTE_PATH}` + } + + return `views://mainview/index.html#${SPOTLIGHT_ROUTE_PATH}` +} + +export function openSpotlightContentWindow(rpc) { + if (spotlightWindow && !spotlightWindow.isDestroyed?.()) { + spotlightWindow.show?.() + spotlightWindow.focus?.() + return spotlightWindow + } + + spotlightWindow = new BrowserWindow({ + title: 'Farm Control Spotlight', + url: getSpotlightRouteUrl(), + rpc, + transparent: true, + frame: { + width: 700, + height: 40, + x: 100, + y: 100 + } + }) + + spotlightWindow.on?.('close', (event) => { + event?.preventDefault?.() + if (spotlightWindow && !spotlightWindow.isDestroyed?.()) { + spotlightWindow.hide?.() + } + }) + + spotlightWindow.on?.('blur', () => { + if (spotlightWindow && !spotlightWindow.isDestroyed?.()) { + spotlightWindow.hide?.() + } + }) + + return spotlightWindow +} + +export function getSpotlightWindow() { + return spotlightWindow +} + +export function registerGlobalShortcuts(rpc) { + try { + const registered = GlobalShortcut.register('Alt+Shift+Q', () => { + openSpotlightContentWindow(rpc) + }) + + if (!registered) { + console.warn('[globalShortcut] Failed to register Alt+Shift+Q') + } + } catch (error) { + console.warn( + '[globalShortcut] Error registering Alt+Shift+Q', + error?.message || error + ) + } +} + +export function unregisterGlobalShortcuts() { + try { + GlobalShortcut.unregisterAll() + } catch (error) { + console.warn( + '[globalShortcut] Error unregistering shortcuts', + error?.message || error + ) + } +} + +export function resizeSpotlightWindow(height) { + if (!spotlightWindow || spotlightWindow.isDestroyed?.()) return false + + try { + const frame = spotlightWindow.getFrame?.() || spotlightWindow.getBounds?.() + const width = frame?.width || 700 + spotlightWindow.setSize?.(width, height) + spotlightWindow.center?.() + return true + } catch (error) { + console.warn( + '[spotlight] Failed to resize window.', + error?.message || error + ) + return false + } +} diff --git a/src/desktop/store.js b/src/desktop/store.js new file mode 100644 index 0000000..0d7e790 --- /dev/null +++ b/src/desktop/store.js @@ -0,0 +1,86 @@ +import { existsSync } from "node:fs"; +import path from "node:path"; +import { mkdir, readFile, writeFile } from "node:fs/promises"; +import { Utils } from "electrobun/bun"; + +const AUTH_SERVICE = "com.tombutcher.farmcontrol"; +const AUTH_SECRET_NAME = "authSession"; +const SETTINGS_FILE = "settings.json"; + +function getSettingsPath() { + return path.join(Utils.paths.userData, SETTINGS_FILE); +} + +async function ensureUserDataDir() { + await mkdir(Utils.paths.userData, { recursive: true }); +} + +export async function getAuthSession() { + try { + const value = await Bun.secrets.get({ + service: AUTH_SERVICE, + name: AUTH_SECRET_NAME, + }); + if (!value) return null; + return JSON.parse(value); + } catch (error) { + console.warn("[auth-session] Failed to read auth session.", error); + return null; + } +} + +export async function setAuthSession(session) { + if (!session || typeof session !== "object") return false; + + try { + await Bun.secrets.set({ + service: AUTH_SERVICE, + name: AUTH_SECRET_NAME, + value: JSON.stringify(session), + }); + return true; + } catch (error) { + console.warn("[auth-session] Failed to write auth session.", error); + return false; + } +} + +export async function clearAuthSession() { + try { + await Bun.secrets.delete({ + service: AUTH_SERVICE, + name: AUTH_SECRET_NAME, + }); + return true; + } catch (error) { + console.warn("[auth-session] Failed to clear auth session.", error); + return false; + } +} + +export async function getAppSettings() { + try { + await ensureUserDataDir(); + const settingsPath = getSettingsPath(); + if (!existsSync(settingsPath)) return {}; + const raw = await readFile(settingsPath, "utf8"); + const settings = JSON.parse(raw); + return settings && typeof settings === "object" ? settings : {}; + } catch (error) { + console.warn("[app-settings] Failed to read settings.", error); + return {}; + } +} + +export async function setAppSettings(settings) { + if (!settings || typeof settings !== "object") return false; + + try { + await ensureUserDataDir(); + await writeFile(getSettingsPath(), JSON.stringify(settings, null, 2)); + return true; + } catch (error) { + console.warn("[app-settings] Failed to write settings.", error); + return false; + } +} diff --git a/src/desktop/updater-runner.js b/src/desktop/updater-runner.js new file mode 100644 index 0000000..2cbf94a --- /dev/null +++ b/src/desktop/updater-runner.js @@ -0,0 +1,158 @@ +import { execSync, spawn } from 'node:child_process' +import { existsSync } from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import process from 'node:process' + +const MAC_APP_NAME = 'Farm Control.app' +const WINDOWS_INSTALL_DIR_KEYS = [ + 'HKCU\\Software\\Tom Butcher\\Farm Control', + 'HKLM\\Software\\Tom Butcher\\Farm Control' +] +const WINDOWS_LAUNCHER_EXE = 'FarmControl.exe' +const WINDOWS_LEGACY_LAUNCHER_EXE = 'launcher.exe' +const WINDOWS_DEFAULT_BIN_DIR = path.join( + process.env.LOCALAPPDATA || path.join(os.homedir(), 'AppData', 'Local'), + 'Programs', + 'Farm Control', + 'bin' +) + +const resolveExistingLauncher = (...candidates) => + candidates.find((candidate) => existsSync(candidate)) || null + +const quoteBatchArg = (value) => `"${String(value).replaceAll('"', '""')}"` + +export const findMacAppBundle = (startPath) => { + let current = path.resolve(startPath) + + while (current !== path.dirname(current)) { + if (current.endsWith('.app')) { + return current + } + + const baseName = path.basename(current) + if (baseName === 'Contents') { + const bundlePath = path.dirname(current) + if (bundlePath.endsWith('.app')) { + return bundlePath + } + } + + current = path.dirname(current) + } + + return null +} + +const readWindowsInstallDirFromRegistry = () => { + for (const registryKey of WINDOWS_INSTALL_DIR_KEYS) { + try { + const output = execSync( + `reg query ${quoteBatchArg(registryKey)} /v InstallDir`, + { encoding: 'utf8', windowsHide: true } + ) + const match = output.match(/InstallDir\s+REG_\w+\s+(.+)/i) + const installDir = match?.[1]?.trim() + if (installDir) { + return installDir + } + } catch { + // Try the next registry key. + } + } + + return null +} + +export const resolveAppLaunchPath = () => { + if (process.platform === 'darwin') { + const bundleFromExec = findMacAppBundle(process.execPath) + if (bundleFromExec) { + return bundleFromExec + } + + const applicationsPath = path.join('/Applications', MAC_APP_NAME) + if (existsSync(applicationsPath)) { + return applicationsPath + } + + return process.execPath + } + + if (process.platform === 'win32') { + // Prefer the installed launcher so restarts target the registered install dir. + const installDir = readWindowsInstallDirFromRegistry() + if (installDir) { + const launcherFromRegistry = resolveExistingLauncher( + path.join(installDir, 'bin', WINDOWS_LAUNCHER_EXE), + path.join(installDir, 'bin', WINDOWS_LEGACY_LAUNCHER_EXE) + ) + if (launcherFromRegistry) { + return launcherFromRegistry + } + } + + const defaultLauncher = resolveExistingLauncher( + path.join(WINDOWS_DEFAULT_BIN_DIR, WINDOWS_LAUNCHER_EXE), + path.join(WINDOWS_DEFAULT_BIN_DIR, WINDOWS_LEGACY_LAUNCHER_EXE) + ) + if (defaultLauncher) { + return defaultLauncher + } + + const execBase = path.basename(process.execPath).toLowerCase() + if ( + execBase === WINDOWS_LAUNCHER_EXE.toLowerCase() || + execBase === WINDOWS_LEGACY_LAUNCHER_EXE + ) { + return process.execPath + } + + const launcherBesideExec = resolveExistingLauncher( + path.join(path.dirname(process.execPath), WINDOWS_LAUNCHER_EXE), + path.join(path.dirname(process.execPath), WINDOWS_LEGACY_LAUNCHER_EXE) + ) + if (launcherBesideExec) { + return launcherBesideExec + } + + const launcherInBin = resolveExistingLauncher( + path.join(path.dirname(process.execPath), 'bin', WINDOWS_LAUNCHER_EXE), + path.join(path.dirname(process.execPath), 'bin', WINDOWS_LEGACY_LAUNCHER_EXE) + ) + if (launcherInBin) { + return launcherInBin + } + + return process.execPath + } + + throw new Error(`App updates are not supported on ${process.platform}.`) +} + +const spawnDetachedMacRestart = ({ appLaunchPath, parentPid }) => { + const child = spawn( + '/bin/sh', + [ + '-c', + `while kill -0 ${parentPid} 2>/dev/null; do sleep 0.5; done; sleep 1; /usr/bin/open ${JSON.stringify(appLaunchPath)}` + ], + { + detached: true, + stdio: 'ignore' + } + ) + child.unref() +} + +export const scheduleAppRestart = ({ parentPid = process.pid } = {}) => { + const appLaunchPath = resolveAppLaunchPath() + + if (process.platform === 'darwin') { + spawnDetachedMacRestart({ appLaunchPath, parentPid }) + return { appLaunchPath } + } + + throw new Error(`App restart scheduling is not supported on ${process.platform}.`) +} diff --git a/src/desktop/winappupdate.js b/src/desktop/winappupdate.js new file mode 100644 index 0000000..e725fe2 --- /dev/null +++ b/src/desktop/winappupdate.js @@ -0,0 +1,357 @@ +import { spawn } from 'child_process' +import { promises as fs } from 'fs' +import os from 'os' +import path from 'path' + +const PE_MZ_HEADER = Buffer.from([0x4d, 0x5a]) // "MZ" +const COPY_PROGRESS_START = 5 +const COPY_PROGRESS_END = 90 +const COPY_PROGRESS_RANGE = COPY_PROGRESS_END - COPY_PROGRESS_START + +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)) + +const formatBytes = (bytes) => { + if (bytes < 1024) return `${bytes} B` + if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KiB` + return `${(bytes / (1024 * 1024)).toFixed(1)} MiB` +} + +const parseWindowsInstallerProgress = (output) => { + const lines = String(output || '').split(/\r?\n/) + let percent = null + let message = 'Installing update...' + let copyTotalBytes = 0 + let copiedBytes = 0 + + for (const line of lines) { + if (line.startsWith('installer:PHASE:')) { + message = line.slice('installer:PHASE:'.length).trim() || message + } else if (line.startsWith('installer:STATUS:')) { + const status = line.slice('installer:STATUS:'.length).trim() + if (status) message = status + } else if (line.startsWith('installer:%')) { + const value = Number.parseFloat(line.slice('installer:%'.length)) + if (Number.isFinite(value)) { + percent = Math.min(100, Math.round(value <= 1 ? value * 100 : value)) + } + } else if (line.startsWith('installer:COPY_TOTAL:')) { + const value = Number.parseInt( + line.slice('installer:COPY_TOTAL:'.length), + 10 + ) + if (Number.isFinite(value) && value > 0) { + copyTotalBytes = value + copiedBytes = 0 + } + } else if (line.startsWith('installer:COPY_FILE:')) { + const copyFile = line.match(/^installer:COPY_FILE:(\d+):(.*)$/) + if (copyFile) { + const fileBytes = Number.parseInt(copyFile[1], 10) + var fileName = copyFile[2].trim() + if (fileName.includes('\\')) { + fileName = fileName.split('\\').pop() + } + + if (Number.isFinite(fileBytes)) { + copiedBytes += fileBytes + if (copyTotalBytes > 0) { + percent = Math.min( + COPY_PROGRESS_END, + COPY_PROGRESS_START + + Math.round( + (copiedBytes / copyTotalBytes) * COPY_PROGRESS_RANGE + ) + ) + } + } + + if (fileName) { + message = `Copying ${fileName} (${formatBytes(fileBytes)})` + } + } + } else if ( + line.startsWith('installer: ') && + !line.startsWith('installer:PHASE:') && + !line.startsWith('installer:STATUS:') && + !line.startsWith('installer:%') && + !line.startsWith('installer:COPY_') + ) { + const text = line.slice('installer: '.length).trim() + if (text) message = text + } + } + + return { percent, message } +} + +const isWindowsInstallSuccessful = (output) => + /installer: The install was successful\./i.test(output) + +const isWindowsInstallFailed = (output) => + /installer: The install failed/i.test(output) + +const isValidNsisInstaller = async (filePath) => { + const handle = await fs.open(filePath, 'r') + try { + const header = Buffer.alloc(PE_MZ_HEADER.length) + await handle.read(header, 0, header.length, 0) + return header.equals(PE_MZ_HEADER) + } finally { + await handle.close() + } +} + +export const prepareInstallerPath = async (installerPath) => { + const fileName = path.basename(installerPath) + const updateDir = path.join( + os.homedir(), + 'AppData', + 'Local', + 'FarmControl', + 'Updates' + ) + await fs.mkdir(updateDir, { recursive: true }) + + const stablePath = path.join(updateDir, fileName) + await fs.copyFile(installerPath, stablePath) + + const resolvedPath = await fs.realpath(stablePath) + const stats = await fs.stat(resolvedPath) + + if (!stats.isFile() || stats.size === 0) { + throw new Error('Update installer file is missing or empty.') + } + + if (!(await isValidNsisInstaller(resolvedPath))) { + throw new Error( + 'Downloaded update is not a valid Windows installer. The file may be corrupted or incomplete.' + ) + } + + return resolvedPath +} + +const startWindowsInstallerProgressWatch = ( + logPath, + sendProgress, + { onInstallSuccessful, onInstallFailed, onStalled, stallTimeoutMs } +) => { + let installerOutput = '' + let offset = 0 + let lastPercent = null + let lastMessage = null + let outcomeNotified = false + let lastActivityAt = Date.now() + + const poll = async () => { + try { + const stat = await fs.stat(logPath) + if (stat.size <= offset) return + + const handle = await fs.open(logPath, 'r') + try { + const buffer = Buffer.alloc(stat.size - offset) + await handle.read(buffer, 0, buffer.length, offset) + offset = stat.size + installerOutput += buffer.toString('utf8') + lastActivityAt = Date.now() + + const { percent, message } = + parseWindowsInstallerProgress(installerOutput) + const resolvedMessage = message || 'Installing update...' + + if (percent !== lastPercent || resolvedMessage !== lastMessage) { + lastPercent = percent + lastMessage = resolvedMessage + sendProgress({ + phase: 'installing', + percent, + message: resolvedMessage + }) + } + + if (!outcomeNotified) { + if (isWindowsInstallFailed(installerOutput)) { + outcomeNotified = true + onInstallFailed?.(installerOutput) + } else if (isWindowsInstallSuccessful(installerOutput)) { + outcomeNotified = true + onInstallSuccessful?.(installerOutput) + } + } + } finally { + await handle.close() + } + } catch (error) { + if (error?.code !== 'ENOENT') { + console.error('[app-update] installer log poll error:', error) + } + } + } + + const intervalId = setInterval(() => { + // The installer runs detached (outside our job object), so a dead + // installer only shows up as the log going quiet before any outcome. + if ( + !outcomeNotified && + stallTimeoutMs > 0 && + Date.now() - lastActivityAt > stallTimeoutMs + ) { + outcomeNotified = true + onStalled?.(installerOutput) + return + } + + poll().catch((error) => { + console.error('[app-update] installer log poll error:', error) + }) + }, 200) + + return async () => { + clearInterval(intervalId) + await poll() + return installerOutput + } +} + +export const launchWindowsInstaller = async ( + mainWindow, + installerPath, + webContents, + { sendProgress, getInstallErrorMessage } +) => { + const resolvedPath = await prepareInstallerPath(installerPath) + const logPath = path.join(path.dirname(resolvedPath), 'install.log') + + sendProgress({ + phase: 'installing', + percent: 0, + message: 'Installing update...' + }) + + await fs.unlink(logPath).catch(() => {}) + + // Allow file handles from the download/copy to settle before the installer opens. + await sleep(2000) + + if (mainWindow && !mainWindow.isDestroyed?.()) { + mainWindow.focus?.() + mainWindow.show?.() + } + + return new Promise((resolve, reject) => { + let settled = false + + const settleSuccess = (output) => { + if (settled) return + settled = true + + const { percent, message } = parseWindowsInstallerProgress(output) + + sendProgress({ + phase: 'installing', + percent: percent ?? 100, + message: message || 'Installation complete. Restarting Farm Control...' + }) + + resolve() + } + + const settleFailure = (message) => { + if (settled) return + settled = true + + sendProgress({ + phase: 'error', + percent: null, + message + }) + reject(new Error(message)) + } + + const stopProgressWatch = startWindowsInstallerProgressWatch( + logPath, + sendProgress, + { + stallTimeoutMs: 3 * 60 * 1000, + onInstallSuccessful: (output) => { + settleSuccess(output) + }, + onInstallFailed: (output) => { + settleFailure(getInstallErrorMessage(null, output)) + }, + onStalled: (output) => { + settleFailure( + getInstallErrorMessage( + new Error('The update installer stopped responding.'), + output + ) + ) + } + } + ) + + const refreshInstallerOutput = async () => { + return await stopProgressWatch() + } + + // Silent NSIS install. + // /S = silent (https://nsis.sourceforge.io/Reference/SilentInstall) + // /UPDATE = in-app update (stage into Farm Control.new; swap after exit) + // /RESTARTFC = installer waits for this process to exit, swaps folders, relaunches + // /PARENTPID = exact process to wait for (CEF may outlive the launcher) + // /LOG= = progress log (installer:% / PHASE / STATUS / COPY_TOTAL / COPY_FILE) + const installerCommandLine = [ + `"${resolvedPath}"`, + '/S', + '/UPDATE', + '/RESTARTFC', + `/PARENTPID=${process.pid}`, + `/LOG="${logPath}"` + ].join(' ') + + // This process runs inside a Windows job object (CEF/launcher) that kills + // every child process when the app exits — a directly spawned installer + // (even with detached: true) inherits the job and dies mid folder-swap the + // moment the app quits. Creating the process via WMI (Win32_Process.Create) + // parents it to the WMI provider host, outside our job, so it survives. + const quoteForPowershell = (value) => `'${value.replace(/'/g, "''")}'` + + const spawnerProcess = spawn( + 'powershell.exe', + [ + '-NoProfile', + '-NonInteractive', + '-WindowStyle', + 'Hidden', + '-Command', + `$result = Invoke-CimMethod -ClassName Win32_Process -MethodName Create -Arguments @{ CommandLine = ${quoteForPowershell(installerCommandLine)} }; exit $result.ReturnValue` + ], + { + stdio: 'ignore', + windowsHide: true + } + ) + + spawnerProcess.on('error', async (error) => { + const output = await refreshInstallerOutput() + console.error('[app-update] installer launch error:', error) + settleFailure(getInstallErrorMessage(error, output)) + }) + + spawnerProcess.on('exit', async (code) => { + // PowerShell exits as soon as the installer is created; from here the + // log watcher owns success/failure. Only a non-zero code (WMI create + // failed) means the installer never started. + if (code === 0 || settled) return + + const output = await refreshInstallerOutput() + settleFailure( + getInstallErrorMessage( + new Error(`Failed to launch the update installer (code ${code}).`), + output + ) + ) + }) + }) +} diff --git a/src/desktop/window.js b/src/desktop/window.js new file mode 100644 index 0000000..8d07c83 --- /dev/null +++ b/src/desktop/window.js @@ -0,0 +1,418 @@ +import Electrobun, { BrowserWindow, Updater, Utils } from 'electrobun/bun' +import { applyApplicationMenu, setupApplicationMenuEvents } from './menu.js' +import { + applyMacOSWindowEffects, + MAC_TRAFFIC_LIGHT_OFFSET +} from './macos-window-effects.js' +import { sendToRenderer, setMessageSender } from './notify.js' +import { + clampWindowToWorkArea, + isWindowWorkAreaMaximized +} from './windows-work-area.js' + +const isMacOS = process.platform === 'darwin' +const isWindows = process.platform === 'win32' +const WINDOWS_STARTUP_MAXIMIZE_DELAY_MS = 1500 + +const DEV_SERVER_PORT = 5780 +const DEV_SERVER_URL = `http://localhost:${DEV_SERVER_PORT}` +import { findProtocolUrl, setSingleInstanceHandlers } from './single-instance.js' + +let mainWindow = null +let webviewDomReady = false +const pendingNavigations = [] + +export function getMainWindow() { + return mainWindow +} + +export function showMainWindow() { + if (!mainWindow) return + + if (mainWindow.isMinimized?.()) { + mainWindow.restore?.() + } + + mainWindow.show?.() + mainWindow.activate?.() +} + +export async function getMainViewUrl() { + const channel = await Updater.localInfo.channel() + if (channel === 'dev' || process.env.NODE_ENV === 'development') { + try { + await fetch(DEV_SERVER_URL, { method: 'HEAD' }) + console.log(`Using Vite dev server at ${DEV_SERVER_URL}`) + return DEV_SERVER_URL + } catch { + console.warn( + 'Vite dev server not running. Start it with `bun run dev:renderer`.' + ) + } + } + + return 'views://mainview/index.html' +} + +function deliverNavigation(redirectPath) { + sendToRenderer('navigate', redirectPath) + + if (!mainWindow) return + + if (mainWindow.isMinimized?.()) { + mainWindow.restore?.() + } + + mainWindow.show?.() + mainWindow.activate?.() +} + +function flushPendingNavigations() { + if (!mainWindow || !webviewDomReady) { + return + } + + while (pendingNavigations.length > 0) { + const redirectPath = pendingNavigations.shift() + setTimeout(() => deliverNavigation(redirectPath), 100) + } +} + +function sendNavigateToRenderer(redirectPath) { + if (!redirectPath || typeof redirectPath !== 'string') { + return + } + + if (!mainWindow || !webviewDomReady) { + pendingNavigations.push(redirectPath) + return + } + + setTimeout(() => deliverNavigation(redirectPath), 100) +} + +export function openInternalUrl(url) { + sendNavigateToRenderer(url) + return true +} + +const PROTOCOL_PREFIX = 'farmcontrol://' + +function parseDeepLinkPath(url) { + if (!url || typeof url !== 'string') { + return null + } + + if (url.startsWith('/')) { + return url + } + + if (!url.startsWith(`${PROTOCOL_PREFIX}app`)) { + return null + } + + const redirectPath = url.slice(`${PROTOCOL_PREFIX}app`.length) || '/' + const normalizedPath = redirectPath.startsWith('/') + ? redirectPath + : `/${redirectPath}` + + try { + return decodeURI(normalizedPath) + } catch { + return normalizedPath + } +} + +export function handleDeepLink(url) { + const path = parseDeepLinkPath(url) + if (!path) { + showMainWindow() + return false + } + + sendNavigateToRenderer(path) + return true +} + +export function handleDeepLinkFromArgv(launchUrl) { + if (process.platform === 'darwin') return + + const url = launchUrl || findProtocolUrl(process.argv) + if (url) { + handleDeepLink(url) + } +} + +function broadcastWindowState() { + sendToRenderer('windowState', getWindowState()) +} + +function applyStartupWindowState(window) { + if (!window) return + + if (isMacOS) { + window.maximize?.() + } + + setTimeout(broadcastWindowState, 100) +} + +function syncWindowsWebviewLayout(window) { + if (!window?.getSize || !window?.setSize) { + return + } + + const { width, height } = window.getSize() + if (!width || !height) { + return + } + + // Re-apply the current size so the native webview relayouts to the window. + window.setSize(width, height) +} + +function handleWindowsWindowChange(window) { + if (clampWindowToWorkArea(window)) { + syncWindowsWebviewLayout(window) + } + + broadcastWindowState() +} + +function applyWindowsStartupWindowState(window) { + if (!window) return + + setTimeout(() => { + window.maximize?.() + // maximize() settles asynchronously; sync state after the frame updates. + setTimeout(() => handleWindowsWindowChange(window), 100) + }, WINDOWS_STARTUP_MAXIMIZE_DELAY_MS) +} + +function setupWindowEvents(window) { + // Electrobun emits resize/focus, not Electron's maximize/fullscreen events. + const onWindowChange = isWindows + ? () => handleWindowsWindowChange(window) + : broadcastWindowState + + window.on?.('resize', onWindowChange) + window.on?.('focus', broadcastWindowState) + window.on?.('move', onWindowChange) +} + +export function setupMainWindowMessaging(window = mainWindow) { + if (!window) { + return + } + + setMessageSender((channel, data) => { + try { + const webview = window.webview + const channelLiteral = JSON.stringify(channel) + const payloadLiteral = JSON.stringify(data ?? null) + + // Prefer direct JS dispatch — WebSocket RPC pushes can be deferred by + // WKWebView until the next interaction during native window transitions. + if (webview?.executeJavascript) { + webview.executeJavascript( + `window.__farmcontrolDispatchRpcMessage?.(${channelLiteral}, ${payloadLiteral})` + ) + return true + } + + const send = webview?.rpc?.send + if (!send) { + console.warn( + `No RPC sender available for channel: ${channel}. Is the window ready?` + ) + return false + } + + send[channel](data) + return true + } catch (error) { + console.warn(`Failed to send RPC message on channel: ${channel}`, error) + return false + } + }) +} + +export async function createMainWindow(rpc) { + const url = await getMainViewUrl() + + mainWindow = new BrowserWindow({ + title: 'Farm Control', + url, + rpc, + titleBarStyle: 'hiddenInset', + ...(isMacOS + ? { transparent: true, trafficLightOffset: MAC_TRAFFIC_LIGHT_OFFSET } + : {}), + frame: { + width: 1200, + height: 800, + x: 100, + y: 100 + } + }) + + if (isMacOS) { + applyMacOSWindowEffects(mainWindow) + } + + setupMainWindowMessaging(mainWindow) + + if (isMacOS) { + applyApplicationMenu() + setupApplicationMenuEvents({ + onNavigate: sendNavigateToRenderer, + onToggleDevTools: () => { + mainWindow?.webview?.toggleDevTools?.() + }, + onCheckForUpdates: () => { + sendToRenderer('checkForUpdates') + } + }) + } + + setupWindowEvents(mainWindow) + applyStartupWindowState(mainWindow) + + Electrobun.events.on('open-url', (event) => { + const url = event?.data?.url + if (url) { + handleDeepLink(url) + } + }) + + return new Promise((resolve) => { + mainWindow.webview.on('dom-ready', () => { + webviewDomReady = true + + if (isWindows) { + applyWindowsStartupWindowState(mainWindow) + } + + flushPendingNavigations() + resolve(mainWindow) + }) + }) +} + +export async function setupDevAuthServer() { + const env = (process.env.NODE_ENV || 'development').trim() + if (env !== 'development') return + + const express = (await import('express')).default + const app = express() + const port = 3500 + + app.use((req, res) => { + const redirectPath = req.originalUrl + res.send(`Open Farmcontrol to continue... (Redirect path: ${redirectPath})`) + sendNavigateToRenderer(redirectPath) + }) + + app.listen(port, () => {}) +} + +export function setupWindowsDeepLinkHandling() { + if (process.platform === 'darwin') { + return + } + + setSingleInstanceHandlers({ + onDeepLink: handleDeepLink, + onFocus: showMainWindow + }) +} + +export function getWindowState() { + if (!mainWindow) { + return { isFullScreen: false, isMaximized: false } + } + + return { + isFullScreen: mainWindow.isFullScreen?.() ?? false, + isMaximized: isWindows + ? isWindowWorkAreaMaximized(mainWindow) + : (mainWindow.isMaximized?.() ?? false) + } +} + +export function handleWindowControl(action) { + if (!mainWindow && action !== 'quit') return + + switch (action) { + case 'minimize': + mainWindow.minimize?.() + break + case 'maximize': { + const currentlyMaximized = isWindows + ? isWindowWorkAreaMaximized(mainWindow) + : (mainWindow.isMaximized?.() ?? false) + + if (currentlyMaximized) { + mainWindow.unmaximize?.() + } else { + mainWindow.maximize?.() + } + + if (isWindows) { + // Frame updates after maximize/unmaximize are async on Windows. + setTimeout(() => handleWindowsWindowChange(mainWindow), 100) + } + break + } + case 'fullscreen': + if (mainWindow.isFullScreen?.()) { + mainWindow.setFullScreen?.(false) + } else { + mainWindow.setFullScreen?.(true) + } + setTimeout(broadcastWindowState, 100) + break + case 'close': + mainWindow.close?.() + break + case 'quit': + Utils.quit() + break + case 'toggle-devtools': + mainWindow?.webview?.toggleDevTools?.() + break + default: + break + } +} + +export function sendNavigationGesture(direction) { + sendToRenderer('navigationGesture', direction) +} + +export function setupNavigationGestures(window) { + if (!window) return + + if (process.platform === 'darwin') { + window.on?.('swipe', (_event, direction) => { + if (direction === 'left') { + sendNavigationGesture('back') + } else if (direction === 'right') { + sendNavigationGesture('forward') + } + }) + } + + window.on?.('app-command', (_event, command) => { + if (command === 'browser-backward') { + sendNavigationGesture('back') + } else if (command === 'browser-forward') { + sendNavigationGesture('forward') + } + }) +} + +export function openExternalUrl(url) { + console.log('openExternalUrl', url) + Utils.openExternal(url) +} diff --git a/src/desktop/windows-app-paths.js b/src/desktop/windows-app-paths.js new file mode 100644 index 0000000..1d93ba5 --- /dev/null +++ b/src/desktop/windows-app-paths.js @@ -0,0 +1,45 @@ +import { existsSync } from 'node:fs' +import { dirname, join } from 'node:path' + +const NATIVE_WRAPPER_DLL = 'libNativeWrapper.dll' +export const WINDOWS_LAUNCHER_EXE = 'FarmControl.exe' +const LEGACY_LAUNCHER_EXE = 'launcher.exe' + +export function resolveWindowsBinDir() { + const candidates = [ + dirname(process.execPath), + process.cwd(), + join(dirname(process.execPath), 'bin'), + join(process.cwd(), 'bin') + ] + + for (const candidate of candidates) { + if ( + existsSync(join(candidate, WINDOWS_LAUNCHER_EXE)) || + existsSync(join(candidate, LEGACY_LAUNCHER_EXE)) || + existsSync(join(candidate, NATIVE_WRAPPER_DLL)) + ) { + return candidate + } + } + + return dirname(process.execPath) +} + +export function ensureWindowsWorkingDirectory() { + if (process.platform !== 'win32') { + return + } + + const binDir = resolveWindowsBinDir() + const wrapperInCwd = existsSync(join(process.cwd(), NATIVE_WRAPPER_DLL)) + const wrapperInBinDir = existsSync(join(binDir, NATIVE_WRAPPER_DLL)) + + if (!wrapperInCwd && wrapperInBinDir) { + try { + process.chdir(binDir) + } catch { + // Ignore if we cannot change directory. + } + } +} diff --git a/src/desktop/windows-work-area.js b/src/desktop/windows-work-area.js new file mode 100644 index 0000000..2714315 --- /dev/null +++ b/src/desktop/windows-work-area.js @@ -0,0 +1,123 @@ +import { Screen } from 'electrobun/bun' + +const FRAME_TOLERANCE_PX = 4 +// Win32 DWM invisible borders sit outside the client work area; Electrobun's +// maximized frame includes those overhangs, so we treat this adjusted rect as +// the canonical "maximized to work area" geometry. +const WIN32_FRAME_OVERHANG_NATIVE = { + x: -8, + y: 0, + width: 16, + height: 8 +} +const WIN32_FRAME_OVERHANG_CEF = { + x: -12, + y: 0, + width: 24, + height: 12 +} + +function getWin32FrameOverhang(window) { + return window?.renderer === 'cef' + ? WIN32_FRAME_OVERHANG_CEF + : WIN32_FRAME_OVERHANG_NATIVE +} + +function framesMatch(a, b, tolerance = FRAME_TOLERANCE_PX) { + return ( + Math.abs(a.x - b.x) <= tolerance && + Math.abs(a.y - b.y) <= tolerance && + Math.abs(a.width - b.width) <= tolerance && + Math.abs(a.height - b.height) <= tolerance + ) +} + +function getMaximizedWorkAreaFrame(workArea, window) { + const overhang = getWin32FrameOverhang(window) + return { + x: workArea.x + overhang.x, + y: workArea.y + overhang.y, + width: workArea.width + overhang.width, + height: workArea.height + overhang.height + } +} + +function getFrameCenter(frame) { + return { + x: frame.x + frame.width / 2, + y: frame.y + frame.height / 2 + } +} + +function getDisplayForFrame(frame) { + const { x, y } = getFrameCenter(frame) + const displays = Screen.getAllDisplays() + + const match = displays.find(({ bounds }) => { + return ( + x >= bounds.x && + x < bounds.x + bounds.width && + y >= bounds.y && + y < bounds.y + bounds.height + ) + }) + + return match ?? Screen.getPrimaryDisplay() +} + +function frameCoversMonitor(frame, bounds) { + return ( + frame.x <= bounds.x + FRAME_TOLERANCE_PX && + frame.y <= bounds.y + FRAME_TOLERANCE_PX && + frame.x + frame.width >= bounds.x + bounds.width - FRAME_TOLERANCE_PX && + frame.y + frame.height >= bounds.y + bounds.height - FRAME_TOLERANCE_PX + ) +} + +export function isWindowWorkAreaMaximized(window) { + if (!window?.getFrame) { + return false + } + + const frame = window.getFrame() + const { workArea } = getDisplayForFrame(frame) + return ( + framesMatch(frame, workArea) || + framesMatch(frame, getMaximizedWorkAreaFrame(workArea, window)) + ) +} + +export function clampWindowToWorkArea(window) { + if (!window?.getFrame || !window?.setFrame) { + return false + } + + if (window.isFullScreen?.()) { + return false + } + + const frame = window.getFrame() + if (!frame.width || !frame.height) { + return false + } + + const display = getDisplayForFrame(frame) + const { bounds, workArea } = display + const maximizedFrame = getMaximizedWorkAreaFrame(workArea, window) + + if (framesMatch(frame, workArea) || framesMatch(frame, maximizedFrame)) { + return false + } + + if (!frameCoversMonitor(frame, bounds)) { + return false + } + + window.setFrame( + maximizedFrame.x, + maximizedFrame.y, + maximizedFrame.width, + maximizedFrame.height + ) + return true +} diff --git a/src/electrobun-bridge.js b/src/electrobun-bridge.js new file mode 100644 index 0000000..2c9f621 --- /dev/null +++ b/src/electrobun-bridge.js @@ -0,0 +1,259 @@ +const listeners = new Map() +const pendingMessages = new Map() +const pendingRequests = new Map() +const RPC_REQUEST_TIMEOUT_MS = 30000 +const RPC_RESPONSE_CHANNEL = 'rpcResponse' +let rpc = null +let initPromise = null +let initialized = false +let nextRequestId = 0 + +export function isElectrobunDesktop() { + return Boolean( + typeof window !== 'undefined' && + window.__electrobunWebviewId && + window.__electrobunRpcSocketPort + ) +} + +export function isElectrobunBridgeReady() { + return initialized && Boolean(rpc?.request) +} + +function dispatchMessage(channel, data) { + if (channel === RPC_RESPONSE_CHANNEL) { + const pendingRequest = pendingRequests.get(data?.id) + if (!pendingRequest) return + + pendingRequests.delete(data.id) + clearTimeout(pendingRequest.timeout) + + if (data.success) { + pendingRequest.resolve(data.result) + } else { + pendingRequest.reject( + new Error(data.error || 'Desktop RPC request failed.') + ) + } + return + } + + const channelListeners = listeners.get(channel) + if (!channelListeners?.size) { + if (!pendingMessages.has(channel)) { + pendingMessages.set(channel, []) + } + pendingMessages.get(channel).push(data) + return + } + + for (const callback of channelListeners) { + callback(data) + } +} + +// Bun delivers push messages via executeJavascript for immediate handling. +// WebSocket RPC messages can be deferred by WKWebView during native window +// transitions (e.g. fullscreen) until the next user interaction. +if (typeof window !== 'undefined') { + window.__farmcontrolDispatchRpcMessage = dispatchMessage +} + +async function setupRpc() { + // electrobun/view captures webview globals at import time — import only after + // Electrobun preload has set them (Vite dev can evaluate modules earlier). + const { default: Electrobun, Electroview } = await import('electrobun/view') + + rpc = Electroview.defineRPC({ + maxRequestTime: 30000, + handlers: { + requests: {}, + messages: { + '*': (channel, data) => { + dispatchMessage(channel, data) + } + } + } + }) + + new Electrobun.Electroview({ rpc }) +} + +function shouldWaitForElectrobun() { + if (isElectrobunDesktop()) { + return true + } + + if (typeof window === 'undefined') { + return false + } + + if (window.__electrobunWebviewId) { + return true + } + + const { protocol, hostname, port } = window.location + + if (protocol === 'views:') { + return true + } + + // Vite dev server used by electrobun dev:app + if (hostname === 'localhost' && port === '5780') { + return true + } + + return Boolean( + window.__electrobun || + window.__electrobunEventBridge || + window.__electrobunInternalBridge + ) +} + +export async function initElectrobunBridge() { + if (initialized) { + return + } + + if (!initPromise) { + initPromise = (async () => { + if (!shouldWaitForElectrobun()) { + return + } + + const deadline = Date.now() + 3000 + + while (Date.now() < deadline) { + if (isElectrobunDesktop()) { + await setupRpc() + window.electronAPI = electronAPI + initialized = true + return + } + + await new Promise((resolve) => setTimeout(resolve, 50)) + } + + console.warn( + 'Electrobun bridge: webview globals not found; desktop RPC unavailable.' + ) + })() + } + + await initPromise +} + +function onMessage(channel, callback) { + void initElectrobunBridge() + + if (!listeners.has(channel)) { + listeners.set(channel, new Set()) + } + listeners.get(channel).add(callback) + + const queued = pendingMessages.get(channel) + if (queued?.length) { + pendingMessages.delete(channel) + for (const payload of queued) { + callback(payload) + } + } + + return () => { + listeners.get(channel)?.delete(callback) + } +} + +function removeAllListeners(channel) { + listeners.delete(channel) + pendingMessages.delete(channel) +} + +function invokeNativeRequest(method, params) { + const nativeBridge = window.__electrobunBunBridge + if (!nativeBridge?.postMessage) { + return null + } + + const id = `${Date.now()}-${++nextRequestId}` + + return new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + pendingRequests.delete(id) + reject(new Error(`Desktop RPC request timed out: ${method}`)) + }, RPC_REQUEST_TIMEOUT_MS) + + pendingRequests.set(id, { resolve, reject, timeout }) + + try { + nativeBridge.postMessage( + JSON.stringify({ + type: 'message', + id: 'rendererRequest', + payload: { id, method, params } + }) + ) + } catch (error) { + clearTimeout(timeout) + pendingRequests.delete(id) + reject(error) + } + }) +} + +async function invokeRequest(method, params = {}) { + await initElectrobunBridge() + + if (!rpc?.request) { + console.warn(`Electrobun RPC unavailable for request: ${method}`) + return null + } + + try { + const nativeRequest = invokeNativeRequest(method, params) + if (nativeRequest) { + return await nativeRequest + } + + return await rpc.request[method](params) + } catch (error) { + console.warn(`Electrobun RPC request failed: ${method}`, error) + return null + } +} + +const electronAPI = { + get isDesktop() { + return isElectrobunDesktop() + }, + onMessage, + removeAllListeners, + getOsInfo: () => invokeRequest('getOsInfo'), + getWindowState: () => invokeRequest('getWindowState'), + windowControl: (action) => invokeRequest('windowControl', { action }), + openExternalUrl: (url) => invokeRequest('openExternalUrl', { url }), + openInternalUrl: (url) => invokeRequest('openInternalUrl', { url }), + getAuthSession: () => invokeRequest('getAuthSession'), + setAuthSession: (session) => invokeRequest('setAuthSession', { session }), + clearAuthSession: () => invokeRequest('clearAuthSession'), + getAppSettings: () => invokeRequest('getAppSettings'), + setAppSettings: (settings) => invokeRequest('setAppSettings', { settings }), + startAppUpdate: (update) => invokeRequest('startAppUpdate', { update }), + checkAppUpdateResult: () => invokeRequest('checkAppUpdateResult'), + checkDuplicateInstallations: () => + invokeRequest('checkDuplicateInstallations'), + removeDuplicateInstallations: () => + invokeRequest('removeDuplicateInstallations'), + resizeSpotlightWindow: (height) => + invokeRequest('resizeSpotlightWindow', { height }), + setSidebarViewMenu: (sections) => + invokeRequest('setSidebarViewMenu', { sections }), + getAppVersion: () => invokeRequest('getAppVersion'), + getAppEngine: () => invokeRequest('getAppEngine') +} + +if (typeof window !== 'undefined') { + window.electronAPI = electronAPI +} + +export default electronAPI diff --git a/src/index.jsx b/src/index.jsx index d3179cc..c901182 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,8 +1,11 @@ +import { initElectrobunBridge } from './electrobun-bridge.js' import reportWebVitals from './reportWebVitals' import ReactDOM from 'react-dom/client' import FarmControlApp from './App' import React from 'react' +await initElectrobunBridge() + const root = ReactDOM.createRoot(document.getElementById('root')) root.render( diff --git a/vite.config.js b/vite.config.js index 58c5eb5..ff138e7 100644 --- a/vite.config.js +++ b/vite.config.js @@ -1,12 +1,15 @@ +import { createRequire } from 'node:module' import react from '@vitejs/plugin-react' import { defineConfig } from 'vite' import eslintPlugin from 'vite-plugin-eslint' import svgr from 'vite-plugin-svgr' -import svgo from 'vite-plugin-svgo' import path from 'path' import { fileURLToPath } from 'url' import { visualizer } from 'rollup-plugin-visualizer' +const require = createRequire(import.meta.url) +const svgo = require('vite-plugin-svgo') + const __filename = fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename)