Kaynağa Gözat

feat: add tauri-schema-worker (#10871)

Amr Bashir 10 ay önce
ebeveyn
işleme
a1cce04260

+ 14 - 26
.changes/config.json

@@ -23,14 +23,14 @@
       "prepublish": [
         "cargo install cargo-audit --features=fix",
         {
-          "command": "cargo generate-lockfile",
+          "command": "echo '<details>\n<summary><em><h4>Cargo Audit</h4></em></summary>\n\n```'",
           "dryRunCommand": true,
-          "runFromRoot": true,
           "pipe": true
         },
         {
-          "command": "echo '<details>\n<summary><em><h4>Cargo Audit</h4></em></summary>\n\n```'",
+          "command": "cargo generate-lockfile",
           "dryRunCommand": true,
+          "runFromRoot": true,
           "pipe": true
         },
         {
@@ -79,15 +79,15 @@
         }
       },
       "prepublish": [
-        {
-          "command": "pnpm i --frozen-lockfile",
-          "dryRunCommand": true
-        },
         {
           "command": "echo '<details>\n<summary><em><h4>PNPM Audit</h4></em></summary>\n\n```'",
           "dryRunCommand": true,
           "pipe": true
         },
+        {
+          "command": "pnpm i --frozen-lockfile",
+          "dryRunCommand": true
+        },
         {
           "command": "pnpm audit",
           "dryRunCommand": true,
@@ -191,16 +191,7 @@
       "path": "./crates/tauri-build",
       "manager": "rust",
       "dependencies": ["tauri-codegen", "tauri-utils"],
-      "postversion": [
-        "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }",
-        "cargo build --manifest-path ../tauri-schema-generator/Cargo.toml"
-      ],
-      "assets": [
-        {
-          "path": "./crates/tauri-schema-generator/schemas/config.schema.json",
-          "name": "config.schema.json"
-        }
-      ]
+      "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }"
     },
     "tauri": {
       "path": "./crates/tauri",
@@ -212,16 +203,16 @@
         "tauri-runtime-wry",
         "tauri-build"
       ],
-      "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }"
+      "postversion": [
+        "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }",
+        "cargo build --manifest-path ../tauri-schema-generator/Cargo.toml"
+      ]
     },
     "@tauri-apps/cli": {
       "path": "./packages/cli",
       "manager": "javascript",
       "dependencies": ["tauri-cli"],
-      "postversion": [
-        "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }",
-        "cargo build --manifest-path ../../crates/tauri-schema-generator/Cargo.toml"
-      ],
+      "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }",
       "prepublish": [],
       "publish": [],
       "postpublish": []
@@ -230,10 +221,7 @@
       "path": "./crates/tauri-cli",
       "manager": "rust",
       "dependencies": ["tauri-bundler", "tauri-utils", "tauri-macos-sign"],
-      "postversion": [
-        "cargo check",
-        "cargo build --manifest-path ../tauri-schema-generator/Cargo.toml"
-      ]
+      "postversion": "cargo check"
     },
     "tauri-driver": {
       "path": "./crates/tauri-driver",

+ 25 - 0
.github/workflows/deploy-schema-worker.yml

@@ -0,0 +1,25 @@
+# Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-License-Identifier: MIT
+
+name: deploy schema worker
+
+on:
+  push:
+    branches:
+      - dev
+    paths:
+      - '.github/workflows/deploy-schema-worker.yml'
+      - 'crates/tauri-schema-worker/**'
+
+jobs:
+  deploy:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@v4
+      - uses: cloudflare/wrangler-action@3
+        with:
+          command: deploy
+          workingDirectory: 'crates/tauri-schema-worker'
+          apiToken: ${{ secrets.SCHEMA_WORKER_CLOUDFLARE_API_TOKEN }}
+          accountId: ${{ secrets.SCHEMA_WORKER_CLOUDFLARE_ACCOUNT_ID  }}

+ 5 - 1
.prettierignore

@@ -1,7 +1,10 @@
-/.changes
 /audits
 /.vscode
 
+# change files are hand-written and shouldn't be formatted
+/.changes/*
+!/.changes/config.json
+
 # dependcies and artifacts directories
 node_modules/
 target/
@@ -25,6 +28,7 @@ crates/tauri-cli/templates
 **/autogenerated/**/*.md
 packages/cli/index.js
 packages/cli/index.d.ts
+crates/tauri-schema-worker/.wrangler
 CHANGELOG.md
 *schema.json
 

+ 121 - 0
Cargo.lock

@@ -1205,6 +1205,16 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "const-oid"
 version = "0.9.6"
@@ -6450,6 +6460,28 @@ dependencies = [
  "serde",
 ]
 
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3b143e2833c57ab9ad3ea280d21fd34e285a42837aeb0ee301f4f41890fa00e"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
 [[package]]
 name = "serde_derive"
 version = "1.0.209"
@@ -7708,6 +7740,20 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "tauri-schema-worker"
+version = "0.0.0"
+dependencies = [
+ "anyhow",
+ "axum",
+ "console_error_panic_hook",
+ "semver",
+ "serde",
+ "tower-service",
+ "worker",
+ "worker-macros",
+]
+
 [[package]]
 name = "tauri-utils"
 version = "1.6.0"
@@ -9326,6 +9372,81 @@ version = "0.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
 
+[[package]]
+name = "worker"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3bd73bd2ea409ae91df99293cbed8b892d39c4c0df5039b646be7586df62c6b"
+dependencies = [
+ "async-trait",
+ "axum",
+ "bytes",
+ "chrono",
+ "futures-channel",
+ "futures-util",
+ "http 1.1.0",
+ "http-body 1.0.1",
+ "js-sys",
+ "matchit",
+ "pin-project",
+ "serde",
+ "serde-wasm-bindgen 0.6.5",
+ "serde_json",
+ "serde_urlencoded",
+ "tokio",
+ "url",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-streams",
+ "web-sys",
+ "worker-kv",
+ "worker-macros",
+ "worker-sys",
+]
+
+[[package]]
+name = "worker-kv"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f06d4d1416a9f8346ee9123b0d9a11b3cfa38e6cfb5a139698017d1597c4d41"
+dependencies = [
+ "js-sys",
+ "serde",
+ "serde-wasm-bindgen 0.5.0",
+ "serde_json",
+ "thiserror",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+]
+
+[[package]]
+name = "worker-macros"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0bbf47d65e77652febb28abedac18b317d8dfe4e57f0d8d9998c4e991fca8e23"
+dependencies = [
+ "async-trait",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.76",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "wasm-bindgen-macro-support",
+ "worker-sys",
+]
+
+[[package]]
+name = "worker-sys"
+version = "0.3.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a4fbb72a85a6509e5ac5dcd1361543468be089ff5ea5c932043b6d0aeac7b6a5"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
 [[package]]
 name = "wry"
 version = "0.43.1"

+ 2 - 0
Cargo.toml

@@ -9,6 +9,7 @@ members = [
   "crates/tauri-codegen",
   "crates/tauri-plugin",
   "crates/tauri-schema-generator",
+  "crates/tauri-schema-worker",
   "crates/tauri-cli",
   "crates/tauri-bundler",
   "crates/tauri-macos-sign",
@@ -50,6 +51,7 @@ codegen-units = 1
 lto = true
 incremental = false
 opt-level = "s"
+strip = true
 
 # profiles for tauri-cli
 [profile.dev.package.miniz_oxide]

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
crates/tauri-cli/config.schema.json


+ 1 - 0
crates/tauri-cli/templates/tauri.conf.json

@@ -1,4 +1,5 @@
 {
+  "$schema": "https://schema.tauri.app/config/2.0.0-rc",
   "productName": "{{ app_name }}",
   "version": "0.1.0",
   "identifier": "com.tauri.dev",

+ 20 - 4
crates/tauri-schema-generator/build.rs

@@ -4,6 +4,7 @@
 
 use std::{error::Error, path::PathBuf};
 
+use serde::Deserialize;
 use tauri_utils::{
   acl::{capability::Capability, Permission, Scopes},
   config::Config,
@@ -16,9 +17,13 @@ macro_rules! schema {
   };
 }
 
+#[derive(Deserialize)]
+pub struct VersionMetadata {
+  tauri: String,
+}
+
 pub fn main() -> Result<(), Box<dyn Error>> {
   let schemas = [
-    schema!("config", Config),
     schema!("capability", Capability),
     schema!("permission", Permission),
     schema!("scope", Scopes),
@@ -32,10 +37,21 @@ pub fn main() -> Result<(), Box<dyn Error>> {
   for (filename, schema) in schemas {
     let schema = serde_json::to_string_pretty(&schema)?;
     write_if_changed(schemas_dir.join(filename), &schema)?;
+  }
+
+  // write config schema file
+  {
+    let metadata = include_str!("../tauri-cli/metadata-v2.json");
+    let tauri_ver = serde_json::from_str::<VersionMetadata>(metadata)?.tauri;
+
+    // set id for generated schema
+    let (filename, mut config_schema) = schema!("config", Config);
+    let schema_metadata = config_schema.schema.metadata.as_mut().unwrap();
+    schema_metadata.id = Some(format!("tauri-config-{}", tauri_ver));
 
-    if filename.starts_with("config") {
-      write_if_changed(out.join("../tauri-cli/config.schema.json"), schema)?;
-    }
+    let config_schema = serde_json::to_string_pretty(&config_schema)?;
+    write_if_changed(schemas_dir.join(filename), &config_schema)?;
+    write_if_changed(out.join("../tauri-cli/config.schema.json"), config_schema)?;
   }
 
   Ok(())

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 0
crates/tauri-schema-generator/schemas/config.schema.json


+ 4 - 0
crates/tauri-schema-worker/.gitignore

@@ -0,0 +1,4 @@
+/target
+/node_modules
+/.wrangler
+/build

+ 18 - 0
crates/tauri-schema-worker/Cargo.toml

@@ -0,0 +1,18 @@
+[package]
+name = "tauri-schema-worker"
+version = "0.0.0"
+edition = "2021"
+publish = false
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+worker = { version = "0.3", features = ['http', 'axum'] }
+worker-macros = { version = "0.3", features = ['http'] }
+console_error_panic_hook = { version = "0.1" }
+axum = { version = "0.7", default-features = false }
+tower-service = "0.3"
+semver = { version = "1.0", features = ["serde"] }
+serde = { version = "1.0", features = ["derive"] }
+anyhow = "1.0"

+ 3 - 0
crates/tauri-schema-worker/README.md

@@ -0,0 +1,3 @@
+# schema.tauri.app worker
+
+Source code for `https://schema.tauri.app` cloudflare worker.

+ 13 - 0
crates/tauri-schema-worker/package.json

@@ -0,0 +1,13 @@
+{
+  "name": "tauri-schema-worker",
+  "version": "0.0.0",
+  "license": "Apache-2.0 OR MIT",
+  "private": "true",
+  "scripts": {
+    "deploy": "wrangler deploy",
+    "dev": "wrangler dev"
+  },
+  "devDependencies": {
+    "wrangler": "^3.73"
+  }
+}

+ 174 - 0
crates/tauri-schema-worker/src/config.rs

@@ -0,0 +1,174 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use anyhow::Context;
+use axum::{
+  extract::Path,
+  http::{header, StatusCode},
+  response::Result,
+  routing::get,
+  Router,
+};
+use semver::{Version, VersionReq};
+use serde::Deserialize;
+use worker::*;
+
+#[derive(Deserialize)]
+pub struct CrateReleases {
+  pub versions: Vec<CrateRelease>,
+}
+
+#[derive(Debug, Deserialize)]
+pub struct CrateRelease {
+  #[serde(alias = "num")]
+  pub version: Version,
+  pub yanked: Option<bool>,
+}
+
+#[derive(Deserialize)]
+pub struct CrateMetadataFull {
+  #[serde(rename = "crate")]
+  pub crate_: CrateMetadata,
+}
+
+#[derive(Deserialize)]
+pub struct CrateMetadata {
+  pub max_stable_version: Version,
+}
+
+const USERAGENT: &str = "tauri-schema-worker (contact@tauri.app)";
+
+pub fn router() -> Router {
+  Router::new()
+    .route("/config", get(stable_schema))
+    .route("/config/latest", get(stable_schema))
+    .route("/config/stable", get(stable_schema))
+    .route("/config/next", get(next_schema)) // pre-releases versions, (rc, alpha and beta)
+    .route("/config/:version", get(schema_for_version))
+}
+
+async fn schema_for_version(Path(version): Path<String>) -> Result<String> {
+  try_schema_for_version(version)
+    .await
+    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
+    .map_err(Into::into)
+}
+
+async fn stable_schema() -> Result<String> {
+  try_stable_schema()
+    .await
+    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
+    .map_err(Into::into)
+}
+
+async fn next_schema() -> Result<String> {
+  try_next_schema()
+    .await
+    .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
+    .map_err(Into::into)
+}
+
+#[worker::send]
+async fn try_schema_for_version(version: String) -> anyhow::Result<String> {
+  let version = version.parse::<VersionReq>()?;
+
+  let releases = crate_releases("tauri").await?;
+
+  if releases.is_empty() {
+    return try_stable_schema().await;
+  }
+
+  let Some(version) = releases.into_iter().find(|r| version.matches(&r.version)) else {
+    return try_stable_schema().await;
+  };
+
+  schema_file_for_version(version.version).await
+}
+
+#[worker::send]
+async fn try_stable_schema() -> anyhow::Result<String> {
+  let max = stable_version("tauri").await?;
+  schema_file_for_version(max).await
+}
+
+#[worker::send]
+async fn try_next_schema() -> anyhow::Result<String> {
+  let releases = crate_releases("tauri").await?;
+  let version = releases
+    .into_iter()
+    .filter(|r| !r.version.pre.is_empty())
+    .map(|r| r.version)
+    .max()
+    .context("Couldn't find latest pre-release")?;
+  schema_file_for_version(version).await
+}
+
+async fn schema_file_for_version(version: Version) -> anyhow::Result<String> {
+  let cache = Cache::open("schema".to_string()).await;
+  let cache_key = format!("https://scheam.tauri.app/config/{version}");
+  if let Some(mut cached) = cache.get(cache_key.clone(), true).await? {
+    console_log!("Serving schema for {version} from cache");
+    return cached.text().await.map_err(Into::into);
+  }
+
+  console_log!("Fetching schema for {version} from remote");
+
+  let path = if version.major >= 2 {
+    "crates/tauri-schema-generator/schemas/config.schema.json"
+  } else {
+    "core/tauri-config-schema/schema.json"
+  };
+  let url = format!("https://raw.githubusercontent.com/tauri-apps/tauri/tauri-v{version}/{path}");
+  let mut res = Fetch::Request(fetch_req(&url)?).send().await?;
+
+  cache.put(cache_key, res.cloned()?).await?;
+
+  res.text().await.map_err(Into::into)
+}
+
+async fn crate_releases(crate_: &str) -> anyhow::Result<Vec<CrateRelease>> {
+  let url = format!("https://crates.io/api/v1/crates/{crate_}/versions");
+  let mut res = Fetch::Request(fetch_req(&url)?).send().await?;
+
+  let versions: CrateReleases = res.json().await?;
+  let versions = versions.versions;
+
+  let flt = |r: &CrateRelease| r.yanked == Some(false);
+  Ok(versions.into_iter().filter(flt).collect())
+}
+
+async fn stable_version(crate_: &str) -> anyhow::Result<Version> {
+  let url = format!("https://crates.io/api/v1/crates/{crate_}");
+  let mut res = Fetch::Request(fetch_req(&url)?).send().await?;
+  let metadata: CrateMetadataFull = res.json().await?;
+  Ok(metadata.crate_.max_stable_version)
+}
+
+fn fetch_req(url: &str) -> anyhow::Result<worker::Request> {
+  let mut headers = Headers::new();
+  headers.append(header::USER_AGENT.as_str(), USERAGENT)?;
+
+  worker::Request::new_with_init(
+    url,
+    &RequestInit {
+      method: Method::Get,
+      headers,
+      cf: CfProperties {
+        cache_ttl: Some(86400),
+        cache_everything: Some(true),
+        cache_ttl_by_status: Some(
+          [
+            ("200-299".to_string(), 86400),
+            ("404".to_string(), 1),
+            ("500-599".to_string(), 0),
+          ]
+          .into(),
+        ),
+        ..Default::default()
+      },
+      ..Default::default()
+    },
+  )
+  .map_err(Into::into)
+}

+ 27 - 0
crates/tauri-schema-worker/src/lib.rs

@@ -0,0 +1,27 @@
+// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
+// SPDX-License-Identifier: Apache-2.0
+// SPDX-License-Identifier: MIT
+
+use axum::{routing::get, Router};
+use tower_service::Service;
+use worker::*;
+
+mod config;
+
+#[worker::event(fetch)]
+async fn main(
+  req: HttpRequest,
+  _env: Env,
+  _ctx: Context,
+) -> worker::Result<axum::http::Response<axum::body::Body>> {
+  console_error_panic_hook::set_once();
+  Ok(router().call(req).await?)
+}
+
+fn router() -> Router {
+  Router::new().route("/", get(root)).merge(config::router())
+}
+
+async fn root() -> &'static str {
+  "tauri schema worker"
+}

+ 11 - 0
crates/tauri-schema-worker/wrangler.toml

@@ -0,0 +1,11 @@
+# Copyright 2019-2022 Tauri Programme within The Commons Conservancy
+# SPDX-License-Identifier: Apache-2.0
+# SPDX-License-Identifier: MIT
+
+name = "tauri-schema"
+main = "build/worker/shim.mjs"
+compatibility_date = "2023-08-23"
+send_metrics = false
+
+[build]
+command = "cargo install -q worker-build && worker-build --release"

+ 1 - 1
examples/api/package.json

@@ -19,7 +19,7 @@
     "@unocss/extractor-svelte": "^0.61.0",
     "unocss": "^0.61.0",
     "@sveltejs/vite-plugin-svelte": "^3.1.1",
-    "svelte": "^4.2.18",
+    "svelte": "^4.2.19",
     "vite": "^5.4.1"
   }
 }

+ 1 - 7
package.json

@@ -19,11 +19,5 @@
   "devDependencies": {
     "prettier": "^3.3.3"
   },
-  "packageManager": "pnpm@9.7.1",
-  "pnpm": {
-    "overrides": {
-      "micromatch@<4.0.8": ">=4.0.8",
-      "svelte@<4.2.19": ">=4.2.19"
-    }
-  }
+  "packageManager": "pnpm@9.9.0"
 }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 454 - 5
pnpm-lock.yaml


+ 1 - 0
pnpm-workspace.yaml

@@ -1,6 +1,7 @@
 packages:
   - packages/api
   - packages/cli
+  - crates/tauri-schema-worker
   - examples/api
   - examples/resources
   - examples/file-associations

Bu fark içinde çok fazla dosya değişikliği olduğu için bazı dosyalar gösterilmiyor