fix(updater): format `Update.date` to RFC 3339 (#2573)

* fix(updater): format `Update.date` to RFC 3339

* Messed up on argument in #2572

* Format

* Update example

* Avoid extra to_string

* Deprecate `Update.available`
pull/2577/head
Tony 2 months ago committed by GitHub
parent 0bc5d58874
commit 2d731f8022
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,6 @@
---
"updater": "minor:bug"
"updater-js": "minor:bug"
---
Fix JS API `Update.date` not formatted to RFC 3339

@ -12,10 +12,14 @@
isChecking = true
try {
const update = await check()
onMessage(`Should update: ${update.available}`)
onMessage(update)
if (update) {
onMessage(`Should update: ${update.available}`)
onMessage(update)
newUpdate = update
newUpdate = update
} else {
onMessage('No update available')
}
} catch (e) {
onMessage(e)
} finally {

@ -1 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(e){"use strict";function t(e,t,s,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?n:"a"===s?n.call(e):n?n.value:t.get(e)}function s(e,t,s,n,i){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var n,i,a,r;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class d{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),i.set(this,0),a.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:r})=>{if(r==t(this,i,"f"))for(t(this,n,"f").call(this,e),s(this,i,t(this,i,"f")+1);t(this,i,"f")in t(this,a,"f");){const e=t(this,a,"f")[t(this,i,"f")];t(this,n,"f").call(this,e),delete t(this,a,"f")[t(this,i,"f")],s(this,i,t(this,i,"f")+1)}else t(this,a,"f")[r]=e}))}set onmessage(e){s(this,n,e)}get onmessage(){return t(this,n,"f")}[(n=new WeakMap,i=new WeakMap,a=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function l(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class h{get rid(){return t(this,r,"f")}constructor(e){r.set(this,void 0),s(this,r,e)}async close(){return l("plugin:resources|close",{rid:this.rid})}}r=new WeakMap;class c extends h{constructor(e){super(e.rid),this.available=e.available,this.currentVersion=e.currentVersion,this.version=e.version,this.date=e.date,this.body=e.body,this.rawJson=e.rawJson}async download(e,t){const s=new d;e&&(s.onmessage=e);const n=await l("plugin:updater|download",{onEvent:s,rid:this.rid,...t});this.downloadedBytes=new h(n)}async install(){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await l("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid}),this.downloadedBytes=void 0}async downloadAndInstall(e,t){const s=new d;e&&(s.onmessage=e),await l("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...t})}async close(){await(this.downloadedBytes?.close()),await super.close()}}return e.Update=c,e.check=async function(e){return e?.headers&&(e.headers=Array.from(new Headers(e.headers).entries())),await l("plugin:updater|check",{...e}).then((e=>e.available?new c(e):null))},e}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(t){"use strict";function e(t,e,s,n){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?n:"a"===s?n.call(t):n?n.value:e.get(t)}function s(t,e,s,n,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,s),s}var n,i,r,a;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class d{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),i.set(this,0),r.set(this,[]),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:a})=>{if(a==e(this,i,"f"))for(e(this,n,"f").call(this,t),s(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,r,"f");){const t=e(this,r,"f")[e(this,i,"f")];e(this,n,"f").call(this,t),delete e(this,r,"f")[e(this,i,"f")],s(this,i,e(this,i,"f")+1)}else e(this,r,"f")[a]=t}))}set onmessage(t){s(this,n,t)}get onmessage(){return e(this,n,"f")}[(n=new WeakMap,i=new WeakMap,r=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function c(t,e={},s){return window.__TAURI_INTERNALS__.invoke(t,e,s)}class h{get rid(){return e(this,a,"f")}constructor(t){a.set(this,void 0),s(this,a,t)}async close(){return c("plugin:resources|close",{rid:this.rid})}}a=new WeakMap;class l extends h{constructor(t){super(t.rid),this.available=!0,this.currentVersion=t.currentVersion,this.version=t.version,this.date=t.date,this.body=t.body,this.rawJson=t.rawJson}async download(t,e){const s=new d;t&&(s.onmessage=t);const n=await c("plugin:updater|download",{onEvent:s,rid:this.rid,...e});this.downloadedBytes=new h(n)}async install(){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await c("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid}),this.downloadedBytes=void 0}async downloadAndInstall(t,e){const s=new d;t&&(s.onmessage=t),await c("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...e})}async close(){await(this.downloadedBytes?.close()),await super.close()}}return t.Update=l,t.check=async function(t){t?.headers&&(t.headers=Array.from(new Headers(t.headers).entries()));const e=await c("plugin:updater|check",{...t});return e?new l(e):null},t}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}

