From cef3764950c98229ee2ea07287ed283acc229e75 Mon Sep 17 00:00:00 2001 From: abose Date: Mon, 19 Jan 2026 15:25:21 +0000 Subject: [PATCH 01/91] ci: bump patch version to 5.0.6 --- package.json | 4 ++-- src-node/package.json | 4 ++-- src/config.json | 4 ++-- src/index.html | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 72a839630..1b90c6007 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "phoenix", - "version": "5.0.5-0", - "apiVersion": "5.0.5", + "version": "5.0.6-0", + "apiVersion": "5.0.6", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" diff --git a/src-node/package.json b/src-node/package.json index f4a0133db..ddaa572c1 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -1,8 +1,8 @@ { "name": "@phcode/node-core", "description": "Phoenix Node Core", - "version": "5.0.5-0", - "apiVersion": "5.0.5", + "version": "5.0.6-0", + "apiVersion": "5.0.6", "keywords": [], "author": "arun@core.ai", "homepage": "https://github.com/phcode-dev/phoenix", diff --git a/src/config.json b/src/config.json index e104b7bb1..fa8ab4986 100644 --- a/src/config.json +++ b/src/config.json @@ -46,8 +46,8 @@ "bugsnagEnv": "development" }, "name": "Phoenix Code", - "version": "5.0.5-0", - "apiVersion": "5.0.5", + "version": "5.0.6-0", + "apiVersion": "5.0.6", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" diff --git a/src/index.html b/src/index.html index 15d2c6ec3..702bb1e10 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,7 @@ - + + + @@ -211,6 +274,7 @@ isDeskTop: !_mobileAndTabletCheck() && !_mobileCheck(), isChromeOS: /CrOS/.test(navigator.userAgent), isTauri: !!window.__TAURI__, + isElectron: !!window.__ELECTRON__, mobile: { isAndroid: (navigator.userAgent.match(/Android/i) !== null), isIos: (navigator.userAgent.match(/iPhone|iPad|iPod/i) !== null), @@ -290,7 +354,7 @@ 'https://create.phcode.dev': true } }; - window.Phoenix.isNativeApp = window.Phoenix.browser.isTauri; + window.Phoenix.isNativeApp = window.__IS_NATIVE_SHELL__; window.Phoenix.TRUSTED_ORIGINS[location.origin] = true; Phoenix.isSupportedBrowser = Phoenix.isNativeApp || (Phoenix.browser.isDeskTop && ("serviceWorker" in navigator)); diff --git a/test/spec/LiveDevelopmentMultiBrowser-test.js b/test/spec/LiveDevelopmentMultiBrowser-test.js index 30bc999ee..6b3b3181d 100644 --- a/test/spec/LiveDevelopmentMultiBrowser-test.js +++ b/test/spec/LiveDevelopmentMultiBrowser-test.js @@ -92,7 +92,7 @@ define(function (require, exports, module) { // we have to popout a new window and cant use the embedded iframe for live preview integ tests // as Firefox sandbox prevents service worker access from nexted iframes. // In tauri, we use node server, so this limitation doesn't apply in tauri, and we stick to iframes. - const useWindowInsteadOfIframe = (Phoenix.browser.desktop.isFirefox && !window.__TAURI__); + const useWindowInsteadOfIframe = Phoenix.browser.desktop.isFirefox; testWindow = await SpecRunnerUtils.createTestWindowAndRun({ forceReload: false, useWindowInsteadOfIframe }); From d4328a66f6b762cb93c94a9acc1aeca4566c6a89 Mon Sep 17 00:00:00 2001 From: abose Date: Tue, 27 Jan 2026 20:13:34 +0530 Subject: [PATCH 10/91] chore: adding metrics, storage assetsURL, zoom window with electron support --- src/extensionsIntegrated/appUpdater/main.js | 3 +- src/phoenix/init_vfs.js | 8 ++++- src/phoenix/shell.js | 7 ++++- src/storage.js | 33 ++++++++++++++------- src/utils/Metrics.js | 15 ++++++++-- 5 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/extensionsIntegrated/appUpdater/main.js b/src/extensionsIntegrated/appUpdater/main.js index 4cf67dc54..cb477df8a 100644 --- a/src/extensionsIntegrated/appUpdater/main.js +++ b/src/extensionsIntegrated/appUpdater/main.js @@ -517,10 +517,11 @@ define(function (require, exports, module) { let updateInstalledDialogShown = false, updateFailedDialogShown = false; AppInit.appReady(function () { - if(!Phoenix.isNativeApp || Phoenix.isTestWindow) { + if(!window.__TAURI__ || Phoenix.isTestWindow) { // app updates are only for desktop builds return; } + // todo electron edge for app updater if (brackets.platform === "mac") { // in mac, the `update.app.tar.gz` is downloaded, and only extracted on app quit. // we do this only in mac as the `.app` file is extracted only at app quit and deleted diff --git a/src/phoenix/init_vfs.js b/src/phoenix/init_vfs.js index 315aa3da4..fe04e5710 100644 --- a/src/phoenix/init_vfs.js +++ b/src/phoenix/init_vfs.js @@ -48,7 +48,13 @@ function _getNativeAssetUrl(fullFilePath) { } return null; } - // todo electron + if(window.__ELECTRON__) { + if(fullFilePath.startsWith(tauriAssetServeDir)){ + const platformPath = fs.getTauriPlatformPath(fullFilePath); + return window.electronAPI.convertToAssetURL(platformPath); + } + return null; + } return null; } diff --git a/src/phoenix/shell.js b/src/phoenix/shell.js index d7437edec..fcdbf3fc4 100644 --- a/src/phoenix/shell.js +++ b/src/phoenix/shell.js @@ -537,7 +537,12 @@ Phoenix.app = { if(scaleFactor < .1 || scaleFactor > 2) { throw new Error("zoomWebView scale factor should be between .1 and 2"); } - return window.__TAURI__.tauri.invoke("zoom_window", {scaleFactor: scaleFactor}); + if(window.__TAURI__) { + return window.__TAURI__.tauri.invoke("zoom_window", {scaleFactor: scaleFactor}); + } + if(window.__ELECTRON__) { + return window.electronAPI.zoomWindow(scaleFactor); + } }, _openUrlInBrowserWin: function (url, browser) { // private API for internal use only. May be removed at any time. diff --git a/src/storage.js b/src/storage.js index 433cafaa4..1a6613602 100644 --- a/src/storage.js +++ b/src/storage.js @@ -206,10 +206,14 @@ import {set, entries, createStore} from './thirdparty/idb-keyval.js'; storageNodeConnector .execPeer("putItem", {key, value: valueToStore}) .catch(_reportPutItemError); - // this is an in-memory tauri store that takes care of multi window case, since we have a single - // instance, all windows share this and can reconstruct the full view from the dumb file + this map - // when the editor boots up instead of having to write the dump file frequently. - window.__TAURI__.invoke('put_item', { key, value: JSON.stringify(valueToStore) }); + // this is an in-memory tauri/electron store that takes care of multi window case, since we have a + // single instance, all windows share this and can reconstruct the full view from the dump file + this + // map when the editor boots up instead of having to write the dump file frequently. + if(window.__TAURI__) { + window.__TAURI__.invoke('put_item', { key, value: JSON.stringify(valueToStore) }); + } else if(window.__ELECTRON__) { + window.electronAPI.putItem(key, JSON.stringify(valueToStore)); + } } if(window.debugMode || isBrowser) { // in debug mode, we write to browser storage in tauri and browser builds for eazy debug of storage. @@ -291,13 +295,18 @@ import {set, entries, createStore} from './thirdparty/idb-keyval.js'; return; } if(isDesktop){ - async function mergeTauriInMemoryStorage() { - // The tauri storeage is mainly used in multi window case, where if there are 2+ windows, each window - // is till live and has not commited the dump file to disc(they only do that on exit or 30 every secs). + async function mergeNativeInMemoryStorage() { + // The native storage is mainly used in multi window case, where if there are 2+ windows, each window + // is still live and has not committed the dump file to disc (they only do that on exit or every 30 secs). // so the dump file may be stale after window._tauriStorageRestorePromise in the case. - // we merge the local memory cache maintained at tauri rust side to address this. + // we merge the local memory cache maintained at tauri/electron side to address this. try { - const map = await window.__TAURI__.invoke('get_all_items') || {}; + let map = {}; + if(window.__TAURI__) { + map = await window.__TAURI__.invoke('get_all_items') || {}; + } else if(window.__ELECTRON__) { + map = await window.electronAPI.getAllItems() || {}; + } for(const key of Object.keys(map)){ cache[key] = JSON.parse(map[key]); } @@ -317,7 +326,7 @@ import {set, entries, createStore} from './thirdparty/idb-keyval.js'; } }) .catch(console.error) - .finally(mergeTauriInMemoryStorage); + .finally(mergeNativeInMemoryStorage); return; } // Use browser default storage- IndexedDB @@ -342,8 +351,10 @@ import {set, entries, createStore} from './thirdparty/idb-keyval.js'; // do things to do that are critical to user experience here // We try to set window zoom as early as possible to prevent zoom flicker const zoomFactor = PhStore.getItem(_PHSTORE_BOOT_DESKTOP_ZOOM_SCALE_KEY) || 1; - if(Phoenix.isNativeApp){ + if(window.__TAURI__){ window.__TAURI__.tauri.invoke("zoom_window", {scaleFactor: zoomFactor}); + } else if(window.__ELECTRON__) { + window.electronAPI.zoomWindow(zoomFactor); } }); /** diff --git a/src/utils/Metrics.js b/src/utils/Metrics.js index 64220d3da..7e6ad646b 100644 --- a/src/utils/Metrics.js +++ b/src/utils/Metrics.js @@ -194,6 +194,17 @@ define(function (require, exports, module) { }); } + function _sendNativeGAEvent(analyticsID, customUserID, events=[]) { + if(window.__TAURI__){ + return _sendTauriGAEvent(analyticsID, customUserID, events=[]); + } + if(window.__ELECTRON__){ + // todo electron send event to metrics window with electron + return; + } + console.error("Metrics send event failed. Unknown native platform"); + } + let tauriGAEvents = new Map(); function _sendGaEvent(eventAct, category, label, count) { @@ -216,7 +227,7 @@ define(function (require, exports, module) { const TAURI_GA_EVENT_QUEUE_INTERVAL = 3000; function _sendQueuedTauriGAEvents() { - _sendTauriGAEvent(brackets.config.googleAnalyticsIDDesktop, userID, Array.from(tauriGAEvents.values())); + _sendNativeGAEvent(brackets.config.googleAnalyticsIDDesktop, userID, Array.from(tauriGAEvents.values())); tauriGAEvents.clear(); } @@ -227,7 +238,7 @@ define(function (require, exports, module) { // https urls and not the tauri custom protocol urls. So we have a hidden window that loads ga from a // http(s) page which is usually `https://phcode.dev/desktop-metrics.html` or // "http://localhost:8000/src/metrics.html" for live dev builds in tauri. - _sendTauriGAEvent(brackets.config.googleAnalyticsIDDesktop, userID); + _sendNativeGAEvent(brackets.config.googleAnalyticsIDDesktop, userID); setInterval(_sendQueuedTauriGAEvents, TAURI_GA_EVENT_QUEUE_INTERVAL); return; } From 930130feca3da7be9233e276932ffd4e92ba5f8e Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 28 Jan 2026 09:34:19 +0530 Subject: [PATCH 11/91] chore: ci to node 24 --- .github/workflows/create-deploy.yml | 2 +- .github/workflows/desktop-linux-prod-test-pull.yml | 2 +- .github/workflows/desktop-linux-test-pull.yml | 2 +- .../desktop-mac-m1-prod-communityEd-test-pull.yml | 2 +- .github/workflows/desktop-mac-m1-prod-test-pull.yml | 2 +- .github/workflows/desktop-mac-m1-test-pull.yml | 2 +- .github/workflows/desktop-mac-test-pull.yml | 2 +- .github/workflows/desktop-windows-test-pull.yml | 2 +- .github/workflows/minor-version-bump.yml | 2 +- .github/workflows/patch-version-bump.yml | 2 +- .../playwright-chromium-linux-community.yml | 2 +- .github/workflows/playwright-chromium-linux.yml | 2 +- .github/workflows/playwright-chromium-macos.yml | 2 +- .../workflows/playwright-chromium-windows-prod.yml | 2 +- .github/workflows/playwright-chromium-windows.yml | 2 +- .github/workflows/playwright-firefox-linux.yml | 2 +- .github/workflows/playwright-firefox-macos.yml | 2 +- .github/workflows/playwright-firefox-windows.yml | 2 +- .github/workflows/playwright-staging-prod.yml | 12 ++++++------ .github/workflows/prod-deploy.yml | 2 +- .github/workflows/pull_request_verify.yml | 2 +- .github/workflows/staging-deploy.yml | 2 +- .github/workflows/tauri-deploy.yml | 2 +- src-node/package.json | 2 +- 24 files changed, 29 insertions(+), 29 deletions(-) diff --git a/.github/workflows/create-deploy.yml b/.github/workflows/create-deploy.yml index 5ab1c8968..fe4644a11 100644 --- a/.github/workflows/create-deploy.yml +++ b/.github/workflows/create-deploy.yml @@ -12,7 +12,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Npm Install run: | npm ci diff --git a/.github/workflows/desktop-linux-prod-test-pull.yml b/.github/workflows/desktop-linux-prod-test-pull.yml index b2933728f..c05460f76 100644 --- a/.github/workflows/desktop-linux-prod-test-pull.yml +++ b/.github/workflows/desktop-linux-prod-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-linux-test-pull.yml b/.github/workflows/desktop-linux-test-pull.yml index b6f9aa0b2..5d5df0e2f 100644 --- a/.github/workflows/desktop-linux-test-pull.yml +++ b/.github/workflows/desktop-linux-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-mac-m1-prod-communityEd-test-pull.yml b/.github/workflows/desktop-mac-m1-prod-communityEd-test-pull.yml index 5b8525ce3..3cf1ada28 100644 --- a/.github/workflows/desktop-mac-m1-prod-communityEd-test-pull.yml +++ b/.github/workflows/desktop-mac-m1-prod-communityEd-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-mac-m1-prod-test-pull.yml b/.github/workflows/desktop-mac-m1-prod-test-pull.yml index 54a6f7bd8..9a23285c8 100644 --- a/.github/workflows/desktop-mac-m1-prod-test-pull.yml +++ b/.github/workflows/desktop-mac-m1-prod-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-mac-m1-test-pull.yml b/.github/workflows/desktop-mac-m1-test-pull.yml index e51a98380..b7f52a5e4 100644 --- a/.github/workflows/desktop-mac-m1-test-pull.yml +++ b/.github/workflows/desktop-mac-m1-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-mac-test-pull.yml b/.github/workflows/desktop-mac-test-pull.yml index 98429cfeb..f47ed8e47 100644 --- a/.github/workflows/desktop-mac-test-pull.yml +++ b/.github/workflows/desktop-mac-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/desktop-windows-test-pull.yml b/.github/workflows/desktop-windows-test-pull.yml index 85c4c99c3..b269da8d0 100644 --- a/.github/workflows/desktop-windows-test-pull.yml +++ b/.github/workflows/desktop-windows-test-pull.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: install Rust stable uses: dtolnay/rust-toolchain@stable with: diff --git a/.github/workflows/minor-version-bump.yml b/.github/workflows/minor-version-bump.yml index db2f0e11b..e68fe3beb 100644 --- a/.github/workflows/minor-version-bump.yml +++ b/.github/workflows/minor-version-bump.yml @@ -11,7 +11,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - uses: actions/checkout@v3 with: ref: main diff --git a/.github/workflows/patch-version-bump.yml b/.github/workflows/patch-version-bump.yml index dbb600c0d..20d1641d3 100644 --- a/.github/workflows/patch-version-bump.yml +++ b/.github/workflows/patch-version-bump.yml @@ -11,7 +11,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - uses: actions/checkout@v3 with: ref: main diff --git a/.github/workflows/playwright-chromium-linux-community.yml b/.github/workflows/playwright-chromium-linux-community.yml index 11f058991..2b846d7f2 100644 --- a/.github/workflows/playwright-chromium-linux-community.yml +++ b/.github/workflows/playwright-chromium-linux-community.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-chromium-linux.yml b/.github/workflows/playwright-chromium-linux.yml index 8c0e12634..01ec519be 100644 --- a/.github/workflows/playwright-chromium-linux.yml +++ b/.github/workflows/playwright-chromium-linux.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-chromium-macos.yml b/.github/workflows/playwright-chromium-macos.yml index 6cb1af160..e2b35f5cb 100644 --- a/.github/workflows/playwright-chromium-macos.yml +++ b/.github/workflows/playwright-chromium-macos.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-chromium-windows-prod.yml b/.github/workflows/playwright-chromium-windows-prod.yml index 8a1087b93..723eb051c 100644 --- a/.github/workflows/playwright-chromium-windows-prod.yml +++ b/.github/workflows/playwright-chromium-windows-prod.yml @@ -17,7 +17,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-chromium-windows.yml b/.github/workflows/playwright-chromium-windows.yml index 13cfec939..e2bcc3d7a 100644 --- a/.github/workflows/playwright-chromium-windows.yml +++ b/.github/workflows/playwright-chromium-windows.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-firefox-linux.yml b/.github/workflows/playwright-firefox-linux.yml index 02e8e6246..8c2e33485 100644 --- a/.github/workflows/playwright-firefox-linux.yml +++ b/.github/workflows/playwright-firefox-linux.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-firefox-macos.yml b/.github/workflows/playwright-firefox-macos.yml index 5b83ff378..bb8940361 100644 --- a/.github/workflows/playwright-firefox-macos.yml +++ b/.github/workflows/playwright-firefox-macos.yml @@ -19,7 +19,7 @@ # - name: setup node # uses: actions/setup-node@v3 # with: -# node-version: 20 +# node-version: 24 # - name: Install dependencies # run: npm ci # - name: Build phoenix diff --git a/.github/workflows/playwright-firefox-windows.yml b/.github/workflows/playwright-firefox-windows.yml index e225a123b..1d8d38920 100644 --- a/.github/workflows/playwright-firefox-windows.yml +++ b/.github/workflows/playwright-firefox-windows.yml @@ -16,7 +16,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/playwright-staging-prod.yml b/.github/workflows/playwright-staging-prod.yml index dd9503049..651ff5833 100644 --- a/.github/workflows/playwright-staging-prod.yml +++ b/.github/workflows/playwright-staging-prod.yml @@ -13,7 +13,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix @@ -101,7 +101,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix @@ -190,7 +190,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix @@ -278,7 +278,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix @@ -366,7 +366,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix @@ -455,7 +455,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Install dependencies run: npm ci - name: Build phoenix diff --git a/.github/workflows/prod-deploy.yml b/.github/workflows/prod-deploy.yml index 1c371e505..155cde100 100644 --- a/.github/workflows/prod-deploy.yml +++ b/.github/workflows/prod-deploy.yml @@ -12,7 +12,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Npm Install run: | npm ci diff --git a/.github/workflows/pull_request_verify.yml b/.github/workflows/pull_request_verify.yml index c2068ddee..17a5ea729 100644 --- a/.github/workflows/pull_request_verify.yml +++ b/.github/workflows/pull_request_verify.yml @@ -12,7 +12,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Npm Install run: | npm ci diff --git a/.github/workflows/staging-deploy.yml b/.github/workflows/staging-deploy.yml index 58b72072a..ae0f37a5b 100644 --- a/.github/workflows/staging-deploy.yml +++ b/.github/workflows/staging-deploy.yml @@ -12,7 +12,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Npm Install run: | npm ci diff --git a/.github/workflows/tauri-deploy.yml b/.github/workflows/tauri-deploy.yml index 0db082ddf..6b31c1519 100644 --- a/.github/workflows/tauri-deploy.yml +++ b/.github/workflows/tauri-deploy.yml @@ -17,7 +17,7 @@ jobs: - name: setup node uses: actions/setup-node@v3 with: - node-version: 20 + node-version: 24 - name: Npm Install run: | npm ci diff --git a/src-node/package.json b/src-node/package.json index 0220fdc5b..fc25d8e4f 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -11,7 +11,7 @@ "_watch_src-node": "cd .. && npm run _watch_src-node" }, "engines": { - "node": "20" + "node": "24" }, "repository": { "type": "git", From 652eecd8d9a5b5a29d469c7cc3dd1fcf571b293a Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 28 Jan 2026 10:03:00 +0530 Subject: [PATCH 12/91] fix: test suite break with node24 upgrade in windows. tauri UNC paths not accepted by node 24 --- src/node-loader.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/node-loader.js b/src/node-loader.js index 6721b299a..a71852c7c 100644 --- a/src/node-loader.js +++ b/src/node-loader.js @@ -637,6 +637,11 @@ function nodeLoader() { window.__TAURI__.path.resolveResource("src-node/index.js") .then(async nodeSrcPath=>{ + // Strip Windows UNC prefix (\\?\) that Tauri adds on Windows + // Node 24 doesn't handle UNC paths correctly in module resolution + if (Phoenix.platform === "win" && nodeSrcPath.startsWith('\\\\?\\')) { + nodeSrcPath = nodeSrcPath.slice(4); + } if(Phoenix.platform === "linux") { // in linux installed distributions, src-node is present in the same dir as the executable. const cliArgs = await window.__TAURI__.invoke('_get_commandline_args'); From 788427182d5ab8a1f8357a55a2af1fc4691f5dc3 Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Mon, 26 Jan 2026 09:42:56 +0000 Subject: [PATCH 13/91] fix: package.json & package-lock.json to reduce vulnerabilities The following vulnerabilities are fixed with an upgrade: - https://snyk.io/vuln/SNYK-JS-LODASH-15053838 --- package-lock.json | 15 ++++++++------- package.json | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index be4da8038..62ced9924 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "jshint": "^2.13.5", "jszip": "^3.8.0", "less": "^4.1.3", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "lru-cache": "^10.2.0", "marked": "^4.0.18", "mime-db": "^1.52.0", @@ -8060,9 +8060,10 @@ } }, "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" }, "node_modules/lodash._escapehtmlchar": { "version": "2.4.1", @@ -19332,9 +19333,9 @@ } }, "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==" }, "lodash._escapehtmlchar": { "version": "2.4.1", diff --git a/package.json b/package.json index cf7150211..9b6bd9c40 100644 --- a/package.json +++ b/package.json @@ -110,7 +110,7 @@ "jshint": "^2.13.5", "jszip": "^3.8.0", "less": "^4.1.3", - "lodash": "^4.17.21", + "lodash": "^4.17.23", "lru-cache": "^10.2.0", "marked": "^4.0.18", "mime-db": "^1.52.0", From ea4c212496edbb651bed31b2a3768d2223ead900 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 09:43:14 +0000 Subject: [PATCH 14/91] build(deps): bump tar and npm in /src-node Removes [tar](https://github.com/isaacs/node-tar). It's no longer used after updating ancestor dependency [npm](https://github.com/npm/cli). These dependencies need to be updated together. Removes `tar` Updates `npm` from 10.1.0 to 11.8.0 - [Release notes](https://github.com/npm/cli/releases) - [Changelog](https://github.com/npm/cli/blob/latest/CHANGELOG.md) - [Commits](https://github.com/npm/cli/compare/libnpmexec-v10.1.0...v11.8.0) --- updated-dependencies: - dependency-name: tar dependency-version: dependency-type: indirect - dependency-name: npm dependency-version: 11.8.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src-node/package-lock.json | 2495 ++++++++++-------------------------- src-node/package.json | 2 +- 2 files changed, 689 insertions(+), 1808 deletions(-) diff --git a/src-node/package-lock.json b/src-node/package-lock.json index e74b9d573..d95b7de1a 100644 --- a/src-node/package-lock.json +++ b/src-node/package-lock.json @@ -14,7 +14,7 @@ "cross-spawn": "^7.0.6", "lmdb": "^2.9.2", "mime-types": "^2.1.35", - "npm": "10.1.0", + "npm": "11.8.0", "open": "^10.1.0", "which": "^2.0.1", "ws": "^8.17.1" @@ -552,17 +552,19 @@ } }, "node_modules/npm": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.1.0.tgz", - "integrity": "sha512-pZ2xybXzNGbJFZEKNbPoEXsE38Xou9VTnxxBk+B3pz0ndsGCs7iWHoUCPSsISU2hjmkWfDkJo3bYKE8RDOg4eg==", + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-11.8.0.tgz", + "integrity": "sha512-n19sJeW+RGKdkHo8SCc5xhSwkKhQUFfZaFzSc+EsYXLjSqIV0tl72aDYQVuzVvfrbysGwdaQsNLNy58J10EBSQ==", "bundleDependencies": [ "@isaacs/string-locale-compare", "@npmcli/arborist", "@npmcli/config", "@npmcli/fs", "@npmcli/map-workspaces", + "@npmcli/metavuln-calculator", "@npmcli/package-json", "@npmcli/promise-spawn", + "@npmcli/redact", "@npmcli/run-script", "@sigstore/tuf", "abbrev", @@ -571,8 +573,6 @@ "chalk", "ci-info", "cli-columns", - "cli-table3", - "columnify", "fastest-levenshtein", "fs-minipass", "glob", @@ -586,7 +586,6 @@ "libnpmdiff", "libnpmexec", "libnpmfund", - "libnpmhook", "libnpmorg", "libnpmpack", "libnpmpublish", @@ -607,7 +606,6 @@ "npm-profile", "npm-registry-fetch", "npm-user-validate", - "npmlog", "p-map", "pacote", "parse-conflict-json", @@ -615,6 +613,7 @@ "qrcode-terminal", "read", "semver", + "spdx-expression-parse", "ssri", "supports-color", "tar", @@ -622,156 +621,120 @@ "tiny-relative-date", "treeverse", "validate-npm-package-name", - "which", - "write-file-atomic" + "which" + ], + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" ], "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^7.1.0", - "@npmcli/config": "^7.2.0", - "@npmcli/fs": "^3.1.0", - "@npmcli/map-workspaces": "^3.0.4", - "@npmcli/package-json": "^5.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.1", - "@sigstore/tuf": "^2.1.0", - "abbrev": "^2.0.0", + "@npmcli/arborist": "^9.1.10", + "@npmcli/config": "^10.5.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/map-workspaces": "^5.0.3", + "@npmcli/metavuln-calculator": "^9.0.3", + "@npmcli/package-json": "^7.0.4", + "@npmcli/promise-spawn": "^9.0.1", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.3", + "@sigstore/tuf": "^4.0.1", + "abbrev": "^4.0.0", "archy": "~1.0.0", - "cacache": "^18.0.0", - "chalk": "^5.3.0", - "ci-info": "^3.8.0", + "cacache": "^20.0.3", + "chalk": "^5.6.2", + "ci-info": "^4.3.1", "cli-columns": "^4.0.0", - "cli-table3": "^0.6.3", - "columnify": "^1.6.0", "fastest-levenshtein": "^1.0.16", "fs-minipass": "^3.0.3", - "glob": "^10.3.3", + "glob": "^13.0.0", "graceful-fs": "^4.2.11", - "hosted-git-info": "^7.0.0", - "ini": "^4.1.1", - "init-package-json": "^6.0.0", - "is-cidr": "^4.0.2", - "json-parse-even-better-errors": "^3.0.0", - "libnpmaccess": "^8.0.0", - "libnpmdiff": "^6.0.1", - "libnpmexec": "^7.0.1", - "libnpmfund": "^4.1.1", - "libnpmhook": "^10.0.0", - "libnpmorg": "^6.0.0", - "libnpmpack": "^6.0.1", - "libnpmpublish": "^9.0.0", - "libnpmsearch": "^7.0.0", - "libnpmteam": "^6.0.0", - "libnpmversion": "^5.0.0", - "make-fetch-happen": "^13.0.0", - "minimatch": "^9.0.3", - "minipass": "^7.0.3", + "hosted-git-info": "^9.0.2", + "ini": "^6.0.0", + "init-package-json": "^8.2.4", + "is-cidr": "^6.0.1", + "json-parse-even-better-errors": "^5.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.0.13", + "libnpmexec": "^10.1.12", + "libnpmfund": "^7.0.13", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.0.13", + "libnpmpublish": "^11.1.3", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.3", + "make-fetch-happen": "^15.0.3", + "minimatch": "^10.1.1", + "minipass": "^7.1.1", "minipass-pipeline": "^1.2.4", "ms": "^2.1.2", - "node-gyp": "^9.4.0", - "nopt": "^7.2.0", - "npm-audit-report": "^5.0.0", - "npm-install-checks": "^6.2.0", - "npm-package-arg": "^11.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-profile": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "npm-user-validate": "^2.0.0", - "npmlog": "^7.0.1", - "p-map": "^4.0.0", - "pacote": "^17.0.4", - "parse-conflict-json": "^3.0.1", - "proc-log": "^3.0.0", + "node-gyp": "^12.1.0", + "nopt": "^9.0.0", + "npm-audit-report": "^7.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.2", + "npm-pick-manifest": "^11.0.3", + "npm-profile": "^12.0.1", + "npm-registry-fetch": "^19.1.1", + "npm-user-validate": "^4.0.0", + "p-map": "^7.0.4", + "pacote": "^21.0.4", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.1.0", "qrcode-terminal": "^0.12.0", - "read": "^2.1.0", - "semver": "^7.5.4", - "ssri": "^10.0.5", - "supports-color": "^9.4.0", - "tar": "^6.1.15", + "read": "^5.0.1", + "semver": "^7.7.3", + "spdx-expression-parse": "^4.0.0", + "ssri": "^13.0.0", + "supports-color": "^10.2.2", + "tar": "^7.5.4", "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", + "tiny-relative-date": "^2.0.2", "treeverse": "^3.0.0", - "validate-npm-package-name": "^5.0.0", - "which": "^4.0.0", - "write-file-atomic": "^5.0.1" + "validate-npm-package-name": "^7.0.2", + "which": "^6.0.0" }, "bin": { "npm": "bin/npm-cli.js", "npx": "bin/npx-cli.js" }, "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@colors/colors": { - "version": "1.5.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", + "node_modules/npm/node_modules/@isaacs/balanced-match": { + "version": "4.0.1", "inBundle": true, "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": "20 || >=22" } }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", + "node_modules/npm/node_modules/@isaacs/brace-expansion": { + "version": "5.0.0", "inBundle": true, "license": "MIT", "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" + "@isaacs/balanced-match": "^4.0.1" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "20 || >=22" } }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", "inBundle": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "ansi-regex": "^6.0.1" + "minipass": "^7.0.4" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=18.0.0" } }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { @@ -780,343 +743,302 @@ "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/agent": { - "version": "2.1.1", + "version": "4.0.0", "inBundle": true, "license": "ISC", "dependencies": { + "agent-base": "^7.1.0", "http-proxy-agent": "^7.0.0", "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.1" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/@npmcli/agent/node_modules/agent-base": { - "version": "7.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/@npmcli/agent/node_modules/http-proxy-agent": { - "version": "7.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/@npmcli/agent/node_modules/https-proxy-agent": { - "version": "7.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/@npmcli/agent/node_modules/socks-proxy-agent": { - "version": "8.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.0.1", - "debug": "^4.3.4", - "socks": "^2.7.1" + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" }, "engines": { - "node": ">= 14" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "7.1.0", + "version": "9.1.10", "inBundle": true, "license": "ISC", "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^3.1.0", - "@npmcli/installed-package-contents": "^2.0.2", - "@npmcli/map-workspaces": "^3.0.2", - "@npmcli/metavuln-calculator": "^7.0.0", - "@npmcli/name-from-folder": "^2.0.0", - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/package-json": "^5.0.0", - "@npmcli/query": "^3.0.0", - "@npmcli/run-script": "^7.0.1", - "bin-links": "^4.0.1", - "cacache": "^18.0.0", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^6.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^2.0.0", + "hosted-git-info": "^9.0.0", "json-stringify-nice": "^1.1.4", - "minimatch": "^9.0.0", - "nopt": "^7.0.0", - "npm-install-checks": "^6.2.0", - "npm-package-arg": "^11.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "npmlog": "^7.0.1", - "pacote": "^17.0.4", - "parse-conflict-json": "^3.0.0", - "proc-log": "^3.0.0", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^9.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.0.0", + "proggy": "^4.0.0", "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^1.0.2", - "read-package-json-fast": "^3.0.2", + "promise-call-limit": "^3.0.1", "semver": "^7.3.7", - "ssri": "^10.0.5", + "ssri": "^13.0.0", "treeverse": "^3.0.0", - "walk-up-path": "^3.0.1" + "walk-up-path": "^4.0.0" }, "bin": { "arborist": "bin/index.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/config": { - "version": "7.2.0", + "version": "10.5.0", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/map-workspaces": "^3.0.2", - "ci-info": "^3.8.0", - "ini": "^4.1.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "read-package-json-fast": "^3.0.2", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^6.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.5", - "walk-up-path": "^3.0.1" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/@npmcli/disparity-colors": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ansi-styles": "^4.3.0" + "walk-up-path": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/fs": { - "version": "3.1.0", + "version": "5.0.0", "inBundle": true, "license": "ISC", "dependencies": { "semver": "^7.3.5" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/git": { - "version": "5.0.3", + "version": "7.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/promise-spawn": "^7.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^9.0.0", - "proc-log": "^3.0.0", - "promise-inflight": "^1.0.1", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", "promise-retry": "^2.0.1", "semver": "^7.3.5", - "which": "^4.0.0" + "which": "^6.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "2.0.2", + "version": "4.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "npm-bundled": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" }, "bin": { - "installed-package-contents": "lib/index.js" + "installed-package-contents": "bin/index.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "3.0.4", + "version": "5.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/name-from-folder": "^2.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0", - "read-package-json-fast": "^3.0.0" + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "7.0.0", + "version": "9.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "cacache": "^18.0.0", - "json-parse-even-better-errors": "^3.0.0", - "pacote": "^17.0.0", + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^5.0.0", + "pacote": "^21.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.5" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "2.0.0", + "version": "4.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "3.0.0", + "version": "5.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "5.0.0", + "version": "7.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^7.0.0", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "proc-log": "^3.0.0", - "semver": "^7.5.3" + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "7.0.0", + "version": "9.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "which": "^4.0.0" + "which": "^6.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@npmcli/query": { - "version": "3.0.0", + "version": "5.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "postcss-selector-parser": "^6.0.10" + "postcss-selector-parser": "^7.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "7.0.1", + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "4.0.0", "inBundle": true, "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^3.0.0", - "@npmcli/promise-spawn": "^7.0.0", - "node-gyp": "^9.0.0", - "read-package-json-fast": "^3.0.0", - "which": "^4.0.0" - }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.3", "inBundle": true, - "license": "MIT", - "optional": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0", + "which": "^6.0.0" + }, "engines": { - "node": ">=14" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@sigstore/bundle": { - "version": "2.1.0", + "version": "4.0.0", "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1" + "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "3.1.0", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.2.1", + "version": "0.5.0", "inBundle": true, "license": "Apache-2.0", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^18.17.0 || >=20.5.0" } }, "node_modules/npm/node_modules/@sigstore/sign": { - "version": "2.1.0", + "version": "4.1.0", "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "make-fetch-happen": "^13.0.0" + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.3", + "proc-log": "^6.1.0", + "promise-retry": "^2.0.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "2.1.0", + "version": "4.0.1", "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/protobuf-specs": "^0.2.1", - "tuf-js": "^2.1.0" + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/@tootallnate/once": { - "version": "2.0.0", + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.1.0", "inBundle": true, - "license": "MIT", + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0" + }, "engines": { - "node": ">= 10" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/@tufjs/canonical-json": { @@ -1128,68 +1050,31 @@ } }, "node_modules/npm/node_modules/@tufjs/models": { - "version": "2.0.0", + "version": "4.1.0", "inBundle": true, "license": "MIT", "dependencies": { "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.3" + "minimatch": "^10.1.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/abbrev": { - "version": "2.0.0", + "version": "4.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/abort-controller": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/agent-base": { - "version": "6.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/npm/node_modules/agentkeepalive": { - "version": "4.5.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/npm/node_modules/aggregate-error": { - "version": "3.1.0", + "version": "7.1.4", "inBundle": true, "license": "MIT", - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, "engines": { - "node": ">=8" + "node": ">= 14" } }, "node_modules/npm/node_modules/ansi-regex": { @@ -1200,22 +1085,8 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "4.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, "node_modules/npm/node_modules/aproba": { - "version": "2.0.0", + "version": "2.1.0", "inBundle": true, "license": "ISC" }, @@ -1224,146 +1095,74 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/are-we-there-yet": { - "version": "4.0.0", + "node_modules/npm/node_modules/bin-links": { + "version": "6.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^4.1.0" + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/base64-js": { - "version": "1.5.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], + "node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/npm/node_modules/bin-links": { - "version": "4.0.2", + "node_modules/npm/node_modules/cacache": { + "version": "20.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "cmd-shim": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "read-cmd-shim": "^4.0.0", - "write-file-atomic": "^5.0.0" + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0", + "unique-filename": "^5.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.2.0", + "node_modules/npm/node_modules/chalk": { + "version": "5.6.2", "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.1", + "node_modules/npm/node_modules/chownr": { + "version": "3.0.0", "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "node_modules/npm/node_modules/buffer": { - "version": "6.0.3", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, - "node_modules/npm/node_modules/builtins": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "18.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/chalk": { - "version": "5.3.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ci-info": { - "version": "3.8.0", + "node_modules/npm/node_modules/ci-info": { + "version": "4.3.1", "funding": [ { "type": "github", @@ -1377,22 +1176,14 @@ } }, "node_modules/npm/node_modules/cidr-regex": { - "version": "3.1.1", + "version": "5.0.1", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "ip-regex": "^4.1.0" + "ip-regex": "5.0.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/clean-stack": { - "version": "2.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" + "node": ">=20" } }, "node_modules/npm/node_modules/cli-columns": { @@ -1407,112 +1198,20 @@ "node": ">= 10" } }, - "node_modules/npm/node_modules/cli-table3": { - "version": "0.6.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.0" - }, - "engines": { - "node": "10.* || >= 12.*" - }, - "optionalDependencies": { - "@colors/colors": "1.5.0" - } - }, - "node_modules/npm/node_modules/clone": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, "node_modules/npm/node_modules/cmd-shim": { - "version": "6.0.1", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/color-support": { - "version": "1.1.3", + "version": "8.0.0", "inBundle": true, "license": "ISC", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/npm/node_modules/columnify": { - "version": "1.6.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "strip-ansi": "^6.0.1", - "wcwidth": "^1.0.0" - }, "engines": { - "node": ">=8.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/concat-map": { - "version": "0.0.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/console-control-strings": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", + "version": "2.0.0", "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 8" + "node": ">= 18" } }, "node_modules/npm/node_modules/cssesc": { @@ -1527,11 +1226,11 @@ } }, "node_modules/npm/node_modules/debug": { - "version": "4.3.4", + "version": "4.4.3", "inBundle": true, "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1542,40 +1241,14 @@ } } }, - "node_modules/npm/node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/defaults": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "dependencies": { - "clone": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/delegates": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/diff": { - "version": "5.1.0", + "version": "8.0.3", "inBundle": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, - "node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", "inBundle": true, @@ -1603,24 +1276,8 @@ "inBundle": true, "license": "MIT" }, - "node_modules/npm/node_modules/event-target-shim": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/events": { - "version": "3.3.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, "node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.1", + "version": "3.1.3", "inBundle": true, "license": "Apache-2.0" }, @@ -1632,21 +1289,6 @@ "node": ">= 4.9.1" } }, - "node_modules/npm/node_modules/foreground-child": { - "version": "3.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/npm/node_modules/fs-minipass": { "version": "3.0.3", "inBundle": true, @@ -1658,50 +1300,17 @@ "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/npm/node_modules/fs.realpath": { - "version": "1.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/function-bind": { - "version": "1.1.1", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/gauge": { - "version": "5.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^4.0.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/npm/node_modules/glob": { - "version": "10.3.3", + "version": "13.0.0", "inBundle": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" + "minimatch": "^10.1.1", + "minipass": "^7.1.2", + "path-scurry": "^2.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -1712,69 +1321,44 @@ "inBundle": true, "license": "ISC" }, - "node_modules/npm/node_modules/has": { - "version": "1.0.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/npm/node_modules/has-unicode": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC" - }, "node_modules/npm/node_modules/hosted-git-info": { - "version": "7.0.0", + "version": "9.0.2", "inBundle": true, "license": "ISC", "dependencies": { - "lru-cache": "^10.0.1" + "lru-cache": "^11.1.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.1.1", + "version": "4.2.0", "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { - "version": "5.0.0", + "version": "7.0.2", "inBundle": true, "license": "MIT", "dependencies": { - "@tootallnate/once": "2", - "agent-base": "6", - "debug": "4" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 6" + "node": ">= 14" } }, "node_modules/npm/node_modules/https-proxy-agent": { - "version": "5.0.1", + "version": "7.0.6", "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "6", + "agent-base": "^7.1.2", "debug": "4" }, "engines": { - "node": ">= 6" - } - }, - "node_modules/npm/node_modules/humanize-ms": { - "version": "1.2.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" + "node": ">= 14" } }, "node_modules/npm/node_modules/iconv-lite": { @@ -1789,34 +1373,15 @@ "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/ieee754": { - "version": "1.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "BSD-3-Clause" - }, "node_modules/npm/node_modules/ignore-walk": { - "version": "6.0.3", + "version": "8.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "minimatch": "^9.0.0" + "minimatch": "^10.0.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/imurmurhash": { @@ -1827,86 +1392,59 @@ "node": ">=0.8.19" } }, - "node_modules/npm/node_modules/indent-string": { - "version": "4.0.0", + "node_modules/npm/node_modules/ini": { + "version": "6.0.0", "inBundle": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/inflight": { - "version": "1.0.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/npm/node_modules/inherits": { - "version": "2.0.4", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/ini": { - "version": "4.1.1", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/init-package-json": { - "version": "6.0.0", + "version": "8.2.4", "inBundle": true, "license": "ISC", "dependencies": { - "npm-package-arg": "^11.0.0", - "promzard": "^1.0.0", - "read": "^2.0.0", - "read-package-json": "^7.0.0", - "semver": "^7.3.5", + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^3.0.1", + "read": "^5.0.1", + "semver": "^7.7.2", "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^5.0.0" + "validate-npm-package-name": "^7.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/ip": { - "version": "2.0.0", + "node_modules/npm/node_modules/ip-address": { + "version": "10.1.0", "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 12" + } }, "node_modules/npm/node_modules/ip-regex": { - "version": "4.3.0", + "version": "5.0.0", "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm/node_modules/is-cidr": { - "version": "4.0.2", + "version": "6.0.1", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { - "cidr-regex": "^3.1.1" + "cidr-regex": "5.0.1" }, "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/is-core-module": { - "version": "2.12.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=20" } }, "node_modules/npm/node_modules/is-fullwidth-code-point": { @@ -1917,39 +1455,20 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/is-lambda": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT" - }, "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/jackspeak": { - "version": "2.2.1", + "version": "3.1.1", "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, + "license": "ISC", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" + "node": ">=16" } }, "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", + "version": "5.0.0", "inBundle": true, "license": "MIT", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/json-stringify-nice": { @@ -1979,207 +1498,195 @@ "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { - "version": "8.0.0", + "version": "10.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "npm-package-arg": "^11.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmdiff": { - "version": "6.0.1", + "version": "8.0.13", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.1.0", - "@npmcli/disparity-colors": "^3.0.0", - "@npmcli/installed-package-contents": "^2.0.2", - "binary-extensions": "^2.2.0", - "diff": "^5.1.0", - "minimatch": "^9.0.0", - "npm-package-arg": "^11.0.0", - "pacote": "^17.0.4", - "tar": "^6.1.13" + "@npmcli/arborist": "^9.1.10", + "@npmcli/installed-package-contents": "^4.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmexec": { - "version": "7.0.1", + "version": "10.1.12", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.1.0", - "@npmcli/run-script": "^7.0.1", - "ci-info": "^3.7.1", - "npm-package-arg": "^11.0.0", - "npmlog": "^7.0.1", - "pacote": "^17.0.4", - "proc-log": "^3.0.0", - "read": "^2.0.0", - "read-package-json-fast": "^3.0.2", + "@npmcli/arborist": "^9.1.10", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^6.0.0", + "promise-retry": "^2.0.1", + "read": "^5.0.1", "semver": "^7.3.7", - "walk-up-path": "^3.0.1" + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmfund": { - "version": "4.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^7.1.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "10.0.0", + "version": "7.0.13", "inBundle": true, "license": "ISC", "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "@npmcli/arborist": "^9.1.10" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmorg": { - "version": "6.0.0", + "version": "8.0.1", "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^19.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmpack": { - "version": "6.0.1", + "version": "9.0.13", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/arborist": "^7.1.0", - "@npmcli/run-script": "^7.0.1", - "npm-package-arg": "^11.0.0", - "pacote": "^17.0.4" + "@npmcli/arborist": "^9.1.10", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmpublish": { - "version": "9.0.0", + "version": "11.1.3", "inBundle": true, "license": "ISC", "dependencies": { - "ci-info": "^3.6.1", - "normalize-package-data": "^6.0.0", - "npm-package-arg": "^11.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.7", - "sigstore": "^2.1.0", - "ssri": "^10.0.5" + "sigstore": "^4.0.0", + "ssri": "^13.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmsearch": { - "version": "7.0.0", + "version": "9.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^19.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmteam": { - "version": "6.0.0", + "version": "8.0.2", "inBundle": true, "license": "ISC", "dependencies": { "aproba": "^2.0.0", - "npm-registry-fetch": "^16.0.0" + "npm-registry-fetch": "^19.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/libnpmversion": { - "version": "5.0.0", + "version": "8.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.3", - "@npmcli/run-script": "^7.0.1", - "json-parse-even-better-errors": "^3.0.0", - "proc-log": "^3.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.7" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/lru-cache": { - "version": "10.0.1", + "version": "11.2.4", "inBundle": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "engines": { - "node": "14 || >=16.14" + "node": "20 || >=22" } }, "node_modules/npm/node_modules/make-fetch-happen": { - "version": "13.0.0", + "version": "15.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", + "@npmcli/agent": "^4.0.0", + "cacache": "^20.0.1", "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", + "minipass-fetch": "^5.0.0", "minipass-flush": "^1.0.5", "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", "promise-retry": "^2.0.1", - "ssri": "^10.0.0" + "ssri": "^13.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/minimatch": { - "version": "9.0.3", + "version": "10.1.1", "inBundle": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^2.0.1" + "@isaacs/brace-expansion": "^5.0.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/npm/node_modules/minipass": { - "version": "7.0.3", + "version": "7.1.2", "inBundle": true, "license": "ISC", "engines": { @@ -2187,38 +1694,27 @@ } }, "node_modules/npm/node_modules/minipass-collect": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-collect/node_modules/minipass": { - "version": "3.3.6", + "version": "2.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" } }, "node_modules/npm/node_modules/minipass-fetch": { - "version": "3.0.4", + "version": "5.0.0", "inBundle": true, "license": "MIT", "dependencies": { "minipass": "^7.0.3", "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" + "minizlib": "^3.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" }, "optionalDependencies": { "encoding": "^0.1.13" @@ -2240,658 +1736,312 @@ "inBundle": true, "license": "ISC", "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-json-stream": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - } - }, - "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minizlib": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/mkdirp": { - "version": "1.0.4", - "inBundle": true, - "license": "MIT", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "1.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/negotiator": { - "version": "0.6.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "9.4.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^7.1.4", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^11.0.3", - "nopt": "^6.0.0", - "npmlog": "^6.0.0", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^2.0.2" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^12.13 || ^14.13 || >=16" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/abbrev": { - "version": "1.1.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/node-gyp/node_modules/are-we-there-yet": { - "version": "3.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { - "version": "1.1.11", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache": { - "version": "17.1.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^3.1.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^7.7.1", - "minipass": "^7.0.3", - "minipass-collect": "^1.0.2", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^4.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11", - "unique-filename": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/brace-expansion": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/glob": { - "version": "10.3.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.0.3", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/minimatch": { - "version": "9.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/cacache/node_modules/minipass": { - "version": "7.0.3", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/gauge": { - "version": "4.0.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.3", - "console-control-strings": "^1.1.0", - "has-unicode": "^2.0.1", - "signal-exit": "^3.0.7", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.5" - }, - "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/glob": { - "version": "7.2.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/lru-cache": { - "version": "7.18.3", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=12" - } - }, - "node_modules/npm/node_modules/node-gyp/node_modules/make-fetch-happen": { - "version": "11.1.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "agentkeepalive": "^4.2.1", - "cacache": "^17.0.0", - "http-cache-semantics": "^4.1.1", - "http-proxy-agent": "^5.0.0", - "https-proxy-agent": "^5.0.0", - "is-lambda": "^1.0.1", - "lru-cache": "^7.7.1", - "minipass": "^5.0.0", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "socks-proxy-agent": "^7.0.0", - "ssri": "^10.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { - "version": "3.1.2", + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", "inBundle": true, "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "minipass": "^3.0.0" }, "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/minipass": { - "version": "5.0.0", + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", "inBundle": true, "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, "engines": { "node": ">=8" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { - "version": "6.0.0", + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "abbrev": "^1.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" + "minipass": "^3.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/npmlog": { - "version": "6.0.2", + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", "inBundle": true, "license": "ISC", "dependencies": { - "are-we-there-yet": "^3.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^4.0.3", - "set-blocking": "^2.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": ">=8" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/readable-stream": { - "version": "3.6.2", + "node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", "inBundle": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "minipass": "^7.1.2" }, "engines": { - "node": ">= 6" + "node": ">= 18" } }, - "node_modules/npm/node_modules/node-gyp/node_modules/signal-exit": { - "version": "3.0.7", + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", "inBundle": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/npm/node_modules/node-gyp/node_modules/which": { - "version": "2.0.2", + "node_modules/npm/node_modules/mute-stream": { + "version": "3.0.0", "inBundle": true, "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "12.1.0", + "inBundle": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^15.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.2", + "tinyglobby": "^0.2.12", + "which": "^6.0.0" }, "bin": { - "node-which": "bin/node-which" + "node-gyp": "bin/node-gyp.js" }, "engines": { - "node": ">= 8" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/nopt": { - "version": "7.2.0", + "version": "9.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "abbrev": "^2.0.0" + "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "6.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-audit-report": { - "version": "5.0.0", + "version": "7.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-bundled": { - "version": "3.0.0", + "version": "5.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "npm-normalize-package-bin": "^3.0.0" + "npm-normalize-package-bin": "^5.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-install-checks": { - "version": "6.2.0", + "version": "8.0.0", "inBundle": true, "license": "BSD-2-Clause", "dependencies": { "semver": "^7.1.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "3.0.1", + "version": "5.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-package-arg": { - "version": "11.0.0", + "version": "13.0.2", "inBundle": true, "license": "ISC", "dependencies": { - "hosted-git-info": "^7.0.0", - "proc-log": "^3.0.0", + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", "semver": "^7.3.5", - "validate-npm-package-name": "^5.0.0" + "validate-npm-package-name": "^7.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-packlist": { - "version": "8.0.0", + "version": "10.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "ignore-walk": "^6.0.0" + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "9.0.0", + "version": "11.0.3", "inBundle": true, "license": "ISC", "dependencies": { - "npm-install-checks": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0", - "npm-package-arg": "^11.0.0", + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", "semver": "^7.3.5" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-profile": { - "version": "9.0.0", + "version": "12.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0" + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "16.0.0", + "version": "19.1.1", "inBundle": true, "license": "ISC", "dependencies": { - "make-fetch-happen": "^13.0.0", + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-json-stream": "^1.0.1", - "minizlib": "^2.1.2", - "npm-package-arg": "^11.0.0", - "proc-log": "^3.0.0" + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/npm-user-validate": { - "version": "2.0.0", + "version": "4.0.0", "inBundle": true, "license": "BSD-2-Clause", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/npmlog": { - "version": "7.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "are-we-there-yet": "^4.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^5.0.0", - "set-blocking": "^2.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/once": { - "version": "1.4.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/p-map": { - "version": "4.0.0", + "version": "7.0.4", "inBundle": true, "license": "MIT", - "dependencies": { - "aggregate-error": "^3.0.0" - }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/npm/node_modules/pacote": { - "version": "17.0.4", + "version": "21.0.4", "inBundle": true, "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", - "cacache": "^18.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", "fs-minipass": "^3.0.0", "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" }, "bin": { - "pacote": "lib/bin.js" + "pacote": "bin/index.js" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/parse-conflict-json": { - "version": "3.0.1", + "version": "5.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "json-parse-even-better-errors": "^3.0.0", + "json-parse-even-better-errors": "^5.0.0", "just-diff": "^6.0.0", "just-diff-apply": "^5.2.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/path-is-absolute": { - "version": "1.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/path-scurry": { - "version": "1.10.1", + "version": "2.0.1", "inBundle": true, "license": "BlueOak-1.0.0", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": "20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "6.0.13", + "version": "7.1.1", "inBundle": true, "license": "MIT", "dependencies": { @@ -2903,19 +2053,19 @@ } }, "node_modules/npm/node_modules/proc-log": { - "version": "3.0.0", + "version": "6.1.0", "inBundle": true, "license": "ISC", "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/process": { - "version": "0.11.10", + "node_modules/npm/node_modules/proggy": { + "version": "4.0.0", "inBundle": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 0.6.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/promise-all-reject-late": { @@ -2927,18 +2077,13 @@ } }, "node_modules/npm/node_modules/promise-call-limit": { - "version": "1.0.2", + "version": "3.0.2", "inBundle": true, "license": "ISC", "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/npm/node_modules/promise-inflight": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", "inBundle": true, @@ -2952,14 +2097,14 @@ } }, "node_modules/npm/node_modules/promzard": { - "version": "1.0.0", + "version": "3.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "read": "^2.0.0" + "read": "^5.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/qrcode-terminal": { @@ -2968,203 +2113,53 @@ "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" } - }, - "node_modules/npm/node_modules/read": { - "version": "2.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "~1.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/read-package-json": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/readable-stream": { - "version": "4.4.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "abort-controller": "^3.0.0", - "buffer": "^6.0.3", - "events": "^3.3.0", - "process": "^0.11.10" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/rimraf": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { - "version": "1.1.11", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/npm/node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { - "version": "3.1.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/npm/node_modules/safe-buffer": { - "version": "5.2.1", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/npm/node_modules/semver": { - "version": "7.5.4", + }, + "node_modules/npm/node_modules/read": { + "version": "5.0.1", "inBundle": true, "license": "ISC", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "mute-stream": "^3.0.0" }, "engines": { - "node": ">=10" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "node_modules/npm/node_modules/read-cmd-shim": { "version": "6.0.0", "inBundle": true, "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, "engines": { - "node": ">=10" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/set-blocking": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", "inBundle": true, "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", "inBundle": true, "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.7.3", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/npm/node_modules/signal-exit": { - "version": "4.0.2", + "version": "4.1.0", "inBundle": true, "license": "ISC", "engines": { @@ -3175,17 +2170,19 @@ } }, "node_modules/npm/node_modules/sigstore": { - "version": "2.1.0", + "version": "4.1.0", "inBundle": true, "license": "Apache-2.0", "dependencies": { - "@sigstore/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.1.0", - "@sigstore/tuf": "^2.1.0" + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.1.0", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.0", + "@sigstore/tuf": "^4.0.1", + "@sigstore/verify": "^3.1.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/smart-buffer": { @@ -3198,29 +2195,29 @@ } }, "node_modules/npm/node_modules/socks": { - "version": "2.7.1", + "version": "2.8.7", "inBundle": true, "license": "MIT", "dependencies": { - "ip": "^2.0.0", + "ip-address": "^10.0.1", "smart-buffer": "^4.2.0" }, "engines": { - "node": ">= 10.13.0", + "node": ">= 10.0.0", "npm": ">= 3.0.0" } }, "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "7.0.0", + "version": "8.0.5", "inBundle": true, "license": "MIT", "dependencies": { - "agent-base": "^6.0.2", - "debug": "^4.3.3", - "socks": "^2.6.2" + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" }, "engines": { - "node": ">= 10" + "node": ">= 14" } }, "node_modules/npm/node_modules/spdx-correct": { @@ -3232,13 +2229,22 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.3.0", + "version": "2.5.0", "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "3.0.1", + "version": "4.0.0", "inBundle": true, "license": "MIT", "dependencies": { @@ -3247,27 +2253,19 @@ } }, "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.13", + "version": "3.0.22", "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { - "version": "10.0.5", + "version": "13.0.0", "inBundle": true, "license": "ISC", "dependencies": { "minipass": "^7.0.3" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/string_decoder": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/string-width": { @@ -3283,20 +2281,6 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/strip-ansi": { "version": "6.0.1", "inBundle": true, @@ -3308,84 +2292,91 @@ "node": ">=8" } }, - "node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/npm/node_modules/supports-color": { - "version": "9.4.0", + "version": "10.2.2", "inBundle": true, "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/npm/node_modules/tar": { - "version": "6.1.15", + "version": "7.5.4", "inBundle": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" } }, - "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", + "node_modules/npm/node_modules/tar/node_modules/yallist": { + "version": "5.0.0", "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", "inBundle": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.15", + "inBundle": true, + "license": "MIT", "dependencies": { - "yallist": "^4.0.0" + "fdir": "^6.5.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/npm/node_modules/tar/node_modules/minipass": { - "version": "5.0.0", + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", "inBundle": true, - "license": "ISC", + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", "inBundle": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } }, "node_modules/npm/node_modules/treeverse": { "version": "3.0.0", @@ -3396,38 +2387,38 @@ } }, "node_modules/npm/node_modules/tuf-js": { - "version": "2.1.0", + "version": "4.1.0", "inBundle": true, "license": "MIT", "dependencies": { - "@tufjs/models": "2.0.0", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.0" + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/unique-filename": { - "version": "3.0.0", + "version": "5.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "unique-slug": "^4.0.0" + "unique-slug": "^6.0.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/unique-slug": { - "version": "4.0.0", + "version": "6.0.0", "inBundle": true, "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/util-deprecate": { @@ -3444,157 +2435,47 @@ "spdx-expression-parse": "^3.0.0" } }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/walk-up-path": { + "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { "version": "3.0.1", "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/wcwidth": { - "version": "1.0.1", - "inBundle": true, "license": "MIT", "dependencies": { - "defaults": "^1.0.3" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/npm/node_modules/which": { - "version": "4.0.0", + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "7.0.2", "inBundle": true, "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, "engines": { - "node": "^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/which/node_modules/isexe": { - "version": "3.1.1", + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", "inBundle": true, "license": "ISC", "engines": { - "node": ">=16" + "node": "20 || >=22" } }, - "node_modules/npm/node_modules/wide-align": { - "version": "1.1.5", + "node_modules/npm/node_modules/which": { + "version": "6.0.0", "inBundle": true, "license": "ISC", "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" + "isexe": "^3.1.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" + "bin": { + "node-which": "bin/which.js" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/wrappy": { - "version": "1.0.2", - "inBundle": true, - "license": "ISC" - }, "node_modules/npm/node_modules/write-file-atomic": { - "version": "5.0.1", + "version": "7.0.0", "inBundle": true, "license": "ISC", "dependencies": { @@ -3602,7 +2483,7 @@ "signal-exit": "^4.0.1" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm/node_modules/yallist": { diff --git a/src-node/package.json b/src-node/package.json index fc25d8e4f..67411e1a2 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -21,7 +21,7 @@ "dependencies": { "@phcode/fs": "^4.0.2", "open": "^10.1.0", - "npm": "10.1.0", + "npm": "11.8.0", "ws": "^8.17.1", "lmdb": "^2.9.2", "mime-types": "^2.1.35", From 70fc688195f70360c79519c72c307a5725babdcf Mon Sep 17 00:00:00 2001 From: abose Date: Wed, 28 Jan 2026 06:20:08 +0000 Subject: [PATCH 15/91] ci: bump patch version to 5.1.1 --- package.json | 6 +++--- src-node/package.json | 6 +++--- src/config.json | 4 ++-- src/index.html | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 9b6bd9c40..f539312be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "phoenix", - "version": "5.1.0-0", - "apiVersion": "5.1.0", + "version": "5.1.1-0", + "apiVersion": "5.1.1", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" @@ -121,4 +121,4 @@ "tinycolor2": "^1.4.2", "underscore": "^1.13.4" } -} +} \ No newline at end of file diff --git a/src-node/package.json b/src-node/package.json index 67411e1a2..badcd55ed 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -1,8 +1,8 @@ { "name": "@phcode/node-core", "description": "Phoenix Node Core", - "version": "5.1.0-0", - "apiVersion": "5.1.0", + "version": "5.1.1-0", + "apiVersion": "5.1.1", "keywords": [], "author": "arun@core.ai", "homepage": "https://github.com/phcode-dev/phoenix", @@ -29,4 +29,4 @@ "which": "^2.0.1", "@expo/sudo-prompt": "^9.3.2" } -} +} \ No newline at end of file diff --git a/src/config.json b/src/config.json index 8485693c9..e3182d669 100644 --- a/src/config.json +++ b/src/config.json @@ -46,8 +46,8 @@ "bugsnagEnv": "development" }, "name": "Phoenix Code", - "version": "5.1.0-0", - "apiVersion": "5.1.0", + "version": "5.1.1-0", + "apiVersion": "5.1.1", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" diff --git a/src/index.html b/src/index.html index 6a052f7f1..842b67ceb 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,7 @@ - + Phoenix Desktop Metrics emitter to GA. - \ No newline at end of file + diff --git a/src/utils/Metrics.js b/src/utils/Metrics.js index 7e6ad646b..19c72b3bb 100644 --- a/src/utils/Metrics.js +++ b/src/utils/Metrics.js @@ -196,10 +196,14 @@ define(function (require, exports, module) { function _sendNativeGAEvent(analyticsID, customUserID, events=[]) { if(window.__TAURI__){ - return _sendTauriGAEvent(analyticsID, customUserID, events=[]); + return _sendTauriGAEvent(analyticsID, customUserID, events); } if(window.__ELECTRON__){ - // todo electron send event to metrics window with electron + window.electronAPI.sendHealthMetric({ + analyticsID: analyticsID, + customUserID: customUserID, + events: events + }); return; } console.error("Metrics send event failed. Unknown native platform"); From b18dfe0c5cac554690aefe164b4393b374caf979 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 20:04:04 +0530 Subject: [PATCH 32/91] chore: f12 to open devtools in electron test runner window --- test/SpecRunner.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test/SpecRunner.html b/test/SpecRunner.html index 9d910e9be..ce16c266d 100644 --- a/test/SpecRunner.html +++ b/test/SpecRunner.html @@ -207,6 +207,13 @@ }); } setupElectronBootVars(); + // F12 to toggle dev tools in Electron + document.addEventListener('keydown', function(e) { + if (e.key === 'F12') { + e.preventDefault(); + window.electronAPI.toggleDevTools(); + } + }); } From 18e5a3fdda214158b71e48a36faef42c45877a40 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 20:26:10 +0530 Subject: [PATCH 33/91] fix: add missing electon test api injection --- src/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.html b/src/index.html index 136ec1f45..7f6159b56 100644 --- a/src/index.html +++ b/src/index.html @@ -175,6 +175,7 @@ console.warn("Phoenix is loaded in iframe, attempting to use electron APIs from window.top"); window.electronAppAPI = window.top.window.electronAppAPI; window.electronFSAPI = window.top.window.electronFSAPI; + window.electronAPI = window.top.window.electronAPI; } if(window.__TAURI__ || window.__ELECTRON__) { window.__IS_NATIVE_SHELL__ = true; From d8974093973ac5fdc4068720448e68fae20b180a Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 20:33:03 +0530 Subject: [PATCH 34/91] fix: integ tests starts running in dev mode --- src/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/index.html b/src/index.html index 7f6159b56..a804594e2 100644 --- a/src/index.html +++ b/src/index.html @@ -173,6 +173,7 @@ // this means that we are loaded in an iframe in the specrunner. Electron doesnt expose APIs // in its iframes, so we directly use the top most windows electron api objects for tests to run properly. console.warn("Phoenix is loaded in iframe, attempting to use electron APIs from window.top"); + window.__ELECTRON__ = true; window.electronAppAPI = window.top.window.electronAppAPI; window.electronFSAPI = window.top.window.electronFSAPI; window.electronAPI = window.top.window.electronAPI; From 8fd4f086e4de1279f2b2890521fda9142572dfd8 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 21:20:19 +0530 Subject: [PATCH 35/91] test: test runner cli processing in electron --- test/UnitTestReporter.js | 30 +++++++++++++++++++------ test/index-dist-test.html | 46 +++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 16 deletions(-) diff --git a/test/UnitTestReporter.js b/test/UnitTestReporter.js index 995b62306..e1a541e19 100644 --- a/test/UnitTestReporter.js +++ b/test/UnitTestReporter.js @@ -65,18 +65,34 @@ define(function (require, exports, module) { return ''; } + function hasCliFlag(args, flagName) { + return args.some(arg => arg === `--${flagName}` || arg.startsWith(`--${flagName}=`)); + } + function quitIfNeeded(exitStatus) { - if(!window.__TAURI__){ + const isTauri = !!window.__TAURI__; + const isElectron = !!window.electronAppAPI?.isElectron; + + if (!isTauri && !isElectron) { return; } + const WAIT_TIME_TO_COMPLETE_TEST_LOGGING_SEC = 10; console.log("Scheduled Quit in Seconds: ", WAIT_TIME_TO_COMPLETE_TEST_LOGGING_SEC); - setTimeout(()=>{ - window.__TAURI__.cli.getMatches().then(matches=>{ - if(matches && matches.args["quit-when-done"] && matches.args["quit-when-done"].occurrences) { - window.__TAURI__.process.exit(exitStatus); - } - }); + setTimeout(() => { + if (isTauri) { + window.__TAURI__.cli.getMatches().then(matches => { + if (matches && matches.args["quit-when-done"] && matches.args["quit-when-done"].occurrences) { + window.__TAURI__.process.exit(exitStatus); + } + }); + } else if (isElectron) { + window.electronAppAPI.getCliArgs().then(args => { + if (hasCliFlag(args, 'quit-when-done')) { + window.electronAppAPI.quitApp(exitStatus); + } + }); + } }, WAIT_TIME_TO_COMPLETE_TEST_LOGGING_SEC * 1000); } diff --git a/test/index-dist-test.html b/test/index-dist-test.html index b0390820b..63dbe9ba7 100644 --- a/test/index-dist-test.html +++ b/test/index-dist-test.html @@ -4,20 +4,48 @@ Starting tests... From d8aa90ee78deb050b7fd2feeeb650549cb813266 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 21:38:08 +0530 Subject: [PATCH 36/91] chore: test framework didnt exist with -q cli flag --- test/UnitTestReporter.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test/UnitTestReporter.js b/test/UnitTestReporter.js index e1a541e19..9894b543d 100644 --- a/test/UnitTestReporter.js +++ b/test/UnitTestReporter.js @@ -65,8 +65,12 @@ define(function (require, exports, module) { return ''; } - function hasCliFlag(args, flagName) { - return args.some(arg => arg === `--${flagName}` || arg.startsWith(`--${flagName}=`)); + function hasCliFlag(args, flagName, shortFlag) { + return args.some(arg => + arg === `--${flagName}` || + arg.startsWith(`--${flagName}=`) || + (shortFlag && arg === `-${shortFlag}`) + ); } function quitIfNeeded(exitStatus) { @@ -88,7 +92,7 @@ define(function (require, exports, module) { }); } else if (isElectron) { window.electronAppAPI.getCliArgs().then(args => { - if (hasCliFlag(args, 'quit-when-done')) { + if (hasCliFlag(args, 'quit-when-done', 'q')) { window.electronAppAPI.quitApp(exitStatus); } }); From 4c92647d168f682ec40366fd880edcd45a62a4d1 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 22:54:54 +0530 Subject: [PATCH 37/91] fix: unit tests should work in electron as well part 1 --- test/SpecRunner.html | 4 ++++ test/spec/ExtensionInstallation-test.js | 5 +++-- test/spec/ExtensionLoader-test.js | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/test/SpecRunner.html b/test/SpecRunner.html index ce16c266d..1665f48c2 100644 --- a/test/SpecRunner.html +++ b/test/SpecRunner.html @@ -213,6 +213,10 @@ e.preventDefault(); window.electronAPI.toggleDevTools(); } + if (e.key === 'F5') { + e.preventDefault(); + location.reload(); + } }); } diff --git a/test/spec/ExtensionInstallation-test.js b/test/spec/ExtensionInstallation-test.js index 8c91e42ca..b8d2120ba 100644 --- a/test/spec/ExtensionInstallation-test.js +++ b/test/spec/ExtensionInstallation-test.js @@ -31,7 +31,8 @@ define(function (require, exports, module) { const testFilePath = SpecRunnerUtils.getTestPath("/spec/extension-test-files"); - const tempDirectory = window.__TAURI__ ? Phoenix.VFS.getTauriAssetServeDir() + "tests": SpecRunnerUtils.getTempDirectory(); + const tempDirectory = Phoenix.isNativeApp ? + Phoenix.VFS.getTauriAssetServeDir() + "tests": SpecRunnerUtils.getTempDirectory(); const extensionsRoot = tempDirectory + "/extensions"; const basicValidSrc = testFilePath + "/basic-valid-extension.zip", @@ -79,7 +80,7 @@ define(function (require, exports, module) { beforeAll(async function () { await SpecRunnerUtils.ensureExistsDirAsync(tempDirectory); - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ basicValid = tempDirectory + "/basic-valid-extension.zip"; missingNameVersion = tempDirectory + "/missing-name-version.zip"; missingNameVersion = tempDirectory + "/missing-name-version.zip"; diff --git a/test/spec/ExtensionLoader-test.js b/test/spec/ExtensionLoader-test.js index 0b06581e3..291b3efed 100644 --- a/test/spec/ExtensionLoader-test.js +++ b/test/spec/ExtensionLoader-test.js @@ -32,7 +32,7 @@ define(function (require, exports, module) { SpecRunnerUtils = require("spec/SpecRunnerUtils"); const testPathSrc = SpecRunnerUtils.getTestPath("/spec/ExtensionLoader-test-files"); - const testPath = window.__TAURI__ ? Phoenix.VFS.getTauriAssetServeDir() + "tests": SpecRunnerUtils.getTempDirectory(); + const testPath = Phoenix.isNativeApp ? Phoenix.VFS.getTauriAssetServeDir() + "tests": SpecRunnerUtils.getTempDirectory(); describe("ExtensionLoader", function () { From ee70b252938617943ec253f4a938533ac19506e4 Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 23:04:55 +0530 Subject: [PATCH 38/91] fix: all unit tests working in electron --- test/spec/ExtensionManager-test.js | 2 +- test/spec/LowLevelFileIO-test.js | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/test/spec/ExtensionManager-test.js b/test/spec/ExtensionManager-test.js index 722982895..5322c8099 100644 --- a/test/spec/ExtensionManager-test.js +++ b/test/spec/ExtensionManager-test.js @@ -49,7 +49,7 @@ define(function (require, exports, module) { mockExtensionList = require("text!spec/ExtensionManager-test-files/mockExtensionList.json"), mockRegistry; - const testPath = window.__TAURI__ ? + const testPath = Phoenix.isNativeApp ? Phoenix.VFS.getTauriAssetServeDir() + "tests" : SpecRunnerUtils.getTempDirectory(); const testSrc = SpecRunnerUtils.getTestPath("/spec/ExtensionManager-test-files"); diff --git a/test/spec/LowLevelFileIO-test.js b/test/spec/LowLevelFileIO-test.js index 5fe7063fd..3ec05e1cf 100644 --- a/test/spec/LowLevelFileIO-test.js +++ b/test/spec/LowLevelFileIO-test.js @@ -797,7 +797,7 @@ define(function (require, exports, module) { describe("specialDirectories", function () { it("should have an application support directory", async function () { // these tests are here as these are absolute unchanging dir convention used by phoenix. - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ const appSupportDIR = window.fs.getTauriVirtualPath(window._tauriBootVars.appLocalDir); expect(brackets.app.getApplicationSupportDirectory().startsWith("/tauri/")).toBeTrue(); expect(brackets.app.getApplicationSupportDirectory()).toBe(appSupportDIR); @@ -807,7 +807,7 @@ define(function (require, exports, module) { }); it("should have a user documents directory", function () { // these tests are here as these are absolute unchanging dir convention used by phoenix. - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ const documentsDIR = window.fs.getTauriVirtualPath(window._tauriBootVars.documentDir); expect(brackets.app.getUserDocumentsDirectory().startsWith("/tauri/")).toBeTrue(); expect(brackets.app.getUserDocumentsDirectory()).toBe(documentsDIR); @@ -817,7 +817,7 @@ define(function (require, exports, module) { }); it("should have a user projects directory", function () { // these tests are here as these are absolute unchanging dir convention used by phoenix. - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ const documentsDIR = window.fs.getTauriVirtualPath(window._tauriBootVars.documentDir); const appName = window._tauriBootVars.appname; const userProjectsDir = `${documentsDIR}${appName}/`; @@ -829,7 +829,7 @@ define(function (require, exports, module) { }); it("should have a temp directory", function () { // these tests are here as these are absolute unchanging dir convention used by phoenix. - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ let tempDIR = window.fs.getTauriVirtualPath(window._tauriBootVars.tempDir); if(!tempDIR.endsWith("/")){ tempDIR = `${tempDIR}/`; @@ -844,7 +844,7 @@ define(function (require, exports, module) { }); it("should have extensions directory", function () { // these tests are here as these are absolute unchanging dir convention used by phoenix. - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ const appSupportDIR = window.fs.getTauriVirtualPath(window._tauriBootVars.appLocalDir); const extensionsDir = `${appSupportDIR}assets/extensions/`; expect(brackets.app.getExtensionsDirectory().startsWith("/tauri/")).toBeTrue(); @@ -855,7 +855,7 @@ define(function (require, exports, module) { }); it("should get virtual serving directory from virtual serving URL in browser", async function () { - if(window.__TAURI__){ + if(Phoenix.isNativeApp){ return; } expect(brackets.VFS.getPathForVirtualServingURL(`${window.fsServerUrl}blinker`)).toBe("/blinker"); @@ -866,7 +866,7 @@ define(function (require, exports, module) { }); it("should not get virtual serving directory from virtual serving URL in tauri", async function () { - if(!window.__TAURI__){ + if(!Phoenix.isNativeApp){ return; } expect(window.fsServerUrl).not.toBeDefined(); From 56b6d360e2e53a9ea81a40dee04d9ef91e0ab75a Mon Sep 17 00:00:00 2001 From: abose Date: Fri, 30 Jan 2026 23:10:43 +0530 Subject: [PATCH 39/91] fix: test suite non clickable after test run --- test/spec/ExtensionManager-test.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/spec/ExtensionManager-test.js b/test/spec/ExtensionManager-test.js index 5322c8099..2571c3328 100644 --- a/test/spec/ExtensionManager-test.js +++ b/test/spec/ExtensionManager-test.js @@ -808,6 +808,12 @@ define(function (require, exports, module) { }); }); + afterEach(function () { + // Clean up any lingering dialogs + Dialogs.cancelModalDialogIfOpen("install-extension-dialog"); + $(".modal-wrapper").remove(); + }); + it("should set flag to keep local files for new installs", async function () { var filename = "/path/to/downloaded/file.zip", file = FileSystem.getFileForPath(filename), From 4ae5507add33e384cf7d45203db492d942089a85 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 13:04:02 +0530 Subject: [PATCH 40/91] test: electron platfrom tests --- test/UnitTestSuite.js | 1 + test/spec/Electron-platform-test.html | 46 +++ test/spec/Electron-platform-test.js | 448 ++++++++++++++++++++++++++ 3 files changed, 495 insertions(+) create mode 100644 test/spec/Electron-platform-test.html create mode 100644 test/spec/Electron-platform-test.js diff --git a/test/UnitTestSuite.js b/test/UnitTestSuite.js index e3f9a3e52..bba6e12ea 100644 --- a/test/UnitTestSuite.js +++ b/test/UnitTestSuite.js @@ -23,6 +23,7 @@ define(function (require, exports, module) { require("spec/Phoenix-platform-test"); require("spec/Tauri-platform-test"); + require("spec/Electron-platform-test"); require("spec/trust-ring-test"); require("spec/utframework-suite-test"); require("spec/Async-test"); diff --git a/test/spec/Electron-platform-test.html b/test/spec/Electron-platform-test.html new file mode 100644 index 000000000..e2122901e --- /dev/null +++ b/test/spec/Electron-platform-test.html @@ -0,0 +1,46 @@ + + + + + Test electron apis accessible + + + +sending event with electron api... + + diff --git a/test/spec/Electron-platform-test.js b/test/spec/Electron-platform-test.js new file mode 100644 index 000000000..d91e16b51 --- /dev/null +++ b/test/spec/Electron-platform-test.js @@ -0,0 +1,448 @@ +/* + * GNU AGPL-3.0 License + * + * Copyright (c) 2021 - present core.ai . All rights reserved. + * Original work Copyright (c) 2013 - 2021 Adobe Systems Incorporated. All rights reserved. + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License + * for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see https://opensource.org/licenses/AGPL-3.0. + * + */ + +/*global describe, it, expect, beforeEach, afterEach, awaitsFor, fs, path, jasmine, expectAsync*/ + +define(function (require, exports, module) { + if(!window.__ELECTRON__) { + return; + } + + const SpecRunnerUtils = require("spec/SpecRunnerUtils"); + + describe("unit: Electron Platform Tests", function () { + + beforeEach(async function () { + + }); + + afterEach(async function () { + + }); + + describe("asset url tests", function () { + it("Should be able to fetch files in {appLocalData}/assets folder", async function () { + const appLocalData = fs.getTauriVirtualPath(await window.electronFSAPI.appLocalDataDir()); + expect(await SpecRunnerUtils.pathExists(appLocalData, true)).toBeTrue(); + expect(appLocalData.split("/")[1]).toEql("tauri"); // should be /tauri/applocaldata/path + + // now write a test html file to the assets folder + const assetHTMLPath = `${appLocalData}/assets/a9322657236.html`; + const assetHtmlText = "Hello world random37834324"; + await SpecRunnerUtils.ensureExistsDirAsync(path.dirname(assetHTMLPath)); + await SpecRunnerUtils.createTextFileAsync(assetHTMLPath, assetHtmlText); + + const appLocalDataPlatformPath = fs.getTauriPlatformPath(assetHTMLPath); + const appLocalDataURL = window.electronAPI.convertToAssetURL(appLocalDataPlatformPath); + + const fetchedData = await ((await fetch(appLocalDataURL)).text()); + expect(fetchedData).toEqual(assetHtmlText); + + // delete test file + await SpecRunnerUtils.deletePathAsync(assetHTMLPath); + }); + + async function testAssetNotAccessibleFolder(platformPath) { + const assets = fs.getTauriVirtualPath(platformPath); + expect(assets.split("/")[1]).toEql("tauri"); // should be /tauri/applocaldata/path + + // now write a test html file to the assets folder + const assetHTMLPath = `${assets}/a9322657236.html`; + const assetHtmlText = "Hello world random37834324"; + await SpecRunnerUtils.createTextFileAsync(assetHTMLPath, assetHtmlText); + + const appLocalDataPlatformPath = fs.getTauriPlatformPath(assetHTMLPath); + const appLocalDataURL = window.electronAPI.convertToAssetURL(appLocalDataPlatformPath); + + let response; + try{ + response = await fetch(appLocalDataURL); + } catch (e) { + // Network error is expected + } + // Electron returns 403 for unauthorized paths instead of throwing + expect(!response || response.status === 403).toBeTrue(); + + // delete test file + await SpecRunnerUtils.deletePathAsync(assetHTMLPath); + } + + it("Should not be able to fetch files in documents folder", async function () { + // unfortunately for tests, this is set to appdata/testDocuments. + // we cant set this to documentDir() as in github actions, + // the user documents directory may not be accessible + await testAssetNotAccessibleFolder(window._tauriBootVars.documentDir); + }); + + it("Should not be able to fetch files in appLocalData folder", async function () { + await testAssetNotAccessibleFolder(await window.electronFSAPI.appLocalDataDir()); + }); + + it("Should NOT have electronAPI access from asset:// protocol", async function () { + // This test verifies that content loaded from asset:// URLs is sandboxed + // and does not have access to Electron APIs (matching Tauri's security posture) + const appLocalData = fs.getTauriVirtualPath(await window.electronFSAPI.appLocalDataDir()); + const securityTestPath = `${appLocalData}/assets/security-test-${Date.now()}.html`; + const SECURITY_TEST_KEY = 'ELECTRON_ASSET_SECURITY_TEST_' + Date.now(); + + // Create the security test HTML in assets folder + // This script will try to use electronAPI if available and report back + const securityTestHtml = ` +Security Test`; + + await SpecRunnerUtils.ensureExistsDirAsync(path.dirname(securityTestPath)); + await SpecRunnerUtils.createTextFileAsync(securityTestPath, securityTestHtml); + + // Get the asset:// URL for the test file + const platformPath = fs.getTauriPlatformPath(securityTestPath); + const assetURL = window.electronAPI.convertToAssetURL(platformPath); + + // Clear any previous test result + await window.electronAPI.putItem(SECURITY_TEST_KEY, null); + + // Try to open a window with the asset:// URL + let windowLabel = null; + try { + windowLabel = await window.electronAPI.createPhoenixWindow(assetURL, { + windowTitle: 'Security Test', + width: 400, + height: 300, + isExtension: true + }); + } catch (e) { + // If window creation fails for asset:// URLs, that's acceptable security behavior + console.log("Window creation blocked for asset:// URL (expected):", e.message); + } + + if (windowLabel) { + // Window was created - wait for it to load and potentially try to use APIs + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Check if the sandboxed window was able to use electronAPI + const items = await window.electronAPI.getAllItems(); + const testResult = items[SECURITY_TEST_KEY]; + + if (testResult) { + const parsed = JSON.parse(testResult); + // SECURITY CHECK: If we got a result, verify no API access was possible + // If any of these are true, it's a security vulnerability + expect(parsed.hasElectronAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronAPI access" + ).toBeFalse(); + expect(parsed.hasElectronFSAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronFSAPI access" + ).toBeFalse(); + expect(parsed.hasElectronAppAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronAppAPI access" + ).toBeFalse(); + } + // If no result was stored, the window couldn't access APIs - test passes + + // Close the security test window by its label + try { + await window.electronAPI.closeWindowByLabel(windowLabel); + } catch (e) { + console.warn("Could not close security test window:", e); + } + } + + // Cleanup + await SpecRunnerUtils.deletePathAsync(securityTestPath); + }); + + // Unique key for inter-window communication + const ELECTRON_TEST_SIGNAL_KEY = 'ELECTRON_PLATFORM_TEST_SIGNAL'; + + function createWebView() { + return new Promise((resolve, reject)=>{ + let currentURL = new URL(location.href); + let pathParts = currentURL.pathname.split('/'); + pathParts[pathParts.length - 1] = 'spec/Electron-platform-test.html'; + currentURL.pathname = pathParts.join('/'); + + let newURL = currentURL.href; + Phoenix.app.openURLInPhoenixWindow(newURL) + .then(electronWindow =>{ + expect(electronWindow.label.startsWith("extn-")).toBeTrue(); + expect(electronWindow.isNativeWindow).toBeTrue(); + + // For Electron, we use shared storage to communicate between windows + // Poll for the signal from the child window + const pollInterval = setInterval(async () => { + try { + const items = await window.electronAPI.getAllItems(); + if (items && items[ELECTRON_TEST_SIGNAL_KEY] === electronWindow.label) { + clearInterval(pollInterval); + // Clear the signal + await window.electronAPI.putItem(ELECTRON_TEST_SIGNAL_KEY, null); + // Create a window-like object with close method + const winLabel = electronWindow.label; + resolve({ + label: winLabel, + close: async function() { + // Signal the child window to close itself + const closeKey = ELECTRON_TEST_SIGNAL_KEY + + '_CLOSE_' + winLabel; + await window.electronAPI.putItem(closeKey, true); + } + }); + } + } catch (e) { + // Ignore polling errors + } + }, 100); + + // Timeout after 10 seconds + setTimeout(() => { + clearInterval(pollInterval); + reject(new Error('Timeout waiting for child window signal')); + }, 10000); + }).catch(reject); + }); + } + + it("Should be able to spawn electron windows", async function () { + const electronWindow = await createWebView(); + await electronWindow.close(); + // Wait for window to actually close + await new Promise(resolve => setTimeout(resolve, 500)); + }); + + it("Should be able to get process ID", async function () { + const processID = await Phoenix.app.getProcessID(); + expect(processID).toEqual(jasmine.any(Number)); + }); + + const maxWindows = 25; + it(`Should be able to spawn ${maxWindows} electron windows`, async function () { + const electronWindows = []; + for(let i=0; i setTimeout(resolve, 1000)); + }, 120000); + }); + + describe("Credentials OTP API Tests", function () { + const scopeName = "testScope"; + const trustRing = window.specRunnerTestKernalModeTrust; + const TEST_TRUST_KEY_NAME = "testTrustKey"; + + function decryptCreds(creds) { + return trustRing.AESDecryptString(creds, trustRing.aesKeys.key, trustRing.aesKeys.iv); + } + + beforeEach(async function () { + // Cleanup before running tests + await window.electronAPI.deleteCredential(scopeName).catch(() => {}); + }); + + afterEach(async function () { + // Cleanup after tests + await window.electronAPI.deleteCredential(scopeName).catch(() => {}); + }); + + if(Phoenix.isTestWindowGitHubActions && Phoenix.platform === "linux"){ + // Credentials test doesn't work in GitHub actions in linux desktop as the runner cant reach key ring. + it("Should not run in github actions in linux desktop", async function () { + expect(1).toEqual(1); + }); + return; + } + + describe("Credential Storage & OTP Generation", function () { + it("Should store credentials successfully", async function () { + const randomUUID = crypto.randomUUID(); + await expectAsync( + window.electronAPI.storeCredential(scopeName, randomUUID) + ).toBeResolved(); + }); + + it("Should get credentials as encrypted string", async function () { + const randomUUID = crypto.randomUUID(); + await window.electronAPI.storeCredential(scopeName, randomUUID); + + const response = await window.electronAPI.getCredential(scopeName); + expect(response).toBeDefined(); + expect(response).not.toEqual(randomUUID); + }); + + it("Should retrieve and decrypt set credentials with kernal mode keys", async function () { + const randomUUID = crypto.randomUUID(); + await window.electronAPI.storeCredential(scopeName, randomUUID); + + const creds = await window.electronAPI.getCredential(scopeName); + expect(creds).toBeDefined(); + const decryptedString = await decryptCreds(creds); + expect(decryptedString).toEqual(randomUUID); + }); + + it("Should return an error if credentials do not exist", async function () { + const response = await window.electronAPI.getCredential(scopeName); + expect(response).toBeNull(); + }); + + it("Should delete stored credentials", async function () { + const randomUUID = crypto.randomUUID(); + await window.electronAPI.storeCredential(scopeName, randomUUID); + + // Ensure credential exists + let creds = await window.electronAPI.getCredential(scopeName); + expect(creds).toBeDefined(); + + // Delete credential + await expectAsync( + window.electronAPI.deleteCredential(scopeName) + ).toBeResolved(); + + // Ensure credential is deleted + creds = await window.electronAPI.getCredential(scopeName); + expect(creds).toBeNull(); + }); + + it("Should handle deletion of non-existent credentials gracefully", async function () { + let error; + try { + await window.electronAPI.deleteCredential(scopeName); + } catch (err) { + error = err; + } + + // The test should fail if no error was thrown + expect(error).toBeDefined(); + + // Check for OS-specific error messages + const expectedErrors = [ + "No matching entry found in secure storage", // Common error on Linux/macOS + "The specified item could not be found in the keychain", // macOS Keychain + "Element not found" // Windows Credential Manager + ]; + + const isExpectedError = expectedErrors.some(msg => error.toString().includes(msg)); + expect(isExpectedError).toBeTrue(); + }); + + it("Should overwrite existing credentials when storing with the same scope", async function () { + const oldUUID = crypto.randomUUID(); + await window.electronAPI.storeCredential(scopeName, oldUUID); + + let creds = await window.electronAPI.getCredential(scopeName); + expect(creds).toBeDefined(); + let response = await decryptCreds(creds); + expect(response).toEqual(oldUUID); + + // Store new credentials with the same scope + const newUUID = crypto.randomUUID(); + await window.electronAPI.storeCredential(scopeName, newUUID); + + creds = await window.electronAPI.getCredential(scopeName); + expect(creds).toBeDefined(); + response = await decryptCreds(creds); + expect(response).toEqual(newUUID); + }); + + // trustRing.getCredential and set tests + async function setSomeKey() { + const randomCred = crypto.randomUUID(); + await trustRing.setCredential(TEST_TRUST_KEY_NAME, randomCred); + const savedCred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); + expect(savedCred).toEqual(randomCred); + return savedCred; + } + + it("Should get and set API key in kernal mode trust ring", async function () { + await setSomeKey(); + }); + + it("Should get and set empty string API key in kernal mode trust ring", async function () { + const randomCred = ""; + await trustRing.setCredential(TEST_TRUST_KEY_NAME, randomCred); + const savedCred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); + expect(savedCred).toEqual(randomCred); + }); + + it("Should remove API key in kernal mode trust ring work as expected", async function () { + await setSomeKey(); + await trustRing.removeCredential(TEST_TRUST_KEY_NAME); + const cred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); + expect(cred).toBeNull(); + }); + + // trust key management + it("Should not be able to set trust key if one is already set", async function () { + const kv = trustRing.generateRandomKeyAndIV(); + let error; + try { + await window.electronAPI.trustWindowAesKey(kv.key, kv.iv); + } catch (err) { + error = err; + } + expect(error.toString()).toContain("Trust has already been established for this window."); + }); + + it("Should be able to remove trust key with key and iv", async function () { + await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); + let error; + try { + await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); + } catch (err) { + error = err; + } + expect(error.toString()).toContain("No trust association found for this window."); + // reinstate trust + await window.electronAPI.trustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); + }); + + it("Should getCredential not work without trust", async function () { + await setSomeKey(); + await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); + let error; + try { + await trustRing.getCredential(TEST_TRUST_KEY_NAME); + } catch (err) { + error = err; + } + expect(error.toString()).toContain("Trust needs to be first established"); + // reinstate trust + await window.electronAPI.trustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); + }); + }); + }); + }); +}); From 7551b84c44568074a50e7872d5d575dfc874bb8b Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 13:57:06 +0530 Subject: [PATCH 41/91] refactor: unified electron and tauri platfrom test working --- src/phoenix/shell.js | 40 +++ test/UnitTestSuite.js | 1 - test/spec/Electron-platform-test.html | 25 +- test/spec/Electron-platform-test.js | 448 -------------------------- test/spec/Tauri-platform-test.js | 302 +++++++++++++---- 5 files changed, 284 insertions(+), 532 deletions(-) delete mode 100644 test/spec/Electron-platform-test.js diff --git a/src/phoenix/shell.js b/src/phoenix/shell.js index f6796f512..7160a1710 100644 --- a/src/phoenix/shell.js +++ b/src/phoenix/shell.js @@ -66,6 +66,25 @@ async function _getTauriWindowLabel(prefix) { throw new Error("Could not get a free window label to create tauri window"); } +/** + * Opens a URL in a new Phoenix window. Works across all platforms (Tauri, Electron, browser). + * + * @param {string} url - The URL to open in the new window + * @param {Object} [options] - Window configuration options + * @param {string} [options.windowTitle] - Title for the window (defaults to label or URL) + * @param {boolean} [options.fullscreen] - Whether to open in fullscreen mode + * @param {boolean} [options.resizable=true] - Whether the window is resizable + * @param {number} [options.height=900] - Window height in pixels + * @param {number} [options.minHeight=600] - Minimum window height in pixels + * @param {number} [options.width=1366] - Window width in pixels + * @param {number} [options.minWidth=800] - Minimum window width in pixels + * @param {boolean} [options.acceptFirstMouse=true] - (Tauri only) Accept first mouse click + * @param {boolean} [options.preferTabs] - (Browser only) Prefer opening in a new tab + * @param {string} [options._prefixPvt] - Internal: window label prefix + * @returns {Promise<{label: string, isNativeWindow: boolean}>} Window object with `label` and `isNativeWindow` properties. + * - In Tauri/Electron: `{ label: string, isNativeWindow: true }` (Tauri returns WebviewWindow instance with these props) + * - In browser: Returns window.open() result with `isNativeWindow: false` + */ async function openURLInPhoenixWindow(url, { windowTitle, fullscreen, resizable, height, minHeight, width, minWidth, acceptFirstMouse, preferTabs, _prefixPvt = PHOENIX_EXTENSION_WINDOW_PREFIX @@ -242,6 +261,27 @@ Phoenix.app = { return window.electronAPI.focusWindow(); } }, + /** + * Closes a window by its label. Returns true if window was found and closed, false otherwise. + * @param {string} label - The window label to close + * @return {Promise} + */ + closeWindowByLabel: async function (label) { + if(!Phoenix.isNativeApp){ + throw new Error("closeWindowByLabel is not supported in browsers"); + } + if(window.__TAURI__){ + const win = window.__TAURI__.window.WebviewWindow.getByLabel(label); + if(win){ + await win.close(); + return true; + } + return false; + } else if(window.__ELECTRON__){ + return window.electronAPI.closeWindowByLabel(label); + } + return false; + }, /** * Gets the commandline argument in desktop builds and null in browser builds. * Will always return CLI of the current process only. diff --git a/test/UnitTestSuite.js b/test/UnitTestSuite.js index bba6e12ea..e3f9a3e52 100644 --- a/test/UnitTestSuite.js +++ b/test/UnitTestSuite.js @@ -23,7 +23,6 @@ define(function (require, exports, module) { require("spec/Phoenix-platform-test"); require("spec/Tauri-platform-test"); - require("spec/Electron-platform-test"); require("spec/trust-ring-test"); require("spec/utframework-suite-test"); require("spec/Async-test"); diff --git a/test/spec/Electron-platform-test.html b/test/spec/Electron-platform-test.html index e2122901e..1c24add2c 100644 --- a/test/spec/Electron-platform-test.html +++ b/test/spec/Electron-platform-test.html @@ -4,31 +4,10 @@ Test electron apis accessible Security Test`; - - await SpecRunnerUtils.ensureExistsDirAsync(path.dirname(securityTestPath)); - await SpecRunnerUtils.createTextFileAsync(securityTestPath, securityTestHtml); - - // Get the asset:// URL for the test file - const platformPath = fs.getTauriPlatformPath(securityTestPath); - const assetURL = window.electronAPI.convertToAssetURL(platformPath); - - // Clear any previous test result - await window.electronAPI.putItem(SECURITY_TEST_KEY, null); - - // Try to open a window with the asset:// URL - let windowLabel = null; - try { - windowLabel = await window.electronAPI.createPhoenixWindow(assetURL, { - windowTitle: 'Security Test', - width: 400, - height: 300, - isExtension: true - }); - } catch (e) { - // If window creation fails for asset:// URLs, that's acceptable security behavior - console.log("Window creation blocked for asset:// URL (expected):", e.message); - } - - if (windowLabel) { - // Window was created - wait for it to load and potentially try to use APIs - await new Promise(resolve => setTimeout(resolve, 2000)); - - // Check if the sandboxed window was able to use electronAPI - const items = await window.electronAPI.getAllItems(); - const testResult = items[SECURITY_TEST_KEY]; - - if (testResult) { - const parsed = JSON.parse(testResult); - // SECURITY CHECK: If we got a result, verify no API access was possible - // If any of these are true, it's a security vulnerability - expect(parsed.hasElectronAPI).withContext( - "SECURITY VIOLATION: asset:// window has electronAPI access" - ).toBeFalse(); - expect(parsed.hasElectronFSAPI).withContext( - "SECURITY VIOLATION: asset:// window has electronFSAPI access" - ).toBeFalse(); - expect(parsed.hasElectronAppAPI).withContext( - "SECURITY VIOLATION: asset:// window has electronAppAPI access" - ).toBeFalse(); - } - // If no result was stored, the window couldn't access APIs - test passes - - // Close the security test window by its label - try { - await window.electronAPI.closeWindowByLabel(windowLabel); - } catch (e) { - console.warn("Could not close security test window:", e); - } - } - - // Cleanup - await SpecRunnerUtils.deletePathAsync(securityTestPath); - }); - - // Unique key for inter-window communication - const ELECTRON_TEST_SIGNAL_KEY = 'ELECTRON_PLATFORM_TEST_SIGNAL'; - - function createWebView() { - return new Promise((resolve, reject)=>{ - let currentURL = new URL(location.href); - let pathParts = currentURL.pathname.split('/'); - pathParts[pathParts.length - 1] = 'spec/Electron-platform-test.html'; - currentURL.pathname = pathParts.join('/'); - - let newURL = currentURL.href; - Phoenix.app.openURLInPhoenixWindow(newURL) - .then(electronWindow =>{ - expect(electronWindow.label.startsWith("extn-")).toBeTrue(); - expect(electronWindow.isNativeWindow).toBeTrue(); - - // For Electron, we use shared storage to communicate between windows - // Poll for the signal from the child window - const pollInterval = setInterval(async () => { - try { - const items = await window.electronAPI.getAllItems(); - if (items && items[ELECTRON_TEST_SIGNAL_KEY] === electronWindow.label) { - clearInterval(pollInterval); - // Clear the signal - await window.electronAPI.putItem(ELECTRON_TEST_SIGNAL_KEY, null); - // Create a window-like object with close method - const winLabel = electronWindow.label; - resolve({ - label: winLabel, - close: async function() { - // Signal the child window to close itself - const closeKey = ELECTRON_TEST_SIGNAL_KEY + - '_CLOSE_' + winLabel; - await window.electronAPI.putItem(closeKey, true); - } - }); - } - } catch (e) { - // Ignore polling errors - } - }, 100); - - // Timeout after 10 seconds - setTimeout(() => { - clearInterval(pollInterval); - reject(new Error('Timeout waiting for child window signal')); - }, 10000); - }).catch(reject); - }); - } - - it("Should be able to spawn electron windows", async function () { - const electronWindow = await createWebView(); - await electronWindow.close(); - // Wait for window to actually close - await new Promise(resolve => setTimeout(resolve, 500)); - }); - - it("Should be able to get process ID", async function () { - const processID = await Phoenix.app.getProcessID(); - expect(processID).toEqual(jasmine.any(Number)); - }); - - const maxWindows = 25; - it(`Should be able to spawn ${maxWindows} electron windows`, async function () { - const electronWindows = []; - for(let i=0; i setTimeout(resolve, 1000)); - }, 120000); - }); - - describe("Credentials OTP API Tests", function () { - const scopeName = "testScope"; - const trustRing = window.specRunnerTestKernalModeTrust; - const TEST_TRUST_KEY_NAME = "testTrustKey"; - - function decryptCreds(creds) { - return trustRing.AESDecryptString(creds, trustRing.aesKeys.key, trustRing.aesKeys.iv); - } - - beforeEach(async function () { - // Cleanup before running tests - await window.electronAPI.deleteCredential(scopeName).catch(() => {}); - }); - - afterEach(async function () { - // Cleanup after tests - await window.electronAPI.deleteCredential(scopeName).catch(() => {}); - }); - - if(Phoenix.isTestWindowGitHubActions && Phoenix.platform === "linux"){ - // Credentials test doesn't work in GitHub actions in linux desktop as the runner cant reach key ring. - it("Should not run in github actions in linux desktop", async function () { - expect(1).toEqual(1); - }); - return; - } - - describe("Credential Storage & OTP Generation", function () { - it("Should store credentials successfully", async function () { - const randomUUID = crypto.randomUUID(); - await expectAsync( - window.electronAPI.storeCredential(scopeName, randomUUID) - ).toBeResolved(); - }); - - it("Should get credentials as encrypted string", async function () { - const randomUUID = crypto.randomUUID(); - await window.electronAPI.storeCredential(scopeName, randomUUID); - - const response = await window.electronAPI.getCredential(scopeName); - expect(response).toBeDefined(); - expect(response).not.toEqual(randomUUID); - }); - - it("Should retrieve and decrypt set credentials with kernal mode keys", async function () { - const randomUUID = crypto.randomUUID(); - await window.electronAPI.storeCredential(scopeName, randomUUID); - - const creds = await window.electronAPI.getCredential(scopeName); - expect(creds).toBeDefined(); - const decryptedString = await decryptCreds(creds); - expect(decryptedString).toEqual(randomUUID); - }); - - it("Should return an error if credentials do not exist", async function () { - const response = await window.electronAPI.getCredential(scopeName); - expect(response).toBeNull(); - }); - - it("Should delete stored credentials", async function () { - const randomUUID = crypto.randomUUID(); - await window.electronAPI.storeCredential(scopeName, randomUUID); - - // Ensure credential exists - let creds = await window.electronAPI.getCredential(scopeName); - expect(creds).toBeDefined(); - - // Delete credential - await expectAsync( - window.electronAPI.deleteCredential(scopeName) - ).toBeResolved(); - - // Ensure credential is deleted - creds = await window.electronAPI.getCredential(scopeName); - expect(creds).toBeNull(); - }); - - it("Should handle deletion of non-existent credentials gracefully", async function () { - let error; - try { - await window.electronAPI.deleteCredential(scopeName); - } catch (err) { - error = err; - } - - // The test should fail if no error was thrown - expect(error).toBeDefined(); - - // Check for OS-specific error messages - const expectedErrors = [ - "No matching entry found in secure storage", // Common error on Linux/macOS - "The specified item could not be found in the keychain", // macOS Keychain - "Element not found" // Windows Credential Manager - ]; - - const isExpectedError = expectedErrors.some(msg => error.toString().includes(msg)); - expect(isExpectedError).toBeTrue(); - }); - - it("Should overwrite existing credentials when storing with the same scope", async function () { - const oldUUID = crypto.randomUUID(); - await window.electronAPI.storeCredential(scopeName, oldUUID); - - let creds = await window.electronAPI.getCredential(scopeName); - expect(creds).toBeDefined(); - let response = await decryptCreds(creds); - expect(response).toEqual(oldUUID); - - // Store new credentials with the same scope - const newUUID = crypto.randomUUID(); - await window.electronAPI.storeCredential(scopeName, newUUID); - - creds = await window.electronAPI.getCredential(scopeName); - expect(creds).toBeDefined(); - response = await decryptCreds(creds); - expect(response).toEqual(newUUID); - }); - - // trustRing.getCredential and set tests - async function setSomeKey() { - const randomCred = crypto.randomUUID(); - await trustRing.setCredential(TEST_TRUST_KEY_NAME, randomCred); - const savedCred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); - expect(savedCred).toEqual(randomCred); - return savedCred; - } - - it("Should get and set API key in kernal mode trust ring", async function () { - await setSomeKey(); - }); - - it("Should get and set empty string API key in kernal mode trust ring", async function () { - const randomCred = ""; - await trustRing.setCredential(TEST_TRUST_KEY_NAME, randomCred); - const savedCred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); - expect(savedCred).toEqual(randomCred); - }); - - it("Should remove API key in kernal mode trust ring work as expected", async function () { - await setSomeKey(); - await trustRing.removeCredential(TEST_TRUST_KEY_NAME); - const cred = await trustRing.getCredential(TEST_TRUST_KEY_NAME); - expect(cred).toBeNull(); - }); - - // trust key management - it("Should not be able to set trust key if one is already set", async function () { - const kv = trustRing.generateRandomKeyAndIV(); - let error; - try { - await window.electronAPI.trustWindowAesKey(kv.key, kv.iv); - } catch (err) { - error = err; - } - expect(error.toString()).toContain("Trust has already been established for this window."); - }); - - it("Should be able to remove trust key with key and iv", async function () { - await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); - let error; - try { - await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); - } catch (err) { - error = err; - } - expect(error.toString()).toContain("No trust association found for this window."); - // reinstate trust - await window.electronAPI.trustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); - }); - - it("Should getCredential not work without trust", async function () { - await setSomeKey(); - await window.electronAPI.removeTrustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); - let error; - try { - await trustRing.getCredential(TEST_TRUST_KEY_NAME); - } catch (err) { - error = err; - } - expect(error.toString()).toContain("Trust needs to be first established"); - // reinstate trust - await window.electronAPI.trustWindowAesKey(trustRing.aesKeys.key, trustRing.aesKeys.iv); - }); - }); - }); - }); -}); diff --git a/test/spec/Tauri-platform-test.js b/test/spec/Tauri-platform-test.js index f7cd73350..37bcdd075 100644 --- a/test/spec/Tauri-platform-test.js +++ b/test/spec/Tauri-platform-test.js @@ -22,13 +22,67 @@ /*global describe, it, expect, beforeEach, afterEach, fs, path, jasmine, expectAsync*/ define(function (require, exports, module) { - if(!window.__TAURI__) { + // Platform detection + const isElectron = !!window.__ELECTRON__; + const isTauri = !!window.__TAURI__; + + if (!isElectron && !isTauri) { return; } - const SpecRunnerUtils = require("spec/SpecRunnerUtils"); + const SpecRunnerUtils = require("spec/SpecRunnerUtils"); + + // Platform abstraction helpers - same tests, different API calls + const platform = { + name: isElectron ? 'Electron' : 'Tauri', + + // Path APIs + appLocalDataDir: () => isElectron + ? window.electronFSAPI.appLocalDataDir() + : window.__TAURI__.path.appLocalDataDir(), + + documentDir: () => isElectron + ? window._tauriBootVars.documentDir // Same source for both + : window._tauriBootVars.documentDir, + + // Asset URL conversion + convertToAssetURL: (platformPath) => isElectron + ? window.electronAPI.convertToAssetURL(platformPath) + : window.__TAURI__.tauri.convertFileSrc(platformPath), + + // Credential APIs + storeCredential: (scopeName, secretVal) => isElectron + ? window.electronAPI.storeCredential(scopeName, secretVal) + : window.__TAURI__.invoke("store_credential", { scopeName, secretVal }), + + getCredential: (scopeName) => isElectron + ? window.electronAPI.getCredential(scopeName) + : window.__TAURI__.invoke("get_credential", { scopeName }), + + deleteCredential: (scopeName) => isElectron + ? window.electronAPI.deleteCredential(scopeName) + : window.__TAURI__.invoke("delete_credential", { scopeName }), - describe("unit: Tauri Platform Tests", function () { + // Trust ring APIs + trustWindowAesKey: (keyIv) => isElectron + ? window.electronAPI.trustWindowAesKey(keyIv.key, keyIv.iv) + : window.__TAURI__.tauri.invoke("trust_window_aes_key", keyIv), + + removeTrustWindowAesKey: (keyIv) => isElectron + ? window.electronAPI.removeTrustWindowAesKey(keyIv.key, keyIv.iv) + : window.__TAURI__.tauri.invoke("remove_trust_window_aes_key", keyIv), + + // Window management - returns platform-specific window object + // For window spawning tests, we use a helper HTML file + getTestHtmlPath: () => isElectron + ? 'spec/Electron-platform-test.html' + : 'spec/Tauri-platform-test.html', + + // Close window by label (uses platform-agnostic Phoenix.app API) + closeWindow: (windowObj) => Phoenix.app.closeWindowByLabel(windowObj.label) + }; + + describe(`unit: ${platform.name} Platform Tests`, function () { beforeEach(async function () { @@ -40,7 +94,7 @@ define(function (require, exports, module) { describe("asset url tests", function () { it("Should be able to fetch files in {appLocalData}/assets folder", async function () { - const appLocalData = fs.getTauriVirtualPath(await window.__TAURI__.path.appLocalDataDir()); + const appLocalData = fs.getTauriVirtualPath(await platform.appLocalDataDir()); expect(await SpecRunnerUtils.pathExists(appLocalData, true)).toBeTrue(); expect(appLocalData.split("/")[1]).toEql("tauri"); // should be /tauri/applocaldata/path @@ -51,7 +105,7 @@ define(function (require, exports, module) { await SpecRunnerUtils.createTextFileAsync(assetHTMLPath, assetHtmlText); const appLocalDataPlatformPath = fs.getTauriPlatformPath(assetHTMLPath); - const appLocalDataURL = window.__TAURI__.tauri.convertFileSrc(appLocalDataPlatformPath); + const appLocalDataURL = platform.convertToAssetURL(appLocalDataPlatformPath); const fetchedData = await ((await fetch(appLocalDataURL)).text()); expect(fetchedData).toEqual(assetHtmlText); @@ -70,15 +124,21 @@ define(function (require, exports, module) { await SpecRunnerUtils.createTextFileAsync(assetHTMLPath, assetHtmlText); const appLocalDataPlatformPath = fs.getTauriPlatformPath(assetHTMLPath); - const appLocalDataURL = window.__TAURI__.tauri.convertFileSrc(appLocalDataPlatformPath); - - let err; - try{ - await fetch(appLocalDataURL); + const appLocalDataURL = platform.convertToAssetURL(appLocalDataPlatformPath); + + // Tauri throws an error, Electron returns 403 response + let accessDenied = false; + try { + const response = await fetch(appLocalDataURL); + // Electron returns 403 for unauthorized access + if (!response.ok) { + accessDenied = true; + } } catch (e) { - err = e; + // Tauri throws an error + accessDenied = true; } - expect(err).toBeDefined(); + expect(accessDenied).withContext("Asset URL should not be accessible outside assets folder").toBeTrue(); // delete test file await SpecRunnerUtils.deletePathAsync(assetHTMLPath); @@ -88,35 +148,155 @@ define(function (require, exports, module) { // unfortunately for tests, this is set to appdata/testDocuments. // we cant set this to await window.__TAURI__.path.documentDir() as in github actions, // the user documents directory is not defined in rust and throws. - await testAssetNotAccessibleFolder(window._tauriBootVars.documentDir); + await testAssetNotAccessibleFolder(platform.documentDir()); }); it("Should not be able to fetch files in appLocalData folder", async function () { - await testAssetNotAccessibleFolder(await window.__TAURI__.path.appLocalDataDir()); + await testAssetNotAccessibleFolder(await platform.appLocalDataDir()); }); + // Electron-specific security test: verify asset:// URLs don't have API access + if (isElectron) { + it("Should NOT have electronAPI access from asset:// protocol", async function () { + // This test verifies that content loaded from asset:// URLs is sandboxed + // and does not have access to Electron APIs (matching Tauri's security posture) + const appLocalData = fs.getTauriVirtualPath(await platform.appLocalDataDir()); + const securityTestPath = `${appLocalData}/assets/security-test-${Date.now()}.html`; + const SECURITY_TEST_KEY = 'ELECTRON_ASSET_SECURITY_TEST_' + Date.now(); + + // Create the security test HTML in assets folder + // This script will try to use electronAPI if available and report back + const securityTestHtml = ` +Security Test`; + + await SpecRunnerUtils.ensureExistsDirAsync(path.dirname(securityTestPath)); + await SpecRunnerUtils.createTextFileAsync(securityTestPath, securityTestHtml); + + // Get the asset:// URL for the test file + const platformPath = fs.getTauriPlatformPath(securityTestPath); + const assetURL = platform.convertToAssetURL(platformPath); + + // Clear any previous test result + await window.electronAPI.putItem(SECURITY_TEST_KEY, null); + + // Try to open a window with the asset:// URL + let windowLabel = null; + try { + windowLabel = await window.electronAPI.createPhoenixWindow(assetURL, { + windowTitle: 'Security Test', + width: 400, + height: 300, + isExtension: true + }); + } catch (e) { + // If window creation fails for asset:// URLs, that's acceptable security behavior + console.log("Window creation blocked for asset:// URL (expected):", e.message); + } + + if (windowLabel) { + // Window was created - wait for it to load and potentially try to use APIs + await new Promise(resolve => setTimeout(resolve, 2000)); + + // Check if the sandboxed window was able to use electronAPI + const items = await window.electronAPI.getAllItems(); + const testResult = items[SECURITY_TEST_KEY]; + + if (testResult) { + const parsed = JSON.parse(testResult); + // SECURITY CHECK: If we got a result, verify no API access was possible + // If any of these are true, it's a security vulnerability + expect(parsed.hasElectronAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronAPI access" + ).toBeFalse(); + expect(parsed.hasElectronFSAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronFSAPI access" + ).toBeFalse(); + expect(parsed.hasElectronAppAPI).withContext( + "SECURITY VIOLATION: asset:// window has electronAppAPI access" + ).toBeFalse(); + } + // If no result was stored, the window couldn't access APIs - test passes + + // Close the security test window by its label + try { + await Phoenix.app.closeWindowByLabel(windowLabel); + } catch (e) { + console.warn("Could not close security test window:", e); + } + } + + // Cleanup + await SpecRunnerUtils.deletePathAsync(securityTestPath); + }); + } + function createWebView() { - return new Promise((resolve, reject)=>{ + return new Promise((resolve, reject) => { let currentURL = new URL(location.href); let pathParts = currentURL.pathname.split('/'); - pathParts[pathParts.length - 1] = 'spec/Tauri-platform-test.html'; + pathParts[pathParts.length - 1] = platform.getTestHtmlPath(); currentURL.pathname = pathParts.join('/'); let newURL = currentURL.href; - Phoenix.app.openURLInPhoenixWindow(newURL) - .then(tauriWindow =>{ - expect(tauriWindow.label.startsWith("extn-")).toBeTrue(); - tauriWindow.listen('TAURI_API_WORKING', function () { - resolve(tauriWindow); + + if (isElectron) { + // For Electron, use the event system (mirrors Tauri) + // We need to handle race: event might fire before or after window reference is available + let electronWindow = null; + let eventReceived = false; + + const tryResolve = () => { + if (electronWindow && eventReceived) { + resolve(electronWindow); + } + }; + + const unlisten = window.electronAPI.onWindowEvent('PLATFORM_API_WORKING', () => { + unlisten(); + eventReceived = true; + tryResolve(); + }); + + Phoenix.app.openURLInPhoenixWindow(newURL) + .then(win => { + expect(win.label.startsWith("extn-")).toBeTrue(); + expect(win.isNativeWindow).toBeTrue(); + electronWindow = win; + tryResolve(); + }).catch(err => { + unlisten(); + reject(err); }); - }).catch(reject); + } else { + // For Tauri, use the event system + Phoenix.app.openURLInPhoenixWindow(newURL) + .then(tauriWindow => { + expect(tauriWindow.label.startsWith("extn-")).toBeTrue(); + tauriWindow.listen('TAURI_API_WORKING', function () { + resolve(tauriWindow); + }); + }).catch(reject); + } }); - } - it("Should be able to spawn tauri windows", async function () { - const tauriWindow = await createWebView(); - await tauriWindow.close(); + it("Should be able to spawn windows", async function () { + const nativeWindow = await createWebView(); + await platform.closeWindow(nativeWindow); }); it("Should be able to get process ID", async function () { @@ -125,14 +305,16 @@ define(function (require, exports, module) { }); const maxWindows = 25; - it(`Should be able to spawn ${maxWindows} tauri windows`, async function () { - const tauriWindows = []; - for(let i=0; i setTimeout(resolve, 1000)); }, 120000); }); @@ -147,12 +329,12 @@ define(function (require, exports, module) { beforeEach(async function () { // Cleanup before running tests - await window.__TAURI__.invoke("delete_credential", { scopeName }).catch(() => {}); + await platform.deleteCredential(scopeName).catch(() => {}); }); afterEach(async function () { // Cleanup after tests - await window.__TAURI__.invoke("delete_credential", { scopeName }).catch(() => {}); + await platform.deleteCredential(scopeName).catch(() => {}); }); if(Phoenix.isTestWindowGitHubActions && Phoenix.platform === "linux"){ @@ -167,56 +349,56 @@ define(function (require, exports, module) { it("Should store credentials successfully", async function () { const randomUUID = crypto.randomUUID(); await expectAsync( - window.__TAURI__.invoke("store_credential", { scopeName, secretVal: randomUUID }) + platform.storeCredential(scopeName, randomUUID) ).toBeResolved(); }); it("Should get credentials as encrypted string", async function () { const randomUUID = crypto.randomUUID(); - await window.__TAURI__.invoke("store_credential", { scopeName, secretVal: randomUUID }); + await platform.storeCredential(scopeName, randomUUID); - const response = await window.__TAURI__.invoke("get_credential", { scopeName }); + const response = await platform.getCredential(scopeName); expect(response).toBeDefined(); expect(response).not.toEqual(randomUUID); }); it("Should retrieve and decrypt set credentials with kernal mode keys", async function () { const randomUUID = crypto.randomUUID(); - await window.__TAURI__.invoke("store_credential", { scopeName, secretVal: randomUUID }); + await platform.storeCredential(scopeName, randomUUID); - const creds = await window.__TAURI__.invoke("get_credential", { scopeName }); + const creds = await platform.getCredential(scopeName); expect(creds).toBeDefined(); const decryptedString = await decryptCreds(creds); expect(decryptedString).toEqual(randomUUID); }); - it("Should return an error if credentials do not exist", async function () { - const response = await window.__TAURI__.invoke("get_credential", { scopeName }); + it("Should return null if credentials do not exist", async function () { + const response = await platform.getCredential(scopeName); expect(response).toBeNull(); }); it("Should delete stored credentials", async function () { const randomUUID = crypto.randomUUID(); - await window.__TAURI__.invoke("store_credential", { scopeName, secretVal: randomUUID }); + await platform.storeCredential(scopeName, randomUUID); // Ensure credential exists - let creds = await window.__TAURI__.invoke("get_credential", { scopeName }); + let creds = await platform.getCredential(scopeName); expect(creds).toBeDefined(); // Delete credential await expectAsync( - window.__TAURI__.invoke("delete_credential", { scopeName }) + platform.deleteCredential(scopeName) ).toBeResolved(); // Ensure credential is deleted - creds = await window.__TAURI__.invoke("get_credential", { scopeName }); + creds = await platform.getCredential(scopeName); expect(creds).toBeNull(); }); it("Should handle deletion of non-existent credentials gracefully", async function () { let error; try { - await window.__TAURI__.invoke("delete_credential", { scopeName }); + await platform.deleteCredential(scopeName); } catch (err) { error = err; } @@ -231,24 +413,24 @@ define(function (require, exports, module) { "Element not found" // Windows Credential Manager ]; - const isExpectedError = expectedErrors.some(msg => error.includes(msg)); + const isExpectedError = expectedErrors.some(msg => error.toString().includes(msg)); expect(isExpectedError).toBeTrue(); }); it("Should overwrite existing credentials when storing with the same scope", async function () { const oldUUID = crypto.randomUUID(); - await window.__TAURI__.invoke("store_credential", { scopeName, secretVal: oldUUID }); + await platform.storeCredential(scopeName, oldUUID); - let creds = await window.__TAURI__.invoke("get_credential", { scopeName }); + let creds = await platform.getCredential(scopeName); expect(creds).toBeDefined(); let response = await decryptCreds(creds); expect(response).toEqual(oldUUID); // Store new credentials with the same scope const newUUID = crypto.randomUUID(); - await window.__TAURI__.invoke("store_credential", { scopeName, secretVal: newUUID }); + await platform.storeCredential(scopeName, newUUID); - creds = await window.__TAURI__.invoke("get_credential", { scopeName }); + creds = await platform.getCredential(scopeName); expect(creds).toBeDefined(); response = await decryptCreds(creds); expect(response).toEqual(newUUID); @@ -286,38 +468,38 @@ define(function (require, exports, module) { const kv = trustRing.generateRandomKeyAndIV(); let error; try { - await window.__TAURI__.tauri.invoke("trust_window_aes_key", kv); + await platform.trustWindowAesKey(kv); } catch (err) { error = err; } - expect(error).toContain("Trust has already been established for this window."); + expect(error.toString()).toContain("Trust has already been established for this window."); }); it("Should be able to remove trust key with key and iv", async function () { - await window.__TAURI__.tauri.invoke("remove_trust_window_aes_key", trustRing.aesKeys); + await platform.removeTrustWindowAesKey(trustRing.aesKeys); let error; try { - await window.__TAURI__.tauri.invoke("remove_trust_window_aes_key", trustRing.aesKeys); + await platform.removeTrustWindowAesKey(trustRing.aesKeys); } catch (err) { error = err; } - expect(error).toContain("No trust association found for this window."); + expect(error.toString()).toContain("No trust association found for this window."); // reinstate trust - await window.__TAURI__.tauri.invoke("trust_window_aes_key", trustRing.aesKeys); + await platform.trustWindowAesKey(trustRing.aesKeys); }); it("Should getCredential not work without trust", async function () { await setSomeKey(); - await window.__TAURI__.tauri.invoke("remove_trust_window_aes_key", trustRing.aesKeys); + await platform.removeTrustWindowAesKey(trustRing.aesKeys); let error; try { await trustRing.getCredential(TEST_TRUST_KEY_NAME); } catch (err) { error = err; } - expect(error).toContain("Trust needs to be first established"); + expect(error.toString()).toContain("Trust needs to be first established"); // reinstate trust - await window.__TAURI__.tauri.invoke("trust_window_aes_key", trustRing.aesKeys); + await platform.trustWindowAesKey(trustRing.aesKeys); }); }); }); From 7b6ae82b14dee1c94ee36eb394d81a507bfd6921 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 13:59:43 +0530 Subject: [PATCH 42/91] refactor: file name to Native-platform-test.js instead of tauri --- test/UnitTestSuite.js | 2 +- test/spec/{Tauri-platform-test.js => Native-platform-test.js} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/spec/{Tauri-platform-test.js => Native-platform-test.js} (100%) diff --git a/test/UnitTestSuite.js b/test/UnitTestSuite.js index e3f9a3e52..f2dd6c590 100644 --- a/test/UnitTestSuite.js +++ b/test/UnitTestSuite.js @@ -22,7 +22,7 @@ define(function (require, exports, module) { require("spec/Phoenix-platform-test"); - require("spec/Tauri-platform-test"); + require("test/spec/Native-platform-test"); require("spec/trust-ring-test"); require("spec/utframework-suite-test"); require("spec/Async-test"); diff --git a/test/spec/Tauri-platform-test.js b/test/spec/Native-platform-test.js similarity index 100% rename from test/spec/Tauri-platform-test.js rename to test/spec/Native-platform-test.js From 72c39a7220d4b87a89a0b8eba4ca51fc8ed6cecd Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 14:14:51 +0530 Subject: [PATCH 43/91] feat: native platfrom window event emitting in Phoenix.app and tests --- src/phoenix/shell.js | 67 +++++++- test/spec/Native-platform-test.js | 146 +++++++++++++----- ...tml => native-platform-electron-test.html} | 0 ...t.html => native-platform-tauri-test.html} | 3 +- 4 files changed, 177 insertions(+), 39 deletions(-) rename test/spec/{Electron-platform-test.html => native-platform-electron-test.html} (100%) rename test/spec/{Tauri-platform-test.html => native-platform-tauri-test.html} (55%) diff --git a/src/phoenix/shell.js b/src/phoenix/shell.js index 7160a1710..c9e3b4ed0 100644 --- a/src/phoenix/shell.js +++ b/src/phoenix/shell.js @@ -729,7 +729,72 @@ Phoenix.app = { getTimeSinceStartup: function () { return Date.now() - Phoenix.startTime; // milliseconds elapsed since app start }, - language: navigator.language + language: navigator.language, + /** + * Broadcast an event to all windows (excludes sender). + * @param {string} eventName - Name of the event + * @param {*} payload - Event data + * @returns {Promise} + */ + emitToAllWindows: async function (eventName, payload) { + if (!Phoenix.isNativeApp) { + throw new Error("emitToAllWindows is not supported in browsers"); + } + if (window.__TAURI__) { + return window.__TAURI__.event.emit(eventName, payload); + } + if (window.__ELECTRON__) { + return window.electronAPI.emitToAllWindows(eventName, payload); + } + }, + /** + * Send an event to a specific window by label. + * @param {string} targetLabel - Window label to send to + * @param {string} eventName - Name of the event + * @param {*} payload - Event data + * @returns {Promise} True if window found and event sent + */ + emitToWindow: async function (targetLabel, eventName, payload) { + if (!Phoenix.isNativeApp) { + throw new Error("emitToWindow is not supported in browsers"); + } + if (window.__TAURI__) { + // Tauri doesn't have direct window-to-window emit, use global emit + // The listener filters by source if needed + return window.__TAURI__.event.emit(eventName, payload); + } + if (window.__ELECTRON__) { + return window.electronAPI.emitToWindow(targetLabel, eventName, payload); + } + return false; + }, + /** + * Listen for events from other windows. + * @param {string} eventName - Name of the event to listen for + * @param {Function} callback - Called with (payload) when event received + * @returns {Function} Unlisten function to remove the listener + */ + onWindowEvent: function (eventName, callback) { + if (!Phoenix.isNativeApp) { + throw new Error("onWindowEvent is not supported in browsers"); + } + if (window.__TAURI__) { + let unlisten = null; + window.__TAURI__.event.listen(eventName, (event) => { + callback(event.payload); + }).then(fn => { unlisten = fn; }); + // Return a function that will unlisten when called + return () => { + if (unlisten) { + unlisten(); + } + }; + } + if (window.__ELECTRON__) { + return window.electronAPI.onWindowEvent(eventName, callback); + } + return () => {}; // No-op for unsupported platforms + } }; if(!window.appshell){ diff --git a/test/spec/Native-platform-test.js b/test/spec/Native-platform-test.js index 37bcdd075..0e4ca767c 100644 --- a/test/spec/Native-platform-test.js +++ b/test/spec/Native-platform-test.js @@ -75,8 +75,8 @@ define(function (require, exports, module) { // Window management - returns platform-specific window object // For window spawning tests, we use a helper HTML file getTestHtmlPath: () => isElectron - ? 'spec/Electron-platform-test.html' - : 'spec/Tauri-platform-test.html', + ? 'spec/native-platform-electron-test.html' + : 'spec/native-platform-tauri-test.html', // Close window by label (uses platform-agnostic Phoenix.app API) closeWindow: (windowObj) => Phoenix.app.closeWindowByLabel(windowObj.label) @@ -253,44 +253,32 @@ define(function (require, exports, module) { let newURL = currentURL.href; - if (isElectron) { - // For Electron, use the event system (mirrors Tauri) - // We need to handle race: event might fire before or after window reference is available - let electronWindow = null; - let eventReceived = false; + // Use unified event API for both platforms + let nativeWindow = null; + let eventReceived = false; - const tryResolve = () => { - if (electronWindow && eventReceived) { - resolve(electronWindow); - } - }; - - const unlisten = window.electronAPI.onWindowEvent('PLATFORM_API_WORKING', () => { - unlisten(); - eventReceived = true; + const tryResolve = () => { + if (nativeWindow && eventReceived) { + resolve(nativeWindow); + } + }; + + const unlisten = Phoenix.app.onWindowEvent('PLATFORM_API_WORKING', () => { + unlisten(); + eventReceived = true; + tryResolve(); + }); + + Phoenix.app.openURLInPhoenixWindow(newURL) + .then(win => { + expect(win.label.startsWith("extn-")).toBeTrue(); + expect(win.isNativeWindow).toBeTrue(); + nativeWindow = win; tryResolve(); + }).catch(err => { + unlisten(); + reject(err); }); - - Phoenix.app.openURLInPhoenixWindow(newURL) - .then(win => { - expect(win.label.startsWith("extn-")).toBeTrue(); - expect(win.isNativeWindow).toBeTrue(); - electronWindow = win; - tryResolve(); - }).catch(err => { - unlisten(); - reject(err); - }); - } else { - // For Tauri, use the event system - Phoenix.app.openURLInPhoenixWindow(newURL) - .then(tauriWindow => { - expect(tauriWindow.label.startsWith("extn-")).toBeTrue(); - tauriWindow.listen('TAURI_API_WORKING', function () { - resolve(tauriWindow); - }); - }).catch(reject); - } }); } @@ -318,6 +306,90 @@ define(function (require, exports, module) { }, 120000); }); + describe("Inter-window Event API Tests", function () { + // Note: emitToAllWindows excludes the sender, so we test cross-window communication + // using spawned windows that emit PLATFORM_API_WORKING event + + it("Should receive events from spawned windows using unified API", async function () { + let eventReceived = false; + let receivedPayload = null; + const unlisten = Phoenix.app.onWindowEvent('PLATFORM_API_WORKING', (payload) => { + eventReceived = true; + receivedPayload = payload; + }); + + // Small delay for listener registration (Tauri's listen is async) + await new Promise(resolve => setTimeout(resolve, 100)); + + let currentURL = new URL(location.href); + let pathParts = currentURL.pathname.split('/'); + pathParts[pathParts.length - 1] = platform.getTestHtmlPath(); + currentURL.pathname = pathParts.join('/'); + + const win = await Phoenix.app.openURLInPhoenixWindow(currentURL.href); + expect(win.label.startsWith("extn-")).toBeTrue(); + + // Wait for the spawned window to emit the event + await new Promise(resolve => setTimeout(resolve, 1000)); + + expect(eventReceived).toBeTrue(); + expect(receivedPayload).toBeDefined(); + + unlisten(); + await platform.closeWindow(win); + }); + + it("Should unlisten properly and not receive events after unlisten", async function () { + let callCount = 0; + const unlisten = Phoenix.app.onWindowEvent('PLATFORM_API_WORKING', () => { + callCount++; + }); + + // Small delay for listener registration + await new Promise(resolve => setTimeout(resolve, 100)); + + // Spawn first window - should receive event + let currentURL = new URL(location.href); + let pathParts = currentURL.pathname.split('/'); + pathParts[pathParts.length - 1] = platform.getTestHtmlPath(); + currentURL.pathname = pathParts.join('/'); + + const win1 = await Phoenix.app.openURLInPhoenixWindow(currentURL.href); + await new Promise(resolve => setTimeout(resolve, 1000)); + expect(callCount).toBeGreaterThanOrEqual(1); + const countAfterFirst = callCount; + + // Unlisten + unlisten(); + await new Promise(resolve => setTimeout(resolve, 100)); + + // Spawn second window - should NOT receive event + const win2 = await Phoenix.app.openURLInPhoenixWindow(currentURL.href); + await new Promise(resolve => setTimeout(resolve, 1000)); + expect(callCount).toEqual(countAfterFirst); // Count should not increase + + await platform.closeWindow(win1); + await platform.closeWindow(win2); + }); + + it("Should not throw when emitting events", async function () { + // Basic sanity test that emit APIs don't throw + await expectAsync( + Phoenix.app.emitToAllWindows('TEST_EVENT', { test: true }) + ).toBeResolved(); + + await expectAsync( + Phoenix.app.emitToWindow('nonexistent-window', 'TEST_EVENT', { test: true }) + ).toBeResolved(); + }); + + it("Should return unlisten function from onWindowEvent", function () { + const unlisten = Phoenix.app.onWindowEvent('TEST_EVENT', () => {}); + expect(typeof unlisten).toEqual('function'); + unlisten(); // Should not throw + }); + }); + describe("Credentials OTP API Tests", function () { const scopeName = "testScope"; const trustRing = window.specRunnerTestKernalModeTrust; diff --git a/test/spec/Electron-platform-test.html b/test/spec/native-platform-electron-test.html similarity index 100% rename from test/spec/Electron-platform-test.html rename to test/spec/native-platform-electron-test.html diff --git a/test/spec/Tauri-platform-test.html b/test/spec/native-platform-tauri-test.html similarity index 55% rename from test/spec/Tauri-platform-test.html rename to test/spec/native-platform-tauri-test.html index 14732a90e..55035470a 100644 --- a/test/spec/Tauri-platform-test.html +++ b/test/spec/native-platform-tauri-test.html @@ -4,7 +4,8 @@ Test tauri apis accessible From ecb94bb896e1e0e40e4ad91847c57b8badedd9f4 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 17:49:11 +0530 Subject: [PATCH 44/91] fix: should always use en language in specrunner window --- test/SpecRunner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/SpecRunner.js b/test/SpecRunner.js index 2fa1677ed..0c17e0ace 100644 --- a/test/SpecRunner.js +++ b/test/SpecRunner.js @@ -44,7 +44,8 @@ require.config({ "thirdparty/preact": "preact-compat", "thirdparty/preact-test-utils": "preact-test-utils" } - } + }, + locale: "en" // force English (US) for consistent test strings }); window.logger = { From a6a2bcaaeadb8ad2a8320492640672dcdc1981f3 Mon Sep 17 00:00:00 2001 From: abose Date: Sat, 31 Jan 2026 23:59:02 +0530 Subject: [PATCH 45/91] fix: all tests working in electron --- test/spec/Storage-integ-test.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test/spec/Storage-integ-test.js b/test/spec/Storage-integ-test.js index 925a65cc2..2d18cbb67 100644 --- a/test/spec/Storage-integ-test.js +++ b/test/spec/Storage-integ-test.js @@ -122,7 +122,7 @@ define(function (require, exports, module) { expect(val).toEql(expectedValue); }); - it("Should be able to create lmdb dumps in tauri", async function () { + it("Should be able to create lmdb dumps in native app", async function () { if(!Phoenix.isNativeApp){ return; } @@ -137,7 +137,14 @@ define(function (require, exports, module) { }); const dumpFileLocation = await window.storageNodeConnector.execPeer("dumpDBToFile"); - const dumpFileText = await window.__TAURI__.fs.readTextFile(dumpFileLocation); + let dumpFileText; + if (window.__TAURI__) { + dumpFileText = await window.__TAURI__.fs.readTextFile(dumpFileLocation); + } else if (window.__ELECTRON__) { + const data = await window.electronFSAPI.fsReadFile(dumpFileLocation); + const decoder = new TextDecoder("utf-8"); + dumpFileText = decoder.decode(data); + } const dumpObj = JSON.parse(dumpFileText); expect(dumpObj[key]).toEql(expectedValue); }); From ef0422cba128f0401196d5a7ad6159771a1b0abf Mon Sep 17 00:00:00 2001 From: abose Date: Sun, 1 Feb 2026 04:53:28 +0000 Subject: [PATCH 46/91] ci: bump patch version to 5.1.2 --- package.json | 6 +++--- src-node/package.json | 6 +++--- src/config.json | 4 ++-- src/index.html | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index d5d08f5a9..f5b228078 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "phoenix", - "version": "5.1.1-0", - "apiVersion": "5.1.1", + "version": "5.1.2-0", + "apiVersion": "5.1.2", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" @@ -122,4 +122,4 @@ "tinycolor2": "^1.4.2", "underscore": "^1.13.4" } -} +} \ No newline at end of file diff --git a/src-node/package.json b/src-node/package.json index 3ebf0415d..357eafe28 100644 --- a/src-node/package.json +++ b/src-node/package.json @@ -1,8 +1,8 @@ { "name": "@phcode/node-core", "description": "Phoenix Node Core", - "version": "5.1.1-0", - "apiVersion": "5.1.1", + "version": "5.1.2-0", + "apiVersion": "5.1.2", "keywords": [], "author": "arun@core.ai", "homepage": "https://github.com/phcode-dev/phoenix", @@ -29,4 +29,4 @@ "which": "^2.0.1", "@expo/sudo-prompt": "^9.3.2" } -} +} \ No newline at end of file diff --git a/src/config.json b/src/config.json index e3182d669..0148ad53c 100644 --- a/src/config.json +++ b/src/config.json @@ -46,8 +46,8 @@ "bugsnagEnv": "development" }, "name": "Phoenix Code", - "version": "5.1.1-0", - "apiVersion": "5.1.1", + "version": "5.1.2-0", + "apiVersion": "5.1.2", "homepage": "https://core.ai", "issues": { "url": "https://github.com/phcode-dev/phoenix/issues" diff --git a/src/index.html b/src/index.html index a804594e2..c0c8f68eb 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,7 @@ - + + + +