diff --git a/.vscode/settings.json b/.vscode/settings.json
index 8c59aec..d6dce3e 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -2,5 +2,8 @@
"editor.semanticHighlighting.enabled": true,
"[typescript]": {
"editor.defaultFormatter": "denoland.vscode-deno"
+ },
+ "[json]": {
+ "editor.defaultFormatter": "denoland.vscode-deno"
}
}
diff --git a/Cargo.lock b/Cargo.lock
index 9c81611..48ba318 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -278,7 +278,7 @@ dependencies = [
[[package]]
name = "deno-webview"
-version = "0.1.3"
+version = "0.1.4"
dependencies = [
"schemars",
"serde",
diff --git a/Cargo.toml b/Cargo.toml
index 922e11e..6025e5d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "deno-webview"
-version = "0.1.3"
+version = "0.1.4"
edition = "2021"
[profile.release]
diff --git a/ClientEvent.json b/ClientEvent.json
deleted file mode 100644
index 99d7ed9..0000000
--- a/ClientEvent.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "$schema": "http://json-schema.org/draft-07/schema#",
- "title": "ClientEvent",
- "oneOf": [
- {
- "type": "object",
- "required": [
- "$type",
- "data"
- ],
- "properties": {
- "$type": {
- "type": "string",
- "enum": [
- "eval"
- ]
- },
- "data": {
- "type": "string"
- }
- }
- }
- ]
-}
\ No newline at end of file
diff --git a/deno.json b/deno.json
index ba72560..5be948d 100644
--- a/deno.json
+++ b/deno.json
@@ -5,7 +5,7 @@
},
"tasks": {
"dev": "deno run --watch main.ts",
- "gen": "cargo test && deno run -A scripts/generate-zod.ts",
+ "gen": "cargo test && deno run -A scripts/generate-zod.ts && deno run -A scripts/sync-versions.ts",
"build": "deno task gen && cargo build -F transparent",
"example:simple": "deno run -A examples/simple.ts"
}
diff --git a/deno.lock b/deno.lock
index 3cab6f3..b108ca7 100644
--- a/deno.lock
+++ b/deno.lock
@@ -2,12 +2,18 @@
"version": "3",
"packages": {
"specifiers": {
+ "jsr:@denosaurs/plug": "jsr:@denosaurs/plug@1.0.6",
"jsr:@denosaurs/plug@^1.0.5": "jsr:@denosaurs/plug@1.0.6",
"jsr:@std/assert@^0.221.0": "jsr:@std/assert@0.221.0",
+ "jsr:@std/collections@^1.0.4": "jsr:@std/collections@1.0.4",
"jsr:@std/encoding@^0.221.0": "jsr:@std/encoding@0.221.0",
"jsr:@std/fmt@^0.221.0": "jsr:@std/fmt@0.221.0",
+ "jsr:@std/fs": "jsr:@std/fs@0.221.0",
"jsr:@std/fs@^0.221.0": "jsr:@std/fs@0.221.0",
+ "jsr:@std/path": "jsr:@std/path@0.221.0",
"jsr:@std/path@^0.221.0": "jsr:@std/path@0.221.0",
+ "jsr:@std/semver": "jsr:@std/semver@1.0.3",
+ "jsr:@std/toml": "jsr:@std/toml@1.0.0",
"jsr:@std/ulid": "jsr:@std/ulid@0.224.1",
"jsr:@valibot/valibot": "jsr:@valibot/valibot@0.42.0",
"jsr:@webview/webview": "jsr:@webview/webview@0.8.0",
@@ -16,6 +22,7 @@
"npm:effection": "npm:effection@3.0.3",
"npm:json-schema-to-zod": "npm:json-schema-to-zod@2.4.1",
"npm:ts-pattern": "npm:ts-pattern@5.0.6",
+ "npm:type-fest": "npm:type-fest@4.25.0",
"npm:zod": "npm:zod@3.23.8"
},
"jsr": {
@@ -31,6 +38,9 @@
"@std/assert@0.221.0": {
"integrity": "a5f1aa6e7909dbea271754fd4ab3f4e687aeff4873b4cef9a320af813adb489a"
},
+ "@std/collections@1.0.4": {
+ "integrity": "bcc90800e489dc6bacdf68eb5dc746d6d8a033cb4f3311f0f9cf8094de429ce7"
+ },
"@std/encoding@0.221.0": {
"integrity": "d1dd76ef0dc5d14088411e6dc1dede53bf8308c95d1537df1214c97137208e45"
},
@@ -50,6 +60,15 @@
"jsr:@std/assert@^0.221.0"
]
},
+ "@std/semver@1.0.3": {
+ "integrity": "7c139c6076a080eeaa4252c78b95ca5302818d7eafab0470d34cafd9930c13c8"
+ },
+ "@std/toml@1.0.0": {
+ "integrity": "c9e37564eedd84084871c66238e00196ec67aa958e09a7f761b3f36273a7a8a5",
+ "dependencies": [
+ "jsr:@std/collections@^1.0.4"
+ ]
+ },
"@std/ulid@0.224.1": {
"integrity": "4de06fdb030ff3990b1b0344e330373c11ce6051ac449fc435667a485a6723fa"
},
@@ -84,6 +103,10 @@
"integrity": "sha512-Y+jOjihlFriWzcBjncPCf2/am+Hgz7LtsWs77pWg5vQQKLQj07oNrJryo/wK2G0ndNaoVn2ownFMeoeAuReu3Q==",
"dependencies": {}
},
+ "type-fest@4.25.0": {
+ "integrity": "sha512-bRkIGlXsnGBRBQRAY56UXBm//9qH4bmJfFvq83gSz41N282df+fjy8ofcEgc1sM8geNt5cl6mC2g9Fht1cs8Aw==",
+ "dependencies": {}
+ },
"zod@3.23.8": {
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"dependencies": {}
diff --git a/examples/simple.ts b/examples/simple.ts
index c666c91..08829b1 100644
--- a/examples/simple.ts
+++ b/examples/simple.ts
@@ -1,6 +1,6 @@
-import { WebView } from "../src/lib.ts";
+import { createWebView } from "../src/lib.ts";
-const webview = new WebView({
+using webview = await createWebView({
title: "Simple",
html: "
Hello, World!
",
});
diff --git a/scripts/sync-versions.ts b/scripts/sync-versions.ts
new file mode 100644
index 0000000..ef17d1c
--- /dev/null
+++ b/scripts/sync-versions.ts
@@ -0,0 +1,25 @@
+/**
+ * Keeps the version of the WebView binary in sync with the version in Cargo.toml.
+ */
+
+import { parse } from "jsr:@std/toml";
+
+const latestVersion = await Deno
+ .readTextFile("./Cargo.toml").then((text) =>
+ parse(text) as { package: { version: string } }
+ ).then((config) => config.package.version);
+
+// Read the content of src/lib.ts
+const libPath = "./src/lib.ts";
+const libContent = await Deno.readTextFile(libPath);
+
+// Replace the version in the URL
+const updatedContent = libContent.replace(
+ /releases\/download\/v\d+\.\d+\.\d+\/deno-webview/,
+ `releases/download/v${latestVersion}/deno-webview`,
+);
+
+// Write the updated content back to src/lib.ts
+await Deno.writeTextFile(libPath, updatedContent);
+
+console.log(`Updated WebView binary version to ${latestVersion} in src/lib.ts`);
diff --git a/src/lib.ts b/src/lib.ts
index 2220d1f..e5bfa20 100644
--- a/src/lib.ts
+++ b/src/lib.ts
@@ -7,6 +7,9 @@ import {
} from "./schemas.ts";
import { monotonicUlid as ulid } from "jsr:@std/ulid";
import type { Except } from "npm:type-fest";
+import { join } from "jsr:@std/path";
+import { ensureDir } from "jsr:@std/fs";
+import { exists } from "jsr:@std/fs";
type JSON =
| string
@@ -68,7 +71,82 @@ const returnAck = (result: WebViewResponse) => {
}
};
-export class WebView implements Disposable {
+async function getWebViewBin(options: WebViewOptions) {
+ if (Deno.permissions.querySync({ name: "env" }).state === "granted") {
+ const binPath = Deno.env.get("WEBVIEW_BIN");
+ if (binPath) return binPath;
+ }
+
+ const flags = options.devtools
+ ? "-devtools"
+ : options.transparent && Deno.build.os === "darwin"
+ ? "-transparent"
+ : "";
+
+ const cacheDir = getCacheDir();
+ const fileName = `deno-webview${flags}${
+ Deno.build.os === "windows" ? ".exe" : ""
+ }`;
+ const filePath = join(cacheDir, fileName);
+
+ // Check if the file already exists in cache
+ if (await exists(filePath)) {
+ return filePath;
+ }
+
+ // If not in cache, download it
+ let url =
+ "https://github.com/zephraph/webview/releases/download/v0.1.4/deno-webview";
+ switch (Deno.build.os) {
+ case "darwin": {
+ url += "-mac" + flags;
+ break;
+ }
+ case "linux": {
+ url += "-linux" + flags;
+ break;
+ }
+ case "windows": {
+ url += "-windows" + flags + ".exe";
+ break;
+ }
+ default:
+ throw new Error("unsupported OS");
+ }
+
+ const res = await fetch(url);
+
+ // Ensure the cache directory exists
+ await ensureDir(cacheDir);
+
+ // Write the binary to disk
+ await Deno.writeFile(filePath, new Uint8Array(await res.arrayBuffer()), {
+ mode: 0o755,
+ });
+
+ return filePath;
+}
+
+// Helper function to get the OS-specific cache directory
+function getCacheDir(): string {
+ switch (Deno.build.os) {
+ case "darwin":
+ return join(Deno.env.get("HOME")!, "Library", "Caches", "deno-webview");
+ case "linux":
+ return join(Deno.env.get("HOME")!, ".cache", "deno-webview");
+ case "windows":
+ return join(Deno.env.get("LOCALAPPDATA")!, "deno-webview", "Cache");
+ default:
+ throw new Error("Unsupported OS");
+ }
+}
+
+export async function createWebView(options: WebViewOptions) {
+ const binPath = await getWebViewBin(options);
+ return new WebView(options, binPath);
+}
+
+class WebView implements Disposable {
#process: Deno.ChildProcess;
#stdin: WritableStreamDefaultWriter;
#stdout: ReadableStreamDefaultReader;
@@ -77,8 +155,8 @@ export class WebView implements Disposable {
#externalEvent = new EventEmitter();
#messageLoop: Promise;
- constructor(options: WebViewOptions) {
- this.#process = new Deno.Command("./target/debug/deno-webview", {
+ constructor(options: WebViewOptions, binPath: string) {
+ this.#process = new Deno.Command(binPath, {
args: [JSON.stringify(options)],
stdin: "piped",
stdout: "piped",
diff --git a/src/main.rs b/src/main.rs
index edf90a4..510ae70 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -137,8 +137,6 @@ fn main() -> wry::Result<()> {
}
let window = window_builder.build(&event_loop).unwrap();
- eprintln!("transparent: {:?}", webview_options.transparent);
-
let webview_builder = match webview_options.target {
WebViewTarget::Url(url) => WebViewBuilder::new(&window).with_url(url),
WebViewTarget::Html(html) => WebViewBuilder::new(&window).with_html(html),
@@ -171,7 +169,6 @@ fn main() -> wry::Result<()> {
let mut stdout_lock = stdout.lock();
while let Ok(event) = to_deno.recv() {
- eprintln!("Sending event: {:?}", event);
match serde_json::to_string(&event) {
Ok(json) => {
let mut buffer = json.replace("\0", "").into_bytes();