forked from akai/readest
feat(updater): nightly update channel (Android/Windows/macOS/Linux) (#4577)
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { invoke } from '@tauri-apps/api/core';
|
||||
import { invoke, Channel } from '@tauri-apps/api/core';
|
||||
|
||||
export interface CopyURIRequest {
|
||||
uri: string;
|
||||
@@ -263,3 +263,31 @@ export async function clearSyncPassphrase(): Promise<SyncPassphraseResponse> {
|
||||
export async function isSyncKeychainAvailable(): Promise<SyncKeychainAvailableResponse> {
|
||||
return invoke<SyncKeychainAvailableResponse>('plugin:native-bridge|is_sync_keychain_available');
|
||||
}
|
||||
|
||||
// ── Nightly updater (main-app commands, no native-bridge prefix) ─────────
|
||||
// `verify_update_signature` gates the custom install flows (portable /
|
||||
// AppImage / Android); `install_nightly_update` drives the Tauri updater for
|
||||
// the platform keys it natively installs (macOS / Windows-NSIS).
|
||||
|
||||
export async function verifyUpdateSignature(
|
||||
path: string,
|
||||
signature: string,
|
||||
pubKey: string,
|
||||
): Promise<boolean> {
|
||||
return invoke<boolean>('verify_update_signature', { path, signature, pubKey });
|
||||
}
|
||||
|
||||
export interface NightlyProgress {
|
||||
event: 'progress' | 'finished';
|
||||
downloaded: number;
|
||||
contentLength: number;
|
||||
}
|
||||
|
||||
export async function installNightlyUpdate(
|
||||
endpoint: string,
|
||||
onProgress?: (p: NightlyProgress) => void,
|
||||
): Promise<void> {
|
||||
const channel = new Channel<NightlyProgress>();
|
||||
if (onProgress) channel.onmessage = onProgress;
|
||||
await invoke<void>('install_nightly_update', { endpoint, channel });
|
||||
}
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
import semver from 'semver';
|
||||
import packageJson from '../../package.json';
|
||||
|
||||
export const getAppVersion = () => {
|
||||
return packageJson.version;
|
||||
};
|
||||
|
||||
export interface ParsedUpdateVersion {
|
||||
base: string; // "X.Y.Z"
|
||||
stamp: number | null; // YYYYMMDDHH, or null when not a nightly
|
||||
isNightly: boolean;
|
||||
}
|
||||
|
||||
// A nightly version is `<base>-<YYYYMMDDHH>`: a single, pure-10-digit
|
||||
// prerelease identifier. Anything else (e.g. `-rc.1`, `-2026`) is treated as a
|
||||
// non-nightly base version.
|
||||
export const parseUpdateVersion = (version: string): ParsedUpdateVersion | null => {
|
||||
const parsed = semver.parse(version);
|
||||
if (!parsed) return null;
|
||||
const base = `${parsed.major}.${parsed.minor}.${parsed.patch}`;
|
||||
let stamp: number | null = null;
|
||||
if (parsed.prerelease.length === 1) {
|
||||
const id = String(parsed.prerelease[0]);
|
||||
if (/^\d{10}$/.test(id)) {
|
||||
stamp = Number(id);
|
||||
}
|
||||
}
|
||||
return { base, stamp, isNightly: stamp !== null };
|
||||
};
|
||||
|
||||
// Base-aware "is candidate newer than current?" used by both the nightly channel
|
||||
// check and (mirrored in Rust) the Tauri updater version_comparator.
|
||||
// Rule: higher X.Y.Z core wins; on equal core a nightly outranks the matching
|
||||
// stable (it was built after it) but never the reverse; two nightlies compare by
|
||||
// stamp.
|
||||
export const isUpdateNewer = (candidate: string, current: string): boolean => {
|
||||
const c = parseUpdateVersion(candidate);
|
||||
const cur = parseUpdateVersion(current);
|
||||
if (!c || !cur) return false;
|
||||
if (c.base !== cur.base) {
|
||||
return semver.compare(c.base, cur.base) > 0;
|
||||
}
|
||||
if (c.isNightly && !cur.isNightly) return true;
|
||||
if (!c.isNightly && cur.isNightly) return false;
|
||||
if (c.isNightly && cur.isNightly) return (c.stamp as number) > (cur.stamp as number);
|
||||
return false;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user