diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index df3890b..6a40678 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,8 @@ jobs: with: node-version: 22 cache: npm + - name: Verify release version + run: node scripts/verify-release-version.js - uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.target }} diff --git a/.gitignore b/.gitignore index 5d673cd..6f4273a 100644 --- a/.gitignore +++ b/.gitignore @@ -18,8 +18,13 @@ CROSS_PLATFORM_CHECKLIST.md Cross-platform-checklist-gemini.MD YouTube_media_download_handoff.md Release_checklist.md +Release Checklist/ +RC Read-only/ +RC Read_only/ # Frontend output and logs +.agents/ +release_notes.md node_modules/ dist/ dist-ssr/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 2374145..08d47e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,23 @@ All notable changes to Firelink will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.2] - 2026-07-21 + +This patch release hardens download lifecycle handling, localization, and packaged release checks. + +### New +- Add localized desktop UI coverage for Persian, Hebrew, Russian, Ukrainian, and Simplified Chinese. +- Add optional batch folders and safer reuse of unfinished downloads with matching filenames. + +### Improved +- Make pause, resume, remove, redownload, queue, scheduler, and settings actions safer when operations overlap. +- Improve first-open navigation, RTL layout, browser-cookie recovery, and download metadata handling. +- Strengthen packaged engine, Windows portable, Linux package, and release-asset verification. + +### Fixed +- Prevent stale or duplicate lifecycle work from deleting or resurrecting the wrong download. +- Keep missed completion events, localized state, and browser handoffs from leaving misleading UI state. + ## [1.1.1] - 2026-07-17 This patch release focuses on transfer reliability, browser captures, and easier download control. diff --git a/README.md b/README.md index 613f977..d6efdb2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ **A fast, focused desktop download manager for macOS, Windows, and Linux.** - [![Version](https://img.shields.io/badge/version-1.1.1-6f42c1?style=flat-square)](https://github.com/nimbold/Firelink/releases) + [![Version](https://img.shields.io/badge/version-1.1.2-6f42c1?style=flat-square)](https://github.com/nimbold/Firelink/releases) [![macOS](https://img.shields.io/badge/macOS-111111?style=flat-square&logo=apple&logoColor=white)](#platforms) [![Windows](.github/badges/windows.svg)](#platforms) [![Linux](https://img.shields.io/badge/Linux-FCC624?style=flat-square&logo=linux&logoColor=black)](#platforms) @@ -37,9 +37,9 @@ Firelink is a cross-platform desktop download manager for direct transfers, brow It combines a Rust/Tauri backend with a React and TypeScript interface. Bundled aria2, yt-dlp, FFmpeg, Deno, and SQLite support the download and media workflows. -The current desktop release is **1.1.1**, paired with Firelink Companion **2.0.5**. +The current desktop release is **1.1.2**, paired with Firelink Companion **2.0.5**. -This release adds YouTube playlist downloads, live connection controls, clipboard capture, and clearer byte-level progress. It also improves slow-transfer recovery, authenticated browser captures, and startup consent handling. +This patch release hardens download lifecycle handling, localization, and packaged release checks. ## Features @@ -107,7 +107,7 @@ What it adds: Install the extension, open Firelink, then pair it from **Settings -> Integrations**. Firefox users can install it from Mozilla Add-ons. Chromium users can load `firelink-chromium.zip` from the [extension releases](https://github.com/nimbold/Firelink-Extension/releases) with the [manual Chromium instructions](https://github.com/nimbold/Firelink-Extension#manual-chromium-installation). -Use the latest [Firelink Companion release](https://github.com/nimbold/Firelink-Extension/releases) with Firelink 1.1.1. The source is in the [Firelink-Extension repository](https://github.com/nimbold/Firelink-Extension), which this repo vendors as the `Extensions/Browser` submodule. +Use the latest [Firelink Companion release](https://github.com/nimbold/Firelink-Extension/releases) with Firelink 1.1.2. The source is in the [Firelink-Extension repository](https://github.com/nimbold/Firelink-Extension), which this repo vendors as the `Extensions/Browser` submodule. ## Platforms diff --git a/package-lock.json b/package-lock.json index 9b98651..32a707c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "firelink", - "version": "1.1.1", + "version": "1.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "firelink", - "version": "1.1.1", + "version": "1.1.2", "license": "MIT", "dependencies": { "@formkit/auto-animate": "^0.10.0", diff --git a/package.json b/package.json index 0dc5628..50eb8a7 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "firelink", "private": true, - "version": "1.1.1", + "version": "1.1.2", "description": "A fast cross-platform desktop download manager powered by Rust, Tauri, React, aria2, and yt-dlp.", "license": "MIT", "homepage": "https://github.com/nimbold/Firelink", diff --git a/scripts/verify-release-version.js b/scripts/verify-release-version.js new file mode 100644 index 0000000..8e33a6c --- /dev/null +++ b/scripts/verify-release-version.js @@ -0,0 +1,69 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const scriptDirectory = path.dirname(fileURLToPath(import.meta.url)); +const repositoryRoot = path.resolve(scriptDirectory, '..'); + +function argValue(name) { + const index = process.argv.indexOf(name); + return index >= 0 ? process.argv[index + 1] : undefined; +} + +function readPackageVersion(root) { + return JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')).version; +} + +function readTauriVersion(root) { + return JSON.parse( + fs.readFileSync(path.join(root, 'src-tauri', 'tauri.conf.json'), 'utf8') + ).version; +} + +function readCargoVersion(root) { + const cargo = fs.readFileSync(path.join(root, 'src-tauri', 'Cargo.toml'), 'utf8'); + const packageSection = cargo.match(/^\[package\]\s*([\s\S]*?)(?=^\[)/m)?.[1]; + const version = packageSection?.match(/^version\s*=\s*"([^"]+)"/m)?.[1]; + if (!version) { + throw new Error('Could not read the [package] version from src-tauri/Cargo.toml.'); + } + return version; +} + +function versionFromRef(ref) { + if (!ref || !ref.startsWith('v')) { + throw new Error(`Expected a semantic version tag such as v1.2.3, received ${ref || 'nothing'}.`); + } + const version = ref.slice(1); + if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(version)) { + throw new Error(`Release tag ${ref} does not contain a valid semantic version.`); + } + return version; +} + +const tag = argValue('--tag') || process.env.GITHUB_REF_NAME; +const expected = versionFromRef(tag); +const versions = { + 'package.json': readPackageVersion(repositoryRoot), + 'src-tauri/Cargo.toml': readCargoVersion(repositoryRoot), + 'src-tauri/tauri.conf.json': readTauriVersion(repositoryRoot), +}; +const mismatches = Object.entries(versions) + .filter(([, version]) => version !== expected) + .map(([file, version]) => `${file}=${version}`); + +if (mismatches.length > 0) { + console.error(`Release tag ${tag} does not match the application manifests (expected ${expected}).`); + for (const mismatch of mismatches) console.error(` ${mismatch}`); + process.exit(1); +} + +const uniqueVersions = new Set(Object.values(versions)); +if (uniqueVersions.size !== 1) { + console.error('Application version manifests do not agree:'); + for (const [file, version] of Object.entries(versions)) console.error(` ${file}=${version}`); + process.exit(1); +} + +console.log(`Release version ${expected} matches ${Object.keys(versions).length} manifests.`); diff --git a/scripts/verify-release-version.node-test.js b/scripts/verify-release-version.node-test.js new file mode 100644 index 0000000..d630133 --- /dev/null +++ b/scripts/verify-release-version.node-test.js @@ -0,0 +1,37 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { spawnSync } from 'node:child_process'; +import test from 'node:test'; + +const repositoryRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const verifier = path.join(repositoryRoot, 'scripts', 'verify-release-version.js'); +const currentVersion = JSON.parse( + fs.readFileSync(path.join(repositoryRoot, 'package.json'), 'utf8') +).version; + +function runVerifier(tag) { + return spawnSync(process.execPath, [verifier, '--tag', tag], { + cwd: repositoryRoot, + encoding: 'utf8', + }); +} + +test('release version verifier accepts the aligned current version', () => { + const result = runVerifier(`v${currentVersion}`); + assert.equal(result.status, 0, result.stderr); + assert.match(result.stdout, new RegExp(`Release version ${currentVersion} matches`)); +}); + +test('release version verifier rejects the already-published prior tag', () => { + const result = runVerifier('v1.1.1'); + assert.equal(result.status, 1); + assert.match(result.stderr, /does not match the application manifests/); +}); + +test('release version verifier rejects non-semver tag names', () => { + const result = runVerifier('release-candidate'); + assert.equal(result.status, 1); + assert.match(result.stderr, /semantic version tag/); +}); diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 63a2fd0..16f503a 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1365,7 +1365,7 @@ checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "firelink" -version = "1.1.1" +version = "1.1.2" dependencies = [ "apple-native-keyring-store", "async-trait", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 21a28d6..0851649 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "firelink" -version = "1.1.1" +version = "1.1.2" description = "A fast cross-platform desktop download manager powered by Rust and Tauri" authors = ["NimBold"] edition = "2021" diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 6878ac3..c8dc57e 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "Firelink", - "version": "1.1.1", + "version": "1.1.2", "identifier": "com.nimbold.firelink", "build": { "beforeDevCommand": "node scripts/stage-engines.js && npm run dev",