chore(deps): refresh compatible packages and FFmpeg sources

- update i18next, React i18n, Lucide, and compatible npm and Cargo locks

- refresh Windows and Linux FFmpeg 9.0.2 archives with verified hashes

- report compatible npm wanted versions and handle nested, duplicate, and optional packages

- update Node and Rust CI pins and document Windows 10 22H2 qualification
This commit is contained in:
NimBold
2026-10-18 12:09:43 +04:00
parent 971af3cd2c
commit 05ff37df22
13 changed files with 555 additions and 139 deletions
+7 -4
View File
@@ -14,7 +14,9 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v7.0.1
- uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable action branch (2026-10-09)
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable action branch (2026-10-16)
with:
toolchain: stable
- name: Install locked cargo-audit
run: cargo install cargo-audit --version 0.22.2 --locked
- name: Reject vulnerable resolved dependencies
@@ -27,7 +29,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [22.23.3, 24.21.0]
node: [22.23.3, 24.22.0, 26.12.0]
steps:
- uses: actions/checkout@v7.0.1
with:
@@ -62,10 +64,11 @@ jobs:
submodules: recursive
- uses: actions/setup-node@v7.1.0
with:
node-version: 24.21.0
node-version: 24.22.0
cache: npm
- uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable action branch (2026-10-09)
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable action branch (2026-10-16)
with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Cache Rust dependencies and build targets
uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2
+3 -2
View File
@@ -44,7 +44,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-node@v7.1.0
with:
node-version: 24.21.0
node-version: 24.22.0
cache: npm
- name: Verify tagged release version
if: github.event_name == 'push' || inputs.publish_release
@@ -58,8 +58,9 @@ jobs:
- name: Verify non-publishing Companion package metadata
if: github.event_name == 'workflow_dispatch' && !inputs.publish_release
run: node scripts/verify-companion-release.js --allow-untagged
- uses: dtolnay/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249 # stable action branch (2026-10-09)
- uses: dtolnay/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec # stable action branch (2026-10-16)
with:
toolchain: stable
targets: ${{ matrix.target }}
- name: Install Linux dependencies
if: runner.os == 'Linux'
+2 -2
View File
@@ -62,8 +62,8 @@ Download the [latest Firelink release](https://github.com/nimbold/Firelink/relea
| Platform | Package | Notes |
| --- | --- | --- |
| macOS Apple silicon | `.dmg` | Ad-hoc signed and not notarized. macOS may require approval in **System Settings -> Privacy & Security**. |
| Windows x64 | NSIS `.exe` | Unsigned. Windows SmartScreen may display a warning. |
| Windows x64 portable | `.zip` | Extract to a writable folder and launch `firelink.exe`. |
| Windows x64 | NSIS `.exe` | Windows 10 22H2 or newer. Unsigned; SmartScreen may display a warning. |
| Windows x64 portable | `.zip` | Windows 10 22H2 or newer. Extract to a writable folder and launch `firelink.exe`. |
| Linux x64 | `.deb`, `.rpm`, or `.AppImage` | The current AppImage requires host glibc 2.35 or newer. |
All packages include aria2, yt-dlp, FFmpeg, Deno, and SQLite support. No separate engine installation is required.
+10 -1
View File
@@ -31,7 +31,7 @@ provisioning now builds the checksum-pinned upstream source archive with
`scripts/aria2/firelink.patch`; this patch also retains Firelink's native DNS,
network target policy, and Torrent routing changes. CI installs the compiler
and static-library prerequisites. Windows uses the MSYS2 UCRT64 environment,
supported by Firelink's Windows 10+ target and returned by the setup action
supported by Firelink's Windows 10 22H2+ target and returned by the setup action
(`FIRELINK_MSYS2_ROOT`, default `C:/msys64` for local builds).
The patch checksum is recorded in both source and payload provenance. Never
replace these builds with stock Aria2 archives: package verification requires
@@ -141,4 +141,13 @@ GitHub Actions builds all targets on native runners, verifies engines inside
final package contents, performs packaged launch smoke where supported, and
publishes the GitHub Release after the build matrix passes.
The Windows hosted runner smoke does not qualify the declared Windows 10
22H2 minimum. Before claiming that minimum as verified for a release, run the
NSIS-installed app and extracted portable package on a clean Windows 10 22H2
client (OS build 19045.x). Run `scripts/smoke-packaged-app.js` against the
installed executable with `--assert-no-visible-child-windows`; run it against
the portable executable with both `--assert-no-visible-child-windows` and
`--assert-portable-data`. Record the tested OS build and artifact version with
release QA results.
No target may silently skip missing engines, failed extraction, checksum mismatch, or missing package output.
+4 -4
View File
@@ -14,8 +14,8 @@
},
"ffmpeg": {
"version": "9.0.2-28-g669f5ab083",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-10-15-13-03/ffmpeg-n9.0.2-28-g669f5ab083-win64-gpl-9.0.zip",
"sha256": "1bb62cfd4bdc12a63a6a1151458ea5ae7001fd055202afc5463517028882a631"
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-10-17-20-51/ffmpeg-n9.0.2-28-g669f5ab083-win64-gpl-9.0.zip",
"sha256": "e84429075cf1b1fa9a85c5d4a5f97899145b4f6a712da02a864393203a3d5cd3"
},
"aria2c": {
"version": "1.37.0-firelink-native-dns-v1",
@@ -46,8 +46,8 @@
},
"ffmpeg": {
"version": "9.0.2-28-g669f5ab083",
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-10-15-13-03/ffmpeg-n9.0.2-28-g669f5ab083-linux64-gpl-9.0.tar.xz",
"sha256": "715ce3c292c749c00b196fc0ff703fe3be12351aa71a626c00d19617b3b280e4"
"url": "https://github.com/BtbN/FFmpeg-Builds/releases/download/autobuild-2026-10-17-20-51/ffmpeg-n9.0.2-28-g669f5ab083-linux64-gpl-9.0.tar.xz",
"sha256": "cc171d4d373f9ca633741d38fae6a17cd914075818febb1465f6f64e6d57f7ca"
},
"aria2c": {
"version": "1.37.0-firelink-native-dns-v1",
+100 -86
View File
@@ -22,11 +22,11 @@
"@tauri-apps/plugin-log": "^2.10.1",
"@tauri-apps/plugin-notification": "^2.7.0",
"@tauri-apps/plugin-opener": "^2.7.2",
"i18next": "^26.4.7",
"lucide-react": "^1.58.0",
"i18next": "^26.5.2",
"lucide-react": "^1.59.0",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"react-i18next": "^17.0.19",
"react-i18next": "^17.1.0",
"zustand": "^5.0.15"
},
"devDependencies": {
@@ -34,6 +34,7 @@
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
"semver": "^7.8.5",
"tailwindcss": "^4.3.3",
"typescript": "^7.0.2",
"vite": "^8.3.4",
@@ -44,9 +45,9 @@
}
},
"node_modules/@babel/runtime": {
"version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
"version": "7.29.10",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.10.tgz",
"integrity": "sha512-NpugTzbKgGrNe45Ui32cN8vCFFMxVtP/9rtfwv0nP5FRDAjvYBxJcLVpYA9mr1jxP6cnIT7x9LUzuDTbWYYNRA==",
"license": "MIT",
"engines": {
"node": ">=6.9.0"
@@ -152,18 +153,18 @@
}
},
"node_modules/@oxc-project/types": {
"version": "0.152.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.152.0.tgz",
"integrity": "sha512-oM/5rLBm2tPkg0iBgkH/FOeR3PCDpY19GTgAZjMFM8h9WI9VW7cLgzp6nwtarYKmovavIQZ+Fe/RKX/8C8O/Rw==",
"version": "0.154.0",
"resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.154.0.tgz",
"integrity": "sha512-KYOUGQFlLWR+s4QMV2Q9ko38TZm7EdO87Qm7rvZLqk/webse/cDjtyxKhg/47l0byCbs/k46LT8qc4PKjAikzA==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/oxc-project"
}
},
"node_modules/@rolldown/binding-android-arm-eabi": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.12.tgz",
"integrity": "sha512-dB/a1214qKfHMXCpgqR4OZT+jS4kTyEXbQGJPqzobt5EwH5rX080pxE37alt3RzvR1bf1Yz/yGqRfrYAxuPw0A==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.14.tgz",
"integrity": "sha512-aWR+XKH9+rW7m5fWq/5360J3mHycrx/o6xZM2DQFdJnTMdyP7/WzxPjhtLbVWdKo2y612/4U1bWqb3HQhiF7vg==",
"cpu": [
"arm"
],
@@ -177,9 +178,9 @@
}
},
"node_modules/@rolldown/binding-android-arm64": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.12.tgz",
"integrity": "sha512-7KHFgQ5VJxIHcLlrwrc3Xbds7oTNQT7Pgi9gQCJKrd2VGab/UksIOYp6VD8MzCstGxOKMgNamPwUCfxPdP1OHg==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.14.tgz",
"integrity": "sha512-QiVxHofl6A8lQU7WAtOUY4QMVZXohxwz7WJJoeh8NBEUyKfIkMRKhYyq8az/1RypNiIXzNTtiS6KwHz0erxYRQ==",
"cpu": [
"arm64"
],
@@ -193,9 +194,9 @@
}
},
"node_modules/@rolldown/binding-darwin-arm64": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.12.tgz",
"integrity": "sha512-3YIhqHD96nA5SaYNRBR16HnGv4oavZvXfD/ayHM+oYZ0WD/8lBAtf6zQua4kEyAvpqrluKXl0lnOBoiNby7x9w==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.14.tgz",
"integrity": "sha512-lTQOzHuBIooh3jIr5XINQkjPGEuGy+Dsy0meXDr6Sjty0b99kYgGh4uBC/8mJX1T0kC8d6S0aPP1Y+bHkh6aBw==",
"cpu": [
"arm64"
],
@@ -209,9 +210,9 @@
}
},
"node_modules/@rolldown/binding-darwin-x64": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.12.tgz",
"integrity": "sha512-UuuJ35MFw4gmFOrE9pEqIV+K3syIKveph+Qc1/ljHZVdoDW4pz/JHR/eMVom+TZGl/5OOvGJOWaOCVt3ZfqhxA==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.14.tgz",
"integrity": "sha512-hyMKEGatjmBYCs/Q4sbIcL/GqpFEqsX3wc+HYVQ/85A4rxc1o7rPm4DUI4GV4k/h0ITddwFSGpqQunI14GXjTA==",
"cpu": [
"x64"
],
@@ -225,9 +226,9 @@
}
},
"node_modules/@rolldown/binding-freebsd-x64": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.12.tgz",
"integrity": "sha512-uMvssit0a4W+/7D8CbHUvG719mH3R2jwXAlh/XcPvuHTE0g++LymF88DCGNX0HM2rBOn0xrzgXktIB6fLSJBTQ==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.14.tgz",
"integrity": "sha512-u371GbXoVXrEgP20PwzoGNOdAOqAMhzo19JzzY+V4YmmnC+DTOoqdbMu+O+54emM59Mik/UdrtWgcuEDKWRPKA==",
"cpu": [
"x64"
],
@@ -241,9 +242,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm-gnueabihf": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.12.tgz",
"integrity": "sha512-XcFu0R0xWnwzSf4IQgFH1rJIckPN1pLy2R+4r9IDB7Yfu/ys9cVqfa4pBrMHj7a3gl8mIR4nRNPg0e5IvEVs6g==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.14.tgz",
"integrity": "sha512-BqwKsdZQf6EqVWr8fv2MrDYzAvOZ7+NYFSJESRGs87fkseEhs0TU9TXgRJTkZoRRkxTizyEg1LKUXfU3/78uqg==",
"cpu": [
"arm"
],
@@ -257,9 +258,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-gnu": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.12.tgz",
"integrity": "sha512-260UrKgn8tz39ak+SMDOirKzr7V04M9dWPw5llW00SwBivCZoWcRBKV1d8cXnRkUmSZA3BdiUmBHWk7734Ulpw==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.14.tgz",
"integrity": "sha512-SD9kY8M009x/7s57Z1dgUVlP5+uYBgKQK0Tkr1WIWngrtUJmRCW1RJFMY7QDla2khXhmg2i5Io7MUjcmZNZ/KQ==",
"cpu": [
"arm64"
],
@@ -276,9 +277,9 @@
}
},
"node_modules/@rolldown/binding-linux-arm64-musl": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.12.tgz",
"integrity": "sha512-5YK1I9SqDkbPgc1IA8BgDl34suqUS2q0KWnBrirm0E51YjOs6eo6dV6jbQfNE/argHRSvd0QUGgtpIoYx+WWpw==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.14.tgz",
"integrity": "sha512-BJ2CL19M6uuWesMgnqJzgxoI+N+eV7b0A9O9vLV42y+gitC41fNa8KElau1tHVzuLWX5GzEuxMPhAO0tQXQMkg==",
"cpu": [
"arm64"
],
@@ -295,9 +296,9 @@
}
},
"node_modules/@rolldown/binding-linux-ppc64-gnu": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.12.tgz",
"integrity": "sha512-Rkcrmp7eFRg74yL5fXEU91JEWbdEPLevWwGtXpmhbjlD1StScbWTmO94Bhly+Mo+ketKYkdmM1vNUKeWSlx8cQ==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.14.tgz",
"integrity": "sha512-4+Kl8daPV8NDHaD7mfCcc1pRM+Qg7ab8DyMm5FG5WoZgv4h2i3KFN1CybYBNbQqmuYm7ftJLvmMI1eHYJ22S/Q==",
"cpu": [
"ppc64"
],
@@ -314,9 +315,9 @@
}
},
"node_modules/@rolldown/binding-linux-s390x-gnu": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.12.tgz",
"integrity": "sha512-qvK4DuAsQc2BSjlx+Xr+IzOIvvxbGZqxFwdWfG6F518Erj0GGISyQbJ6pIappnOxlNPzNHvo/L0BwB30GZ+zVw==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.14.tgz",
"integrity": "sha512-V/h8ePq1fKDrmtFMz6xcCN3DKvuvMRrwwD1q0PkBeeo4DpK64biaKvqWGVxqCeYKqeRk7gE7/iKPxLCn08O97A==",
"cpu": [
"s390x"
],
@@ -333,9 +334,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-gnu": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.12.tgz",
"integrity": "sha512-Q9uLBO53Xd4QIq1WOycVQyPP1O4HhraEV2qqb3uTrnVw6QZih9duY4vNXOivL1xoUS1/z+W8eF4NMfl2a8Sdjw==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.14.tgz",
"integrity": "sha512-WxalXzgrLVpKC93xfpaJ3gCXUWzeCr+FRCbDVD2mUAy4L6Vo3lNVz0epUEUpxPWJkLNYUwM4OSIikv36OJ9mLg==",
"cpu": [
"x64"
],
@@ -352,9 +353,9 @@
}
},
"node_modules/@rolldown/binding-linux-x64-musl": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.12.tgz",
"integrity": "sha512-3IBxWFMjbOZskDPKv8Lf9BCnahlKuHthWkYnyIxOH/QcJrFcS4EmcenthApkwr/5+nEqZlLzeYbxeMaX7A5u4g==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.14.tgz",
"integrity": "sha512-3G3tnAmTpdk9jO3GQtyHXqeFD2SlecfTws/Y3M2mmj9nMBwwuLT4kur8sZKeu7ENUHSpVO3cIsm5A52LEWWwlg==",
"cpu": [
"x64"
],
@@ -371,9 +372,9 @@
}
},
"node_modules/@rolldown/binding-openharmony-arm64": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.12.tgz",
"integrity": "sha512-xtX61xg4LKPkPWilZU1ynKClz5Gj4bf74LML4r3eVLWumKnGjoEr1OSHQhMdbBDoYTi+yjrujvpZe2pUnqCrrA==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.14.tgz",
"integrity": "sha512-qyr5XiNGxm2ytx17vvtcJ9nXn6v1gENETi503bJx3OGwZ1tSonj7BosxbMa/xeAfSl5iS9X6KjEWYXLu6v1L7Q==",
"cpu": [
"arm64"
],
@@ -387,9 +388,9 @@
}
},
"node_modules/@rolldown/binding-win32-arm64-msvc": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.12.tgz",
"integrity": "sha512-At7fPB6PCaIjzgIhEZFxuT+BBFqiQibJDT4d3PhiR3f4E7bbMZF4aKblbFfEM3sETRDd1YiQx/+U/g/B/ou5Ew==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.14.tgz",
"integrity": "sha512-oA4o5o0S2yB199YyYXDzKUv1Z56Rc+mgOjwm7Z/vJ9Z8igiDPYvoOuDyo6g7AK/ZaF09nPhDKVnGBcYHO11GXA==",
"cpu": [
"arm64"
],
@@ -403,9 +404,9 @@
}
},
"node_modules/@rolldown/binding-win32-x64-msvc": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.12.tgz",
"integrity": "sha512-WIw2haVKwjuYdXkHaoC0mF8Le71TuCBxjrdKqLbJGctbBABj+ClfmNvtbOnzpq3RokNo5+V1qhtSzJyXorsklQ==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.14.tgz",
"integrity": "sha512-9mE94bf2GZUaR/fUSXCMpBoWkctu421Mi0ORpm4zqfbkjKep7RxzPFa5etcGs5h+2KApoWBOA/hAJa/7saGgEQ==",
"cpu": [
"x64"
],
@@ -1606,9 +1607,9 @@
}
},
"node_modules/i18next": {
"version": "26.4.7",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.4.7.tgz",
"integrity": "sha512-p/3hqy6EcuqRs6wNwBYwGGC1fzBJSMxV9zMuN814ab/7QjdZbXfjXwuPZdQbngX6KDOTxM01uUiZyqmMB8ghZg==",
"version": "26.5.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-26.5.2.tgz",
"integrity": "sha512-6fIXt//2MZNok3tULyjnypxe3vbsy3pV1bVg8p2x3yKrzZvp7z3T+wXx/88LQsATRdhyJeAUAvUxEtxsHdJ29w==",
"funding": [
{
"type": "individual",
@@ -1904,9 +1905,9 @@
}
},
"node_modules/lucide-react": {
"version": "1.58.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.58.0.tgz",
"integrity": "sha512-hXaFNm6mk6QVtBnDGBn1YAs8j2tGUk0A4s/CpclIcczfxeXiW1rdOLVo6zCsoIih9XXsGvDODQerl749a2n7bA==",
"version": "1.59.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-1.59.0.tgz",
"integrity": "sha512-5qgMyyCPU6OvnKpLS2t693+ZtiqA8oaSweWoUows0BLFKFf6V75m4+CptpmohZHpD5IuOVIBXHBBiv2vpLJmtw==",
"license": "ISC",
"peerDependencies": {
"@types/react": "*",
@@ -1978,9 +1979,9 @@
}
},
"node_modules/postcss": {
"version": "8.5.29",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz",
"integrity": "sha512-49cGhUbXj8Qenv0iTMxA1cFBzxXoctpC9Ujd77t1WcbJIr6nF/eI7g/8MgxrYldFRuAXvja7xQRwavoW7kgrxQ==",
"version": "8.5.30",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.30.tgz",
"integrity": "sha512-zkd+e9S1AQHhmaBKye9zlFHWjOwVgqXl1q3ECYy8561K7qxR2cREf/STLskulBFd78k6AOFeA+ff1TtEzk9bAA==",
"funding": [
{
"type": "opencollective",
@@ -1997,7 +1998,7 @@
],
"license": "MIT",
"dependencies": {
"nanoid": "^3.3.19",
"nanoid": "^3.3.20",
"picocolors": "^1.1.1",
"source-map-js": "^1.2.2"
},
@@ -2027,9 +2028,9 @@
}
},
"node_modules/react-i18next": {
"version": "17.0.19",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.0.19.tgz",
"integrity": "sha512-BRHqiqOfW4J/LBVtbBFHoBoZm/Ez2/tkHPitYtn0CSpkYhEaEAsZMPsg7hZlomu30UJYQ6ZKiP3pwa3QnxGvQw==",
"version": "17.1.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-17.1.0.tgz",
"integrity": "sha512-4VouOnTDyvhvqXx6WZ+s3/cgSiaLutILdYkO3P1Ms+4qcKR7At+JP4Vi7IeHkVLyVV+DmN1l23Pn73UcwSGGPA==",
"license": "MIT",
"dependencies": {
"@babel/runtime": "^7.29.7",
@@ -2054,12 +2055,12 @@
}
},
"node_modules/rolldown": {
"version": "1.2.12",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.12.tgz",
"integrity": "sha512-8wafseiaG80xmXSfqidUNqZcylTlhmPZZt+za2m+js2sFZ8dTNlhIOV2WcbIPx2hgwPBJpEUGFAMZ9bgBBLTSQ==",
"version": "1.2.14",
"resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.14.tgz",
"integrity": "sha512-eTBTTqMR6uHKLgcUqpJP8ntzDI6V4LYA8negAMBEI7gkgVvOdrx6VsvS2Ym+83KhOPdLCHWJu0w7UQFJZhHKNw==",
"license": "MIT",
"dependencies": {
"@oxc-project/types": "=0.152.0",
"@oxc-project/types": "=0.154.0",
"@rolldown/pluginutils": "^1.0.0"
},
"bin": {
@@ -2069,21 +2070,21 @@
"node": "^20.19.0 || >=22.12.0"
},
"optionalDependencies": {
"@rolldown/binding-android-arm-eabi": "1.2.12",
"@rolldown/binding-android-arm64": "1.2.12",
"@rolldown/binding-darwin-arm64": "1.2.12",
"@rolldown/binding-darwin-x64": "1.2.12",
"@rolldown/binding-freebsd-x64": "1.2.12",
"@rolldown/binding-linux-arm-gnueabihf": "1.2.12",
"@rolldown/binding-linux-arm64-gnu": "1.2.12",
"@rolldown/binding-linux-arm64-musl": "1.2.12",
"@rolldown/binding-linux-ppc64-gnu": "1.2.12",
"@rolldown/binding-linux-s390x-gnu": "1.2.12",
"@rolldown/binding-linux-x64-gnu": "1.2.12",
"@rolldown/binding-linux-x64-musl": "1.2.12",
"@rolldown/binding-openharmony-arm64": "1.2.12",
"@rolldown/binding-win32-arm64-msvc": "1.2.12",
"@rolldown/binding-win32-x64-msvc": "1.2.12"
"@rolldown/binding-android-arm-eabi": "1.2.14",
"@rolldown/binding-android-arm64": "1.2.14",
"@rolldown/binding-darwin-arm64": "1.2.14",
"@rolldown/binding-darwin-x64": "1.2.14",
"@rolldown/binding-freebsd-x64": "1.2.14",
"@rolldown/binding-linux-arm-gnueabihf": "1.2.14",
"@rolldown/binding-linux-arm64-gnu": "1.2.14",
"@rolldown/binding-linux-arm64-musl": "1.2.14",
"@rolldown/binding-linux-ppc64-gnu": "1.2.14",
"@rolldown/binding-linux-s390x-gnu": "1.2.14",
"@rolldown/binding-linux-x64-gnu": "1.2.14",
"@rolldown/binding-linux-x64-musl": "1.2.14",
"@rolldown/binding-openharmony-arm64": "1.2.14",
"@rolldown/binding-win32-arm64-msvc": "1.2.14",
"@rolldown/binding-win32-x64-msvc": "1.2.14"
}
},
"node_modules/scheduler": {
@@ -2092,6 +2093,19 @@
"integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==",
"license": "MIT"
},
"node_modules/semver": {
"version": "7.8.5",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/source-map-js": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz",
+4 -3
View File
@@ -58,11 +58,11 @@
"@tauri-apps/plugin-log": "^2.10.1",
"@tauri-apps/plugin-notification": "^2.7.0",
"@tauri-apps/plugin-opener": "^2.7.2",
"i18next": "^26.4.7",
"lucide-react": "^1.58.0",
"i18next": "^26.5.2",
"lucide-react": "^1.59.0",
"react": "^19.3.1",
"react-dom": "^19.3.1",
"react-i18next": "^17.0.19",
"react-i18next": "^17.1.0",
"zustand": "^5.0.15"
},
"devDependencies": {
@@ -70,6 +70,7 @@
"@types/react": "^19.3.0",
"@types/react-dom": "^19.3.0",
"@vitejs/plugin-react": "^6.1.2",
"semver": "^7.8.5",
"tailwindcss": "^4.3.3",
"typescript": "^7.0.2",
"vite": "^8.3.4",
+178 -16
View File
@@ -1,9 +1,10 @@
#!/usr/bin/env node
import { execFileSync } from 'node:child_process';
import { execFileSync, execSync } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import semver from 'semver';
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const repoRoot = path.resolve(__dirname, '..');
@@ -72,16 +73,29 @@ function npmExecutable(platform = process.platform) {
return platform === 'win32' ? 'npm.cmd' : 'npm';
}
function npmOutdated(cwd) {
function npmOutdated(cwd, {
platform = process.platform,
runFile = execFileSync,
runShell = execSync,
} = {}) {
if (!fs.existsSync(path.join(cwd, 'package.json'))) {
throw new Error(`npm workspace is missing package.json: ${cwd}`);
}
const args = ['outdated', '--all', '--json'];
const options = {
cwd,
encoding: 'utf8',
maxBuffer: 16 * 1024 * 1024,
stdio: ['ignore', 'pipe', 'pipe'],
};
try {
execFileSync(npmExecutable(), ['outdated', '--json'], {
cwd,
encoding: 'utf8',
stdio: ['ignore', 'pipe', 'pipe'],
});
if (platform === 'win32') {
// npm.cmd is a command shim, not a native executable. Keep the command
// fixed here (no user-controlled arguments) and let cmd.exe run it.
runShell(`${npmExecutable(platform)} ${args.join(' ')}`, options);
} else {
runFile(npmExecutable(platform), args, options);
}
return {};
} catch (error) {
if (error.status !== 1) {
@@ -323,6 +337,140 @@ function printCargoReport(updates) {
return updates.length;
}
function npmUpdateRows(outdated, { cwd = process.cwd(), lockfilePackages = {} } = {}) {
if (!outdated || typeof outdated !== 'object' || Array.isArray(outdated)) {
throw new Error('npm outdated response was not a package map');
}
const lockfileVersionAtLocation = location => {
if (typeof location !== 'string' || !location.trim()) return undefined;
let lockfilePath = location.trim().replaceAll('\\', '/');
if (path.isAbsolute(location)) {
const relativePath = path.relative(cwd, location);
if (path.isAbsolute(relativePath) || relativePath === '..' || relativePath.startsWith(`..${path.sep}`)) {
return undefined;
}
lockfilePath = relativePath.split(path.sep).join('/');
}
lockfilePath = lockfilePath.replace(/^\.\//, '');
if (lockfilePath === '..' || lockfilePath.startsWith('../')) return undefined;
return normalizeVersion(lockfilePackages[lockfilePath]?.version);
};
const lockfileVersionsForName = name => {
const suffix = `/node_modules/${name}`;
return Object.entries(lockfilePackages)
.filter(([lockfilePath]) => lockfilePath === `node_modules/${name}` || lockfilePath.endsWith(suffix))
.map(([, entry]) => normalizeVersion(entry?.version))
.filter(Boolean);
};
const rows = new Map();
for (const [name, value] of Object.entries(outdated)) {
const records = Array.isArray(value) ? value : [value];
const normalizedRecords = records.map(info => {
if (!info || typeof info !== 'object' || Array.isArray(info)) {
throw new Error(`npm outdated response for ${name} was not a package record`);
}
return {
info,
installedVersion: normalizeVersion(info.current),
locatedVersion: lockfileVersionAtLocation(info.location),
wanted: normalizeVersion(info.wanted),
latest: normalizeVersion(info.latest),
};
});
for (const record of normalizedRecords) {
if (!record.wanted || !record.latest) {
throw new Error(`npm outdated response for ${name} omitted wanted or latest version`);
}
}
const unresolved = normalizedRecords
.map((record, index) => ({ record, index }))
.filter(({ record }) => !record.installedVersion && !record.locatedVersion);
const lockVersions = unresolved.length ? lockfileVersionsForName(name) : [];
const resolvedLockVersions = new Map();
if (lockVersions.length === 1) {
for (const { index } of unresolved) resolvedLockVersions.set(index, lockVersions[0]);
} else if (lockVersions.length > 1) {
if (lockVersions.length !== unresolved.length) {
throw new Error(`npm outdated response for ${name} omitted locations for duplicate package-lock entries`);
}
const remainingLockVersions = [...lockVersions];
const remainingRecords = [];
for (const { record, index } of unresolved) {
const wanted = semver.valid(record.wanted);
if (!wanted) continue;
const exactIndex = remainingLockVersions.findIndex(version => semver.valid(version)
&& semver.eq(version, wanted));
if (exactIndex >= 0) {
resolvedLockVersions.set(index, remainingLockVersions.splice(exactIndex, 1)[0]);
} else {
remainingRecords.push({ record, index, wanted });
}
}
if (remainingRecords.length !== remainingLockVersions.length) {
throw new Error(`npm outdated response for ${name} could not be matched safely to package-lock entries`);
}
remainingRecords.sort((left, right) => semver.compare(left.wanted, right.wanted));
remainingLockVersions.sort((left, right) => {
const leftVersion = semver.valid(left);
const rightVersion = semver.valid(right);
if (!leftVersion || !rightVersion) {
throw new Error(`npm lockfile contains a non-semver duplicate for ${name}`);
}
return semver.compare(leftVersion, rightVersion);
});
remainingRecords.forEach(({ index }, offset) => {
resolvedLockVersions.set(index, remainingLockVersions[offset]);
});
}
for (const [index, record] of normalizedRecords.entries()) {
const currentVersions = record.installedVersion
? [record.installedVersion]
: record.locatedVersion
? [record.locatedVersion]
: resolvedLockVersions.has(index)
? [resolvedLockVersions.get(index)]
: [];
// npm can include optional or peer packages that are absent from both
// this host's physical tree and the lockfile. They are not resolved
// Firelink dependencies. When lock entries exist, map them to records
// by physical location or the matching npm `wanted` version.
if (!currentVersions.length) continue;
if (!semver.valid(record.wanted) || !semver.valid(record.latest)) continue;
for (const current of currentVersions) {
if (!semver.valid(current) || semver.gte(current, record.wanted)) continue;
const key = `${name}\0${current}\0${record.wanted}\0${record.latest}`;
const row = rows.get(key) || {
name,
current,
wanted: record.wanted,
latest: record.latest,
lockfileOnly: !record.installedVersion,
dependents: new Set(),
};
row.lockfileOnly = row.lockfileOnly && !record.installedVersion;
if (typeof record.info.dependent === 'string' && record.info.dependent.trim()) {
row.dependents.add(record.info.dependent.trim());
}
rows.set(key, row);
}
}
}
return [...rows.values()]
.map(row => ({ ...row, dependents: [...row.dependents].sort() }))
.sort((left, right) => left.name.localeCompare(right.name)
|| left.current.localeCompare(right.current)
|| left.wanted.localeCompare(right.wanted));
}
function hasUpdateCheckFailures({
outdatedCount,
engineIssueCount,
@@ -335,17 +483,28 @@ function hasUpdateCheckFailures({
|| providerBehind.length > 0;
}
function printNpmReport(label, outdated) {
const entries = Object.entries(outdated);
if (!entries.length) {
function printNpmReport(label, outdated, cwd) {
let lockfilePackages = {};
if (Object.keys(outdated).length > 0) {
const lockfilePath = path.join(cwd, 'package-lock.json');
const lockfile = JSON.parse(fs.readFileSync(lockfilePath, 'utf8'));
if (!lockfile.packages || typeof lockfile.packages !== 'object' || Array.isArray(lockfile.packages)) {
throw new Error(`npm lockfile did not contain a package map: ${lockfilePath}`);
}
lockfilePackages = lockfile.packages;
}
const rows = npmUpdateRows(outdated, { cwd, lockfilePackages });
if (!rows.length) {
console.log(`${label}: current`);
return 0;
}
console.log(`${label}: ${entries.length} outdated package(s)`);
for (const [name, info] of entries) {
console.log(` ${name}: ${info.current} -> ${info.latest} (wanted ${info.wanted})`);
console.log(`${label}: ${rows.length} compatible package update(s)`);
for (const row of rows) {
const dependents = row.dependents.length ? ` via ${row.dependents.join(', ')}` : '';
const source = row.lockfileOnly ? ' (from lockfile)' : '';
console.log(` ${row.name}: ${row.current}${source} -> ${row.wanted} (latest ${row.latest})${dependents}`);
}
return entries.length;
return rows.length;
}
function sourceEngineVersions(sourceLock) {
@@ -500,10 +659,11 @@ function checkRows(
async function main() {
let outdatedCount = 0;
outdatedCount += printNpmReport('root npm', npmOutdated(repoRoot));
outdatedCount += printNpmReport('root npm', npmOutdated(repoRoot), repoRoot);
outdatedCount += printNpmReport(
'Browser extension npm',
npmOutdated(path.join(repoRoot, 'Extensions', 'Browser'))
npmOutdated(path.join(repoRoot, 'Extensions', 'Browser')),
path.join(repoRoot, 'Extensions', 'Browser')
);
outdatedCount += printCargoReport(cargoCompatibleUpdates());
@@ -726,5 +886,7 @@ export {
latestBtbnFfmpegStableBuild,
latestMartinRiedlMacArm64Release,
npmExecutable,
npmOutdated,
npmUpdateRows,
providerAssetHashes,
};
+202 -1
View File
@@ -10,6 +10,8 @@ import {
latestMartinRiedlMacArm64Release,
hasUpdateCheckFailures,
npmExecutable,
npmOutdated,
npmUpdateRows,
providerAssetHashes,
} from './check-updates.js';
@@ -243,10 +245,209 @@ test('update checks pass only when every blocking count is clear', () => {
}), false);
});
test('npm executable selection uses the Windows command shim when needed', () => {
test('npm outdated runs the Windows command shim through a shell', () => {
assert.equal(npmExecutable('win32'), 'npm.cmd');
assert.equal(npmExecutable('darwin'), 'npm');
assert.equal(npmExecutable('linux'), 'npm');
let shellCommand;
let shellOptions;
let fileRunCalled = false;
assert.deepEqual(npmOutdated(process.cwd(), {
platform: 'win32',
runFile: () => { fileRunCalled = true; },
runShell: (command, options) => {
shellCommand = command;
shellOptions = options;
return '{}';
},
}), {});
assert.equal(shellCommand, 'npm.cmd outdated --all --json');
assert.equal(shellOptions.cwd, process.cwd());
assert.equal(shellOptions.encoding, 'utf8');
assert.equal(fileRunCalled, false);
});
test('npm update rows deduplicate nested records and retain compatible and major versions', () => {
const rows = npmUpdateRows({
'@babel/runtime': [
{
current: '7.29.7',
wanted: '7.29.10',
latest: '8.0.7',
dependent: 'react-i18next',
location: '/workspace/node_modules/@babel/runtime',
},
{
current: '7.29.7',
wanted: '7.29.10',
latest: '8.0.7',
dependent: 'another-package',
location: '/workspace/node_modules/@babel/runtime',
},
{
current: '7.29.7',
wanted: '7.29.10',
latest: '8.0.7',
dependent: 'react-i18next',
location: '/workspace/node_modules/@babel/runtime',
},
],
});
assert.deepEqual(rows, [{
name: '@babel/runtime',
current: '7.29.7',
wanted: '7.29.10',
latest: '8.0.7',
lockfileOnly: false,
dependents: ['another-package', 'react-i18next'],
}]);
});
test('npm update rows safely ignore absent optional platform packages', () => {
const rows = npmUpdateRows({
'@rolldown/binding-linux-x64-gnu': {
wanted: '1.2.14',
latest: '1.2.14',
dependent: 'rolldown',
location: '/workspace/node_modules/@rolldown/binding-linux-x64-gnu',
},
'@types/node': [
{
wanted: '26.6.5',
latest: '26.6.5',
dependent: 'vite',
},
{
wanted: '26.6.5',
latest: '26.6.5',
dependent: 'vitest',
},
],
}, {
cwd: '/workspace',
lockfilePackages: {
'node_modules/@rolldown/binding-linux-x64-gnu': { version: '1.2.14' },
'node_modules/@types/node': { version: '26.6.5' },
},
});
assert.deepEqual(rows, []);
});
test('npm update rows find compatible lockfile updates for absent optional packages', () => {
const rows = npmUpdateRows({
'@rolldown/binding-linux-x64-gnu': {
wanted: '1.2.14',
latest: '1.2.14',
dependent: 'rolldown',
},
}, {
cwd: '/workspace',
lockfilePackages: {
'node_modules/@rolldown/binding-linux-x64-gnu': { version: '1.2.12' },
},
});
assert.deepEqual(rows, [{
name: '@rolldown/binding-linux-x64-gnu',
current: '1.2.12',
wanted: '1.2.14',
latest: '1.2.14',
lockfileOnly: true,
dependents: ['rolldown'],
}]);
});
test('npm update rows match duplicate optional records to lockfile wanted versions', () => {
const rows = npmUpdateRows({
'lightningcss-linux-x64-gnu': [
{ wanted: '1.32.0', latest: '1.33.0', dependent: 'lightningcss' },
{ wanted: '1.33.0', latest: '1.33.0', dependent: 'lightningcss' },
],
}, {
cwd: '/workspace',
lockfilePackages: {
'node_modules/lightningcss-linux-x64-gnu': { version: '1.32.0' },
'node_modules/vite/node_modules/lightningcss-linux-x64-gnu': { version: '1.33.0' },
},
});
assert.deepEqual(rows, []);
});
test('npm update rows retain stale duplicates when current is absent on this platform', () => {
const rows = npmUpdateRows({
'lightningcss-linux-x64-gnu': [
{ wanted: '1.33.0', latest: '1.33.0', dependent: 'lightningcss' },
{ wanted: '1.33.0', latest: '1.33.0', dependent: 'lightningcss' },
],
}, {
cwd: '/workspace',
lockfilePackages: {
'node_modules/lightningcss-linux-x64-gnu': { version: '1.32.0' },
'node_modules/vite/node_modules/lightningcss-linux-x64-gnu': { version: '1.33.0' },
},
});
assert.deepEqual(rows, [{
name: 'lightningcss-linux-x64-gnu',
current: '1.32.0',
wanted: '1.33.0',
latest: '1.33.0',
lockfileOnly: true,
dependents: ['lightningcss'],
}]);
});
test('npm update rows recognize a prerelease to its compatible stable version', () => {
const rows = npmUpdateRows({
package: {
current: '1.0.0-rc.1',
wanted: '1.0.0',
latest: '2.0.0',
},
});
assert.deepEqual(rows, [{
name: 'package',
current: '1.0.0-rc.1',
wanted: '1.0.0',
latest: '2.0.0',
lockfileOnly: false,
dependents: [],
}]);
});
test('npm update rows ignore absent optional packages that are not in the lockfile', () => {
assert.deepEqual(npmUpdateRows({
'optional-package': {
wanted: '1.2.0',
latest: '2.0.0',
},
}, { cwd: '/workspace' }), []);
});
test('npm update rows fail closed when an absent duplicate has ambiguous lockfile versions', () => {
assert.throws(() => npmUpdateRows({
package: {
wanted: '1.2.0',
latest: '2.0.0',
},
}, {
lockfilePackages: {
'node_modules/first/node_modules/package': { version: '1.0.0' },
'node_modules/second/node_modules/package': { version: '1.1.0' },
},
}), /omitted locations for duplicate package-lock entries/);
});
test('npm update rows fail closed for malformed package records', () => {
assert.throws(
() => npmUpdateRows({ broken: [{ current: '1.0.0', latest: '2.0.0' }] }),
/omitted wanted or latest version/,
);
});
test('selects a complete BtbN build for the current stable series', async () => {
+4 -3
View File
@@ -34,10 +34,11 @@ test('frontend CI covers the supported Node lines and native builds use the curr
const desktopJob = ciWorkflow.slice(ciWorkflow.indexOf('\n desktop:'));
assert.match(ciWorkflow, /uses: actions\/setup-node@v7(?:\.\d+){0,2}/);
assert.match(frontendJob, /node:\s*\[22\.23\.3,\s*24\.21\.0\]/);
assert.match(frontendJob, /node:\s*\[22\.23\.3,\s*24\.22\.0,\s*26\.12\.0\]/);
assert.match(frontendJob, /node-version: \$\{\{ matrix\.node \}\}/);
assert.match(desktopJob, /node-version: 24\.21\.0/);
assert.match(releaseWorkflow, /node-version: 24\.21\.0/);
assert.match(desktopJob, /node-version: 24\.22\.0/);
assert.match(releaseWorkflow, /node-version: 24\.22\.0/);
assert.doesNotMatch(`${ciWorkflow}\n${releaseWorkflow}`, /node-version: 24\.21\.0/);
assert.doesNotMatch(`${ciWorkflow}\n${releaseWorkflow}`, /node-version: 22\.12(?:\D|$)/);
});
+24
View File
@@ -8,6 +8,12 @@ const releaseWorkflow = fs.readFileSync(
path.join(repositoryRoot, '.github', 'workflows', 'release.yml'),
'utf8',
);
const ciWorkflow = fs.readFileSync(
path.join(repositoryRoot, '.github', 'workflows', 'ci.yml'),
'utf8',
);
const readme = fs.readFileSync(path.join(repositoryRoot, 'README.md'), 'utf8');
const releaseGuide = fs.readFileSync(path.join(repositoryRoot, 'RELEASE.md'), 'utf8');
test('release Linux dependency installation is mirror-normalized and bounded', () => {
assert.match(releaseWorkflow, /azure\\\.archive\\\.ubuntu\\\.com/);
@@ -40,6 +46,24 @@ test('Linux release pins and verifies appimagetool and its runtime inputs', () =
assert.match(releaseWorkflow, /APPIMAGETOOL_RUNTIME_FILE: \$\{\{ runner\.temp \}\}\/appimage-runtime/);
});
test('CI covers the declared Node floor and current runtimes while native jobs use Node 24 LTS', () => {
assert.match(ciWorkflow, /node: \[22\.23\.3, 24\.22\.0, 26\.12\.0\]/);
assert.equal((ciWorkflow.match(/node-version: 24\.22\.0/g) || []).length, 1);
assert.equal((releaseWorkflow.match(/node-version: 24\.22\.0/g) || []).length, 1);
assert.doesNotMatch(`${ciWorkflow}\n${releaseWorkflow}`, /node-version: 24\.21\.0/);
});
test('Tauri CI and release workflows pin stable explicitly and Windows support floor is consistent', () => {
const workflows = `${ciWorkflow}\n${releaseWorkflow}`;
assert.equal((workflows.match(/dtolnay\/rust-toolchain@b725eda525362e7cf34af9a7243cac1e3f01a7ec/g) || []).length, 3);
assert.equal((workflows.match(/toolchain: stable/g) || []).length, 3);
assert.doesNotMatch(workflows, /dtolnay\/rust-toolchain@686976e191b89faba57d3206551f0f330d8cb249/);
assert.match(readme, /Windows 10 22H2 or newer/);
assert.match(releaseGuide, /Windows 10 22H2\+ target/);
assert.match(releaseGuide, /clean Windows 10 22H2\s+client \(OS build 19045\.x\)/);
assert.match(releaseGuide, /--assert-no-visible-child-windows.*--assert-portable-data/s);
});
test('Windows release job packages portable ZIP with portable.flag and data cleanup', () => {
assert.match(releaseWorkflow, /Set-Content -Path \(Join-Path \$portableRoot 'portable\.flag'\) -Value 'portable'/);
assert.match(releaseWorkflow, /node scripts\/smoke-packaged-app\.js --executable \$portableExe --assert-no-visible-child-windows --assert-portable-data/);
+16 -16
View File
@@ -2341,9 +2341,9 @@ dependencies = [
[[package]]
name = "inout"
version = "0.2.3"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8c0d789294fb457b791f7797a04478704788f30b407e5d0b01deaa846572d9f"
checksum = "3ce983bb6fb399067d101fbfc9e74174e07e9f29a2bc679efefeb8c645819c3f"
dependencies = [
"block-padding",
"hybrid-array",
@@ -2624,9 +2624,9 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.190"
version = "0.2.191"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78"
checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a"
[[package]]
name = "libdbus-sys"
@@ -2996,9 +2996,9 @@ dependencies = [
[[package]]
name = "num_threads"
version = "0.1.7"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9"
checksum = "cabcc654086861f9e1bc5115258de62ef92c79b20f4615a1b0cc57c4e82027d4"
dependencies = [
"libc",
]
@@ -4056,9 +4056,9 @@ dependencies = [
[[package]]
name = "schannel"
version = "0.1.29"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939"
checksum = "9cb23c424d8ee841bb4d813677ca237e2a610067d594fec130f87d6093495ab5"
dependencies = [
"windows-sys 0.61.2",
]
@@ -5705,9 +5705,9 @@ checksum = "a2c754d6c33795a1c324727428e5a7dedb5b06195f9890bdbcba760d3e246563"
[[package]]
name = "unicode-normalization"
version = "0.1.25"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd4f6878c9cb28d874b009da9e8d183b5abc80117c40bbd187a1fde336be6e8"
checksum = "75cd3fb03d5288b3ba9a1ee103ac7e9cbb59f0b03d64f8ddfcc04dd42758a85d"
dependencies = [
"tinyvec",
]
@@ -6747,9 +6747,9 @@ dependencies = [
[[package]]
name = "zbus_names"
version = "4.3.4"
version = "4.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8bf88b4a3ff53e883001e0e0115b297a9d53c31b9c1edd2bfdd853e3428624e"
checksum = "812a12be4ead7a59e18ea8f047d08add0066b73bc62fc1467066a2472ae088dd"
dependencies = [
"serde",
"winnow 1.0.4",
@@ -6874,9 +6874,9 @@ dependencies = [
[[package]]
name = "zvariant"
version = "5.15.0"
version = "5.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1d34c27cc6cdd1f458427519dd6b8612f7b7e3f7b9a0b2355d041dda9869147"
checksum = "80bf6d6cd6a4b601acb64cfb8284cdc643fcfa75ef26ae3c46ec8aa4e8a1fbb7"
dependencies = [
"endi",
"enumflags2",
@@ -6889,9 +6889,9 @@ dependencies = [
[[package]]
name = "zvariant_derive"
version = "5.15.0"
version = "5.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "864155e69b4352db0c7f374917bf45d1e0c8d17659c8b3dbf9795f3673f8c497"
checksum = "ef2672456ba1cb54b5eaec136e63135b3c7495fb938e53b28a62e633496d486d"
dependencies = [
"proc-macro-crate 3.5.0",
"proc-macro2",
+1 -1
View File
@@ -74,7 +74,7 @@ objc2-app-kit = { version = "0.3", default-features = false, features = ["NSAppl
objc2-core-services = "0.3"
objc2-foundation = { version = "0.3", default-features = false, features = ["NSAppleEventDescriptor", "NSAppleEventManager", "NSAppleScript", "NSDictionary", "NSNotification", "NSObject", "NSString", "objc2-core-services", "std"] }
smappservice-rs = "0.1.3"
unicode-normalization = "0.1.25"
unicode-normalization = "0.1.26"
[target.'cfg(target_os = "windows")'.dependencies]
windows-native-keyring-store = "1.1.0"