bump specta

This commit is contained in:
Brendan Allan
2026-01-30 09:11:13 +08:00
parent f69ea40e55
commit bef9938c0a
10 changed files with 274 additions and 222 deletions

View File

@@ -84,7 +84,7 @@ function ServerKey(props: ParentProps) {
)
}
export function AppInterface(props: { defaultUrl?: string, root?: (props: ParentProps) => JSX.Element }) {
export function AppInterface(props: { defaultUrl?: string; root?: (props: ParentProps) => JSX.Element }) {
const platform = usePlatform()
const stored = (() => {
@@ -105,6 +105,8 @@ export function AppInterface(props: { defaultUrl?: string, root?: (props: Parent
return window.location.origin
}
console.log("interface")
return (
<ServerProvider defaultUrl={defaultServerUrl()}>
<ServerKey>
@@ -119,7 +121,7 @@ export function AppInterface(props: { defaultUrl?: string, root?: (props: Parent
<ModelsProvider>
<CommandProvider>
<HighlightsProvider>
<Layout>{props.root?.(rootProps) ?? rootProps.children}</Layout>
<Layout>{rootProps.children}</Layout>
</HighlightsProvider>
</CommandProvider>
</ModelsProvider>

View File

@@ -1079,6 +1079,9 @@ const GlobalSyncContext = createContext<ReturnType<typeof createGlobalSync>>()
export function GlobalSyncProvider(props: ParentProps) {
const value = createGlobalSync()
createEffect(() => {
console.log({ ...value })
})
return (
<Switch>
<Match when={value.ready}>

View File

@@ -1977,9 +1977,9 @@ dependencies = [
[[package]]
name = "ico"
version = "0.4.0"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98"
checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
dependencies = [
"byteorder",
"png 0.17.16",
@@ -2994,14 +2994,14 @@ dependencies = [
"listeners",
"objc2",
"objc2-web-kit",
"reqwest",
"reqwest 0.12.28",
"semver",
"serde",
"serde_json",
"specta 2.0.0-rc.22 (git+https://github.com/specta-rs/specta?rev=5409c179845bce2dc4a7315870c83c8d80c0dee4)",
"specta",
"specta-typescript",
"tauri",
"tauri-build",
"tauri-build 2.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"tauri-plugin-clipboard-manager",
"tauri-plugin-decorum",
"tauri-plugin-deep-link",
@@ -3895,6 +3895,40 @@ dependencies = [
"webpki-roots",
]
[[package]]
name = "reqwest"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62"
dependencies = [
"base64 0.22.1",
"bytes",
"futures-core",
"futures-util",
"http",
"http-body",
"http-body-util",
"hyper",
"hyper-util",
"js-sys",
"log",
"percent-encoding",
"pin-project-lite",
"serde",
"serde_json",
"sync_wrapper",
"tokio",
"tokio-util",
"tower",
"tower-http",
"tower-service",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-streams",
"web-sys",
]
[[package]]
name = "rfd"
version = "0.16.0"
@@ -4442,25 +4476,17 @@ dependencies = [
[[package]]
name = "specta"
version = "2.0.0-rc.22"
source = "git+https://github.com/specta-rs/specta?rev=5409c179845bce2dc4a7315870c83c8d80c0dee4#5409c179845bce2dc4a7315870c83c8d80c0dee4"
source = "git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0#f1e55f8c774a9506e3ca6bec1265ce5dda6831a0"
dependencies = [
"paste",
"rustc_version",
"specta-macros",
]
[[package]]
name = "specta"
version = "2.0.0-rc.22"
source = "git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0#f1e55f8c774a9506e3ca6bec1265ce5dda6831a0"
dependencies = [
"rustc_version",
]
[[package]]
name = "specta-macros"
version = "2.0.0-rc.18"
source = "git+https://github.com/specta-rs/specta?rev=5409c179845bce2dc4a7315870c83c8d80c0dee4#5409c179845bce2dc4a7315870c83c8d80c0dee4"
source = "git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0#f1e55f8c774a9506e3ca6bec1265ce5dda6831a0"
dependencies = [
"Inflector",
"proc-macro2",
@@ -4473,7 +4499,7 @@ name = "specta-serde"
version = "0.0.9"
source = "git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0#f1e55f8c774a9506e3ca6bec1265ce5dda6831a0"
dependencies = [
"specta 2.0.0-rc.22 (git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0)",
"specta",
]
[[package]]
@@ -4481,7 +4507,7 @@ name = "specta-typescript"
version = "0.0.9"
source = "git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0#f1e55f8c774a9506e3ca6bec1265ce5dda6831a0"
dependencies = [
"specta 2.0.0-rc.22 (git+https://github.com/specta-rs/specta?rev=f1e55f8c774a9506e3ca6bec1265ce5dda6831a0)",
"specta",
"specta-serde",
]
@@ -4695,8 +4721,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "tauri"
version = "2.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a3868da5508446a7cd08956d523ac3edf0a8bc20bf7e4038f9a95c2800d2033"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"anyhow",
"bytes",
@@ -4722,18 +4747,18 @@ dependencies = [
"percent-encoding",
"plist",
"raw-window-handle",
"reqwest",
"reqwest 0.13.1",
"serde",
"serde_json",
"serde_repr",
"serialize-to-javascript",
"specta 2.0.0-rc.22 (git+https://github.com/specta-rs/specta?rev=5409c179845bce2dc4a7315870c83c8d80c0dee4)",
"specta",
"swift-rs",
"tauri-build",
"tauri-build 2.5.3 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"tauri-macros",
"tauri-runtime",
"tauri-runtime-wry",
"tauri-utils",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"thiserror 2.0.18",
"tokio",
"tray-icon",
@@ -4760,7 +4785,28 @@ dependencies = [
"semver",
"serde",
"serde_json",
"tauri-utils",
"tauri-utils 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tauri-winres",
"toml 0.9.11+spec-1.1.0",
"walkdir",
]
[[package]]
name = "tauri-build"
version = "2.5.3"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"anyhow",
"cargo_toml",
"dirs",
"glob",
"heck 0.5.0",
"json-patch",
"schemars 0.8.22",
"semver",
"serde",
"serde_json",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"tauri-winres",
"toml 0.9.11+spec-1.1.0",
"walkdir",
@@ -4769,8 +4815,7 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9fa9844cefcf99554a16e0a278156ae73b0d8680bbc0e2ad1e4287aadd8489cf"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"base64 0.22.1",
"brotli",
@@ -4785,7 +4830,7 @@ dependencies = [
"serde_json",
"sha2",
"syn 2.0.114",
"tauri-utils",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"thiserror 2.0.18",
"time",
"url",
@@ -4796,15 +4841,14 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "2.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3764a12f886d8245e66b7ee9b43ccc47883399be2019a61d80cf0f4117446fde"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"heck 0.5.0",
"proc-macro2",
"quote",
"syn 2.0.114",
"tauri-codegen",
"tauri-utils",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
]
[[package]]
@@ -4819,7 +4863,7 @@ dependencies = [
"schemars 0.8.22",
"serde",
"serde_json",
"tauri-utils",
"tauri-utils 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.9.11+spec-1.1.0",
"walkdir",
]
@@ -4869,7 +4913,7 @@ dependencies = [
"serde_json",
"tauri",
"tauri-plugin",
"tauri-utils",
"tauri-utils 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 2.0.18",
"tracing",
"url",
@@ -4911,7 +4955,7 @@ dependencies = [
"serde_repr",
"tauri",
"tauri-plugin",
"tauri-utils",
"tauri-utils 2.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"thiserror 2.0.18",
"toml 0.9.11+spec-1.1.0",
"url",
@@ -4928,7 +4972,7 @@ dependencies = [
"data-url",
"http",
"regex",
"reqwest",
"reqwest 0.12.28",
"schemars 0.8.22",
"serde",
"serde_json",
@@ -5079,7 +5123,7 @@ dependencies = [
"minisign-verify",
"osakit",
"percent-encoding",
"reqwest",
"reqwest 0.12.28",
"semver",
"serde",
"serde_json",
@@ -5113,8 +5157,7 @@ dependencies = [
[[package]]
name = "tauri-runtime"
version = "2.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "87f766fe9f3d1efc4b59b17e7a891ad5ed195fa8d23582abb02e6c9a01137892"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"cookie",
"dpi",
@@ -5127,7 +5170,7 @@ dependencies = [
"raw-window-handle",
"serde",
"serde_json",
"tauri-utils",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"thiserror 2.0.18",
"url",
"webkit2gtk",
@@ -5138,8 +5181,7 @@ dependencies = [
[[package]]
name = "tauri-runtime-wry"
version = "2.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "187a3f26f681bdf028f796ccf57cf478c1ee422c50128e5a0a6ebeb3f5910065"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"gtk",
"http",
@@ -5154,7 +5196,7 @@ dependencies = [
"softbuffer",
"tao",
"tauri-runtime",
"tauri-utils",
"tauri-utils 2.8.1 (git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee)",
"url",
"webkit2gtk",
"webview2-com",
@@ -5170,7 +5212,7 @@ dependencies = [
"heck 0.5.0",
"serde",
"serde_json",
"specta 2.0.0-rc.22 (git+https://github.com/specta-rs/specta?rev=5409c179845bce2dc4a7315870c83c8d80c0dee4)",
"specta",
"specta-typescript",
"tauri",
"tauri-specta-macros",
@@ -5194,6 +5236,42 @@ name = "tauri-utils"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76a423c51176eb3616ee9b516a9fa67fed5f0e78baaba680e44eb5dd2cc37490"
dependencies = [
"anyhow",
"cargo_metadata",
"ctor",
"dunce",
"glob",
"html5ever",
"http",
"infer",
"json-patch",
"kuchikiki",
"log",
"memchr",
"phf 0.11.3",
"proc-macro2",
"quote",
"regex",
"schemars 0.8.22",
"semver",
"serde",
"serde-untagged",
"serde_json",
"serde_with",
"swift-rs",
"thiserror 2.0.18",
"toml 0.9.11+spec-1.1.0",
"url",
"urlpattern",
"uuid",
"walkdir",
]
[[package]]
name = "tauri-utils"
version = "2.8.1"
source = "git+https://github.com/tauri-apps/tauri?rev=4d5d78daf636feaac20c5bc48a6071491c4291ee#4d5d78daf636feaac20c5bc48a6071491c4291ee"
dependencies = [
"anyhow",
"brotli",
@@ -6041,9 +6119,9 @@ dependencies = [
[[package]]
name = "webkit2gtk"
version = "2.0.1"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a"
checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793"
dependencies = [
"bitflags 1.3.2",
"cairo-rs",
@@ -6065,9 +6143,9 @@ dependencies = [
[[package]]
name = "webkit2gtk-sys"
version = "2.0.1"
version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c"
checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5"
dependencies = [
"bitflags 1.3.2",
"cairo-sys-rs",
@@ -6726,9 +6804,9 @@ checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9"
[[package]]
name = "wry"
version = "0.53.5"
version = "0.54.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "728b7d4c8ec8d81cab295e0b5b8a4c263c0d41a785fb8f8c4df284e5411140a2"
checksum = "5ed1a195b0375491dd15a7066a10251be217ce743cf4bbbbdcf5391d6473bee0"
dependencies = [
"base64 0.22.1",
"block2",

View File

@@ -44,13 +44,13 @@ uuid = { version = "1.19.0", features = ["v4"] }
tauri-plugin-decorum = "1.1.1"
comrak = { version = "0.50", default-features = false }
url = "2"
specta = { git = "https://github.com/specta-rs/specta", rev = "5409c179845bce2dc4a7315870c83c8d80c0dee4" }
specta-typescript = { git = "https://github.com/specta-rs/specta", rev = "f1e55f8c774a9506e3ca6bec1265ce5dda6831a0" }
tauri-specta = { git = "https://github.com/specta-rs/tauri-specta", rev = "c0cd3c58e29191845e2bd2b30238246469903727", features = ["derive", "typescript"] }
specta = "=2.0.0-rc.22"
specta-typescript = "0.0.9"
tauri-specta = { version = "=2.0.0-rc.21", features = ["derive", "typescript"] }
[target.'cfg(target_os = "linux")'.dependencies]
gtk = "0.18.2"
webkit2gtk = "=2.0.1"
webkit2gtk = "=2.0.2"
[target.'cfg(target_os = "macos")'.dependencies]
objc2 = "0.6"
@@ -65,6 +65,8 @@ windows = { version = "0.61", features = [
] }
[patch.crates-io]
specta = { git = "https://github.com/specta-rs/specta", rev = "5409c179845bce2dc4a7315870c83c8d80c0dee4" }
specta-typescript = { git = "https://github.com/specta-rs/specta", rev = "f1e55f8c774a9506e3ca6bec1265ce5dda6831a0" }
tauri-specta = { git = "https://github.com/specta-rs/tauri-specta", rev = "c0cd3c58e29191845e2bd2b30238246469903727" }
specta = { git = "https://github.com/specta-rs/specta", rev = "106425eac4964d8ff34d3a02f1612e33117b08bb" }
specta-typescript = { git = "https://github.com/specta-rs/specta", rev = "106425eac4964d8ff34d3a02f1612e33117b08bb" }
tauri-specta = { git = "https://github.com/specta-rs/tauri-specta", rev = "52c122a2110385857cbfc5a970016fa424007170" }
# TODO: https://github.com/tauri-apps/tauri/pull/14812
# tauri = { git = "https://github.com/tauri-apps/tauri", rev = "4d5d78daf636feaac20c5bc48a6071491c4291ee" }

View File

@@ -7,8 +7,8 @@ mod window_customizer;
use cli::{install_cli, sync_cli};
use futures::channel::mpsc;
use futures::future;
use futures::{FutureExt, StreamExt};
use futures::{SinkExt, future};
#[cfg(windows)]
use job_object::*;
use specta_typescript::Typescript;
@@ -27,7 +27,7 @@ use tauri_plugin_deep_link::DeepLinkExt;
use tauri_plugin_dialog::{DialogExt, MessageDialogButtons, MessageDialogResult};
use tauri_plugin_shell::process::{CommandChild, CommandEvent};
use tauri_plugin_store::StoreExt;
use tauri_specta::{Builder, collect_commands};
use tauri_specta::{Builder, Event, collect_commands, collect_events};
use tokio::sync::oneshot;
use crate::deep_link::DeepLinkAction;
@@ -258,6 +258,20 @@ async fn check_server_health(url: &str, password: Option<&str>) -> bool {
.unwrap_or(false)
}
struct AppState {
ready_tx: tokio::sync::Mutex<Option<oneshot::Sender<()>>>,
}
#[tauri::command]
#[specta::specta]
async fn notify_ready(state: tauri::State<'_, AppState>) -> Result<(), ()> {
if let Some(ready_tx) = state.ready_tx.lock().await.take() {
let _ = ready_tx.send(());
}
Ok(())
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
let updater_enabled = option_env!("TAURI_SIGNING_PRIVATE_KEY").is_some();
@@ -267,7 +281,7 @@ pub fn run() {
.arg("opencode-cli")
.output();
let mut builder = Builder::<tauri::Wry>::new()
let builder = Builder::<tauri::Wry>::new()
// Then register them (separated by a comma)
.commands(collect_commands![
kill_sidecar,
@@ -275,8 +289,10 @@ pub fn run() {
ensure_server_ready,
get_default_server_url,
set_default_server_url,
markdown::parse_markdown_command
]);
markdown::parse_markdown_command,
notify_ready
])
.events(collect_events![DeepLinkAction]);
#[cfg(debug_assertions)] // <- Only export on non-release builds
builder
@@ -327,6 +343,11 @@ pub fn run() {
#[cfg(windows)]
app.manage(JobObjectState::new());
let (ready_tx, ready_rx) = oneshot::channel::<()>();
app.manage(AppState {
ready_tx: tokio::sync::Mutex::new(Some(ready_tx))
});
let primary_monitor = app.primary_monitor().ok().flatten();
let size = primary_monitor
.map(|m| m.size().to_logical(m.scale_factor()))
@@ -386,8 +407,6 @@ pub fn run() {
}
});
let (ready_tx, ready_rx) = oneshot::channel::<()>();
{
let app = app.clone();
tauri::async_runtime::spawn(async move {
@@ -444,7 +463,7 @@ pub fn run() {
tauri::async_runtime::spawn(deeplink_rx.for_each(move |url| {
if let Some(action) = DeepLinkAction::from_url(url)
&& let Some(window) = app.get_webview_window("main") {
let _ = window.emit("opencode:deep-link", action);
let _ = action.emit(&window);
}
future::ready(())

View File

@@ -1,123 +1,62 @@
// This file has been generated by Tauri Specta. Do not edit this file manually.
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
/** user-defined commands **/
import { invoke as __TAURI_INVOKE, Channel } from "@tauri-apps/api/core"
import * as __TAURI_EVENT from "@tauri-apps/api/event"
/** Commands */
export const commands = {
async killSidecar() : Promise<void> {
await TAURI_INVOKE("kill_sidecar");
},
async installCli() : Promise<Result<string, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("install_cli") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async ensureServerReady() : Promise<Result<ServerReadyData, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("ensure_server_ready") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async getDefaultServerUrl() : Promise<Result<string | null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("get_default_server_url") };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async setDefaultServerUrl(url: string | null) : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("set_default_server_url", { url }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async parseMarkdownCommand(markdown: string) : Promise<Result<string, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("parse_markdown_command", { markdown }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
}
killSidecar: () => __TAURI_INVOKE<void>("kill_sidecar"),
installCli: () => typedError<string, string>(__TAURI_INVOKE("install_cli")),
ensureServerReady: () => typedError<ServerReadyData, string>(__TAURI_INVOKE("ensure_server_ready")),
getDefaultServerUrl: () => typedError<string | null, string>(__TAURI_INVOKE("get_default_server_url")),
setDefaultServerUrl: (url: string | null) =>
typedError<null, string>(__TAURI_INVOKE("set_default_server_url", { url })),
parseMarkdownCommand: (markdown: string) =>
typedError<string, string>(__TAURI_INVOKE("parse_markdown_command", { markdown })),
notifyReady: () => typedError<null, null>(__TAURI_INVOKE("notify_ready")),
}
/** user-defined events **/
/** user-defined constants **/
/** user-defined types **/
export type ServerReadyData = { url: string; password: string | null }
/** tauri-specta globals **/
import {
invoke as TAURI_INVOKE,
Channel as TAURI_CHANNEL,
} from "@tauri-apps/api/core";
import * as TAURI_API_EVENT from "@tauri-apps/api/event";
import { type WebviewWindow as __WebviewWindow__ } from "@tauri-apps/api/webviewWindow";
type __EventObj__<T> = {
listen: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
once: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
emit: null extends T
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
};
export type Result<T, E> =
| { status: "ok"; data: T }
| { status: "error"; error: E };
function __makeEvents__<T extends Record<string, any>>(
mappings: Record<keyof T, string>,
) {
return new Proxy(
{} as unknown as {
[K in keyof T]: __EventObj__<T[K]> & {
(handle: __WebviewWindow__): __EventObj__<T[K]>;
};
},
{
get: (_, event) => {
const name = mappings[event as keyof T];
return new Proxy((() => {}) as any, {
apply: (_, __, [window]: [__WebviewWindow__]) => ({
listen: (arg: any) => window.listen(name, arg),
once: (arg: any) => window.once(name, arg),
emit: (arg: any) => window.emit(name, arg),
}),
get: (_, command: keyof __EventObj__<any>) => {
switch (command) {
case "listen":
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
case "once":
return (arg: any) => TAURI_API_EVENT.once(name, arg);
case "emit":
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
}
},
});
},
},
);
/** Events */
export const events = {
deepLinkAction: makeEvent<DeepLinkAction>("deep-link-action"),
}
/* Types */
export type DeepLinkAction = { OpenProject: { directory: string; session: string | null } }
export type ServerReadyData = {
url: string
password: string | null
}
/* Tauri Specta runtime */
async function typedError<T, E>(
result: Promise<T>,
): Promise<{ status: "ok"; data: T } | { status: "error"; error: E }> {
try {
return { status: "ok", data: await result }
} catch (e) {
if (e instanceof Error) throw e
return { status: "error", error: e as any }
}
}
function makeEvent<T>(name: string) {
const base = {
listen: (cb: __TAURI_EVENT.EventCallback<T>) => __TAURI_EVENT.listen(name, cb),
once: (cb: __TAURI_EVENT.EventCallback<T>) => __TAURI_EVENT.once(name, cb),
emit: (payload: T) =>
__TAURI_EVENT.emit(name, payload) as unknown as T extends null
? () => Promise<void>
: (payload: T) => Promise<void>,
}
const fn = (target: import("@tauri-apps/api/webview").Webview | import("@tauri-apps/api/window").Window) => ({
listen: (cb: __TAURI_EVENT.EventCallback<T>) => target.listen(name, cb),
once: (cb: __TAURI_EVENT.EventCallback<T>) => target.once(name, cb),
emit: (payload: T) =>
target.emit(name, payload) as unknown as T extends null ? () => Promise<void> : (payload: T) => Promise<void>,
})
return Object.assign(fn, base)
}

View File

@@ -1,15 +1,17 @@
import { invoke } from "@tauri-apps/api/core"
import { message } from "@tauri-apps/plugin-dialog"
import { initI18n, t } from "./i18n"
import { commands } from "./bindings"
export async function installCli(): Promise<void> {
await initI18n()
try {
const path = await invoke<string>("install_cli")
await message(t("desktop.cli.installed.message", { path }), { title: t("desktop.cli.installed.title") })
} catch (e) {
await message(t("desktop.cli.failed.message", { error: String(e) }), { title: t("desktop.cli.failed.title") })
const res = await commands.installCli()
if (res.status === "ok") {
await message(t("desktop.cli.installed.message", { path: res.data }), { title: t("desktop.cli.installed.title") })
} else {
await message(t("desktop.cli.failed.message", { error: String(res.error) }), {
title: t("desktop.cli.failed.title"),
})
}
}

View File

@@ -3,11 +3,9 @@ import "./webview-zoom"
import { render } from "solid-js/web"
import { AppBaseProviders, AppInterface, PlatformProvider, Platform } from "@opencode-ai/app"
import { open, save } from "@tauri-apps/plugin-dialog"
import { getCurrent, onOpenUrl } from "@tauri-apps/plugin-deep-link"
import { open as shellOpen } from "@tauri-apps/plugin-shell"
import { type as ostype } from "@tauri-apps/plugin-os"
import { check, Update } from "@tauri-apps/plugin-updater"
import { invoke } from "@tauri-apps/api/core"
import { getCurrentWindow } from "@tauri-apps/api/window"
import { isPermissionGranted, requestPermission } from "@tauri-apps/plugin-notification"
import { relaunch } from "@tauri-apps/plugin-process"
@@ -22,6 +20,7 @@ import { createMenu } from "./menu"
import { initI18n, t } from "./i18n"
import pkg from "../package.json"
import "./styles.css"
import { commands, events } from "./bindings"
const root = document.getElementById("root")
if (import.meta.env.DEV && !(root instanceof HTMLElement)) {
@@ -43,21 +42,21 @@ window.getComputedStyle = ((elt: Element, pseudoElt?: string | null) => {
let update: Update | null = null
const deepLinkEvent = "opencode:deep-link"
// const deepLinkEvent = "opencode:deep-link"
const emitDeepLinks = (urls: string[]) => {
if (urls.length === 0) return
window.__OPENCODE__ ??= {}
const pending = window.__OPENCODE__.deepLinks ?? []
window.__OPENCODE__.deepLinks = [...pending, ...urls]
window.dispatchEvent(new CustomEvent(deepLinkEvent, { detail: { urls } }))
}
// const emitDeepLinks = (urls: string[]) => {
// if (urls.length === 0) return
// window.__OPENCODE__ ??= {}
// const pending = window.__OPENCODE__.deepLinks ?? []
// window.__OPENCODE__.deepLinks = [...pending, ...urls]
// window.dispatchEvent(new CustomEvent(deepLinkEvent, { detail: { urls } }))
// }
const listenForDeepLinks = async () => {
const startUrls = await getCurrent().catch(() => null)
if (startUrls?.length) emitDeepLinks(startUrls)
await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined)
}
// const listenForDeepLinks = async () => {
// const startUrls = await getCurrent().catch(() => null)
// if (startUrls?.length) emitDeepLinks(startUrls)
// await onOpenUrl((urls) => emitDeepLinks(urls)).catch(() => undefined)
// }
const createPlatform = (password: Accessor<string | null>): Platform => ({
platform: "desktop",
@@ -274,12 +273,12 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
update: async () => {
if (!UPDATER_ENABLED || !update) return
if (ostype() === "windows") await invoke("kill_sidecar").catch(() => undefined)
if (ostype() === "windows") await commands.killSidecar().catch(() => undefined)
await update.install().catch(() => undefined)
},
restart: async () => {
await invoke("kill_sidecar").catch(() => undefined)
await commands.killSidecar().catch(() => undefined)
await relaunch()
},
@@ -334,22 +333,21 @@ const createPlatform = (password: Accessor<string | null>): Platform => ({
}
},
getDefaultServerUrl: async () => {
const result = await invoke<string | null>("get_default_server_url").catch(() => null)
return result
},
getDefaultServerUrl: () => commands.getDefaultServerUrl().then((v) => (v.status === "ok" ? v.data : null)),
setDefaultServerUrl: async (url: string | null) => {
await invoke("set_default_server_url", { url })
await commands.setDefaultServerUrl(url)
},
parseMarkdown: async (markdown: string) => {
return invoke<string>("parse_markdown_command", { markdown })
},
parseMarkdown: (markdown) =>
commands.parseMarkdownCommand(markdown).then((v) => {
if (v.status === "ok") return v.data
throw new Error(v.error)
}),
})
createMenu()
void listenForDeepLinks()
// void listenForDeepLinks()
render(() => {
const [serverPassword, setServerPassword] = createSignal<string | null>(null)
@@ -379,6 +377,14 @@ render(() => {
window.__OPENCODE__ ??= {}
window.__OPENCODE__.serverPassword = data().password ?? undefined
onMount(() => {
commands.notifyReady()
})
events.deepLinkAction.listen((deepLink) => {
console.log({ deepLink })
})
return <AppInterface defaultUrl={data().url} />
}}
</ServerGate>
@@ -392,8 +398,9 @@ type ServerReadyData = { url: string; password: string | null }
// Gate component that waits for the server to be ready
function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.Element }) {
const [serverData] = createResource<ServerReadyData>(() =>
invoke("ensure_server_ready").then((v) => {
return new Promise((res) => setTimeout(() => res(v as ServerReadyData), 2000))
commands.ensureServerReady().then((v) => {
if (v.status === "ok") return v.data
throw new Error(v.error)
}),
)
@@ -406,7 +413,7 @@ function ServerGate(props: { children: (data: Accessor<ServerReadyData>) => JSX.
}
const restartApp = async () => {
await invoke("kill_sidecar").catch(() => undefined)
await commands.killSidecar().catch(() => undefined)
await relaunch().catch(() => undefined)
}

View File

@@ -1,11 +1,11 @@
import { Menu, MenuItem, PredefinedMenuItem, Submenu } from "@tauri-apps/api/menu"
import { type as ostype } from "@tauri-apps/plugin-os"
import { invoke } from "@tauri-apps/api/core"
import { relaunch } from "@tauri-apps/plugin-process"
import { runUpdater, UPDATER_ENABLED } from "./updater"
import { installCli } from "./cli"
import { initI18n, t } from "./i18n"
import { commands } from "./bindings"
export async function createMenu() {
if (ostype() !== "macos") return
@@ -35,7 +35,7 @@ export async function createMenu() {
}),
await MenuItem.new({
action: async () => {
await invoke("kill_sidecar").catch(() => undefined)
await commands.killSidecar().catch(() => undefined)
await relaunch().catch(() => undefined)
},
text: t("desktop.menu.restart"),

View File

@@ -1,10 +1,10 @@
import { check } from "@tauri-apps/plugin-updater"
import { relaunch } from "@tauri-apps/plugin-process"
import { ask, message } from "@tauri-apps/plugin-dialog"
import { invoke } from "@tauri-apps/api/core"
import { type as ostype } from "@tauri-apps/plugin-os"
import { initI18n, t } from "./i18n"
import { commands } from "./bindings"
export const UPDATER_ENABLED = window.__OPENCODE__?.updaterEnabled ?? false
@@ -39,13 +39,13 @@ export async function runUpdater({ alertOnFail }: { alertOnFail: boolean }) {
if (!shouldUpdate) return
try {
if (ostype() === "windows") await invoke("kill_sidecar")
if (ostype() === "windows") await commands.killSidecar()
await update.install()
} catch {
await message(t("desktop.updater.installFailed.message"), { title: t("desktop.updater.installFailed.title") })
return
}
await invoke("kill_sidecar")
await commands.killSidecar()
await relaunch()
}