From a13f7cc8e2235a973e988b47dbcbf1da48c11208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 14:18:54 +0100 Subject: [PATCH 01/23] Convert nseventforwarder package to ESM --- desktop/packages/nseventforwarder/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop/packages/nseventforwarder/package.json b/desktop/packages/nseventforwarder/package.json index bc99c152c3eb..319ac7d086e7 100644 --- a/desktop/packages/nseventforwarder/package.json +++ b/desktop/packages/nseventforwarder/package.json @@ -4,7 +4,9 @@ "author": "Mullvad VPN", "license": "GPL-3.0", "description": "", + "type": "module", "main": "./lib/index.cjs", + "module": "./lib/index.mjs", "scripts": { "cargo-build": "npm run build-typescript && cargo build", "build-typescript": "tsc", From 8fe7c92c4d0b762f68b50583be7e0cc600fa8eb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 14:18:33 +0100 Subject: [PATCH 02/23] Convert windows-utils package to ESM --- desktop/packages/windows-utils/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop/packages/windows-utils/package.json b/desktop/packages/windows-utils/package.json index e61266b999bf..06bfb1515c70 100644 --- a/desktop/packages/windows-utils/package.json +++ b/desktop/packages/windows-utils/package.json @@ -4,7 +4,9 @@ "author": "Mullvad VPN", "license": "GPL-3.0", "description": "", + "type": "module", "main": "./lib/index.cjs", + "module": "./lib/index.mjs", "scripts": { "cargo-build": "npm run build-typescript && cargo build", "build-debug": "npm run cargo-build && (test -d debug || mkdir debug) && cp ../../../target/debug/windows_utils.dll debug/index.node", From 03d75e9d7a34402a9b6a17081f0dd94de2d01eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 12:59:05 +0100 Subject: [PATCH 03/23] Convert mullvad-vpn package to ESM --- desktop/packages/mullvad-vpn/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/desktop/packages/mullvad-vpn/package.json b/desktop/packages/mullvad-vpn/package.json index 8b9041214d61..1d7668246bb9 100644 --- a/desktop/packages/mullvad-vpn/package.json +++ b/desktop/packages/mullvad-vpn/package.json @@ -9,6 +9,7 @@ "name": "Mullvad VPN", "email": "support@mullvadvpn.net" }, + "type": "module", "repository": "https://github.com/mullvad/mullvadvpn-app", "license": "GPL-3.0", "dependencies": { From a19ad3167e95a0e93c73e023bad048b72f614c68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 13:03:09 +0100 Subject: [PATCH 04/23] Ensure preload file is output with correct file extension After migrating the project to ESM the .mjs extension is used for the built preload file, however we want to retain the .js extension. --- desktop/packages/mullvad-vpn/vite.config.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/desktop/packages/mullvad-vpn/vite.config.ts b/desktop/packages/mullvad-vpn/vite.config.ts index 8085e82cbbd2..6cf57ae111a5 100644 --- a/desktop/packages/mullvad-vpn/vite.config.ts +++ b/desktop/packages/mullvad-vpn/vite.config.ts @@ -112,6 +112,13 @@ const viteConfig = defineConfig({ vite: { build: { outDir: OUT_DIR, + rollupOptions: { + output: { + // We have to specify preload.js here as otherwise it would + // use the '.mjs' file extension. + entryFileNames: 'preload.js', + }, + }, }, }, }, From 0a6be85ef882be3cdc3a02949a8328362261bf5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 13:01:50 +0100 Subject: [PATCH 05/23] Replace __dirname with import.meta.dirname --- desktop/packages/mullvad-vpn/src/main/changelog.ts | 2 +- desktop/packages/mullvad-vpn/src/main/index.ts | 4 ++-- desktop/packages/mullvad-vpn/src/main/load-translations.ts | 2 +- .../packages/mullvad-vpn/src/main/notification-controller.ts | 2 +- desktop/packages/mullvad-vpn/src/main/proc.ts | 3 ++- desktop/packages/mullvad-vpn/src/main/tray-icon.ts | 2 +- desktop/packages/mullvad-vpn/src/main/user-interface.ts | 4 ++-- desktop/packages/mullvad-vpn/test/e2e/setup/main.ts | 4 ++-- 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/desktop/packages/mullvad-vpn/src/main/changelog.ts b/desktop/packages/mullvad-vpn/src/main/changelog.ts index 3b72fc17e33c..2ff756ddbec1 100644 --- a/desktop/packages/mullvad-vpn/src/main/changelog.ts +++ b/desktop/packages/mullvad-vpn/src/main/changelog.ts @@ -7,7 +7,7 @@ import log from '../shared/logging'; // Reads and parses the changelog file. export function readChangelog(): IChangelog { try { - const changelogPath = path.join(__dirname, '..', 'changes.txt'); + const changelogPath = path.join(import.meta.dirname, '..', 'changes.txt'); const contents = fs.readFileSync(changelogPath).toString(); return parseChangelog(contents); } catch (e) { diff --git a/desktop/packages/mullvad-vpn/src/main/index.ts b/desktop/packages/mullvad-vpn/src/main/index.ts index c7106f75e755..d9466a84744f 100644 --- a/desktop/packages/mullvad-vpn/src/main/index.ts +++ b/desktop/packages/mullvad-vpn/src/main/index.ts @@ -79,7 +79,7 @@ const ALLOWED_PERMISSIONS = ['clipboard-sanitized-write']; const SANDBOX_DISABLED = app.commandLine.hasSwitch('no-sandbox'); const UPDATE_NOTIFICATION_DISABLED = process.env.MULLVAD_DISABLE_UPDATE_NOTIFICATION === '1'; -const GEO_DIR = path.resolve(__dirname, 'assets/geo'); +const GEO_DIR = path.resolve(import.meta.dirname, 'assets/geo'); class ApplicationMain implements @@ -1018,7 +1018,7 @@ class ApplicationMain } private allowFileAccess(url: string): boolean { - const buildDir = path.normalize(path.join(path.resolve(__dirname), '..', '..')); + const buildDir = path.normalize(path.join(path.resolve(import.meta.dirname), '..', '..')); if (url.startsWith('file:')) { // Extract the path from the URL diff --git a/desktop/packages/mullvad-vpn/src/main/load-translations.ts b/desktop/packages/mullvad-vpn/src/main/load-translations.ts index 670e9a2a5b30..5736d23dfa0b 100644 --- a/desktop/packages/mullvad-vpn/src/main/load-translations.ts +++ b/desktop/packages/mullvad-vpn/src/main/load-translations.ts @@ -6,7 +6,7 @@ import path from 'path'; import log from '../shared/logging'; const SOURCE_LANGUAGE = 'en'; -const LOCALES_DIR = path.resolve(__dirname, 'locales'); +const LOCALES_DIR = path.resolve(import.meta.dirname, 'locales'); export function loadTranslations( currentLocale: string, diff --git a/desktop/packages/mullvad-vpn/src/main/notification-controller.ts b/desktop/packages/mullvad-vpn/src/main/notification-controller.ts index e8e58713598a..a65fe2b19798 100644 --- a/desktop/packages/mullvad-vpn/src/main/notification-controller.ts +++ b/desktop/packages/mullvad-vpn/src/main/notification-controller.ts @@ -76,7 +76,7 @@ export default class NotificationController { } if (usePngIcon) { - const imagePath = path.join(__dirname, 'assets/images/icon-notification.png'); + const imagePath = path.join(import.meta.dirname, 'assets/images/icon-notification.png'); // `nativeImage` is undefined when running tests this.notificationIcon = nativeImage?.createFromPath(imagePath); } diff --git a/desktop/packages/mullvad-vpn/src/main/proc.ts b/desktop/packages/mullvad-vpn/src/main/proc.ts index 1e8118268dce..328735edbc9a 100644 --- a/desktop/packages/mullvad-vpn/src/main/proc.ts +++ b/desktop/packages/mullvad-vpn/src/main/proc.ts @@ -7,7 +7,8 @@ export function resolveBin(binaryName: string) { function getBasePath(): string { if (process.env.NODE_ENV === 'development') { return ( - process.env.MULLVAD_PATH || path.resolve(path.join(__dirname, '../../../../target/debug')) + process.env.MULLVAD_PATH || + path.resolve(path.join(import.meta.dirname, '../../../../target/debug')) ); } else { return process.resourcesPath; diff --git a/desktop/packages/mullvad-vpn/src/main/tray-icon.ts b/desktop/packages/mullvad-vpn/src/main/tray-icon.ts index ba2ce42b4f17..a541041b5151 100644 --- a/desktop/packages/mullvad-vpn/src/main/tray-icon.ts +++ b/desktop/packages/mullvad-vpn/src/main/tray-icon.ts @@ -5,7 +5,7 @@ export class TrayIcon { constructor(public fileName?: string) {} public get basePath() { - const basePath = path.resolve(__dirname, 'assets/images/menubar-icons'); + const basePath = path.resolve(import.meta.dirname, 'assets/images/menubar-icons'); return basePath; } diff --git a/desktop/packages/mullvad-vpn/src/main/user-interface.ts b/desktop/packages/mullvad-vpn/src/main/user-interface.ts index f0ff1e816a40..7a32e81b367f 100644 --- a/desktop/packages/mullvad-vpn/src/main/user-interface.ts +++ b/desktop/packages/mullvad-vpn/src/main/user-interface.ts @@ -199,7 +199,7 @@ export default class UserInterface implements WindowControllerDelegate { if (process.env.NODE_ENV === 'development' && process.env.VITE_DEV_SERVER_URL) { await window.loadURL(process.env.VITE_DEV_SERVER_URL); } else { - await window.loadFile(path.join(__dirname, 'index.html')); + await window.loadFile(path.join(import.meta.dirname, 'index.html')); } } catch (e) { const error = e as Error; @@ -285,7 +285,7 @@ export default class UserInterface implements WindowControllerDelegate { show: false, frame: unpinnedWindow, webPreferences: { - preload: path.join(__dirname, 'preload.js'), + preload: path.join(import.meta.dirname, 'preload.js'), nodeIntegration: false, nodeIntegrationInWorker: false, nodeIntegrationInSubFrames: false, diff --git a/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts b/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts index 43572c11fb11..0ea3b4959f2e 100644 --- a/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts +++ b/desktop/packages/mullvad-vpn/test/e2e/setup/main.ts @@ -94,7 +94,7 @@ class ApplicationMain { frame: true, webPreferences: { offscreen: CI_E2E && !TEST_SHOW_WINDOW, - preload: path.join(__dirname, 'preload.js'), + preload: path.join(import.meta.dirname, 'preload.js'), nodeIntegration: false, nodeIntegrationInWorker: false, nodeIntegrationInSubFrames: false, @@ -109,7 +109,7 @@ class ApplicationMain { this.registerIpcListeners(); - await window.loadFile(path.join(__dirname, 'index.html')); + await window.loadFile(path.join(import.meta.dirname, 'index.html')); if (process.argv.includes('--show-window')) { window.show(); From 4aafb50c401803fa4ae4c4de6807b8cf3e6a21b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Wed, 10 Sep 2025 16:37:08 +0200 Subject: [PATCH 06/23] Change TS moduleResolution to bundler and update TS output to es2022 When the @vitejs/plugin-react package was updated it was no longer compatible with the TS config's `moduleResolution` setting, as such the TS config had to be updated. `moduleResolution` has to changed to `bundler`, and because of that we can no longer target `commonjs` as the output format. As such we also had to bump the `module` config option to `es2022`. With these changes in mind it made sense to also bump the TS target to `es2022` from `es2021`. The emitted code built by typescript is now a lot more modern than in previous builds. --- desktop/packages/mullvad-vpn/tsconfig.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/desktop/packages/mullvad-vpn/tsconfig.json b/desktop/packages/mullvad-vpn/tsconfig.json index fbd82c8b4c9c..63ac9d39fa51 100644 --- a/desktop/packages/mullvad-vpn/tsconfig.json +++ b/desktop/packages/mullvad-vpn/tsconfig.json @@ -1,18 +1,19 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "moduleResolution": "bundler", "esModuleInterop": true, "jsx": "react-jsx", - "module": "commonjs", + "module": "es2022", "outDir": "build", "rootDirs": [ "src", "assets" ], "skipLibCheck": true, - "target": "es2021", + "target": "es2022", "lib": [ - "es2021", + "es2022", "dom" ], "typeRoots": [ From f100dab45bd43f2b3c3eada9d54c2bdbcb760f2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 12:56:01 +0100 Subject: [PATCH 07/23] Rename CJS files to use .cjs extensions --- .../scripts/{extract-translations.js => extract-translations.cjs} | 0 .../tasks/{build-production.js => build-production.cjs} | 0 .../tasks/{build-standalone.js => build-standalone.cjs} | 0 .../packages/mullvad-vpn/tasks/{build-test.js => build-test.cjs} | 0 desktop/packages/mullvad-vpn/tasks/{build.js => build.cjs} | 0 .../packages/mullvad-vpn/tasks/{constants.js => constants.cjs} | 0 .../mullvad-vpn/tasks/{distribution.js => distribution.cjs} | 0 .../packages/mullvad-vpn/tasks/{pack-linux.js => pack-linux.cjs} | 0 desktop/packages/mullvad-vpn/tasks/{pack-mac.js => pack-mac.cjs} | 0 .../mullvad-vpn/tasks/{pack-windows.js => pack-windows.cjs} | 0 .../mullvad-vpn/tasks/{pre-develop.js => pre-develop.cjs} | 0 desktop/packages/mullvad-vpn/tasks/{utils.js => utils.cjs} | 0 12 files changed, 0 insertions(+), 0 deletions(-) rename desktop/packages/mullvad-vpn/scripts/{extract-translations.js => extract-translations.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{build-production.js => build-production.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{build-standalone.js => build-standalone.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{build-test.js => build-test.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{build.js => build.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{constants.js => constants.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{distribution.js => distribution.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{pack-linux.js => pack-linux.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{pack-mac.js => pack-mac.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{pack-windows.js => pack-windows.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{pre-develop.js => pre-develop.cjs} (100%) rename desktop/packages/mullvad-vpn/tasks/{utils.js => utils.cjs} (100%) diff --git a/desktop/packages/mullvad-vpn/scripts/extract-translations.js b/desktop/packages/mullvad-vpn/scripts/extract-translations.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/scripts/extract-translations.js rename to desktop/packages/mullvad-vpn/scripts/extract-translations.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/build-production.js b/desktop/packages/mullvad-vpn/tasks/build-production.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/build-production.js rename to desktop/packages/mullvad-vpn/tasks/build-production.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/build-standalone.js b/desktop/packages/mullvad-vpn/tasks/build-standalone.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/build-standalone.js rename to desktop/packages/mullvad-vpn/tasks/build-standalone.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/build-test.js b/desktop/packages/mullvad-vpn/tasks/build-test.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/build-test.js rename to desktop/packages/mullvad-vpn/tasks/build-test.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/build.js b/desktop/packages/mullvad-vpn/tasks/build.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/build.js rename to desktop/packages/mullvad-vpn/tasks/build.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/constants.js b/desktop/packages/mullvad-vpn/tasks/constants.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/constants.js rename to desktop/packages/mullvad-vpn/tasks/constants.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/distribution.js b/desktop/packages/mullvad-vpn/tasks/distribution.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/distribution.js rename to desktop/packages/mullvad-vpn/tasks/distribution.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/pack-linux.js b/desktop/packages/mullvad-vpn/tasks/pack-linux.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/pack-linux.js rename to desktop/packages/mullvad-vpn/tasks/pack-linux.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/pack-mac.js b/desktop/packages/mullvad-vpn/tasks/pack-mac.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/pack-mac.js rename to desktop/packages/mullvad-vpn/tasks/pack-mac.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/pack-windows.js b/desktop/packages/mullvad-vpn/tasks/pack-windows.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/pack-windows.js rename to desktop/packages/mullvad-vpn/tasks/pack-windows.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/pre-develop.js b/desktop/packages/mullvad-vpn/tasks/pre-develop.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/pre-develop.js rename to desktop/packages/mullvad-vpn/tasks/pre-develop.cjs diff --git a/desktop/packages/mullvad-vpn/tasks/utils.js b/desktop/packages/mullvad-vpn/tasks/utils.cjs similarity index 100% rename from desktop/packages/mullvad-vpn/tasks/utils.js rename to desktop/packages/mullvad-vpn/tasks/utils.cjs From eacdbfbb70152b857ac1124d16389f22b63c17c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 13:05:26 +0100 Subject: [PATCH 08/23] Use file extension in imports in CJS files --- desktop/packages/mullvad-vpn/tasks/build-production.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/build-standalone.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/build-test.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/build.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/pack-linux.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/pack-mac.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/pack-windows.cjs | 4 ++-- desktop/packages/mullvad-vpn/tasks/pre-develop.cjs | 2 +- desktop/packages/mullvad-vpn/tasks/utils.cjs | 2 +- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/desktop/packages/mullvad-vpn/tasks/build-production.cjs b/desktop/packages/mullvad-vpn/tasks/build-production.cjs index 09b141d2c571..6f61abcf6ec2 100644 --- a/desktop/packages/mullvad-vpn/tasks/build-production.cjs +++ b/desktop/packages/mullvad-vpn/tasks/build-production.cjs @@ -1,5 +1,5 @@ -const { build } = require('./build'); -const { setNodeEnvironment } = require('./utils'); +const { build } = require('./build.cjs'); +const { setNodeEnvironment } = require('./utils.cjs'); async function buildProduction() { setNodeEnvironment('production'); diff --git a/desktop/packages/mullvad-vpn/tasks/build-standalone.cjs b/desktop/packages/mullvad-vpn/tasks/build-standalone.cjs index 37c6c3cd8166..8905472b1189 100644 --- a/desktop/packages/mullvad-vpn/tasks/build-standalone.cjs +++ b/desktop/packages/mullvad-vpn/tasks/build-standalone.cjs @@ -1,5 +1,5 @@ -const { BUILD_STANDALONE_DIR } = require('./constants'); -const { removeRecursively, runCommand, setNodeEnvironment } = require('./utils'); +const { BUILD_STANDALONE_DIR } = require('./constants.cjs'); +const { removeRecursively, runCommand, setNodeEnvironment } = require('./utils.cjs'); async function transpileBuildStandalone() { await runCommand('npx tsc -p tsconfig.standalone.json'); diff --git a/desktop/packages/mullvad-vpn/tasks/build-test.cjs b/desktop/packages/mullvad-vpn/tasks/build-test.cjs index c09ff10f92b1..11c595dceb8a 100644 --- a/desktop/packages/mullvad-vpn/tasks/build-test.cjs +++ b/desktop/packages/mullvad-vpn/tasks/build-test.cjs @@ -1,5 +1,5 @@ -const { build } = require('./build.js'); -const { setNodeEnvironment } = require('./utils.js'); +const { build } = require('./build.cjs'); +const { setNodeEnvironment } = require('./utils.cjs'); async function buildTest() { setNodeEnvironment('test'); diff --git a/desktop/packages/mullvad-vpn/tasks/build.cjs b/desktop/packages/mullvad-vpn/tasks/build.cjs index 5ce22e966456..e2623e9d04a0 100644 --- a/desktop/packages/mullvad-vpn/tasks/build.cjs +++ b/desktop/packages/mullvad-vpn/tasks/build.cjs @@ -1,5 +1,5 @@ -const { copyAssetsToBuildDirectory, removeRecursively, runNpmScript } = require('./utils'); -const { BUILD_DIR } = require('./constants'); +const { copyAssetsToBuildDirectory, removeRecursively, runNpmScript } = require('./utils.cjs'); +const { BUILD_DIR } = require('./constants.cjs'); async function build() { await removeRecursively(BUILD_DIR); diff --git a/desktop/packages/mullvad-vpn/tasks/pack-linux.cjs b/desktop/packages/mullvad-vpn/tasks/pack-linux.cjs index 80ef9ad206b2..0a9474d5e480 100644 --- a/desktop/packages/mullvad-vpn/tasks/pack-linux.cjs +++ b/desktop/packages/mullvad-vpn/tasks/pack-linux.cjs @@ -1,5 +1,5 @@ -const { build } = require('./build'); -const { packLinux } = require('./distribution'); +const { build } = require('./build.cjs'); +const { packLinux } = require('./distribution.cjs'); async function buildAndPackage() { await build(); diff --git a/desktop/packages/mullvad-vpn/tasks/pack-mac.cjs b/desktop/packages/mullvad-vpn/tasks/pack-mac.cjs index 49fa03dd50a2..e30c2aeba111 100644 --- a/desktop/packages/mullvad-vpn/tasks/pack-mac.cjs +++ b/desktop/packages/mullvad-vpn/tasks/pack-mac.cjs @@ -1,5 +1,5 @@ -const { build } = require('./build'); -const { packMac } = require('./distribution'); +const { build } = require('./build.cjs'); +const { packMac } = require('./distribution.cjs'); async function buildAndPackage() { await build(); diff --git a/desktop/packages/mullvad-vpn/tasks/pack-windows.cjs b/desktop/packages/mullvad-vpn/tasks/pack-windows.cjs index cc830cb7127c..7181184506ee 100644 --- a/desktop/packages/mullvad-vpn/tasks/pack-windows.cjs +++ b/desktop/packages/mullvad-vpn/tasks/pack-windows.cjs @@ -1,5 +1,5 @@ -const { build } = require('./build'); -const { packWin } = require('./distribution'); +const { build } = require('./build.cjs'); +const { packWin } = require('./distribution.cjs'); async function buildAndPackage() { await build(); diff --git a/desktop/packages/mullvad-vpn/tasks/pre-develop.cjs b/desktop/packages/mullvad-vpn/tasks/pre-develop.cjs index f0502add3350..9c1942bc5bc9 100644 --- a/desktop/packages/mullvad-vpn/tasks/pre-develop.cjs +++ b/desktop/packages/mullvad-vpn/tasks/pre-develop.cjs @@ -1,4 +1,4 @@ -const { copyAssetsToBuildDirectory, setNodeEnvironment } = require('./utils.js'); +const { copyAssetsToBuildDirectory, setNodeEnvironment } = require('./utils.cjs'); async function preDevelop() { setNodeEnvironment('development'); diff --git a/desktop/packages/mullvad-vpn/tasks/utils.cjs b/desktop/packages/mullvad-vpn/tasks/utils.cjs index ac18bc998062..fe8214d02851 100644 --- a/desktop/packages/mullvad-vpn/tasks/utils.cjs +++ b/desktop/packages/mullvad-vpn/tasks/utils.cjs @@ -1,7 +1,7 @@ const childProcess = require('child_process'); const fs = require('fs/promises'); const path = require('path'); -const { BUILD_DIR, GEO_DIR, LOCALES_DIR, IMAGES_DIR, ICONS_DIR } = require('./constants'); +const { BUILD_DIR, GEO_DIR, LOCALES_DIR, IMAGES_DIR, ICONS_DIR } = require('./constants.cjs'); async function copyAssetsToBuildDirectory() { await Promise.all([ From 26341828e717f62d82d18ef0e69ee9e5ca43bb85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 12:56:35 +0100 Subject: [PATCH 09/23] Update package.json to use .cjs for tasks' file extension --- desktop/packages/mullvad-vpn/package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/desktop/packages/mullvad-vpn/package.json b/desktop/packages/mullvad-vpn/package.json index 1d7668246bb9..bd7804f2e8a1 100644 --- a/desktop/packages/mullvad-vpn/package.json +++ b/desktop/packages/mullvad-vpn/package.json @@ -70,10 +70,10 @@ }, "scripts": { "preinstall": "test -d node_modules || mkdir node_modules", - "build": "node tasks/build-production.js", + "build": "node tasks/build-production.cjs", "build:vite": "vite build", - "build:test": "node tasks/build-test.js", - "build:standalone": "node tasks/build-standalone.js", + "build:test": "node tasks/build-test.cjs", + "build:standalone": "node tasks/build-standalone.cjs", "pack-test-executable": "./scripts/build-test-executable.sh", "build-test-executable": "npm run pack-test-executable", "lint": "eslint . --max-warnings 0", @@ -84,14 +84,14 @@ "e2e:sequential:no-build": "xvfb-maybe -- playwright test -c test/e2e/installed/playwright.config.ts --workers 1", "e2e:update-snapshots": "npm run e2e:no-build -- --update-snapshots", "develop": "npm run develop:pre && npm run develop:vite", - "develop:pre": "node tasks/pre-develop.js", + "develop:pre": "node tasks/pre-develop.cjs", "develop:vite": "vite", "test": "cross-env NODE_ENV=test vitest test/unit", "type-check": "tsc --noEmit", - "update-translations": "node scripts/extract-translations", - "pack:mac": "node tasks/pack-mac.js", - "pack:win": "node tasks/pack-windows.js", - "pack:linux": "node tasks/pack-linux.js" + "update-translations": "node scripts/extract-translations.cjs", + "pack:mac": "node tasks/pack-mac.cjs", + "pack:win": "node tasks/pack-windows.cjs", + "pack:linux": "node tasks/pack-linux.cjs" }, "volta": { "extends": "../../package.json" From 4d2a15ddd27ceca3a1be705135d64f7685b01e4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 14:00:05 +0100 Subject: [PATCH 10/23] Include .cjs files in linting --- desktop/eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/eslint.config.mjs b/desktop/eslint.config.mjs index 956904baf9ce..2b6f2ce28a9f 100644 --- a/desktop/eslint.config.mjs +++ b/desktop/eslint.config.mjs @@ -97,7 +97,7 @@ export default tseslint.config( }, }, { - files: ['**/*.{js,mjs,ts,tsx}'], + files: ['**/*.{js,cjs,mjs,ts,tsx}'], plugins: { 'simple-import-sort': simpleImportSort, }, From 0216dd8184cdce1515ae13ed3da38313618fdd63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 12:58:22 +0100 Subject: [PATCH 11/23] Update redux to 5.0.1 --- desktop/packages/mullvad-vpn/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/packages/mullvad-vpn/package.json b/desktop/packages/mullvad-vpn/package.json index bd7804f2e8a1..73ced264c5d8 100644 --- a/desktop/packages/mullvad-vpn/package.json +++ b/desktop/packages/mullvad-vpn/package.json @@ -26,7 +26,7 @@ "react-dom": "^19.1.1", "react-redux": "^9.2.0", "react-router": "^5.3.4", - "redux": "^4.2.0", + "redux": "^5.0.1", "simple-plist": "^1.3.1", "sprintf-js": "^1.1.2", "styled-components": "^6.1.19", From a94c2eb5c6bf00f1f7210d2392920725d3a5015a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Wed, 10 Sep 2025 16:35:52 +0200 Subject: [PATCH 12/23] Update @vitejs/plugin-react to 5.0.2 --- desktop/packages/mullvad-vpn/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/packages/mullvad-vpn/package.json b/desktop/packages/mullvad-vpn/package.json index 73ced264c5d8..8bbf960d570e 100644 --- a/desktop/packages/mullvad-vpn/package.json +++ b/desktop/packages/mullvad-vpn/package.json @@ -43,7 +43,7 @@ "@types/react-router": "^5.1.19", "@types/sprintf-js": "^1.1.2", "@types/topojson-specification": "^1.0.2", - "@vitejs/plugin-react": "^4.7.0", + "@vitejs/plugin-react": "^5.0.2", "cross-env": "^7.0.3", "electron": "39.2.6", "electron-builder": "26.6.0", From 88068bee6baef8ed679deb1a46c9d1f5ef5cd5b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 15:25:57 +0100 Subject: [PATCH 13/23] Add react/react-dom to be deduped This was previously done by the @vitejs/plugin-react package but must now be done manually. --- desktop/packages/mullvad-vpn/vite.config.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/desktop/packages/mullvad-vpn/vite.config.ts b/desktop/packages/mullvad-vpn/vite.config.ts index 6cf57ae111a5..c31adaf937c3 100644 --- a/desktop/packages/mullvad-vpn/vite.config.ts +++ b/desktop/packages/mullvad-vpn/vite.config.ts @@ -50,6 +50,9 @@ const viteConfig = defineConfig({ build: { outDir: OUT_DIR, }, + resolve: { + dedupe: ['react', 'react-dom'], + }, plugins: [ electron({ main: { From 8f762c1635b3e69cb8d4b6fdb42a1e455e205086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Mon, 5 Jan 2026 13:49:39 +0100 Subject: [PATCH 14/23] Fix type error by passing enhancer as the third argument to createStore --- desktop/packages/mullvad-vpn/src/renderer/redux/store.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/packages/mullvad-vpn/src/renderer/redux/store.ts b/desktop/packages/mullvad-vpn/src/renderer/redux/store.ts index 0f8b120aa2e4..5de327a0cea9 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/redux/store.ts +++ b/desktop/packages/mullvad-vpn/src/renderer/redux/store.ts @@ -55,7 +55,7 @@ export default function configureStore() { const rootReducer = combineReducers(reducers); - return createStore(rootReducer, composeEnhancers()); + return createStore(rootReducer, {}, composeEnhancers()); } function composeEnhancers(): StoreEnhancer { From 59cc270538c3b07fa8a6da0b2a3f85c37362442a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 15:56:55 +0100 Subject: [PATCH 15/23] Sort exports --- desktop/packages/mullvad-vpn/src/shared/constants/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/packages/mullvad-vpn/src/shared/constants/index.ts b/desktop/packages/mullvad-vpn/src/shared/constants/index.ts index d2cc15e20ffd..d0cedbfdfdb9 100644 --- a/desktop/packages/mullvad-vpn/src/shared/constants/index.ts +++ b/desktop/packages/mullvad-vpn/src/shared/constants/index.ts @@ -1,2 +1,2 @@ -export * from './urls'; export * from './strings'; +export * from './urls'; From 884853bf6d6aeb5dc07b9bd287ea034b2843aecc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:10:59 +0100 Subject: [PATCH 16/23] Update tsconfig to allow importing .ts extensions --- desktop/packages/mullvad-vpn/tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/desktop/packages/mullvad-vpn/tsconfig.json b/desktop/packages/mullvad-vpn/tsconfig.json index 63ac9d39fa51..8584db07c3e8 100644 --- a/desktop/packages/mullvad-vpn/tsconfig.json +++ b/desktop/packages/mullvad-vpn/tsconfig.json @@ -1,6 +1,8 @@ { "extends": "../../tsconfig.json", "compilerOptions": { + "allowImportingTsExtensions": true, + "noEmit": true, "moduleResolution": "bundler", "esModuleInterop": true, "jsx": "react-jsx", From 24cc1f2f651aa8d52e95d3748d71e1fc21f02779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:13:15 +0100 Subject: [PATCH 17/23] Extract allowed HTML tags to separate constants file --- .../mullvad-vpn/src/renderer/lib/html-formatter.tsx | 7 ++----- desktop/packages/mullvad-vpn/src/shared/constants/index.ts | 1 + .../mullvad-vpn/src/shared/constants/translations.ts | 7 +++++++ 3 files changed, 10 insertions(+), 5 deletions(-) create mode 100644 desktop/packages/mullvad-vpn/src/shared/constants/translations.ts diff --git a/desktop/packages/mullvad-vpn/src/renderer/lib/html-formatter.tsx b/desktop/packages/mullvad-vpn/src/renderer/lib/html-formatter.tsx index 880c8973216f..dc97af83c7f3 100644 --- a/desktop/packages/mullvad-vpn/src/renderer/lib/html-formatter.tsx +++ b/desktop/packages/mullvad-vpn/src/renderer/lib/html-formatter.tsx @@ -1,17 +1,14 @@ import React, { JSX } from 'react'; import styled from 'styled-components'; -import { type ValueOfArray } from '../../shared/utility-types'; +import type { AllowedTag } from '../../shared/constants'; import { colors } from './foundations'; const Bold = styled.span({ fontWeight: 700 }); const Emphasis = styled.em({ color: colors.white, fontWeight: 600 }); -export const ALLOWED_TAGS = ['b', 'br', 'em', 'a'] as const; -export type AllowedTags = ValueOfArray; - export type Transformer = (value: string) => React.ReactElement; -export type TransformerMap = Record; +export type TransformerMap = Record; const defaultTransformers: Partial = { b: (value) => {value}, diff --git a/desktop/packages/mullvad-vpn/src/shared/constants/index.ts b/desktop/packages/mullvad-vpn/src/shared/constants/index.ts index d0cedbfdfdb9..137e7d15a5ff 100644 --- a/desktop/packages/mullvad-vpn/src/shared/constants/index.ts +++ b/desktop/packages/mullvad-vpn/src/shared/constants/index.ts @@ -1,2 +1,3 @@ export * from './strings'; +export * from './translations'; export * from './urls'; diff --git a/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts b/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts new file mode 100644 index 000000000000..edf47e004bed --- /dev/null +++ b/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts @@ -0,0 +1,7 @@ +import type { ValueOfArray } from '../utility-types'; + +export const translations = { + allowedTags: ['b', 'br', 'em', 'a'], +} as const; + +export type AllowedTag = ValueOfArray; From b8214d920841e4adb3b83bf0ffae9c062751cee5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:17:25 +0100 Subject: [PATCH 18/23] Import allowed HTML tags from translations constants --- .../mullvad-vpn/scripts/verify-translations-format.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts index af8cd56e6603..b6e48cef04f4 100644 --- a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts +++ b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts @@ -2,8 +2,8 @@ import fs from 'fs'; import { GetTextTranslation, po } from 'gettext-parser'; import path from 'path'; -import { ALLOWED_TAGS } from '../src/renderer/lib/html-formatter'; -import { ValueOfArray } from '../src/shared/utility-types'; +import { type AllowedTag, translations } from '../src/shared/constants/translations.ts'; +const { allowedTags } = translations; const LOCALES_DIR = path.join('locales'); @@ -71,8 +71,9 @@ function checkFormatSpecifiers(translation: GetTextTranslation): boolean { .every((result) => result); } -function isAllowedTag(tag: string): tag is ValueOfArray { - return ALLOWED_TAGS.some((allowedTag) => tag === allowedTag); +function isAllowedTag(tag: string): tag is AllowedTag { + return allowedTags.some((allowedTag) => tag === allowedTag); +} } function checkHtmlTagsImpl(value: string): { correct: boolean; amount: number } { From a1eff54f8911fce5f4938cdc4b08dc2867f0a069 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:18:27 +0100 Subject: [PATCH 19/23] Move allowed void tags to translations constants --- .../scripts/verify-translations-format.ts | 15 ++++++++++----- .../src/shared/constants/translations.ts | 2 ++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts index b6e48cef04f4..b48916e4e054 100644 --- a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts +++ b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts @@ -2,13 +2,15 @@ import fs from 'fs'; import { GetTextTranslation, po } from 'gettext-parser'; import path from 'path'; -import { type AllowedTag, translations } from '../src/shared/constants/translations.ts'; -const { allowedTags } = translations; +import { + type AllowedTag, + type AllowedVoidTag, + translations, +} from '../src/shared/constants/translations.ts'; +const { allowedTags, allowedVoidTags } = translations; const LOCALES_DIR = path.join('locales'); -const ALLOWED_VOID_TAGS = ['br']; - // Make sure to report these strings to crowdin. View this as a temporary escape // hatch, not a permanent solution. const IGNORED_STRINGS: Set = new Set([ @@ -74,6 +76,9 @@ function checkFormatSpecifiers(translation: GetTextTranslation): boolean { function isAllowedTag(tag: string): tag is AllowedTag { return allowedTags.some((allowedTag) => tag === allowedTag); } + +function isAllowedVoidTag(tag: string): tag is AllowedVoidTag { + return allowedVoidTags.some((allowedTag) => tag === allowedTag); } function checkHtmlTagsImpl(value: string): { correct: boolean; amount: number } { @@ -94,7 +99,7 @@ function checkHtmlTagsImpl(value: string): { correct: boolean; amount: number } return { correct: false, amount: NaN }; } - if (!ALLOWED_VOID_TAGS.includes(tag)) { + if (!isAllowedVoidTag(tag)) { if (endTag) { // End tags require a matching start tag. if (tag !== tagStack.pop()) { diff --git a/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts b/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts index edf47e004bed..52d5a04bd932 100644 --- a/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts +++ b/desktop/packages/mullvad-vpn/src/shared/constants/translations.ts @@ -2,6 +2,8 @@ import type { ValueOfArray } from '../utility-types'; export const translations = { allowedTags: ['b', 'br', 'em', 'a'], + allowedVoidTags: ['br'], } as const; export type AllowedTag = ValueOfArray; +export type AllowedVoidTag = ValueOfArray; From 6e735d005cc9f8b8e22f410f66d3bb085366766f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:19:55 +0100 Subject: [PATCH 20/23] Use explicit type import syntax --- .../packages/mullvad-vpn/scripts/verify-translations-format.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts index b48916e4e054..ab404533aaef 100644 --- a/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts +++ b/desktop/packages/mullvad-vpn/scripts/verify-translations-format.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import { GetTextTranslation, po } from 'gettext-parser'; +import { type GetTextTranslation, po } from 'gettext-parser'; import path from 'path'; import { From 3e67725ce5ad21b9acebb165fc7d13f818c4eccd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:19:31 +0100 Subject: [PATCH 21/23] Use node instead of ts-node when verifying translations Node now has the ability to run typescript code natively. --- scripts/localization | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/localization b/scripts/localization index da05b455bc59..2ac9284a1ea9 100755 --- a/scripts/localization +++ b/scripts/localization @@ -95,7 +95,7 @@ function verify { local out_of_sync=$? pushd ../desktop/packages/mullvad-vpn - npm exec ts-node scripts/verify-translations-format.ts + npm exec node scripts/verify-translations-format.ts local incorrect_format=$? popd From 3d08282327f1fcceba7d5da585882fae4d4e95ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 9 Jan 2026 16:24:05 +0100 Subject: [PATCH 22/23] Remove ts-node Since version 22.19 node natively supports executing typescript files. --- desktop/package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/desktop/package.json b/desktop/package.json index 765c0e3f14b9..0fbddec2b670 100644 --- a/desktop/package.json +++ b/desktop/package.json @@ -28,7 +28,6 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-simple-import-sort": "^12.1.1", "prettier": "^3.3.3", - "ts-node": "^10.9.2", "typescript": "^5.9.3", "typescript-eslint": "^8.15.0" }, From 9ab9240b705c8da4d00fd31a5d1db14da3ddbb5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20J=C3=A4rvel=C3=B6v?= Date: Fri, 30 Jan 2026 16:58:47 +0100 Subject: [PATCH 23/23] Update package-lock.json --- desktop/package-lock.json | 874 ++++++++++++++------------------------ 1 file changed, 309 insertions(+), 565 deletions(-) diff --git a/desktop/package-lock.json b/desktop/package-lock.json index 2173c0067642..0bc7a1f43093 100644 --- a/desktop/package-lock.json +++ b/desktop/package-lock.json @@ -23,7 +23,6 @@ "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-simple-import-sort": "^12.1.1", "prettier": "^3.3.3", - "ts-node": "^10.9.2", "typescript": "^5.9.3", "typescript-eslint": "^8.15.0" }, @@ -56,13 +55,13 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -71,9 +70,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true, "license": "MIT", "engines": { @@ -144,14 +143,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -184,13 +183,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -281,29 +280,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -375,9 +374,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -409,13 +408,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.6" }, "bin": { "parser": "bin/babel-parser.js" @@ -486,33 +485,33 @@ } }, "node_modules/@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", "debug": "^4.3.1" }, "engines": { @@ -543,31 +542,19 @@ "dev": true }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, "node_modules/@develar/schema-utils": { "version": "2.6.5", "resolved": "https://registry.npmjs.org/@develar/schema-utils/-/schema-utils-2.6.5.tgz", @@ -2033,16 +2020,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "node_modules/@js-sdsl/ordered-map": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", @@ -2491,6 +2468,13 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.44.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", @@ -2796,30 +2780,6 @@ "node": ">=10" } }, - "node_modules/@tsconfig/node10": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.7.tgz", - "integrity": "sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.7.tgz", - "integrity": "sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.0.tgz", - "integrity": "sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -3420,6 +3380,107 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@vitejs/plugin-react": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.5", + "@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" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@vitejs/plugin-react/node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@vitejs/plugin-react/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vitejs/plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, "node_modules/@vitest/expect": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", @@ -3946,12 +4007,6 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4947,12 +5002,6 @@ "buffer": "^5.1.0" } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-dirname": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", @@ -5223,16 +5272,6 @@ "dev": true, "optional": true }, - "node_modules/diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -8086,12 +8125,6 @@ "semver": "bin/semver.js" } }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "node_modules/make-fetch-happen": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", @@ -9445,9 +9478,9 @@ } }, "node_modules/react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true, "license": "MIT", "engines": { @@ -9555,6 +9588,12 @@ "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", "dev": true }, + "node_modules/redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", + "license": "MIT" + }, "node_modules/reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -10843,58 +10882,6 @@ "typescript": ">=4.2.0" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node/node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -11167,12 +11154,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "devOptional": true }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, "node_modules/verror": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", @@ -11891,15 +11872,6 @@ "fd-slicer": "~1.1.0" } }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -11965,7 +11937,7 @@ "react-dom": "^19.1.1", "react-redux": "^9.2.0", "react-router": "^5.3.4", - "redux": "^4.2.0", + "redux": "^5.0.1", "simple-plist": "^1.3.1", "sprintf-js": "^1.1.2", "styled-components": "^6.1.19", @@ -11982,7 +11954,7 @@ "@types/react-router": "^5.1.19", "@types/sprintf-js": "^1.1.2", "@types/topojson-specification": "^1.0.2", - "@vitejs/plugin-react": "^4.7.0", + "@vitejs/plugin-react": "^5.0.2", "cross-env": "^7.0.3", "electron": "39.2.6", "electron-builder": "26.6.0", @@ -12008,114 +11980,6 @@ "@rollup/rollup-win32-x64-msvc": "4.34.6" } }, - "packages/mullvad-vpn/node_modules/@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "packages/mullvad-vpn/node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - } - }, - "packages/mullvad-vpn/node_modules/@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "packages/mullvad-vpn/node_modules/@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true, - "license": "MIT" - }, - "packages/mullvad-vpn/node_modules/@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "peerDependencies": { - "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" - } - }, - "packages/mullvad-vpn/node_modules/debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "packages/mullvad-vpn/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, "packages/mullvad-vpn/node_modules/react": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", @@ -12137,15 +12001,6 @@ "react": "^19.1.1" } }, - "packages/mullvad-vpn/node_modules/redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.9.2" - } - }, "packages/mullvad-vpn/node_modules/scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -12193,20 +12048,20 @@ } }, "@babel/code-frame": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", - "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz", + "integrity": "sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "@babel/compat-data": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.4.tgz", - "integrity": "sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.6.tgz", + "integrity": "sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg==", "dev": true }, "@babel/core": { @@ -12256,13 +12111,13 @@ } }, "@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.6.tgz", + "integrity": "sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw==", "dev": true, "requires": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -12290,12 +12145,12 @@ } }, "@babel/helper-compilation-targets": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", - "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", "dev": true, "requires": { - "@babel/compat-data": "^7.27.2", + "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", @@ -12365,24 +12220,24 @@ } }, "@babel/helper-module-imports": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", - "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "requires": { - "@babel/traverse": "^7.27.1", - "@babel/types": "^7.27.1" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-optimise-call-expression": { @@ -12428,9 +12283,9 @@ "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true }, "@babel/helper-validator-option": { @@ -12450,12 +12305,12 @@ } }, "@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.6.tgz", + "integrity": "sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==", "dev": true, "requires": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.6" } }, "@babel/plugin-proposal-private-methods": { @@ -12495,28 +12350,28 @@ } }, "@babel/template": { - "version": "7.27.2", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", - "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/parser": "^7.27.2", - "@babel/types": "^7.27.1" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/traverse": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.4.tgz", - "integrity": "sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.6.tgz", + "integrity": "sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg==", "dev": true, "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6", "debug": "^4.3.1" }, "dependencies": { @@ -12538,22 +12393,13 @@ } }, "@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.6.tgz", + "integrity": "sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg==", "dev": true, "requires": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" - } - }, - "@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "requires": { - "@jridgewell/trace-mapping": "0.3.9" + "@babel/helper-validator-identifier": "^7.28.5" } }, "@develar/schema-utils": { @@ -13457,16 +13303,6 @@ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true }, - "@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, "@js-sdsl/ordered-map": { "version": "4.4.2", "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", @@ -13800,6 +13636,12 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "@rolldown/pluginutils": { + "version": "1.0.0-beta.53", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.53.tgz", + "integrity": "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ==", + "dev": true + }, "@rollup/rollup-android-arm-eabi": { "version": "4.44.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", @@ -13955,30 +13797,6 @@ "defer-to-connect": "^2.0.0" } }, - "@tsconfig/node10": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.7.tgz", - "integrity": "sha512-aBvUmXLQbayM4w3A8TrjwrXs4DZ8iduJnuJLLRGdkWlyakCf1q6uHZJBzXoRA/huAEknG5tcUyQxN3A+In5euQ==", - "dev": true - }, - "@tsconfig/node12": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.7.tgz", - "integrity": "sha512-dgasobK/Y0wVMswcipr3k0HpevxFJLijN03A8mYfEPvWvOs14v0ZlYTR4kIgMx8g4+fTyTFv8/jLCIfRqLDJ4A==", - "dev": true - }, - "@tsconfig/node14": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.0.tgz", - "integrity": "sha512-RKkL8eTdPv6t5EHgFKIVQgsDapugbuOptNd9OOunN/HAkzmmTnZELx1kNCK0rSdUYGmiFMM3rRQMAWiyp023LQ==", - "dev": true - }, - "@tsconfig/node16": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.2.tgz", - "integrity": "sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==", - "dev": true - }, "@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -14439,6 +14257,76 @@ } } }, + "@vitejs/plugin-react": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-5.1.2.tgz", + "integrity": "sha512-EcA07pHJouywpzsoTUqNh5NwGayl2PPVEJKUSinGGSxFGYn+shYbqMGBg6FXDqgXum9Ou/ecb+411ssw8HImJQ==", + "dev": true, + "requires": { + "@babel/core": "^7.28.5", + "@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" + }, + "dependencies": { + "@babel/core": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.6.tgz", + "integrity": "sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.28.6", + "@babel/generator": "^7.28.6", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + } + }, + "@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "requires": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + } + }, + "debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "requires": { + "ms": "^2.1.3" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + } + } + }, "@vitest/expect": { "version": "4.0.16", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.0.16.tgz", @@ -14812,12 +14700,6 @@ "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", "optional": true }, - "arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -15512,12 +15394,6 @@ "buffer": "^5.1.0" } }, - "create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "cross-dirname": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/cross-dirname/-/cross-dirname-0.1.0.tgz", @@ -15710,12 +15586,6 @@ "dev": true, "optional": true }, - "diff": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", - "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", - "dev": true - }, "dir-compare": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dir-compare/-/dir-compare-4.2.0.tgz", @@ -17747,12 +17617,6 @@ } } }, - "make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, "make-fetch-happen": { "version": "14.0.3", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-14.0.3.tgz", @@ -18006,7 +17870,7 @@ "@types/react-router": "^5.1.19", "@types/sprintf-js": "^1.1.2", "@types/topojson-specification": "^1.0.2", - "@vitejs/plugin-react": "^4.7.0", + "@vitejs/plugin-react": "^5.0.2", "argv-split": "^2.0.1", "cross-env": "^7.0.3", "electron": "39.2.6", @@ -18030,7 +17894,7 @@ "react-dom": "^19.1.1", "react-redux": "^9.2.0", "react-router": "^5.3.4", - "redux": "^4.2.0", + "redux": "^5.0.1", "simple-plist": "^1.3.1", "sprintf-js": "^1.1.2", "styled-components": "^6.1.19", @@ -18041,82 +17905,6 @@ "xvfb-maybe": "^0.2.1" }, "dependencies": { - "@babel/core": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.4.tgz", - "integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.27.1", - "@babel/generator": "^7.28.3", - "@babel/helper-compilation-targets": "^7.27.2", - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helpers": "^7.28.4", - "@babel/parser": "^7.28.4", - "@babel/template": "^7.27.2", - "@babel/traverse": "^7.28.4", - "@babel/types": "^7.28.4", - "@jridgewell/remapping": "^2.3.5", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } - } - }, - "@babel/helpers": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz", - "integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==", - "dev": true, - "requires": { - "@babel/template": "^7.27.2", - "@babel/types": "^7.28.4" - } - }, - "@rolldown/pluginutils": { - "version": "1.0.0-beta.27", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", - "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", - "dev": true - }, - "@vitejs/plugin-react": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", - "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", - "dev": true, - "requires": { - "@babel/core": "^7.28.0", - "@babel/plugin-transform-react-jsx-self": "^7.27.1", - "@babel/plugin-transform-react-jsx-source": "^7.27.1", - "@rolldown/pluginutils": "1.0.0-beta.27", - "@types/babel__core": "^7.20.5", - "react-refresh": "^0.17.0" - } - }, - "debug": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", - "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, - "requires": { - "ms": "^2.1.3" - } - }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, "react": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", @@ -18130,14 +17918,6 @@ "scheduler": "^0.26.0" } }, - "redux": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.1.tgz", - "integrity": "sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==", - "requires": { - "@babel/runtime": "^7.9.2" - } - }, "scheduler": { "version": "0.26.0", "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", @@ -18826,9 +18606,9 @@ } }, "react-refresh": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", - "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.18.0.tgz", + "integrity": "sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==", "dev": true }, "react-router": { @@ -18921,6 +18701,11 @@ } } }, + "redux": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", + "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==" + }, "reflect.getprototypeof": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", @@ -19837,35 +19622,6 @@ "dev": true, "requires": {} }, - "ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "requires": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "dependencies": { - "acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "dev": true - } - } - }, "tslib": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz", @@ -20045,12 +19801,6 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "devOptional": true }, - "v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, "verror": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.1.tgz", @@ -20491,12 +20241,6 @@ "fd-slicer": "~1.1.0" } }, - "yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true - }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",