@ -38,7 +38,6 @@ interface DownloadOptions {
interface UpdateMetadata {
rid: number
available: boolean
currentVersion: string
version: string
date?: string
@ -53,6 +52,8 @@ type DownloadEvent =
| { event: 'Finished' }
class Update extends Resource {
// TODO: remove this field in v3
/** @deprecated This is always true, check if the return value is `null` instead when using {@linkcode check} */
available: boolean
currentVersion: string
version: string
@ -63,7 +64,7 @@ class Update extends Resource {
constructor(metadata: UpdateMetadata) {
super(metadata.rid)
this.available = metadata.available
this.available = true
this.currentVersion = metadata.currentVersion
this.version = metadata.version
this.date = metadata.date
@ -131,12 +132,10 @@ async function check(options?: CheckOptions): Promise<Update | null> {
options.headers = Array.from(new Headers(options.headers).entries())
}
return await invoke<UpdateMetadata>('plugin:updater|check', {
const metadata = await invoke<UpdateMetadata | null>('plugin:updater|check', {
...options
}).then((meta) =>
// TODO: Handle this in the rust side
meta.available ? new Update(meta) : null
)
})
return metadata ? new Update(metadata) : null
}
export type { CheckOptions, DownloadOptions, DownloadEvent }

@ -28,8 +28,7 @@ pub enum DownloadEvent {
#[derive(Serialize, Default)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Metadata {
rid: Option<ResourceId>,
available: bool,
rid: ResourceId,
current_version: String,
version: String,
date: Option<String>,
@ -40,8 +39,6 @@ pub(crate) struct Metadata {
struct DownloadedBytes(pub Vec<u8>);
impl Resource for DownloadedBytes {}
// TODO: Align this with the result of `updater.check` to Result<Option<Metadata>>
// and remove `available` instead of handling this in the js side
#[tauri::command]
pub(crate) async fn check<R: Runtime>(
webview: Webview<R>,
@ -49,7 +46,7 @@ pub(crate) async fn check<R: Runtime>(
timeout: Option<u64>,
proxy: Option<String>,
target: Option<String>,
) -> Result<Metadata> {
) -> Result<Option<Metadata>> {
let mut builder = webview.updater_builder();
if let Some(headers) = headers {
for (k, v) in headers {
@ -69,18 +66,28 @@ pub(crate) async fn check<R: Runtime>(
let updater = builder.build()?;
let update = updater.check().await?;
let mut metadata = Metadata::default();
if let Some(update) = update {
metadata.available = true;
metadata.current_version.clone_from(&update.current_version);
metadata.version.clone_from(&update.version);
metadata.date = update.date.map(|d| d.to_string());
metadata.body.clone_from(&update.body);
metadata.raw_json.clone_from(&update.raw_json);
metadata.rid = Some(webview.resources_table().add(update));
let formatted_date = if let Some(date) = update.date {
let formatted_date = date
.format(&time::format_description::well_known::Rfc3339)
.map_err(|_| crate::Error::FormatDate)?;
Some(formatted_date)
} else {
None
};
let metadata = Metadata {
current_version: update.current_version.clone(),
version: update.version.clone(),
date: formatted_date,
body: update.body.clone(),
raw_json: update.raw_json.clone(),
rid: webview.resources_table().add(update),
};
Ok(Some(metadata))
} else {
Ok(None)
}
Ok(metadata)
}
#[tauri::command]

@ -77,6 +77,8 @@ pub enum Error {
InvalidHeaderValue(#[from] http::header::InvalidHeaderValue),
#[error(transparent)]
InvalidHeaderName(#[from] http::header::InvalidHeaderName),
#[error("Failed to format date")]
FormatDate,
/// The configured updater endpoint must use a secure protocol like `https`
#[error("The configured updater endpoint must use a secure protocol like `https`.")]
InsecureTransportProtocol,

@ -310,7 +310,8 @@ impl UpdaterBuilder {
I: IntoIterator<Item = S>,
S: Into<OsString>,
{
self.installer_args.extend(args.into_iter().map(Into::into));
self.current_exe_args
.extend(args.into_iter().map(Into::into));
self
}
}

Loading…
Cancel
Save