diff --git a/.cargo/audit.toml b/.cargo/audit.toml index 2e1b9855704c..c67661d57351 100644 --- a/.cargo/audit.toml +++ b/.cargo/audit.toml @@ -1,6 +1,9 @@ [advisories] ignore = [ - "RUSTSEC-2020-0095", # difference is unmaintained (used by `mockito`) - "RUSTSEC-2020-0071", # potential segfault in the time crate (not fixed on `zip` and `mac-notification-sys`) - "RUSTSEC-2020-0159" # potential segfault in `localtime_r` invocations on the chrono crate (not fixed on `mac-notification-sys`) + # rsa Marvin Attack + "RUSTSEC-2023-0071", + # difference is unmaintained + "RUSTSEC-2020-0095", + # proc-macro-error is unmaintained + "RUSTSEC-2024-0370", ] diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 000000000000..4de6d529ed80 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,4 @@ +[env] +# workaround needed to prevent `STATUS_ENTRYPOINT_NOT_FOUND` error in tests +# see https://github.com/tauri-apps/tauri/pull/4383#issuecomment-1212221864 +__TAURI_WORKSPACE__ = "true" diff --git a/.changes/README.md b/.changes/README.md new file mode 100644 index 000000000000..318eea024e77 --- /dev/null +++ b/.changes/README.md @@ -0,0 +1,44 @@ +# Changes + +##### via https://github.com/jbolda/covector + +As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version _number_, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend that it represents the overall change for organizational purposes. + +When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. + +Use the following format: + +```md +--- +'package-a': 'patch:enhance' +'package-b': 'patch:enhance' +--- + +Change summary goes here +``` + +Summaries do not have a specific character limit, but are text only. These summaries are used within the (future implementation of) changelogs. They will give context to the change and also point back to the original PR if more details and context are needed. + +Changes will be designated as a `major`, `minor` or `patch` as further described in [semver](https://semver.org/). + +Given a version number MAJOR.MINOR.PATCH, increment the: + +- MAJOR version when you make incompatible API changes, +- MINOR version when you add functionality in a backwards compatible manner, and +- PATCH version when you make backwards compatible bug fixes. + +Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format, but will be discussed prior to usage (as extra steps will be necessary in consideration of merging and publishing). + +Additionally you could specify a tag for the change file to group it with other changes by prefixing the bump with `:`, for example: + +```md +--- +'package-a': 'patch:enhance' +--- + +Change summary goes here +``` + +which will group this change file with other changes that specify the `bug` tag. + +For list of available tags, see the `changeTags` key in [./config.json](./config.json) diff --git a/.changes/allow-conf-gitignore.md b/.changes/allow-conf-gitignore.md deleted file mode 100644 index cf63422e61c0..000000000000 --- a/.changes/allow-conf-gitignore.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Allows the `tauri.conf.json` file to be git ignored on the path lookup function. diff --git a/.changes/allowlist-clipboard.md b/.changes/allowlist-clipboard.md deleted file mode 100644 index 451fb8dc6241..000000000000 --- a/.changes/allowlist-clipboard.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -The `allowlist` configuration now includes a `clipboard` object, controlling the exposure of the `writeText` and `readText` APIs. diff --git a/.changes/allowlist-dialog.md b/.changes/allowlist-dialog.md deleted file mode 100644 index ffbcd6a568cf..000000000000 --- a/.changes/allowlist-dialog.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": patch -"tauri": patch ---- - -The dialog allowlist now includes flags for the `message`, `ask` and `confirm` APIs. diff --git a/.changes/allowlist-process.md b/.changes/allowlist-process.md deleted file mode 100644 index 490c3d1fb5ca..000000000000 --- a/.changes/allowlist-process.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -The `allowlist` configuration now includes a `process` object, controlling the exposure of the `relaunch` and `exit` APIs. diff --git a/.changes/allowlist-window.md b/.changes/allowlist-window.md deleted file mode 100644 index 7fe9048de4b4..000000000000 --- a/.changes/allowlist-window.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -tauri-utils: patch ---- - -The `window` allowlist now includes options to enable all window modification APIs: `center`, `close`, `create`, `hide`, `maximize`, `minimize`, `print`, `requestUserAttention`, `setAlwaysOnTop`, `setDecorations`, `setFocus`, `setFullscreen`, `setIcon`, `setMaxSize`, `setMinSize`, `setPosition`, `setResizable`, `setSize`, `setSkipTaskbar`, `setTitle`, `show`, `startDragging`, `unmaximize` and `unminimize`. diff --git a/.changes/always-rebuilding.md b/.changes/always-rebuilding.md deleted file mode 100644 index c44613b16050..000000000000 --- a/.changes/always-rebuilding.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Remove `cargo:rerun-if-changed` check for non-existent file that caused projects to _always_ rebuild. diff --git a/.changes/api-WebviewWindow-fileDropEnabled.md b/.changes/api-WebviewWindow-fileDropEnabled.md deleted file mode 100644 index 06835a9298fb..000000000000 --- a/.changes/api-WebviewWindow-fileDropEnabled.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Add `fileDropEnabled` property to `WindowOptions` so you can now disable it when creating windows from js. diff --git a/.changes/api-add-log-dir.md b/.changes/api-add-log-dir.md deleted file mode 100644 index 7cd73ba19ef5..000000000000 --- a/.changes/api-add-log-dir.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"api": patch ---- - -Add `logDir` function to the `path` module to access the sugested log directory. -Add `BaseDirectory.Log` to the `fs` module. diff --git a/.changes/api-app-window-browser.md b/.changes/api-app-window-browser.md deleted file mode 100644 index a43ef8b4c497..000000000000 --- a/.changes/api-app-window-browser.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Do not crash if `__TAURI_METADATA__` is not set, log an error instead. diff --git a/.changes/api-change-events.md b/.changes/api-change-events.md deleted file mode 100644 index 863895524624..000000000000 --- a/.changes/api-change-events.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch ---- - -* **Breaking change:** Renamed `tauri::Event` to `tauri::RunEvent` -* Exported `tauri::Event` and `tauri::EventHandler` so you can define a function and pass it to `Window::listen` diff --git a/.changes/api-dialog-ask-message-confirm.md b/.changes/api-dialog-ask-message-confirm.md deleted file mode 100644 index f698df09a108..000000000000 --- a/.changes/api-dialog-ask-message-confirm.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Expose `ask`, `message` and `confirm` APIs on the dialog module. diff --git a/.changes/api-emit-payload-type.md b/.changes/api-emit-payload-type.md deleted file mode 100644 index 4ed130564181..000000000000 --- a/.changes/api-emit-payload-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Event `emit` now automatically serialize non-string types. diff --git a/.changes/api-features.md b/.changes/api-features.md deleted file mode 100644 index 51c5d93ece9b..000000000000 --- a/.changes/api-features.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `tauri::api` modules `http`, `notification`, `dialog`, and `process::Command` APIs are now hidden behind a feature flag, `http-api`, `notification`, `dialog` and `command`, respectively. diff --git a/.changes/api-fetch-empty-reponse.md b/.changes/api-fetch-empty-reponse.md deleted file mode 100644 index d0b81376f7ac..000000000000 --- a/.changes/api-fetch-empty-reponse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Fix `http.fetch` throwing error if the response is successful but the body is empty. diff --git a/.changes/api-file-dialog-title.md b/.changes/api-file-dialog-title.md deleted file mode 100644 index 2613a41604e0..000000000000 --- a/.changes/api-file-dialog-title.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"api": patch -"tauri": patch ---- - -Add `title` option to file open/save dialogs. diff --git a/.changes/api-fix-os-platform-return.md b/.changes/api-fix-os-platform-return.md deleted file mode 100644 index fdf7d03b079b..000000000000 --- a/.changes/api-fix-os-platform-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Fix `os.platform` returning `macos` and `windows` instead of `darwin` and `win32`. diff --git a/.changes/api-format-callback.md b/.changes/api-format-callback.md deleted file mode 100644 index a517cff7c268..000000000000 --- a/.changes/api-format-callback.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -The `formatCallback` helper function now returns a number instead of a string. diff --git a/.changes/api-raw-headers.md b/.changes/api-raw-headers.md deleted file mode 100644 index 2d384f6b38ba..000000000000 --- a/.changes/api-raw-headers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Added `rawHeaders` to `http > Response`. diff --git a/.changes/api-relaunch-cleanup.md b/.changes/api-relaunch-cleanup.md deleted file mode 100644 index 825658a3edad..000000000000 --- a/.changes/api-relaunch-cleanup.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Run `AppHandle` cleanup code before restarting the application on the `process > relaunch` API. diff --git a/.changes/api-remove-current-dir.md b/.changes/api-remove-current-dir.md deleted file mode 100644 index 375fa7f78110..000000000000 --- a/.changes/api-remove-current-dir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": "patch" ---- - -Removed the `currentDir` API from the `path` module. diff --git a/.changes/api-remove-ts-files.md b/.changes/api-remove-ts-files.md deleted file mode 100644 index 8497514e9a03..000000000000 --- a/.changes/api-remove-ts-files.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Remove `.ts` files on the published package. diff --git a/.changes/api-transfrom-icon-about-menu-item.md b/.changes/api-transfrom-icon-about-menu-item.md new file mode 100644 index 000000000000..b62f4636e84f --- /dev/null +++ b/.changes/api-transfrom-icon-about-menu-item.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/api": "patch:bug" +--- + +Fix error when calling `PredefinedMenuItem.new` to create an `About` menu item that uses an `Image` instance for the about icon. + diff --git a/.changes/api-transfrom-icon-icon-menu-item.md b/.changes/api-transfrom-icon-icon-menu-item.md new file mode 100644 index 000000000000..734e59d17f87 --- /dev/null +++ b/.changes/api-transfrom-icon-icon-menu-item.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/api": "patch:bug" +--- + +Fix error when calling `IconMenuItem.new` using an `Image` instance for the icon. + diff --git a/.changes/api-use-uint8array.md b/.changes/api-use-uint8array.md deleted file mode 100644 index a23c35bbf564..000000000000 --- a/.changes/api-use-uint8array.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -**Breaking change:** Replaces all usages of `number[]` with `Uint8Array` to be closer aligned with the wider JS ecosystem. diff --git a/.changes/api-window-type-for-size-and-position.md b/.changes/api-window-type-for-size-and-position.md deleted file mode 100644 index 0b7818c1f575..000000000000 --- a/.changes/api-window-type-for-size-and-position.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"api": patch ---- - -`WindowManager` methods `innerPosition` `outerPosition` now correctly return instance of `PhysicalPosition`. -`WindowManager` methods `innerSize` `outerSize` now correctly return instance of `PhysicalSize`. diff --git a/.changes/app-any-thread.md b/.changes/app-any-thread.md deleted file mode 100644 index a413e36af267..000000000000 --- a/.changes/app-any-thread.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `any_thread()` to the `tauri::Builder` to run applications on any thread (only exposed on Linux and Windows). diff --git a/.changes/app-folder-structure.md b/.changes/app-folder-structure.md deleted file mode 100644 index c4396de4ddf6..000000000000 --- a/.changes/app-folder-structure.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.js": patch -"cli.rs": patch ---- - -Do not force Tauri application code on `src-tauri` folder and use a glob pattern to look for a subfolder with a `tauri.conf.json` file. diff --git a/.changes/asset-allowlist.md b/.changes/asset-allowlist.md deleted file mode 100644 index ca00d66be72b..000000000000 --- a/.changes/asset-allowlist.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -Added `asset` allowlist configuration, which enables the `asset` protocol and defines it access scope. diff --git a/.changes/asset-cors.md b/.changes/asset-cors.md deleted file mode 100644 index 4444dc4ffdc6..000000000000 --- a/.changes/asset-cors.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Enable CORS on the `asset` protocol. diff --git a/.changes/asset-protocol-feature-flag.md b/.changes/asset-protocol-feature-flag.md deleted file mode 100644 index f3cc874bf255..000000000000 --- a/.changes/asset-protocol-feature-flag.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `asset://` custom protocol is only defined when either the `api-all`, `protocol-all` or `protocol-asset` feature flags are enabled. These feature flags are accessible with the `tauri.conf.json` allowlist. diff --git a/.changes/asset-resolver.md b/.changes/asset-resolver.md deleted file mode 100644 index cadbb49e790a..000000000000 --- a/.changes/asset-resolver.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Expose the `asset_resolver` API on the `App` and `AppHandle` structs. diff --git a/.changes/async-cli.js.md b/.changes/async-cli.js.md deleted file mode 100644 index fa33265badd4..000000000000 --- a/.changes/async-cli.js.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Change the `run` function to take a callback and run asynchronously instead of blocking the event loop. diff --git a/.changes/async-runtime-refactor.md b/.changes/async-runtime-refactor.md deleted file mode 100644 index 4367fe552fa3..000000000000 --- a/.changes/async-runtime-refactor.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** Refactored the types returned from the `async_runtime` module. diff --git a/.changes/async-runtime-set.md b/.changes/async-runtime-set.md deleted file mode 100644 index 7b00e0127e89..000000000000 --- a/.changes/async-runtime-set.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `tauri::async_runtime::set` method, allowing to share your tokio runtime with Tauri. diff --git a/.changes/async-runtime-spawn-blocking.md b/.changes/async-runtime-spawn-blocking.md deleted file mode 100644 index b39939c1e7ae..000000000000 --- a/.changes/async-runtime-spawn-blocking.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `tauri::async_runtime::spawn_blocking` API. diff --git a/.changes/before-script-envs.md b/.changes/before-script-envs.md deleted file mode 100644 index d1a28bfa0f85..000000000000 --- a/.changes/before-script-envs.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Define `TAURI_PLATFORM`, `TAURI_ARCH`, `TAURI_FAMILY`, `TAURI_PLATFORM_TYPE`, `TAURI_PLATFORM_VERSION` and `TAURI_DEBUG` environment variables for the `beforeDevCommand` and `beforeBuildCommand` scripts. diff --git a/.changes/build-rerun-if-resource-sidecar-change.md b/.changes/build-rerun-if-resource-sidecar-change.md deleted file mode 100644 index ef8a0c95ed63..000000000000 --- a/.changes/build-rerun-if-resource-sidecar-change.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Rerun if sidecar or resource change. diff --git a/.changes/build-specify-win-sdk.md b/.changes/build-specify-win-sdk.md deleted file mode 100644 index 1eab9d981be7..000000000000 --- a/.changes/build-specify-win-sdk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Allow user to specify windows sdk path in build.rs. \ No newline at end of file diff --git a/.changes/builder-create-window-result.md b/.changes/builder-create-window-result.md deleted file mode 100644 index c8fb7a85fa01..000000000000 --- a/.changes/builder-create-window-result.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** The `Builder#create_window` API now returns a Result validating the window label. diff --git a/.changes/bundler-add-provider-short-name.md b/.changes/bundler-add-provider-short-name.md deleted file mode 100644 index 65eaae6be092..000000000000 --- a/.changes/bundler-add-provider-short-name.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Provide a provider short name for macOS app notarization if your Apple developer account is connected to more than one team. diff --git a/.changes/bundler-add-tsp-signing.md b/.changes/bundler-add-tsp-signing.md deleted file mode 100644 index 94ec67f95192..000000000000 --- a/.changes/bundler-add-tsp-signing.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"tauri-bundler": patch -"cli.rs": patch -"cli.js": patch -"tauri": patch ---- - -Added `tsp` config option under `tauri > bundle > windows`, which enables Time-Stamp Protocol (RFC 3161) for the timestamping -server under code signing on Windows if set to `true`. \ No newline at end of file diff --git a/.changes/bundler-appimage-fuse.md b/.changes/bundler-appimage-fuse.md deleted file mode 100644 index ec7a25876ef4..000000000000 --- a/.changes/bundler-appimage-fuse.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Allow building AppImages on systems without FUSE setup. diff --git a/.changes/bundler-fix-appimage.md b/.changes/bundler-fix-appimage.md deleted file mode 100644 index fcaf8b4dbaca..000000000000 --- a/.changes/bundler-fix-appimage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'tauri-bundler': patch ---- - -Fixes AppImage crashes caused by missing WebKit runtime files. diff --git a/.changes/bundler-msi-init-installdir.md b/.changes/bundler-msi-init-installdir.md deleted file mode 100644 index 430f2ba1c2f7..000000000000 --- a/.changes/bundler-msi-init-installdir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Initialize the preselected installation path with the location of the previous installation. \ No newline at end of file diff --git a/.changes/bundler-nsis-portuguese.md b/.changes/bundler-nsis-portuguese.md new file mode 100644 index 000000000000..e0a586c38380 --- /dev/null +++ b/.changes/bundler-nsis-portuguese.md @@ -0,0 +1,8 @@ +--- +"tauri-bundler": "patch:enhance" +"tauri-cli": "patch:enhance" +"@tauri-apps/cli": "patch:enhance" +--- + +Add support for `Portuguese` language for NSIS windows installer. + diff --git a/.changes/bundler-print-cfg.md b/.changes/bundler-print-cfg.md deleted file mode 100644 index d382978884e9..000000000000 --- a/.changes/bundler-print-cfg.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Replaces usage of the nightly command `RUSTC_BOOTSTRAP=1 rustc -Z unstable-options --print target-spec-json` with the stable command `rustc --print cfg`, improving target triple detection. diff --git a/.changes/bundler-skip-ci.md b/.changes/bundler-skip-ci.md new file mode 100644 index 000000000000..66ad0f001898 --- /dev/null +++ b/.changes/bundler-skip-ci.md @@ -0,0 +1,5 @@ +--- +tauri-bundler: 'patch:enhance' +--- + +The bundler now reads the `TAURI_BUNDLER_DMG_IGNORE_CI` env var to decide whether to check for `CI: true` when building DMG files. diff --git a/.changes/callback-validation.md b/.changes/callback-validation.md deleted file mode 100644 index 4aa93397bf85..000000000000 --- a/.changes/callback-validation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `callback` and `error` invoke fields, along with other `transformCallback` usages, are now validated to be numeric. diff --git a/.changes/clap-3.0.md b/.changes/clap-3.0.md deleted file mode 100644 index e429b6a0b9a3..000000000000 --- a/.changes/clap-3.0.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Revert the `clap` usage back to the version 3.0 API. diff --git a/.changes/clap-beta.4-core.md b/.changes/clap-beta.4-core.md deleted file mode 100644 index bc371dabe284..000000000000 --- a/.changes/clap-beta.4-core.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Change `Error::ParseCliArguments(clap::Error)` to `Error::ParseCliArguments(String)` because `clap::Error` is not `Send`. diff --git a/.changes/clap-beta.4.md b/.changes/clap-beta.4.md deleted file mode 100644 index d29f9f87f9de..000000000000 --- a/.changes/clap-beta.4.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -Change `CliArg` numeric types from `u64` to `usize`. diff --git a/.changes/cli-config-path.md b/.changes/cli-config-path.md deleted file mode 100644 index 8354c6e53a9c..000000000000 --- a/.changes/cli-config-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Allow `config` arg to be a path to a JSON file on the `dev` and `build` commands. diff --git a/.changes/cli-improve-waiting-devserver-msg.md b/.changes/cli-improve-waiting-devserver-msg.md deleted file mode 100644 index 6425061c815a..000000000000 --- a/.changes/cli-improve-waiting-devserver-msg.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Improve "waiting for your dev server to start" message. diff --git a/.changes/cli-include-vswhere.md b/.changes/cli-include-vswhere.md deleted file mode 100644 index ac2bce797a68..000000000000 --- a/.changes/cli-include-vswhere.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Include `vswhere.exe` on the published package. diff --git a/.changes/cli-private-key-pwd-panic.md b/.changes/cli-private-key-pwd-panic.md deleted file mode 100644 index 291d8bb11b8f..000000000000 --- a/.changes/cli-private-key-pwd-panic.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Do not panic if the updater private key password is wrong. diff --git a/.changes/cli-runner-args.md b/.changes/cli-runner-args.md deleted file mode 100644 index 88a2cdf034c5..000000000000 --- a/.changes/cli-runner-args.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Allow passing arguments to the `build` runner (`tauri build -- ...`). diff --git a/.changes/cli-runner-error-message.md b/.changes/cli-runner-error-message.md deleted file mode 100644 index 395559c314ad..000000000000 --- a/.changes/cli-runner-error-message.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Improve error message when the dev runner command fails. diff --git a/.changes/cli-template-minimum-mac-system-version.md b/.changes/cli-template-minimum-mac-system-version.md deleted file mode 100644 index a08e97dc9443..000000000000 --- a/.changes/cli-template-minimum-mac-system-version.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Remove `minimumSystemVersion: null` from the application template configuration. diff --git a/.changes/cli.js-cjs-output.md b/.changes/cli.js-cjs-output.md deleted file mode 100644 index 53bf7d818539..000000000000 --- a/.changes/cli.js-cjs-output.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Added CommonJS output to the `dist` folder. diff --git a/.changes/cli.js-fix-ico.md b/.changes/cli.js-fix-ico.md deleted file mode 100644 index 05b5bab9eb48..000000000000 --- a/.changes/cli.js-fix-ico.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Fixes `.ico` icon generation. diff --git a/.changes/cli.js-improve-error.md b/.changes/cli.js-improve-error.md deleted file mode 100644 index 083e5b00724f..000000000000 --- a/.changes/cli.js-improve-error.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Show full error message from `cli.rs` instead of just the outermost underlying error message. diff --git a/.changes/cli.js-windows-32bit.md b/.changes/cli.js-windows-32bit.md deleted file mode 100644 index b147ba2783b5..000000000000 --- a/.changes/cli.js-windows-32bit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Added `i686-pc-windows-msvc` to the prebuilt targets. diff --git a/.changes/cli.rs-active-toolchain.md b/.changes/cli.rs-active-toolchain.md deleted file mode 100644 index b39202bcdca3..000000000000 --- a/.changes/cli.rs-active-toolchain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Add `rustup` version and active rust toolchain to the `info` command output. diff --git a/.changes/cli.rs-build-tools-info.md b/.changes/cli.rs-build-tools-info.md deleted file mode 100644 index 6165773ca2fd..000000000000 --- a/.changes/cli.rs-build-tools-info.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Add `Visual Studio Build Tools` installed versions to the `info` command output. diff --git a/.changes/cli.rs-default-svelte-port.md b/.changes/cli.rs-default-svelte-port.md deleted file mode 100644 index 97ba9adb88f6..000000000000 --- a/.changes/cli.rs-default-svelte-port.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -The inferred development server port for Svelte is now `8080` (assumes latest Svelte with `sirv-cli >= 2.0.0`). diff --git a/.changes/cli.rs-detect-git.md b/.changes/cli.rs-detect-git.md deleted file mode 100644 index d6cde127f145..000000000000 --- a/.changes/cli.rs-detect-git.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Detect if tauri is used from git in the `info` command. diff --git a/.changes/cli.rs-dialoguer.md b/.changes/cli.rs-dialoguer.md deleted file mode 100644 index 073e45e828ab..000000000000 --- a/.changes/cli.rs-dialoguer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Drop the `dialoguer` soft fork and use the published version instead. diff --git a/.changes/cli.rs-fix-windows-x86.md b/.changes/cli.rs-fix-windows-x86.md deleted file mode 100644 index e4c4833aa1bd..000000000000 --- a/.changes/cli.rs-fix-windows-x86.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Fix `build` command when executed on a 32-bit Windows machine when pulling from the `binary-releases` repo. diff --git a/.changes/cli.rs-refactor-signer.md b/.changes/cli.rs-refactor-signer.md deleted file mode 100644 index fbafd3be5b1b..000000000000 --- a/.changes/cli.rs-refactor-signer.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -The `generate` and `sign` commands are now available under a `signer` subcommand. diff --git a/.changes/cli.rs-template-plugin-builder.md b/.changes/cli.rs-template-plugin-builder.md deleted file mode 100644 index b6e62ebac2e9..000000000000 --- a/.changes/cli.rs-template-plugin-builder.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Change the `plugin init` templates to use the new `tauri::plugin::Builder` syntax. diff --git a/.changes/cli.rs-use-tauri-utils.md b/.changes/cli.rs-use-tauri-utils.md deleted file mode 100644 index d83665e22d8a..000000000000 --- a/.changes/cli.rs-use-tauri-utils.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Use `tauri-utils` to get the `Config` types. diff --git a/.changes/cli.rs-validate-dist-dir.md b/.changes/cli.rs-validate-dist-dir.md deleted file mode 100644 index cd00837b7834..000000000000 --- a/.changes/cli.rs-validate-dist-dir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Print warning and exit if `distDir` contains `node_modules`, `src-tauri` or `target` folders. diff --git a/.changes/cli.rs-wix-license.md b/.changes/cli.rs-wix-license.md deleted file mode 100644 index 25b10f15f9c3..000000000000 --- a/.changes/cli.rs-wix-license.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Fix `tauri build` failing on Windows if `tauri.conf.json > tauri > bundle > Windows > wix > license` is used. diff --git a/.changes/colorful-cli.md b/.changes/colorful-cli.md deleted file mode 100644 index 911c737ba978..000000000000 --- a/.changes/colorful-cli.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": "patch" -"cli.js": "patch" ---- - -Improve readability of the `info` subcommand output. diff --git a/.changes/command-feature-flag.md b/.changes/command-feature-flag.md deleted file mode 100644 index 7868da9f2051..000000000000 --- a/.changes/command-feature-flag.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `api::process::Command` APIs are now hidden behind the `command` feature flag. \ No newline at end of file diff --git a/.changes/command-output-carriage-return.md b/.changes/command-output-carriage-return.md deleted file mode 100644 index 54994e08ca52..000000000000 --- a/.changes/command-output-carriage-return.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `tauri::api::process::Command` API now properly reads stdout and stderr messages that ends with a carriage return (`\r`) instead of just a newline (`\n`). diff --git a/.changes/config.json b/.changes/config.json index e075525b9255..dbd4bc8b8846 100644 --- a/.changes/config.json +++ b/.changes/config.json @@ -1,29 +1,36 @@ { "gitSiteUrl": "https://www.github.com/tauri-apps/tauri/", - "timeout": 3600000, + "changeTags": { + "feat": "New Features", + "enhance": "Enhancements", + "bug": "Bug Fixes", + "pref": "Performance Improvements", + "changes": "What's Changed", + "sec": "Security fixes", + "deps": "Dependencies", + "breaking": "Breaking Changes" + }, + "defaultChangeTag": "changes", "pkgManagers": { "rust": { - "errorOnVersionRange": "1.0.0-rc.100 - 99.x || ^1.1.0-0 || ^2.0.0-0", "version": true, - "getPublishedVersion": "cargo search ${ pkgFile.pkg.package.name } --limit 1 | sed -nE \"s/^[^\\\"]*\\\"//; s/\\\".*//1p\"", + "getPublishedVersion": { + "use": "fetch:check", + "options": { + "url": "https://crates.io/api/v1/crates/${ pkg.pkgFile.pkg.package.name }/${ pkg.pkgFile.version }" + } + }, "prepublish": [ - "sudo apt-get update", - "sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf", "cargo install cargo-audit --features=fix", { - "command": "cargo generate-lockfile", - "dryRunCommand": true, - "runFromRoot": true, - "pipe": true - }, - { - "command": "echo \"# Cargo Audit\"", + "command": "echo '
\n

Cargo Audit

\n\n```'", "dryRunCommand": true, "pipe": true }, { - "command": "echo '```'", + "command": "cargo generate-lockfile", "dryRunCommand": true, + "runFromRoot": true, "pipe": true }, { @@ -33,71 +40,56 @@ "pipe": true }, { - "command": "echo '```'", + "command": "echo '```\n\n
\n'", "dryRunCommand": true, "pipe": true } ], "publish": [ - "sleep 15s", { - "command": "cargo package --allow-dirty --no-verify", - "dryRunCommand": true - }, - { - "command": "echo \"# Cargo Publish\"", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "echo '```'", + "command": "echo '
\n

Cargo Publish

\n\n```'", "dryRunCommand": true, "pipe": true }, { - "command": "cargo publish --no-verify", - "dryRunCommand": "cargo publish --no-verify --dry-run --allow-dirty", + "command": "cargo publish", + "dryRunCommand": "cargo publish --dry-run", "pipe": true }, { - "command": "echo '```'", + "command": "echo '```\n\n
\n'", "dryRunCommand": true, "pipe": true } ], - "postpublish": [ - "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor } -f", - "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor }.${ pkgFile.versionMinor } -f", - "git push --tags -f" - ], - "assets": [ - { - "path": "${ pkg.path }/target/package/${ pkg.pkg }-${ pkgFile.version }.crate", - "name": "${ pkg.pkg }-${ pkgFile.version }.crate" - } - ] + "postpublish": { + "use": "fetch:check", + "options": { + "url": "https://crates.io/api/v1/crates/${ pkg.pkgFile.pkg.package.name }/${ pkg.pkgFile.version }" + }, + "retries": [5000, 5000, 5000] + } }, "javascript": { - "errorOnVersionRange": "1.0.0-rc.100 - 99.x || ^1.1.0-0 || ^2.0.0-0", "version": true, - "getPublishedVersion": "npm view ${ pkgFile.pkg.name } version", + "getPublishedVersion": { + "use": "fetch:check", + "options": { + "url": "https://registry.npmjs.com/${ pkg.pkgFile.pkg.name }/${ pkg.pkgFile.version }" + } + }, "prepublish": [ { - "command": "yarn", - "dryRunCommand": true - }, - { - "command": "echo \"# Yarn Audit\n\"", + "command": "echo '
\n

PNPM Audit

\n\n```'", "dryRunCommand": true, "pipe": true }, { - "command": "echo '
\nclick to view\n\n```'", - "dryRunCommand": true, - "pipe": true + "command": "pnpm i --frozen-lockfile", + "dryRunCommand": true }, { - "command": "yarn audit", + "command": "pnpm audit", "dryRunCommand": true, "runFromRoot": true, "pipe": true @@ -106,179 +98,133 @@ "command": "echo '```\n\n
\n'", "dryRunCommand": true, "pipe": true - }, - { - "command": "npm pack", - "dryRunCommand": true } ], "publish": [ - "sleep 15s", { - "command": "echo \"# Yarn Package Publish\"", + "command": "echo '
\n

PNPM Publish

\n\n```'", "dryRunCommand": true, "pipe": true }, { - "command": "echo '```'", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "yarn publish --access public --loglevel silly", - "dryRunCommand": "npm publish --dry-run --access public", + "command": "pnpm publish --access public --loglevel silly --no-git-checks", + "dryRunCommand": "npm publish --dry-run --access public --no-git-checks", "pipe": true }, { - "command": "echo '```'", + "command": "echo '```\n\n
\n'", "dryRunCommand": true, "pipe": true } ], - "postpublish": [ - "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor } -f", - "git tag ${ pkg.pkg }-v${ pkgFile.versionMajor }.${ pkgFile.versionMinor } -f", - "git push --tags -f" - ] + "postpublish": { + "use": "fetch:check", + "options": { + "url": "https://registry.npmjs.com/${ pkg.pkgFile.pkg.name }/${ pkg.pkgFile.version }" + }, + "retries": [5000, 5000, 5000] + } } }, "packages": { - "api": { - "path": "./tooling/api", + "@tauri-apps/api": { + "path": "./packages/api", "manager": "javascript", - "assets": [ - { - "path": "./tooling/api/dist/tauri-apps-api-${ pkgFile.version }.tgz", - "name": "api-${ pkgFile.version }.tgz" - } - ], - "prepublish": [ - { - "command": "yarn", - "dryRunCommand": true - }, - { - "command": "echo \"# Yarn Audit\n\"", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "echo '
\nclick to view\n\n```'", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "yarn audit", - "dryRunCommand": true, - "runFromRoot": true, - "pipe": true - }, - { - "command": "echo '```\n\n
\n'", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "yarn npm-pack", - "dryRunCommand": true - } - ], "publish": [ { - "command": "echo \"# Yarn Package Publish\"", + "command": "echo '
\n

PNPM Publish

\n\n```'", "dryRunCommand": true, "pipe": true }, { - "command": "echo '```'", + "command": "pnpm npm-publish", "dryRunCommand": true, "pipe": true }, { - "command": "yarn npm-publish", - "dryRunCommand": true, - "pipe": true - }, - { - "command": "echo '```'", + "command": "echo '```\n\n
\n'", "dryRunCommand": true, "pipe": true } ] }, "tauri-utils": { - "path": "./core/tauri-utils", + "path": "./crates/tauri-utils", + "manager": "rust" + }, + "tauri-macos-sign": { + "path": "./crates/tauri-macos-sign", "manager": "rust" }, "tauri-bundler": { - "path": "./tooling/bundler", + "path": "./crates/tauri-bundler", "manager": "rust", - "dependencies": ["tauri-utils"] + "dependencies": ["tauri-utils", "tauri-macos-sign"] }, "tauri-runtime": { - "path": "./core/tauri-runtime", + "path": "./crates/tauri-runtime", "manager": "rust", - "dependencies": ["tauri-utils"], - "postversion": "node ../../.scripts/covector/sync-prerelease.js ${ pkg.pkg } ${ release.type }" + "dependencies": ["tauri-utils"] }, "tauri-runtime-wry": { - "path": "./core/tauri-runtime-wry", + "path": "./crates/tauri-runtime-wry", "manager": "rust", - "dependencies": ["tauri-utils", "tauri-runtime"], - "postversion": "node ../../.scripts/covector/sync-prerelease.js ${ pkg.pkg } ${ release.type }" + "dependencies": ["tauri-utils", "tauri-runtime"] }, "tauri-codegen": { - "path": "./core/tauri-codegen", + "path": "./crates/tauri-codegen", "manager": "rust", "dependencies": ["tauri-utils"] }, "tauri-macros": { - "path": "./core/tauri-macros", + "path": "./crates/tauri-macros", "manager": "rust", "dependencies": ["tauri-codegen", "tauri-utils"] }, + "tauri-plugin": { + "path": "./crates/tauri-plugin", + "manager": "rust", + "dependencies": ["tauri-utils"], + "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }" + }, "tauri-build": { - "path": "./core/tauri-build", + "path": "./crates/tauri-build", "manager": "rust", "dependencies": ["tauri-codegen", "tauri-utils"], - "postversion": "node ../../.scripts/covector/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }" + "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }" }, "tauri": { - "path": "./core/tauri", + "path": "./crates/tauri", "manager": "rust", "dependencies": [ "tauri-macros", "tauri-utils", "tauri-runtime", - "tauri-runtime-wry" + "tauri-runtime-wry", + "tauri-build" ], - "postversion": "node ../../.scripts/covector/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" + ] }, - "cli.js": { - "path": "./tooling/cli/node", + "@tauri-apps/cli": { + "path": "./packages/cli", "manager": "javascript", - "dependencies": ["cli.rs"], - "postversion": "node ../../../.scripts/covector/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }", + "dependencies": ["tauri-cli"], + "postversion": "node ../../.scripts/ci/sync-cli-metadata.js ${ pkg.pkg } ${ release.type }", "prepublish": [], "publish": [], "postpublish": [] }, - "cli.rs": { - "path": "./tooling/cli", + "tauri-cli": { + "path": "./crates/tauri-cli", "manager": "rust", - "dependencies": ["tauri-bundler", "tauri-utils"], - "postversion": "cargo check", - "assets": [ - { - "path": "${ pkg.path }/target/package/tauri-cli-${ pkgFile.version }.crate", - "name": "${ pkg.pkg }-${ pkgFile.version }.crate" - } - ] + "dependencies": ["tauri-bundler", "tauri-utils", "tauri-macos-sign"] }, "tauri-driver": { - "path": "./tooling/webdriver", - "manager": "rust", - "postversion": "node ../../.scripts/covector/sync-prerelease.js ${ pkg.pkg } ${ release.type }" + "path": "./crates/tauri-driver", + "manager": "rust" } } } diff --git a/.changes/consistent-event-name-usage.md b/.changes/consistent-event-name-usage.md deleted file mode 100644 index 907fd3bdfad4..000000000000 --- a/.changes/consistent-event-name-usage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Change the `event` field of the `Event` interface to type `EventName` instead of `string`. \ No newline at end of file diff --git a/.changes/core-add-log-dir.md b/.changes/core-add-log-dir.md deleted file mode 100644 index c694620382bd..000000000000 --- a/.changes/core-add-log-dir.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Add `tauri::api::path::log_dir` function to access the sugested log directory path. diff --git a/.changes/core-background-color-permissions.md b/.changes/core-background-color-permissions.md new file mode 100644 index 000000000000..c09ed3727cf6 --- /dev/null +++ b/.changes/core-background-color-permissions.md @@ -0,0 +1,5 @@ +--- +tauri: "patch:bug" +--- + +Add webview and window color setters to autogenerated permissions. diff --git a/.changes/core-builder-on-tray-icon-event.md b/.changes/core-builder-on-tray-icon-event.md new file mode 100644 index 000000000000..8a4115049bd3 --- /dev/null +++ b/.changes/core-builder-on-tray-icon-event.md @@ -0,0 +1,6 @@ +--- +"tauri": "minor:feat" +--- + +Add `tauri::Builder::on_tray_icon_event` handler. + diff --git a/.changes/core-center-window.md b/.changes/core-center-window.md deleted file mode 100644 index 4b9653be87fe..000000000000 --- a/.changes/core-center-window.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -Fix `window.center` panic when window size is bigger than screen size. diff --git a/.changes/core-env.md b/.changes/core-env.md deleted file mode 100644 index 328d91833c75..000000000000 --- a/.changes/core-env.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `process`, `path` and `updater` APIs now takes a `tauri::Env` argument, used to force environment variables load on startup to prevent env var update attacks. diff --git a/.changes/core-path-endpoint-path-doesnt-exist-error.md b/.changes/core-path-endpoint-path-doesnt-exist-error.md deleted file mode 100644 index 2a2d24bd0cc0..000000000000 --- a/.changes/core-path-endpoint-path-doesnt-exist-error.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"api": patch ---- - -Now `resolve()`, `join()` and `normalize()` from the `path` module, won't throw errors if the path doesn't exist, which matches NodeJS behavior. diff --git a/.changes/core-scope-is-forbidden.md b/.changes/core-scope-is-forbidden.md new file mode 100644 index 000000000000..f3c230364cc5 --- /dev/null +++ b/.changes/core-scope-is-forbidden.md @@ -0,0 +1,5 @@ +--- +tauri: 'minor:feat' +--- + +Added `Scope::is_forbidden` to check if a path was explicitly forbidden. diff --git a/.changes/create-window-return-window.md b/.changes/create-window-return-window.md deleted file mode 100644 index 73e224c633b1..000000000000 --- a/.changes/create-window-return-window.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** Return `Window` on `App` and `AppHandle`'s `create_window` function. diff --git a/.changes/csp-nonces.md b/.changes/csp-nonces.md deleted file mode 100644 index 4762aeeea201..000000000000 --- a/.changes/csp-nonces.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-codegen": patch -"tauri-utils": patch ---- - -Apply `nonce` to `script` and `style` tags and set them on the `CSP` (`script-src` and `style-src` fetch directives). diff --git a/.changes/current-binary-caching.md b/.changes/current-binary-caching.md deleted file mode 100644 index c404d6ac9fc5..000000000000 --- a/.changes/current-binary-caching.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -tauri: patch -tauri-utils: patch ---- - -The path returned from `tauri::api::process::current_binary` is now cached when loading the binary. diff --git a/.changes/custom-invoke-system.md b/.changes/custom-invoke-system.md deleted file mode 100644 index 66396453907d..000000000000 --- a/.changes/custom-invoke-system.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added an API to use a custom invoke system to receive and respond to commands (`Builder#invoke_system`). diff --git a/.changes/data-store-identifier.md b/.changes/data-store-identifier.md new file mode 100644 index 000000000000..922ad089e6a0 --- /dev/null +++ b/.changes/data-store-identifier.md @@ -0,0 +1,7 @@ +--- +"tauri": "minor:feat" +"tauri-runtime": "minor:feat" +"tauri-runtime-wry": "minor:feat" +--- + +Add `WebviewWindowBuilder/WebviewBuilder::data_store_identifier` on macOS. diff --git a/.changes/data-url-csp.md b/.changes/data-url-csp.md deleted file mode 100644 index 461446cd39e3..000000000000 --- a/.changes/data-url-csp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Inject configured `CSP` on `data:` URLs. diff --git a/.changes/deb-updater-support.md b/.changes/deb-updater-support.md new file mode 100644 index 000000000000..001a5b1dccd7 --- /dev/null +++ b/.changes/deb-updater-support.md @@ -0,0 +1,7 @@ +--- +'tauri-bundler': minor:feat +'tauri-cli': minor:feat +'@tauri-apps/cli': minor:feat +--- + +Generate signature for `.deb` packages when `createUpdaterArtifacts` option is enabled. diff --git a/.changes/dev-csp.md b/.changes/dev-csp.md deleted file mode 100644 index ce9f40968998..000000000000 --- a/.changes/dev-csp.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": patch -"cli.rs": patch ---- - -Added `dev_csp` to the `security` configuration object. diff --git a/.changes/dev-server-exit.md b/.changes/dev-server-exit.md deleted file mode 100644 index 6e92eaea9263..000000000000 --- a/.changes/dev-server-exit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Kill process if `beforeDevCommand` exits with a non-zero status code. diff --git a/.changes/emit-and-trigger-tauri-events.md b/.changes/emit-and-trigger-tauri-events.md deleted file mode 100644 index 1e925fe0311a..000000000000 --- a/.changes/emit-and-trigger-tauri-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Emit `tauri://*` events to Rust listeners. diff --git a/.changes/emit-window-created-backend.md b/.changes/emit-window-created-backend.md deleted file mode 100644 index f03e855d8bd7..000000000000 --- a/.changes/emit-window-created-backend.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Emit `tauri://window-created` event for windows created on the backend. diff --git a/.changes/enable-linux-cookie-persistence.md b/.changes/enable-linux-cookie-persistence.md deleted file mode 100644 index 0a51cdc1108c..000000000000 --- a/.changes/enable-linux-cookie-persistence.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": "patch" -"tauri-runtime-wry": patch ---- - -Enable non-session cookie persistence on Linux. diff --git a/.changes/enhance-minimum-system-version-deserialization.md b/.changes/enhance-minimum-system-version-deserialization.md deleted file mode 100644 index 9fe7025b13a1..000000000000 --- a/.changes/enhance-minimum-system-version-deserialization.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -Use the default value for `MacConfig.minimumSystemVersion` if the value is set to an empty string. diff --git a/.changes/expose-escape-json-string.md b/.changes/expose-escape-json-string.md deleted file mode 100644 index 792d69a8ff45..000000000000 --- a/.changes/expose-escape-json-string.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Expose `tauri::api::ipc::{serialize_js_with, serialize_js}` functions. diff --git a/.changes/extension-path.md b/.changes/extension-path.md new file mode 100644 index 000000000000..caec2b54d50e --- /dev/null +++ b/.changes/extension-path.md @@ -0,0 +1,7 @@ +--- +"tauri": "minor:feat" +"tauri-runtime": "minor:feat" +"tauri-runtime-wry": "minor:feat" +--- + +Add `WebviewWindowBuilder/WebviewBuilder::extensions_path` on Linux and Windows. diff --git a/.changes/fix-add-capability-panic.md b/.changes/fix-add-capability-panic.md new file mode 100644 index 000000000000..2263dc78774c --- /dev/null +++ b/.changes/fix-add-capability-panic.md @@ -0,0 +1,5 @@ +--- +tauri: 'patch:bug' +--- + +Fix panic when a plugin command is run with a capability added at runtime (via `Manager::add_capability`). diff --git a/.changes/fix-apijs-mockipc-cb-type.md b/.changes/fix-apijs-mockipc-cb-type.md new file mode 100644 index 000000000000..fa1bb70acfdb --- /dev/null +++ b/.changes/fix-apijs-mockipc-cb-type.md @@ -0,0 +1,5 @@ +--- +"@tauri-apps/api": "patch:bug" +--- + +Removed the generic in the type of the callback function argument in `mockIPC` which prevented its proper use in tests using TypeScript. diff --git a/.changes/fix-asset-protocol-panicking.md b/.changes/fix-asset-protocol-panicking.md deleted file mode 100644 index 332a9861ed5e..000000000000 --- a/.changes/fix-asset-protocol-panicking.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Resolve `asset` protocol HTTP request instead of panicking if the file does not exist or cannot be read. diff --git a/.changes/fix-block-on-runtime.md b/.changes/fix-block-on-runtime.md deleted file mode 100644 index 44ef3ba2d7a3..000000000000 --- a/.changes/fix-block-on-runtime.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Avoid `async_runtime::block_on` panics when used along another tokio runtime. diff --git a/.changes/fix-cli-lookup.md b/.changes/fix-cli-lookup.md deleted file mode 100644 index 6ed43e85062e..000000000000 --- a/.changes/fix-cli-lookup.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Check the current folder before checking the directories on the app and tauri dir path lookup function. diff --git a/.changes/fix-cli-plugin-path.md b/.changes/fix-cli-plugin-path.md new file mode 100644 index 000000000000..dcc04a37e214 --- /dev/null +++ b/.changes/fix-cli-plugin-path.md @@ -0,0 +1,6 @@ +--- +'tauri-cli': patch:bug +'@tauri-apps/cli': patch:bug +--- + +Fix the exclude path in file `Cargo.toml` of plugin template generated by cli. Path changed in [#9346](https://github.com/tauri-apps/tauri/pull/9346) diff --git a/.changes/fix-cli-prompts.md b/.changes/fix-cli-prompts.md deleted file mode 100644 index b35e304f7936..000000000000 --- a/.changes/fix-cli-prompts.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Fix `init` command prompting for values even if the argument has been provided on the command line. diff --git a/.changes/fix-cli-signer-sign-cmd.md b/.changes/fix-cli-signer-sign-cmd.md deleted file mode 100644 index 1f49618c1bcf..000000000000 --- a/.changes/fix-cli-signer-sign-cmd.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Fixes the signature of the `signer sign` command to not have duplicated short flags. diff --git a/.changes/fix-cli.js-windows-freezing.md b/.changes/fix-cli.js-windows-freezing.md deleted file mode 100644 index bae8abcd6199..000000000000 --- a/.changes/fix-cli.js-windows-freezing.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Fixes CLI freezing when running `light.exe` on Windows without the `--verbose` flag. diff --git a/.changes/fix-close-requested-js-event.md b/.changes/fix-close-requested-js-event.md deleted file mode 100644 index cfc1519a9a51..000000000000 --- a/.changes/fix-close-requested-js-event.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Prevent window closing if `tauri://close-requested` is listened on the JS layer. Users must call `appWindow.close()` manually when listening to that event. diff --git a/.changes/fix-csp-fallback-route.md b/.changes/fix-csp-fallback-route.md deleted file mode 100644 index 9003863d5e4f..000000000000 --- a/.changes/fix-csp-fallback-route.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Properly apply the CSP when loading a route that fallbacks to index.html. diff --git a/.changes/fix-csp-linux.md b/.changes/fix-csp-linux.md deleted file mode 100644 index cdc655495f0c..000000000000 --- a/.changes/fix-csp-linux.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fix CSP usage on Linux when changing it via the `on_web_resource_request` handler. diff --git a/.changes/fix-deadlock-create-window-from-menu.md b/.changes/fix-deadlock-create-window-from-menu.md deleted file mode 100644 index 6ac2fb83515b..000000000000 --- a/.changes/fix-deadlock-create-window-from-menu.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-runtime-wry": patch -"tauri": patch ---- - -Fixes a deadlock when creating a window from a menu event handler. - \ No newline at end of file diff --git a/.changes/fix-deadlock-path-iter.md b/.changes/fix-deadlock-path-iter.md deleted file mode 100644 index 3aa9c8a92fa1..000000000000 --- a/.changes/fix-deadlock-path-iter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Fixes a deadlock on the `ResourcePaths` iterator. diff --git a/.changes/fix-default-freeze-prototype.md b/.changes/fix-default-freeze-prototype.md deleted file mode 100644 index 364ca39ce55b..000000000000 --- a/.changes/fix-default-freeze-prototype.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch ---- - -Change default value for the `freezePrototype` configuration to `false`. diff --git a/.changes/fix-dialog-default-path.md b/.changes/fix-dialog-default-path.md deleted file mode 100644 index 1aefe3f2c320..000000000000 --- a/.changes/fix-dialog-default-path.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"api": patch ---- - -Fixes the dialog `defaultPath` usage on Linux. diff --git a/.changes/fix-drop-sync.md b/.changes/fix-drop-sync.md deleted file mode 100644 index 6026d52b3149..000000000000 --- a/.changes/fix-drop-sync.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -`tauri::plugin::Builder` closures are no longer required to implement `Sync`. diff --git a/.changes/fix-ease-plugin-hook-requirements.md b/.changes/fix-ease-plugin-hook-requirements.md deleted file mode 100644 index 9b8f666e1828..000000000000 --- a/.changes/fix-ease-plugin-hook-requirements.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Ease the requirements for plugin hooks. `setup` and `setup_with_config` can now be `FnOnce` and `on_webview_ready`, `on_event` and `on_page_load` can be `FnMut`. diff --git a/.changes/fix-focus-blur-events-wry.md b/.changes/fix-focus-blur-events-wry.md deleted file mode 100644 index a853b593cef4..000000000000 --- a/.changes/fix-focus-blur-events-wry.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime-wry": patch -"tauri": patch ---- - -Fixes `WindowEvent::Focus` and `WindowEvent::Blur` events not firing. diff --git a/.changes/fix-focus-blur-events.md b/.changes/fix-focus-blur-events.md deleted file mode 100644 index 1d14f5c961d4..000000000000 --- a/.changes/fix-focus-blur-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes `tauri://focus` and `tauri://blur` events not firing. diff --git a/.changes/fix-inner-size.md b/.changes/fix-inner-size.md deleted file mode 100644 index 989445b6c8ed..000000000000 --- a/.changes/fix-inner-size.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-runtime-wry": patch ---- - -Use webview's inner_size instead of window's value to get the correct size on macOS. diff --git a/.changes/fix-linux-resource-path.md b/.changes/fix-linux-resource-path.md deleted file mode 100644 index 7b684afd5c08..000000000000 --- a/.changes/fix-linux-resource-path.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": patch -"tauri": patch ---- - -Fixes resource directory resolution on Linux. diff --git a/.changes/fix-menu-ids.md b/.changes/fix-menu-ids.md deleted file mode 100644 index 6b87270a0bd3..000000000000 --- a/.changes/fix-menu-ids.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes the menu id mapping not reflecting the current window. diff --git a/.changes/fix-once-fnonce.md b/.changes/fix-once-fnonce.md deleted file mode 100644 index fd167c1d4f75..000000000000 --- a/.changes/fix-once-fnonce.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -`Manager::once_global` and `Window::once` allow `FnOnce` callbacks. diff --git a/.changes/fix-out-dir-detection.md b/.changes/fix-out-dir-detection.md deleted file mode 100644 index 4d58c009ae21..000000000000 --- a/.changes/fix-out-dir-detection.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Fixes output directory detection when using Cargo workspaces. diff --git a/.changes/fix-path-resolution-node_modules.md b/.changes/fix-path-resolution-node_modules.md deleted file mode 100644 index c993a1739dc9..000000000000 --- a/.changes/fix-path-resolution-node_modules.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Fixes Tauri path resolution on projects without Git or a `.gitignore` file. diff --git a/.changes/fix-path-scope-first-component.md b/.changes/fix-path-scope-first-component.md deleted file mode 100644 index bf0f8e5e3a58..000000000000 --- a/.changes/fix-path-scope-first-component.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes filesystem and asset scope stripping the first component of the allowed path. diff --git a/.changes/fix-path-scope-validation.md b/.changes/fix-path-scope-validation.md deleted file mode 100644 index b0e0da0be3ba..000000000000 --- a/.changes/fix-path-scope-validation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Ignore trailing slashes on path scope validation. diff --git a/.changes/fix-ready-check.md b/.changes/fix-ready-check.md deleted file mode 100644 index 02ddcf78d151..000000000000 --- a/.changes/fix-ready-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Properly check if document is loaded before invoking commands. diff --git a/.changes/fix-resource-id.md b/.changes/fix-resource-id.md new file mode 100644 index 000000000000..177f8a7bfe2f --- /dev/null +++ b/.changes/fix-resource-id.md @@ -0,0 +1,5 @@ +--- +'tauri': patch:bug +--- + +Fixed a panic caused by an assert when the resource random id has been used already. \ No newline at end of file diff --git a/.changes/fix-runtime-traits-requirements.md b/.changes/fix-runtime-traits-requirements.md deleted file mode 100644 index 681577f5c750..000000000000 --- a/.changes/fix-runtime-traits-requirements.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime": patch ---- - -Fix requirements for `RuntimeHandle`, `ClipboardManager`, `GlobalShortcutHandle` and `TrayHandle`. diff --git a/.changes/fix-safe-block-on.md b/.changes/fix-safe-block-on.md deleted file mode 100644 index 4469e0767bbc..000000000000 --- a/.changes/fix-safe-block-on.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes `Command::output` and `Command::status` deadlock when running on async commands. diff --git a/.changes/fix-tray-command.md b/.changes/fix-tray-command.md deleted file mode 100644 index 6de01cedc5b2..000000000000 --- a/.changes/fix-tray-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Initialize system tray before windows so `tray_handle` can be accessed on command handlers. diff --git a/.changes/fix-tray-menu-ids-update.md b/.changes/fix-tray-menu-ids-update.md deleted file mode 100644 index d27a75b3a32d..000000000000 --- a/.changes/fix-tray-menu-ids-update.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Update tray menu id map when `SystemTrayHandle::set_menu` is called. diff --git a/.changes/fix-tray-remove-windows.md b/.changes/fix-tray-remove-windows.md deleted file mode 100644 index ab347c29c5df..000000000000 --- a/.changes/fix-tray-remove-windows.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-runtime-wry": patch ---- - -Reimplement `remove_system_tray` on Windows to drop the `SystemTray` to run its cleanup code. diff --git a/.changes/fix-updater-msi.md b/.changes/fix-updater-msi.md deleted file mode 100644 index 2ff95e6cc88f..000000000000 --- a/.changes/fix-updater-msi.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Properly create the updater bundle for all generated Microsoft Installer files. diff --git a/.changes/fix-updater-percent-decode.md b/.changes/fix-updater-percent-decode.md deleted file mode 100644 index 8cc304cbd990..000000000000 --- a/.changes/fix-updater-percent-decode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes an issue with the updater when replacing the `{{target}}` and `{{current_version}}` variables due to percent-encoding on the `Url` that is parsed from the configuration. diff --git a/.changes/fix-window-created-listen.md b/.changes/fix-window-created-listen.md deleted file mode 100644 index 6713df383243..000000000000 --- a/.changes/fix-window-created-listen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Immediately listen to `tauri://window-created` event to catch it before the application triggers it. diff --git a/.changes/fix-window-creation-deadlock.md b/.changes/fix-window-creation-deadlock.md deleted file mode 100644 index 9f88bcc97ca1..000000000000 --- a/.changes/fix-window-creation-deadlock.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -Fixes a deadlock on the `Focused` event when the window is not visible. diff --git a/.changes/fix-window-label-api.md b/.changes/fix-window-label-api.md deleted file mode 100644 index e2c3ac45937b..000000000000 --- a/.changes/fix-window-label-api.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Fixes `window.label` property returning null instead of the actual label. diff --git a/.changes/fix-window-specific-event-system.md b/.changes/fix-window-specific-event-system.md deleted file mode 100644 index 2682c8745756..000000000000 --- a/.changes/fix-window-specific-event-system.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch ---- - -The `tauri::Window#emit` functiow now correctly sends the event to all windows that has a registered listener. -**Breaking change:** `Window#emit_and_trigger` and `Window#emit` now requires the payload to be cloneable. diff --git a/.changes/fix-windows-resources.md b/.changes/fix-windows-resources.md deleted file mode 100644 index adc999eecf5f..000000000000 --- a/.changes/fix-windows-resources.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Fixes resources bundling on Windows when the path is on the root of the Tauri folder. diff --git a/.changes/fix-windows-sidecar.md b/.changes/fix-windows-sidecar.md deleted file mode 100644 index 6f7c77f11928..000000000000 --- a/.changes/fix-windows-sidecar.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Fixes sidecar bundling on Windows. diff --git a/.changes/fix-yarn-pnp.md b/.changes/fix-yarn-pnp.md deleted file mode 100644 index d56e9f3296ba..000000000000 --- a/.changes/fix-yarn-pnp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Automatically unplug `@tauri-apps/cli` in yarn 2+ installations to fix the download of the rust-cli. diff --git a/.changes/fixed-webview2-runtime.md b/.changes/fixed-webview2-runtime.md deleted file mode 100644 index 8cc45d8dc943..000000000000 --- a/.changes/fixed-webview2-runtime.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch -"cli.rs": patch ---- - -Allow using a fixed version for the Webview2 runtime via the `tauri > bundle > windows > webviewFixedRuntimePath` config option. diff --git a/.changes/force-updater-public-key.md b/.changes/force-updater-public-key.md deleted file mode 100644 index 24e25f514a2c..000000000000 --- a/.changes/force-updater-public-key.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch ---- - -The updater `pubkey` is now a required field for security reasons. Sign your updates with the `tauri signer` command. diff --git a/.changes/fs-absolute-paths.md b/.changes/fs-absolute-paths.md deleted file mode 100644 index 306270e695af..000000000000 --- a/.changes/fs-absolute-paths.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow absolute paths on the filesystem APIs as long as it does not include parent directory components. diff --git a/.changes/fs-endpoints-context.md b/.changes/fs-endpoints-context.md deleted file mode 100644 index 20d6743a7d81..000000000000 --- a/.changes/fs-endpoints-context.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added context to the file system endpoint errors. diff --git a/.changes/fs-extract-api-feature.md b/.changes/fs-extract-api-feature.md deleted file mode 100644 index 39f5e5d52d0d..000000000000 --- a/.changes/fs-extract-api-feature.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** The `tauri::api::file::Extract` API is now available when the `fs-extract-api` feature is enabled. diff --git a/.changes/fs-scope-events.md b/.changes/fs-scope-events.md deleted file mode 100644 index 71d2630799ef..000000000000 --- a/.changes/fs-scope-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow listening to events on the filesystem and asset scopes. diff --git a/.changes/fs-scope-forbidden-paths.md b/.changes/fs-scope-forbidden-paths.md deleted file mode 100644 index af6dae0066a1..000000000000 --- a/.changes/fs-scope-forbidden-paths.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow configuring forbidden paths on the asset and filesystem scopes. diff --git a/.changes/fs-scope-runtime.md b/.changes/fs-scope-runtime.md deleted file mode 100644 index 4f1739f53066..000000000000 --- a/.changes/fs-scope-runtime.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Extend the allowed patterns for the filesystem and asset protocol when the user selects a path (dialog open and save commands and file drop on the window). diff --git a/.changes/get-menu.md b/.changes/get-menu.md deleted file mode 100644 index db34c3bf1600..000000000000 --- a/.changes/get-menu.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -Replace `WindowBuilder`'s `has_menu` with `get_menu`. diff --git a/.changes/going-rc.md b/.changes/going-rc.md deleted file mode 100644 index 67941b46ec2a..000000000000 --- a/.changes/going-rc.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -'api': major -'cli.js': major -'cli.rs': major -'tauri': major -'tauri-bundler': major -'tauri-utils': major -'tauri-codegen': major -'tauri-macros': major -'tauri-build': major -'tauri-driver': patch ---- - -Upgrade to `rc`! diff --git a/.changes/http-refactor.md b/.changes/http-refactor.md deleted file mode 100644 index 75e53e9e789b..000000000000 --- a/.changes/http-refactor.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -`tauri::api::HttpRequestBuilder::new` now returns a `Result` to validate the url. diff --git a/.changes/http-scope-host-pattern.md b/.changes/http-scope-host-pattern.md deleted file mode 100644 index af937f42c87f..000000000000 --- a/.changes/http-scope-host-pattern.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The HTTP scope now matches the entire URL using a glob pattern instead of only its path. diff --git a/.changes/icon-compile-time.md b/.changes/icon-compile-time.md deleted file mode 100644 index 16e8b095d2bb..000000000000 --- a/.changes/icon-compile-time.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-codegen": patch ---- - -Parse window icons at compile time. diff --git a/.changes/icon-feature.md b/.changes/icon-feature.md deleted file mode 100644 index b0de25988c05..000000000000 --- a/.changes/icon-feature.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -**Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features. diff --git a/.changes/increase-tauri-dir-lookup-depth.md b/.changes/increase-tauri-dir-lookup-depth.md deleted file mode 100644 index eb9ac27f35f5..000000000000 --- a/.changes/increase-tauri-dir-lookup-depth.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Increase `tauri.conf.json` directory lookup depth to `3` and allow changing it with the `TAURI_PATH_DEPTH` environment variable. diff --git a/.changes/info-extend-crates.md b/.changes/info-extend-crates.md deleted file mode 100644 index 6380ca86332d..000000000000 --- a/.changes/info-extend-crates.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Added `tauri-build`, `tao` and `wry` version to the `info` command output. diff --git a/.changes/info-linux-de-and-session.md b/.changes/info-linux-de-and-session.md new file mode 100644 index 000000000000..024c5f23591b --- /dev/null +++ b/.changes/info-linux-de-and-session.md @@ -0,0 +1,7 @@ +--- +"tauri-cli": "patch:feat" +"@tauri-apps/cli": "patch:feat" +--- + +Include Linux destkop environment and session type in `tauri info` command. + diff --git a/.changes/isolation-pattern.md b/.changes/isolation-pattern.md deleted file mode 100644 index 12b4942ad892..000000000000 --- a/.changes/isolation-pattern.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch -"tauri-codegen": patch ---- - -Added the `isolation` pattern. diff --git a/.changes/join-handle-abort.md b/.changes/join-handle-abort.md deleted file mode 100644 index 3e4d7622947b..000000000000 --- a/.changes/join-handle-abort.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `abort` method to `tauri::async_runtime::JoinHandle`. diff --git a/.changes/json5-capability-files.md b/.changes/json5-capability-files.md new file mode 100644 index 000000000000..b0fe7fb54699 --- /dev/null +++ b/.changes/json5-capability-files.md @@ -0,0 +1,6 @@ +--- +"tauri": patch:bug +"tauri-utils": patch:bug +--- + +Fix `.json5` capability files not recognized even with `config-json5` feature enabled diff --git a/.changes/json5.md b/.changes/json5.md deleted file mode 100644 index 00a934e8818d..000000000000 --- a/.changes/json5.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -"tauri": patch -"tauri-build": patch -"tauri-codegen": patch -"tauri-macros": patch -"tauri-utils": patch -"cli.rs": patch ---- - -Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. - -Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: - -1. Check if `tauri.conf.json` exists - a. Parse it with `serde_json` - b. Parse it with `json5` if `serde_json` fails - c. Return original `serde_json` error if all above steps failed -2. Check if `tauri.conf.json5` exists - a. Parse it with `json5` - b. Return error if all above steps failed -3. Return error if all above steps failed diff --git a/.changes/label-validation.md b/.changes/label-validation.md deleted file mode 100644 index 8d7042407a12..000000000000 --- a/.changes/label-validation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Return an error when creating a window with an invalid label instead of panicking. diff --git a/.changes/link-stop-propagation.md b/.changes/link-stop-propagation.md deleted file mode 100644 index 5f7c8a5feb6c..000000000000 --- a/.changes/link-stop-propagation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow preventing opening the default browser on a click on an `` element via `stopImmediatePropagation()`. diff --git a/.changes/linux-cors.md b/.changes/linux-cors.md deleted file mode 100644 index 4dc7ecd290f2..000000000000 --- a/.changes/linux-cors.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -Fix empty header from CORS on Linux. - diff --git a/.changes/linux-run-return.md b/.changes/linux-run-return.md deleted file mode 100644 index f59b6cbe1f1e..000000000000 --- a/.changes/linux-run-return.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -The `run_return` API is now available on Linux. diff --git a/.changes/macos-deployment-target.md b/.changes/macos-deployment-target.md deleted file mode 100644 index b3220657a61f..000000000000 --- a/.changes/macos-deployment-target.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Automatically emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET` with the value set on `tauri.conf.json > tauri > bundle > macos > minimumSystemVersion`. diff --git a/.changes/main-thread-api-calls.md b/.changes/main-thread-api-calls.md deleted file mode 100644 index a9bddb9feb21..000000000000 --- a/.changes/main-thread-api-calls.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-runtime-wry": patch ---- - -Allow window, global shortcut and clipboard APIs to be called on the main thread. diff --git a/.changes/menu-with-items-constructor.md b/.changes/menu-with-items-constructor.md deleted file mode 100644 index 1c5a43f0f20e..000000000000 --- a/.changes/menu-with-items-constructor.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": patch -"tauri": patch ---- - -Add `Menu::with_items` constructor, taking an iterator of `MenuEntry`. diff --git a/.changes/minimum-mac-version.md b/.changes/minimum-mac-version.md deleted file mode 100644 index 85008ca87dd5..000000000000 --- a/.changes/minimum-mac-version.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": patch -"tauri": patch ---- - -Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. diff --git a/.changes/misign-update.md b/.changes/misign-update.md deleted file mode 100644 index e1a0281d82a3..000000000000 --- a/.changes/misign-update.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The updater now expects signatures created with the latest CLI release. diff --git a/.changes/mock-functions.md b/.changes/mock-functions.md deleted file mode 100644 index 44867bce8487..000000000000 --- a/.changes/mock-functions.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": minor ---- - -Provide functions to mock IPC calls during testing and static site generation. diff --git a/.changes/msi-run-from-install-path.md b/.changes/msi-run-from-install-path.md deleted file mode 100644 index 4be08fa49e87..000000000000 --- a/.changes/msi-run-from-install-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Fixes the Microsoft Installer launch path. diff --git a/.changes/mutable-callbacks.md b/.changes/mutable-callbacks.md deleted file mode 100644 index 979bd92c5930..000000000000 --- a/.changes/mutable-callbacks.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-runtime-wry": minor -"tauri-runtime": minor -"tauri": minor ---- - -Change event loop callbacks definition to allow callers to move in mutable values. \ No newline at end of file diff --git a/.changes/notification-regression.md b/.changes/notification-regression.md deleted file mode 100644 index 2e2d1193d4d7..000000000000 --- a/.changes/notification-regression.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fixes `Notification.requestPermission()` deadlock. diff --git a/.changes/object-csp.md b/.changes/object-csp.md deleted file mode 100644 index efe2605a1787..000000000000 --- a/.changes/object-csp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allows the configuration CSP to be an object mapping a directive name to its source list. diff --git a/.changes/open-devtools.md b/.changes/open-devtools.md deleted file mode 100644 index 416969967ce5..000000000000 --- a/.changes/open-devtools.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `Window#open_devtools` API. diff --git a/.changes/overlay.md b/.changes/overlay.md new file mode 100644 index 000000000000..2c29c2da2431 --- /dev/null +++ b/.changes/overlay.md @@ -0,0 +1,11 @@ +--- +"tauri": minor:feat +"tauri-runtime-wry": minor:feat +"tauri-runtime": minor:feat +'@tauri-apps/api': minor:feat +--- + +Add badging APIs: +- `Window/WebviewWindow::set_badge_count` for Linux, macOS and IOS. +- `Window/WebviewWindow::set_overlay_icon` for Windows Only. +- `Window/WebviewWindow::set_badge_label`for macOS Only. \ No newline at end of file diff --git a/.changes/package-json-configure-app-path.md b/.changes/package-json-configure-app-path.md deleted file mode 100644 index 39ba4210136d..000000000000 --- a/.changes/package-json-configure-app-path.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Read `package.json` and check for a `tauri` object containing the `appPath` string, which points to the tauri crate path. diff --git a/.changes/path-plugin-is-absolute.md b/.changes/path-plugin-is-absolute.md new file mode 100644 index 000000000000..c0a8a69a543b --- /dev/null +++ b/.changes/path-plugin-is-absolute.md @@ -0,0 +1,5 @@ +--- +"@tauri-apps/api": "patch:bug" +--- + +Fix error where using `isAbsolute` would return `Command not found`. diff --git a/.changes/perf-cli-dir-lookup.md b/.changes/perf-cli-dir-lookup.md deleted file mode 100644 index 3a1c9dc99788..000000000000 --- a/.changes/perf-cli-dir-lookup.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"cli.js": patch ---- - -Respect `.gitignore` configuration when looking for the folder with the `tauri.conf.json` file. diff --git a/.changes/plugin-builder.md b/.changes/plugin-builder.md deleted file mode 100644 index 970467870628..000000000000 --- a/.changes/plugin-builder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Add a `plugin::Builder` struct to make plugin creation more convenient. diff --git a/.changes/plugin-command.md b/.changes/plugin-command.md deleted file mode 100644 index 865b5af03e0f..000000000000 --- a/.changes/plugin-command.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Added `$ tauri plugin init` command, which initializes a Tauri plugin. diff --git a/.changes/plugin-on_event.md b/.changes/plugin-on_event.md deleted file mode 100644 index d844fd78d857..000000000000 --- a/.changes/plugin-on_event.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `on_event` on the `Plugin` trait, which allows a plugin to react to the event loop. diff --git a/.changes/pre.json b/.changes/pre.json deleted file mode 100644 index 24eef0aecdc8..000000000000 --- a/.changes/pre.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "tag": "rc", - "changes": [ - ".changes/allowlist-clipboard.md", - ".changes/allowlist-dialog.md", - ".changes/allowlist-process.md", - ".changes/allowlist-window.md", - ".changes/always-rebuilding.md", - ".changes/api-WebviewWindow-fileDropEnabled.md", - ".changes/api-add-log-dir.md", - ".changes/api-app-window-browser.md", - ".changes/api-change-events.md", - ".changes/api-dialog-ask-message-confirm.md", - ".changes/api-emit-payload-type.md", - ".changes/api-features.md", - ".changes/api-fetch-empty-reponse.md", - ".changes/api-file-dialog-title.md", - ".changes/api-fix-os-platform-return.md", - ".changes/api-format-callback.md", - ".changes/api-raw-headers.md", - ".changes/api-relaunch-cleanup.md", - ".changes/api-remove-current-dir.md", - ".changes/api-remove-ts-files.md", - ".changes/api-use-uint8array.md", - ".changes/api-window-type-for-size-and-position.md", - ".changes/app-any-thread.md", - ".changes/app-folder-structure.md", - ".changes/asset-allowlist.md", - ".changes/asset-cors.md", - ".changes/asset-protocol-feature-flag.md", - ".changes/asset-resolver.md", - ".changes/async-cli.js.md", - ".changes/async-runtime-refactor.md", - ".changes/async-runtime-set.md", - ".changes/async-runtime-spawn-blocking.md", - ".changes/before-script-envs.md", - ".changes/build-rerun-if-resource-sidecar-change.md", - ".changes/build-specify-win-sdk.md", - ".changes/builder-create-window-result.md", - ".changes/bundler-add-provider-short-name.md", - ".changes/bundler-add-tsp-signing.md", - ".changes/bundler-appimage-fuse.md", - ".changes/bundler-fix-appimage.md", - ".changes/bundler-msi-init-installdir.md", - ".changes/bundler-print-cfg.md", - ".changes/callback-validation.md", - ".changes/clap-3.0.md", - ".changes/clap-beta.4-core.md", - ".changes/clap-beta.4.md", - ".changes/cli-config-path.md", - ".changes/cli-improve-waiting-devserver-msg.md", - ".changes/cli-include-vswhere.md", - ".changes/cli-private-key-pwd-panic.md", - ".changes/cli-runner-args.md", - ".changes/cli-runner-error-message.md", - ".changes/cli.js-cjs-output.md", - ".changes/cli.js-fix-ico.md", - ".changes/cli.js-improve-error.md", - ".changes/cli.js-windows-32bit.md", - ".changes/cli.rs-active-toolchain.md", - ".changes/cli.rs-build-tools-info.md", - ".changes/cli.rs-default-svelte-port.md", - ".changes/cli.rs-detect-git.md", - ".changes/cli.rs-dialoguer.md", - ".changes/cli.rs-fix-windows-x86.md", - ".changes/cli.rs-refactor-signer.md", - ".changes/cli.rs-template-plugin-builder.md", - ".changes/cli.rs-use-tauri-utils.md", - ".changes/cli.rs-validate-dist-dir.md", - ".changes/cli.rs-wix-license.md", - ".changes/command-feature-flag.md", - ".changes/command-output-carriage-return.md", - ".changes/consistent-event-name-usage.md", - ".changes/core-add-log-dir.md", - ".changes/core-center-window.md", - ".changes/core-env.md", - ".changes/core-path-endpoint-path-doesnt-exist-error.md", - ".changes/create-window-return-window.md", - ".changes/csp-nonces.md", - ".changes/current-binary-caching.md", - ".changes/custom-invoke-system.md", - ".changes/data-url-csp.md", - ".changes/dev-csp.md", - ".changes/dev-server-exit.md", - ".changes/emit-and-trigger-tauri-events.md", - ".changes/emit-window-created-backend.md", - ".changes/enable-linux-cookie-persistence.md", - ".changes/expose-escape-json-string.md", - ".changes/fix-asset-protocol-panicking.md", - ".changes/fix-block-on-runtime.md", - ".changes/fix-cli-lookup.md", - ".changes/fix-cli-prompts.md", - ".changes/fix-cli-signer-sign-cmd.md", - ".changes/fix-cli.js-windows-freezing.md", - ".changes/fix-close-requested-js-event.md", - ".changes/fix-deadlock-create-window-from-menu.md", - ".changes/fix-deadlock-path-iter.md", - ".changes/fix-default-freeze-prototype.md", - ".changes/fix-dialog-default-path.md", - ".changes/fix-drop-sync.md", - ".changes/fix-ease-plugin-hook-requirements.md", - ".changes/fix-focus-blur-events-wry.md", - ".changes/fix-focus-blur-events.md", - ".changes/fix-inner-size.md", - ".changes/fix-linux-resource-path.md", - ".changes/fix-menu-ids.md", - ".changes/fix-once-fnonce.md", - ".changes/fix-out-dir-detection.md", - ".changes/fix-path-resolution-node_modules.md", - ".changes/fix-path-scope-first-component.md", - ".changes/fix-path-scope-validation.md", - ".changes/fix-ready-check.md", - ".changes/fix-runtime-traits-requirements.md", - ".changes/fix-safe-block-on.md", - ".changes/fix-tray-command.md", - ".changes/fix-tray-menu-ids-update.md", - ".changes/fix-tray-remove-windows.md", - ".changes/fix-updater-msi.md", - ".changes/fix-updater-percent-decode.md", - ".changes/fix-window-created-listen.md", - ".changes/fix-window-creation-deadlock.md", - ".changes/fix-window-label-api.md", - ".changes/fix-window-specific-event-system.md", - ".changes/fix-windows-sidecar.md", - ".changes/fix-yarn-pnp.md", - ".changes/fixed-webview2-runtime.md", - ".changes/force-updater-public-key.md", - ".changes/fs-absolute-paths.md", - ".changes/fs-endpoints-context.md", - ".changes/fs-extract-api-feature.md", - ".changes/fs-scope-events.md", - ".changes/fs-scope-forbidden-paths.md", - ".changes/fs-scope-runtime.md", - ".changes/get-menu.md", - ".changes/going-rc.md", - ".changes/http-refactor.md", - ".changes/http-scope-host-pattern.md", - ".changes/icon-compile-time.md", - ".changes/icon-feature.md", - ".changes/increase-tauri-dir-lookup-depth.md", - ".changes/info-extend-crates.md", - ".changes/isolation-pattern.md", - ".changes/join-handle-abort.md", - ".changes/json5.md", - ".changes/label-validation.md", - ".changes/link-stop-propagation.md", - ".changes/linux-cors.md", - ".changes/linux-run-return.md", - ".changes/macos-deployment-target.md", - ".changes/main-thread-api-calls.md", - ".changes/menu-with-items-constructor.md", - ".changes/minimum-mac-version.md", - ".changes/misign-update.md", - ".changes/mock-functions.md", - ".changes/msi-run-from-install-path.md", - ".changes/mutable-callbacks.md", - ".changes/notification-regression.md", - ".changes/object-csp.md", - ".changes/open-devtools.md", - ".changes/package-json-configure-app-path.md", - ".changes/perf-cli-dir-lookup.md", - ".changes/plugin-builder.md", - ".changes/plugin-command.md", - ".changes/plugin-on_event.md", - ".changes/prevent-path-traversal.md", - ".changes/private-api.md", - ".changes/range-parse-asterisk.md", - ".changes/raw-headers.md", - ".changes/raw-window-handle.md", - ".changes/read-fs-read-file.md", - ".changes/refactor-cli-dev-args.md", - ".changes/refactor-command-feature.md", - ".changes/refactor-create-tao-window.md", - ".changes/refactor-dialog-apis.md", - ".changes/refactor-notification-permission-check.md", - ".changes/refactor-resources-sidecar-copying.md", - ".changes/refactor-window-event-close-requested.md", - ".changes/refactor-window-metadata.md", - ".changes/refactor-zip-features.md", - ".changes/remove-current-base-directory.md", - ".changes/remove-tauricon.md", - ".changes/remove-window-default.md", - ".changes/rpc-mod-refactor.md", - ".changes/run-on-main-thread.md", - ".changes/runtime-any-thread.md", - ".changes/runtime-handle-run-on-main-thread.md", - ".changes/runtime-ipc.md", - ".changes/runtime-open-devtools.md", - ".changes/runtime-window-creation-result.md", - ".changes/rust-1.56.0.md", - ".changes/rust-1.57-usage.md", - ".changes/rust-1.57.md", - ".changes/scope-config.md", - ".changes/scopes.md", - ".changes/setup-fn-once.md", - ".changes/shell-open-with-refactor.md", - ".changes/sidecar-allowlist.md", - ".changes/sidecar-runtime-rename.md", - ".changes/sidecar-scope-improvement.md", - ".changes/simplify-window-label-types.md", - ".changes/streaming-small-file-fix.md", - ".changes/strip.md", - ".changes/template-csp-null.md", - ".changes/tooling-fix-pnpm-info-error.md", - ".changes/tray-set-menu.md", - ".changes/universal-apple-target-sidecar.md", - ".changes/universal-apple-target.md", - ".changes/unlisten-fix.md", - ".changes/unlisten.md", - ".changes/updater-endpoint-url-https.md", - ".changes/updater-restart-cleanup.md", - ".changes/validate-allowlist.md", - ".changes/validate-appimage.md", - ".changes/validate-event-name.md", - ".changes/validate-window-label.md", - ".changes/version-package-json.md", - ".changes/wait-dev-server-url.md", - ".changes/warn-macos-private-api.md", - ".changes/webdriver-args.md", - ".changes/webview-attributes-clipboard.md", - ".changes/webview2-com.md", - ".changes/window-builder.md", - ".changes/window-confirm.md", - ".changes/window-request-handler.md", - ".changes/windows-0.25.0.md", - ".changes/windows-modify-cmd-string-behaviour.md", - ".changes/windows-null.md", - ".changes/wix-localization.md", - ".changes/wix-registry-keys.md", - ".changes/wix-run-app.md", - ".changes/wix-signing.md", - ".changes/wry-13.md" - ] -} diff --git a/.changes/prevent-path-traversal.md b/.changes/prevent-path-traversal.md deleted file mode 100644 index f7e83be938f9..000000000000 --- a/.changes/prevent-path-traversal.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Prevent path traversal on the file system APIs. diff --git a/.changes/private-api.md b/.changes/private-api.md deleted file mode 100644 index 53624fba6f9a..000000000000 --- a/.changes/private-api.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime-wry": patch -"cli.rs": patch ---- - -**Breaking change:** Add `macos-private-api` feature flag, enabled via `tauri.conf.json > tauri > macOSPrivateApi`. diff --git a/.changes/range-parse-asterisk.md b/.changes/range-parse-asterisk.md deleted file mode 100644 index b2ad0ddec5d1..000000000000 --- a/.changes/range-parse-asterisk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow range in the form of `bytes=0-*` on the asset protocol. diff --git a/.changes/raw-headers.md b/.changes/raw-headers.md deleted file mode 100644 index 87ea3e7d4137..000000000000 --- a/.changes/raw-headers.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Add `raw_headers` to `tauri::api::http::ResponseData`. diff --git a/.changes/raw-window-handle.md b/.changes/raw-window-handle.md deleted file mode 100644 index ffa0856fdd74..000000000000 --- a/.changes/raw-window-handle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Implement `raw_window_handle::RawWindowHandle` for `tauri::Window` on `Windows` and `macOS`. The `tauri::api::dialog::window_parent` function was removed since now you can use the window directly. diff --git a/.changes/read-fs-read-file.md b/.changes/read-fs-read-file.md deleted file mode 100644 index 3adbbd22c097..000000000000 --- a/.changes/read-fs-read-file.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"api": patch ---- - -Reimplement endpoint to read file as string for performance. diff --git a/.changes/readme.md b/.changes/readme.md deleted file mode 100644 index fe4afd7d62c2..000000000000 --- a/.changes/readme.md +++ /dev/null @@ -1,37 +0,0 @@ -# Changes - -##### via https://github.com/jbolda/covector - -As you create PRs and make changes that require a version bump, please add a new markdown file in this folder. You do not note the version _number_, but rather the type of bump that you expect: major, minor, or patch. The filename is not important, as long as it is a `.md`, but we recommend it represents the overall change for our sanity. - -When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. - -Use the following format: - -```md ---- -"api": patch -"tauri-bundler": patch -"cli.rs": patch -"cli.js": patch -"tauri-utils": patch -"tauri-macros": patch -"tauri-build": patch -"tauri-codegen": patch -"tauri": patch ---- - -Change summary goes here -``` - -Summaries do not have a specific character limit, but are text only. These summaries are used within the (future implementation of) changelogs. They will give context to the change and also point back to the original PR if more details and context are needed. - -Changes will be designated as a `major`, `minor` or `patch` as further described in [semver](https://semver.org/). - -Given a version number MAJOR.MINOR.PATCH, increment the: - -- MAJOR version when you make incompatible API changes, -- MINOR version when you add functionality in a backwards compatible manner, and -- PATCH version when you make backwards compatible bug fixes. - -Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format, but will be discussed prior to usage (as extra steps will be necessary in consideration of merging and publishing). diff --git a/.changes/refactor-cli-dev-args.md b/.changes/refactor-cli-dev-args.md deleted file mode 100644 index 6104bd450722..000000000000 --- a/.changes/refactor-cli-dev-args.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -**Breaking change:** The extra arguments passed to `tauri dev` using `-- ...` are now propagated to the runner (defaults to cargo). To pass arguments to your binary using Cargo, you now need to run `tauri dev -- -- ...` (notice the double `--`). diff --git a/.changes/refactor-command-feature.md b/.changes/refactor-command-feature.md deleted file mode 100644 index 0eb081940c5f..000000000000 --- a/.changes/refactor-command-feature.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** Renamed the `command` Cargo feature to `process-command-api`. diff --git a/.changes/refactor-create-tao-window.md b/.changes/refactor-create-tao-window.md deleted file mode 100644 index 8bad9c78b84c..000000000000 --- a/.changes/refactor-create-tao-window.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime-wry": patch -"tauri": patch ---- - -Refactor `create_tao_window` API to return `Weak` instead of `Arc`. diff --git a/.changes/refactor-dialog-apis.md b/.changes/refactor-dialog-apis.md deleted file mode 100644 index d78dbeda50d4..000000000000 --- a/.changes/refactor-dialog-apis.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added the `tauri::api::dialog::blocking` module. diff --git a/.changes/refactor-file-drop.md b/.changes/refactor-file-drop.md deleted file mode 100644 index d2bfbc377fc0..000000000000 --- a/.changes/refactor-file-drop.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -The file drop event is now part of the `WindowEvent` enum instead of a having a dedicated handler. diff --git a/.changes/refactor-notification-permission-check.md b/.changes/refactor-notification-permission-check.md deleted file mode 100644 index 3c16e2f2b5b3..000000000000 --- a/.changes/refactor-notification-permission-check.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The notification endpoint now checks for the permission flag and requests if the value is not set. diff --git a/.changes/refactor-resources-sidecar-copying.md b/.changes/refactor-resources-sidecar-copying.md deleted file mode 100644 index b20407f19acd..000000000000 --- a/.changes/refactor-resources-sidecar-copying.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"cli.rs": patch -"tauri-bundler": patch -"tauri-utils": patch -"tauri-build": patch ---- - -Move the copying of resources and sidecars from `cli.rs` to `tauri-build` so using the Cargo CLI directly processes the files for the application execution in development. diff --git a/.changes/refactor-window-event-close-requested.md b/.changes/refactor-window-event-close-requested.md deleted file mode 100644 index 1c5219b14ed4..000000000000 --- a/.changes/refactor-window-event-close-requested.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** The `WindowEvent::CloseRequested` variant now includes `label` and `signal_tx` fields to allow preventing closing the window. diff --git a/.changes/refactor-window-metadata.md b/.changes/refactor-window-metadata.md deleted file mode 100644 index ba23c2abce9e..000000000000 --- a/.changes/refactor-window-metadata.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": "patch" ---- - -**Breaking change:** Move `__currentWindow` and `__windows` values from `window.__TAURI__` to `window.__TAURI_METADATA__`. diff --git a/.changes/refactor-zip-features.md b/.changes/refactor-zip-features.md deleted file mode 100644 index afefa6734280..000000000000 --- a/.changes/refactor-zip-features.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Disabled the default features for the `zip` crate. diff --git a/.changes/remove-current-base-directory.md b/.changes/remove-current-base-directory.md deleted file mode 100644 index 8413cce8927d..000000000000 --- a/.changes/remove-current-base-directory.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"api": patch ---- - -Remove the `BaseDirectory::Current` enum variant for security reasons. diff --git a/.changes/remove-tauricon.md b/.changes/remove-tauricon.md deleted file mode 100644 index 658eb068ae5e..000000000000 --- a/.changes/remove-tauricon.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.js": patch ---- - -Removed the `icon` command, now exposed as a separate package, see https://github.com/tauri-apps/tauricon. diff --git a/.changes/remove-window-default.md b/.changes/remove-window-default.md deleted file mode 100644 index 63d85d24ef30..000000000000 --- a/.changes/remove-window-default.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch ---- - -**Breaking change** Remove default webview window when `tauri.conf.json > tauri > windows` is not set. diff --git a/.changes/rpc-mod-refactor.md b/.changes/rpc-mod-refactor.md deleted file mode 100644 index 6f54a83845a8..000000000000 --- a/.changes/rpc-mod-refactor.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** Renamed the `rpc` module to `ipc`. diff --git a/.changes/run-on-main-thread.md b/.changes/run-on-main-thread.md deleted file mode 100644 index 5af644d68554..000000000000 --- a/.changes/run-on-main-thread.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Expose `run_on_main_thread` APIs on `Window` and `AppHandle`. diff --git a/.changes/runtime-any-thread.md b/.changes/runtime-any-thread.md deleted file mode 100644 index f0b20ccec620..000000000000 --- a/.changes/runtime-any-thread.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -Added `any_thread` constructor on the `Runtime` trait (only possible on Linux and Windows). diff --git a/.changes/runtime-create-proxy.md b/.changes/runtime-create-proxy.md deleted file mode 100644 index ebc72568421a..000000000000 --- a/.changes/runtime-create-proxy.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -Added `create_proxy` to the `Runtime` and `RuntimeHandle` traits. diff --git a/.changes/runtime-file-drop-event.md b/.changes/runtime-file-drop-event.md deleted file mode 100644 index 6fd9beb2b1be..000000000000 --- a/.changes/runtime-file-drop-event.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime": patch ---- - -**Breaking change:** Move the `FileDropEvent` struct to the `window` module. diff --git a/.changes/runtime-handle-run-on-main-thread.md b/.changes/runtime-handle-run-on-main-thread.md deleted file mode 100644 index 06854acdc229..000000000000 --- a/.changes/runtime-handle-run-on-main-thread.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": "patch" -"tauri-runtime-wry": patch ---- - -Added `run_on_main_thread` API on `RuntimeHandle`. diff --git a/.changes/runtime-ipc.md b/.changes/runtime-ipc.md deleted file mode 100644 index d7c7d63ccaf0..000000000000 --- a/.changes/runtime-ipc.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -**Breaking change:** Renamed the `RPC` interface to `IPC`. diff --git a/.changes/runtime-open-devtools.md b/.changes/runtime-open-devtools.md deleted file mode 100644 index 72d31a52d2d1..000000000000 --- a/.changes/runtime-open-devtools.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -Added `open_devtools` to the `Dispatcher` trait. diff --git a/.changes/runtime-user-event.md b/.changes/runtime-user-event.md deleted file mode 100644 index b88273faff5a..000000000000 --- a/.changes/runtime-user-event.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -Allow specifying a user event type for the event loop message. diff --git a/.changes/runtime-window-creation-result.md b/.changes/runtime-window-creation-result.md deleted file mode 100644 index 836ee43a4bf0..000000000000 --- a/.changes/runtime-window-creation-result.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime": patch ---- - -The `PendingWindow::new` and `PendingWindow::with_config` functions now return `Result` validating the window label. diff --git a/.changes/rust-1.56.0.md b/.changes/rust-1.56.0.md deleted file mode 100644 index c41f453a69e0..000000000000 --- a/.changes/rust-1.56.0.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"tauri": patch -"cli.rs": patch -"tauri-bundler": patch -"tauri-utils": patch -"tauri-macros": patch -"tauri-codegen": patch -"tauri-runtime": patch -"tauri-runtime-wry": patch -"tauri-driver": patch -"tauri-build": patch ---- - -The minimum Rust version is now `1.56`. diff --git a/.changes/rust-1.57-usage.md b/.changes/rust-1.57-usage.md deleted file mode 100644 index 45b37f3890b7..000000000000 --- a/.changes/rust-1.57-usage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": patch ---- - -Use `is_symlink` API compatible with Rust v1.57 instead of std/fs/struct.Metadata.html#method.is_symlink. diff --git a/.changes/rust-1.57.md b/.changes/rust-1.57.md deleted file mode 100644 index 24cb734f547b..000000000000 --- a/.changes/rust-1.57.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The minimum Rust version is now 1.57. diff --git a/.changes/rust-tauri-events.md b/.changes/rust-tauri-events.md deleted file mode 100644 index 62ba67563a6e..000000000000 --- a/.changes/rust-tauri-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": minor ---- - -**Breaking change:** The `tauri://` events are no longer emitted to listeners using `Window::listen`. Use the `App::run` closure, `Window::on_window_event` and `Window::on_menu_event` instead. diff --git a/.changes/scope-config.md b/.changes/scope-config.md deleted file mode 100644 index b364a27be192..000000000000 --- a/.changes/scope-config.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-utils": patch ---- - -Adds `scope` glob array config under `tauri > allowlist > fs`. -Adds `assetScope` glob array config under `tauri > allowlist > protocol`. -Adds `scope` URL array config under `tauri > allowlist > http`. diff --git a/.changes/scopes.md b/.changes/scopes.md deleted file mode 100644 index 096838e7b4f5..000000000000 --- a/.changes/scopes.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"tauri": patch ---- - -Scopes the `filesystem` APIs from the webview access using `tauri.conf.json > tauri > allowlist > fs > scope`. -Scopes the `asset` protocol access using `tauri.conf.json > tauri > allowlist > protocol > assetScope`. -Scopes the `http` APIs from the webview access using `tauri.conf.json > tauri > allowlist > http > scope`. -Scopes the `shell` execute API from the webview access using `tauri.conf.json > tauri > allowlist > shell > scope`. Additionally, check the `tauri.conf.json > tauri > bundle > externalBin` to prevent access to unknown sidecars. diff --git a/.changes/set-show-menu-on-left-click-windows-api.md b/.changes/set-show-menu-on-left-click-windows-api.md new file mode 100644 index 000000000000..2cf5ce40977d --- /dev/null +++ b/.changes/set-show-menu-on-left-click-windows-api.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/api": "minor:feat" +--- + +Add `TrayIcon.setShowMenuOnLeftClick` method and deprecate `TrayIcon.setMenuOnLeftClick` to match the Rust API. + diff --git a/.changes/setup-fn-once.md b/.changes/setup-fn-once.md deleted file mode 100644 index 7f06a05ed92a..000000000000 --- a/.changes/setup-fn-once.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": "patch" ---- - -`Builder#setup` closure type changed from `Fn` to `FnOnce`. diff --git a/.changes/shell-open-with-refactor.md b/.changes/shell-open-with-refactor.md deleted file mode 100644 index d2124c7b43f6..000000000000 --- a/.changes/shell-open-with-refactor.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `tauri::api::shell::open`'s `with` argument is now an enum value instead of any string. diff --git a/.changes/show-menu-on-left-click-windows-api.md b/.changes/show-menu-on-left-click-windows-api.md new file mode 100644 index 000000000000..c13b44136259 --- /dev/null +++ b/.changes/show-menu-on-left-click-windows-api.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/api": "minor:feat" +--- + +Add `TrayIconOptions.showMenuOnLeftClick` field and deprecate `TrayIconOptions.menuOnLeftClick` to match the Rust API. + diff --git a/.changes/show-menu-on-left-click-windows.md b/.changes/show-menu-on-left-click-windows.md new file mode 100644 index 000000000000..721a1d8aed51 --- /dev/null +++ b/.changes/show-menu-on-left-click-windows.md @@ -0,0 +1,6 @@ +--- +"tauri": "minor:feat" +--- + +Add `TrayIconBuilder::show_menu_on_left_click` method and deprecate `TrayIconBuilder::menu_on_left_click` for consistent naming and clarity. + diff --git a/.changes/sidecar-allowlist.md b/.changes/sidecar-allowlist.md deleted file mode 100644 index f85d37c34368..000000000000 --- a/.changes/sidecar-allowlist.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": patch -"tauri": patch ---- - -The `shell` allowlist now includes a `sidecar` flag, which enables the use of the `shell` API to execute sidecars. diff --git a/.changes/sidecar-runtime-rename.md b/.changes/sidecar-runtime-rename.md deleted file mode 100644 index 2124f7abd4e5..000000000000 --- a/.changes/sidecar-runtime-rename.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-bundler": patch ---- - -**Breaking change:** The sidecar's target triple suffix is now removed at build time. diff --git a/.changes/sidecar-scope-improvement.md b/.changes/sidecar-scope-improvement.md deleted file mode 100644 index 5103449e85c3..000000000000 --- a/.changes/sidecar-scope-improvement.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -The `cmd` field is no longer required on the shell scope for sidecars. diff --git a/.changes/simplify-window-creation.md b/.changes/simplify-window-creation.md deleted file mode 100644 index 9db428a1d776..000000000000 --- a/.changes/simplify-window-creation.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime-wry": minor ---- - -Use a random window id instead of `tao::window::WindowId` to not block the thread waiting for the event loop to process the window creation. diff --git a/.changes/simplify-window-label-types.md b/.changes/simplify-window-label-types.md deleted file mode 100644 index 5aab845e1d81..000000000000 --- a/.changes/simplify-window-label-types.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"api": patch ---- - -Change `WindowLabel` type to `string`. diff --git a/.changes/specta-feature-fix.md b/.changes/specta-feature-fix.md new file mode 100644 index 000000000000..b937c68a6854 --- /dev/null +++ b/.changes/specta-feature-fix.md @@ -0,0 +1,5 @@ +--- +"tauri": patch:bug +--- + +Fix `specta-util` dependency not found error when using `specta` feature diff --git a/.changes/state-debug.md b/.changes/state-debug.md deleted file mode 100644 index 3e3d63b1834c..000000000000 --- a/.changes/state-debug.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Implement `Debug` for `tauri::State`. diff --git a/.changes/state-manage-return-val.md b/.changes/state-manage-return-val.md deleted file mode 100644 index 6a661e7dac11..000000000000 --- a/.changes/state-manage-return-val.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -**Breaking change:** The `Manager::manage` function now returns a bool indicating whether the type is already managed or not. diff --git a/.changes/streaming-small-file-fix.md b/.changes/streaming-small-file-fix.md deleted file mode 100644 index e4b316e40800..000000000000 --- a/.changes/streaming-small-file-fix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Fix streaming of small files using the `asset` protocol. diff --git a/.changes/strip.md b/.changes/strip.md deleted file mode 100644 index f49c954b149e..000000000000 --- a/.changes/strip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": "patch" ---- - -Automatically `strip` the built binary on Linux and macOS if `--debug` is not specified. diff --git a/.changes/tauri-build-default-anyhow-fmt.md b/.changes/tauri-build-default-anyhow-fmt.md deleted file mode 100644 index 0fda6ac66714..000000000000 --- a/.changes/tauri-build-default-anyhow-fmt.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Print error context on the `build` panic. diff --git a/.changes/template-csp-null.md b/.changes/template-csp-null.md deleted file mode 100644 index 3851f2907b83..000000000000 --- a/.changes/template-csp-null.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Change the `init` template configuration to disable CSP for better usability for new users. diff --git a/.changes/tooling-fix-pnpm-info-error.md b/.changes/tooling-fix-pnpm-info-error.md deleted file mode 100644 index f5494b3412ab..000000000000 --- a/.changes/tooling-fix-pnpm-info-error.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'cli.rs': patch ---- - -Fixes pnpm error when running `pnpm tauri info`. diff --git a/.changes/tray-icon-menu-on-left-click-windows-api.md b/.changes/tray-icon-menu-on-left-click-windows-api.md new file mode 100644 index 000000000000..bb1014f908c5 --- /dev/null +++ b/.changes/tray-icon-menu-on-left-click-windows-api.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/api": "minor:enhance" +--- + +Add support for `TrayIconOptions.menuOnLeftClick` option and `TrayIcon.setMenuOnLeftClick` on Windows. + diff --git a/.changes/tray-icon-menu-on-left-click-windows.md b/.changes/tray-icon-menu-on-left-click-windows.md new file mode 100644 index 000000000000..a414e88b61d1 --- /dev/null +++ b/.changes/tray-icon-menu-on-left-click-windows.md @@ -0,0 +1,6 @@ +--- +"tauri": "minor:enhance" +--- + +Add support for `TrayIconBuilder::menu_on_left_click` and `TrayIcon::set_show_menu_on_left_click` on Windows. + diff --git a/.changes/tray-set-menu.md b/.changes/tray-set-menu.md deleted file mode 100644 index d0b2dc500fb7..000000000000 --- a/.changes/tray-set-menu.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Add `set_menu` API on `tauri::SystemTrayHandle`. diff --git a/.changes/universal-apple-target-sidecar.md b/.changes/universal-apple-target-sidecar.md deleted file mode 100644 index 13eb66b43453..000000000000 --- a/.changes/universal-apple-target-sidecar.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"tauri-bundler": patch -"api": patch ---- - -When building Universal macOS Binaries through the virtual target `universal-apple-darwin`: - -- Expect a universal binary to be created by the user -- Ensure that binary is bundled and accessed correctly at runtime diff --git a/.changes/universal-apple-target.md b/.changes/universal-apple-target.md deleted file mode 100644 index fcd7eead2a18..000000000000 --- a/.changes/universal-apple-target.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Add support to building Universal macOS Binaries through the virtual target `universal-apple-darwin` (run `tauri build --target universal-apple-darwin`). diff --git a/.changes/unlisten-fix.md b/.changes/unlisten-fix.md deleted file mode 100644 index 2cc72fb724dd..000000000000 --- a/.changes/unlisten-fix.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"api": patch ---- - -Fixes a regression on the `unlisten` command. diff --git a/.changes/unlisten.md b/.changes/unlisten.md deleted file mode 100644 index d60cce4adc40..000000000000 --- a/.changes/unlisten.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Adds `unlisten` function to the `Window` struct. diff --git a/.changes/unmanaged-state-command.md b/.changes/unmanaged-state-command.md new file mode 100644 index 000000000000..fca4ecb6fc2f --- /dev/null +++ b/.changes/unmanaged-state-command.md @@ -0,0 +1,5 @@ +--- +"tauri": "patch:bug" +--- + +Fix panic when invoking a command with an unmanaged state, an error will be returned instead. diff --git a/.changes/updater-endpoint-url-https.md b/.changes/updater-endpoint-url-https.md deleted file mode 100644 index cd998f3bd6b0..000000000000 --- a/.changes/updater-endpoint-url-https.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-utils": patch ---- - -Force updater endpoint URL to use `https` on release builds. diff --git a/.changes/updater-events.md b/.changes/updater-events.md deleted file mode 100644 index 73e98f62ba68..000000000000 --- a/.changes/updater-events.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": minor ---- - -Send updater events to the `App::run` closure. diff --git a/.changes/updater-no-window.md b/.changes/updater-no-window.md deleted file mode 100644 index c814c4bfb0e3..000000000000 --- a/.changes/updater-no-window.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Run the updater on startup even if no window was created. diff --git a/.changes/updater-restart-cleanup.md b/.changes/updater-restart-cleanup.md deleted file mode 100644 index 4f9525e13d79..000000000000 --- a/.changes/updater-restart-cleanup.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Run `AppHandle` cleanup code before restarting the application when a new update is installed. diff --git a/.changes/validate-allowlist.md b/.changes/validate-allowlist.md deleted file mode 100644 index a8ead7e2e92d..000000000000 --- a/.changes/validate-allowlist.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-build": patch ---- - -Validate `tauri` dependency `features` under `Cargo.toml` matching `tauri.conf.json`'s `allowlist`. diff --git a/.changes/validate-appimage.md b/.changes/validate-appimage.md deleted file mode 100644 index ef18a4764083..000000000000 --- a/.changes/validate-appimage.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Validate the `std::env::current_exe` return value if `APPDIR` or `APPIMAGE` environment variables are set. diff --git a/.changes/validate-event-name.md b/.changes/validate-event-name.md deleted file mode 100644 index 43badb3fa53f..000000000000 --- a/.changes/validate-event-name.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": "patch" ---- - -The event name is now validated. On a IPC message, it returns an error if it fails validation; on the Rust side, it panics. -It must include only alphanumeric characters, `-`, `/`, `:` and `_`. diff --git a/.changes/validate-window-label.md b/.changes/validate-window-label.md deleted file mode 100644 index 9f4b71deaaa0..000000000000 --- a/.changes/validate-window-label.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch ---- - -The window label is now validated and must be alphanumeric, resulting in a panic if it isn't. diff --git a/.changes/version-package-json.md b/.changes/version-package-json.md deleted file mode 100644 index f22887f99121..000000000000 --- a/.changes/version-package-json.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Allow `tauri.conf.json > package > version` to specify a path to a `package.json` file and pull the version from it. diff --git a/.changes/wait-dev-server-url.md b/.changes/wait-dev-server-url.md deleted file mode 100644 index 612b53e55e96..000000000000 --- a/.changes/wait-dev-server-url.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -Wait for `devPath` URL to be reachable before starting the application. Skipped if the `TAURI_SKIP_DEVSERVER_CHECK` environment variable is set to `true`. diff --git a/.changes/warn-macos-private-api.md b/.changes/warn-macos-private-api.md deleted file mode 100644 index a855a97b5822..000000000000 --- a/.changes/warn-macos-private-api.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -Print a warning to stderr if the window transparency has been set to true but `macos-private-api` is not enabled. diff --git a/.changes/webdriver-args.md b/.changes/webdriver-args.md deleted file mode 100644 index 7296a4bbee50..000000000000 --- a/.changes/webdriver-args.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-driver": patch ---- - -Add `args` field (array of application CLI arguments) to the `tauri:options` capabilities. diff --git a/.changes/webview-attributes-clipboard.md b/.changes/webview-attributes-clipboard.md deleted file mode 100644 index 7f34d4c05f92..000000000000 --- a/.changes/webview-attributes-clipboard.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch ---- - -Added `clipboard` field on the `WebviewAttributes` struct, which must be set to `true` to enable clipboard access on the webview. diff --git a/.changes/webview2-com.md b/.changes/webview2-com.md deleted file mode 100644 index bddac4929581..000000000000 --- a/.changes/webview2-com.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -Replace all of the `winapi` crate references with the `windows` crate, and replace `webview2` and `webview2-sys` with `webview2-com` and `webview2-com-sys` built with the `windows` crate. This goes along with updates to the TAO and WRY `next` branches. \ No newline at end of file diff --git a/.changes/window-builder.md b/.changes/window-builder.md deleted file mode 100644 index 6c239e0396a6..000000000000 --- a/.changes/window-builder.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added a `WindowBuilder` type. diff --git a/.changes/window-confirm.md b/.changes/window-confirm.md deleted file mode 100644 index e6ddc59adf25..000000000000 --- a/.changes/window-confirm.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Show `Ok/Cancel` buttons instead of `Yes/No` when executing `window.confirm`. diff --git a/.changes/window-event-file-drop.md b/.changes/window-event-file-drop.md deleted file mode 100644 index 42c3de0ce83c..000000000000 --- a/.changes/window-event-file-drop.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": minor -"tauri-runtime-wry": minor ---- - -Added the `WindowEvent::FileDrop` variant. diff --git a/.changes/window-request-handler.md b/.changes/window-request-handler.md deleted file mode 100644 index 0b5d7fe2edd1..000000000000 --- a/.changes/window-request-handler.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch ---- - -Added `WindowBuilder::on_web_resource_request`, which allows customizing the tauri custom protocol response. diff --git a/.changes/windows-0.25.0.md b/.changes/windows-0.25.0.md deleted file mode 100644 index 60365d3157d5..000000000000 --- a/.changes/windows-0.25.0.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri": patch -"tauri-runtime": patch -"tauri-runtime-wry": patch ---- - -Update the `windows` crate to 0.25.0, which comes with pre-built libraries. WRY and Tao can both reference the same types directly from the `windows` crate instead of sharing bindings in `webview2-com-sys`. \ No newline at end of file diff --git a/.changes/windows-modify-cmd-string-behaviour.md b/.changes/windows-modify-cmd-string-behaviour.md deleted file mode 100644 index 9be3b3c64c06..000000000000 --- a/.changes/windows-modify-cmd-string-behaviour.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"cli.rs": patch ---- - -On Windows, Fix `beforeDevCommand` and `beforeBuildCommand` not executing the expected command if it contains quotes. This is done by executing them with `CMD /S /C {command}` instead of `CMD /C {command}` on Windows. \ No newline at end of file diff --git a/.changes/windows-null.md b/.changes/windows-null.md deleted file mode 100644 index 532322bb0a3f..000000000000 --- a/.changes/windows-null.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -This is a temporary fix of null pointer crash on `get_content` of web resource request. -We will switch it back once upstream is updated. diff --git a/.changes/wix-localization.md b/.changes/wix-localization.md deleted file mode 100644 index 4187442a40e2..000000000000 --- a/.changes/wix-localization.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"cli.rs": patch -"tauri-bundler": patch ---- - -Allow setting the localization file for WiX. diff --git a/.changes/wix-registry-keys.md b/.changes/wix-registry-keys.md deleted file mode 100644 index f9930f3d4c27..000000000000 --- a/.changes/wix-registry-keys.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Fix registry keys on the WiX template. diff --git a/.changes/wix-run-app.md b/.changes/wix-run-app.md deleted file mode 100644 index 30db1d3ff296..000000000000 --- a/.changes/wix-run-app.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Configure WiX to add an option to launch the application after finishing setup. diff --git a/.changes/wix-signing.md b/.changes/wix-signing.md deleted file mode 100644 index af26aca9189f..000000000000 --- a/.changes/wix-signing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": patch ---- - -Sign WiX installer in addition to the executable file. diff --git a/.changes/wry-13.md b/.changes/wry-13.md deleted file mode 100644 index b6248fcc68e8..000000000000 --- a/.changes/wry-13.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-runtime-wry": patch ---- - -Update wry to 0.13. - diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000000..f80ffd87ad1c --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,12 @@ +# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/master/containers/ubuntu/.devcontainer/base.Dockerfile +# [Choice] Ubuntu version (use jammy or bionic on local arm64/Apple Silicon): jammy, focal, bionic +ARG VARIANT="jammy" +FROM mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT} + +# Derived from Tauri contribution and setup guides: +# See: https://github.com/tauri-apps/tauri/blob/dev/.github/CONTRIBUTING.md#development-guide +# See: https://v2.tauri.app/start/prerequisites/ +ARG TAURI_BUILD_DEPS="build-essential curl libappindicator3-dev libgtk-3-dev librsvg2-dev libssl-dev libwebkit2gtk-4.1-dev wget" + +RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ + && apt-get install -y --no-install-recommends $TAURI_BUILD_DEPS diff --git a/.devcontainer/README.md b/.devcontainer/README.md new file mode 100644 index 000000000000..e72d611aed3d --- /dev/null +++ b/.devcontainer/README.md @@ -0,0 +1,39 @@ +# VS Code Devcontainer for Tauri + +## Overview + +Please note that most of these instructions are derived from Microsoft's VS Code documentation: [Developing inside a Container](https://code.visualstudio.com/docs/remote/containers). Check the official documentation if you encounter problems and submit a PR with any corrections you find for the instructions below. + +The development container included in this repository is derived from [Microsoft's default Ubuntu development container](https://github.com/microsoft/vscode-dev-containers/tree/master/containers/ubuntu). Contents of the Ubuntu Docker image can be in the [VS Code devcontainer Ubuntu base Dockerfile](https://github.com/microsoft/vscode-dev-containers/blob/main/containers/ubuntu/.devcontainer/base.Dockerfile). The contents of the container used for development can be found in the [Dockerfile](./Dockerfile) located in the same directory as this README. + +## Usage + +1. Ensure you have all [Devcontainer Prerequisites](#devcontainer-prerequisites) +2. Open the directory containing your [`tauri-apps/tauri`](https://github.com/tauri-apps/tauri) code. +3. Install the [Remote Development](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack) extension pack for VS Code. This will be included if you install recommended workspace extensions upon opening this repository. +4. Ensure Docker is running +5. [Open your workspace in the provided devcontainer](https://code.visualstudio.com/docs/remote/containers#_open-an-existing-workspace-in-a-container): Open this repository in VS Code and run **Remote-Containers: Reopen in Container...** from the Command Palette (F1). + +### Devcontainer Prerequisites + +Prerequisites are mainly derived from VS Code's instructions for usage of development containers, documented here: [Developing inside a Container: Getting Started](https://code.visualstudio.com/docs/remote/containers#_getting-started). + +1. Docker (Docker Desktop recommended) +2. VS Code +3. X window host - required if you want to be able to interact with a GUI from your Docker host + +### A note on filesystem performance + +Due to limitations in how Docker shares files between the Docker host and a container, it's also recommended that developers [clone Tauri source code into a container volume](https://code.visualstudio.com/remote/advancedcontainers/improve-performance#_use-clone-repository-in-container-volume). This is optional, but highly advised as many filesystem/IO heavy operations (`cargo build`, `pnpm install`, etc) will be very slow if they operate on directories shared with a Docker container from the Docker host. + +To do this, open your project with VS Code and run **Remote-Containers: Clone Repository in Container Volume...** from the Command Palette (F1). + +### Accessing a Tauri application running you the devcontainer + +Docker Desktop provides facilities for [allowing the development container to connect to a service on the Docker host](https://docs.docker.com/desktop/windows/networking/#i-want-to-connect-from-a-container-to-a-service-on-the-host). So long as you have an X window server running on your Docker host, the devcontainer can connect to it and expose your Tauri GUI via an X window. + +**Export the `DISPLAY` variable within the devcontainer terminal you launch your Tauri application from to expose your GUI outside of the devcontainer**. + +```bash +export DISPLAY="host.docker.internal:0" +``` diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..a7a9805c37a9 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.234.0/containers/ubuntu +{ + "name": "Ubuntu", + "build": { + "dockerfile": "Dockerfile", + // Update 'VARIANT' to pick an Ubuntu version: jammy / ubuntu-22.04, focal / ubuntu-20.04, bionic /ubuntu-18.04 + // Use ubuntu-22.04 or ubuntu-18.04 on local arm64/Apple Silicon. + "args": { "VARIANT": "ubuntu-22.04" } + }, + + // Set *default* container specific settings.json values on container create. + "settings": {}, + + // Add the IDs of extensions you want installed when the container is created. + "extensions": [], + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "uname -a", + + // Comment out to connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root. + "remoteUser": "vscode", + "features": { + "node": "lts", + "rust": "latest" + } +} diff --git a/.docker/cross/aarch64.Dockerfile b/.docker/cross/aarch64.Dockerfile new file mode 100644 index 000000000000..c57ec56392c7 --- /dev/null +++ b/.docker/cross/aarch64.Dockerfile @@ -0,0 +1,44 @@ +FROM ubuntu:22.04 +ARG DEBIAN_FRONTEND=noninteractive + +COPY common.sh lib.sh / +RUN /common.sh + +COPY cmake.sh / +RUN /cmake.sh + +COPY xargo.sh / +RUN /xargo.sh + +RUN apt-get update && apt-get install --assume-yes --no-install-recommends \ + g++-aarch64-linux-gnu \ + libc6-dev-arm64-cross + +COPY deny-debian-packages.sh / +RUN TARGET_ARCH=arm64 /deny-debian-packages.sh \ + binutils \ + binutils-aarch64-linux-gnu + +COPY qemu.sh / +RUN /qemu.sh aarch64 softmmu + +COPY dropbear.sh / +RUN /dropbear.sh + +COPY linux-image.sh / +RUN /linux-image.sh aarch64 + +COPY linux-runner / + +ENV CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc \ + CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_RUNNER="/linux-runner aarch64" \ + CC_aarch64_unknown_linux_gnu=aarch64-linux-gnu-gcc \ + CXX_aarch64_unknown_linux_gnu=aarch64-linux-gnu-g++ \ + BINDGEN_EXTRA_CLANG_ARGS_aarch64_unknown_linux_gnu="--sysroot=/usr/aarch64-linux-gnu" \ + QEMU_LD_PREFIX=/usr/aarch64-linux-gnu \ + RUST_TEST_THREADS=1 \ + PKG_CONFIG_PATH="/usr/lib/aarch64-linux-gnu/pkgconfig/:${PKG_CONFIG_PATH}" + +RUN dpkg --add-architecture arm64 +RUN apt-get update +RUN apt-get install --assume-yes --no-install-recommends libssl-dev:arm64 libdbus-1-dev:arm64 libsoup2.4-dev:arm64 libssl-dev:arm64 libgtk-3-dev:arm64 webkit2gtk-4.1-dev:arm64 libappindicator3-1:arm64 librsvg2-dev:arm64 patchelf:arm64 diff --git a/.docker/cross/cmake.sh b/.docker/cross/cmake.sh new file mode 100755 index 000000000000..9ed4ee6a008d --- /dev/null +++ b/.docker/cross/cmake.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +main() { + local version=3.23.1 + + install_packages curl + + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://github.com/Kitware/CMake/releases/download/v${version}/cmake-${version}-linux-x86_64.sh" -o cmake.sh + sh cmake.sh --skip-license --prefix=/usr/local + + popd + + purge_packages + + rm -rf "${td}" + rm -rf /var/lib/apt/lists/* + rm "${0}" +} + +main "${@}" diff --git a/.docker/cross/common.sh b/.docker/cross/common.sh new file mode 100755 index 000000000000..24d56194d806 --- /dev/null +++ b/.docker/cross/common.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +# For architectures except amd64 and i386, look for packages on ports.ubuntu.com instead. +# This is important if you enable additional architectures so you can install libraries to cross-compile against. +# Look for 'dpkg --add-architecture' in the README for more details. +if grep -i ubuntu /etc/os-release >/dev/null; then + sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list > /etc/apt/sources.list.d/ports.list + sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list +fi + +install_packages \ + autoconf \ + automake \ + binutils \ + ca-certificates \ + curl \ + file \ + gcc \ + git \ + libtool \ + m4 \ + make + +if_centos install_packages \ + clang-devel \ + gcc-c++ \ + glibc-devel \ + pkgconfig + +if_ubuntu install_packages \ + g++ \ + libc6-dev \ + libclang-dev \ + pkg-config diff --git a/.docker/cross/deny-debian-packages.sh b/.docker/cross/deny-debian-packages.sh new file mode 100755 index 000000000000..3193333e936d --- /dev/null +++ b/.docker/cross/deny-debian-packages.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +main() { + local package + + for package in "${@}"; do + echo "Package: ${package}:${TARGET_ARCH} +Pin: release * +Pin-Priority: -1" > "/etc/apt/preferences.d/${package}" + echo "${package}" + done + + rm "${0}" +} + +main "${@}" diff --git a/.docker/cross/dropbear.sh b/.docker/cross/dropbear.sh new file mode 100755 index 000000000000..097814e8601d --- /dev/null +++ b/.docker/cross/dropbear.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +main() { + local version=2022.82 + + install_packages \ + autoconf \ + automake \ + bzip2 \ + curl \ + make + + if_centos install_packages zlib-devel + if_ubuntu install_packages zlib1g-dev + + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://matt.ucc.asn.au/dropbear/releases/dropbear-${version}.tar.bz2" -O + tar --strip-components=1 -xjf "dropbear-${version}.tar.bz2" + + # Remove some unwanted message + sed -i '/skipping hostkey/d' cli-kex.c + sed -i '/failed to identify current user/d' cli-runopts.c + + ./configure \ + --disable-syslog \ + --disable-shadow \ + --disable-lastlog \ + --disable-utmp \ + --disable-utmpx \ + --disable-wtmp \ + --disable-wtmpx \ + --disable-pututline \ + --disable-pututxline + + make "-j$(nproc)" PROGRAMS=dbclient + cp dbclient /usr/local/bin/ + + purge_packages + + popd + + rm -rf "${td}" + rm "${0}" +} + +main "${@}" diff --git a/.docker/cross/lib.sh b/.docker/cross/lib.sh new file mode 100644 index 000000000000..0d299b8a6e71 --- /dev/null +++ b/.docker/cross/lib.sh @@ -0,0 +1,45 @@ +purge_list=() + +install_packages() { + if grep -i ubuntu /etc/os-release; then + apt-get update + + for pkg in "${@}"; do + if ! dpkg -L "${pkg}" >/dev/null 2>/dev/null; then + apt-get install --assume-yes --no-install-recommends "${pkg}" + + purge_list+=( "${pkg}" ) + fi + done + else + for pkg in "${@}"; do + if ! yum list installed "${pkg}" >/dev/null 2>/dev/null; then + yum install -y "${pkg}" + + purge_list+=( "${pkg}" ) + fi + done + fi +} + +purge_packages() { + if (( ${#purge_list[@]} )); then + if grep -i ubuntu /etc/os-release; then + apt-get purge --assume-yes --auto-remove "${purge_list[@]}" + else + yum remove -y "${purge_list[@]}" + fi + fi +} + +if_centos() { + if grep -q -i centos /etc/os-release; then + eval "${@}" + fi +} + +if_ubuntu() { + if grep -q -i ubuntu /etc/os-release; then + eval "${@}" + fi +} diff --git a/.docker/cross/linux-image.sh b/.docker/cross/linux-image.sh new file mode 100755 index 000000000000..dc85ed45c571 --- /dev/null +++ b/.docker/cross/linux-image.sh @@ -0,0 +1,274 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +main() { + # arch in the rust target + local arch="${1}" \ + kversion=4.19.0-20 + + local debsource="deb http://http.debian.net/debian/ buster main" + debsource="${debsource}\ndeb http://security.debian.org/ buster/updates main" + + local dropbear="dropbear-bin" + + local -a deps + local kernel= + local libgcc="libgcc1" + + # select debian arch and kernel version + case "${arch}" in + aarch64) + arch=arm64 + kernel="${kversion}-arm64" + ;; + armv7) + arch=armhf + kernel="${kversion}-armmp" + ;; + i686) + arch=i386 + kernel="${kversion}-686" + ;; + mips|mipsel) + kernel="${kversion}-4kc-malta" + ;; + mips64el) + kernel="${kversion}-5kc-malta" + ;; + powerpc) + # there is no buster powerpc port, so we use jessie + # use a more recent kernel from backports + kversion='4.9.0-0.bpo.6' + kernel="${kversion}-powerpc" + debsource="deb http://archive.debian.org/debian jessie main" + debsource="${debsource}\ndeb http://archive.debian.org/debian jessie-backports main" + debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unstable main" + debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main" + + # archive.debian.org Release files are expired. + echo "Acquire::Check-Valid-Until false;" | tee -a /etc/apt/apt.conf.d/10-nocheckvalid + echo "APT::Get::AllowUnauthenticated true;" | tee -a /etc/apt/apt.conf.d/10-nocheckvalid + + dropbear="dropbear" + deps=(libcrypt1:"${arch}") + ;; + powerpc64) + # there is no stable port + arch=ppc64 + # https://packages.debian.org/en/sid/linux-image-powerpc64 + kversion='5.*' + kernel="${kversion}-powerpc64" + libgcc="libgcc-s1" + debsource="deb http://ftp.ports.debian.org/debian-ports unstable main" + debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main" + # sid version of dropbear requires these dependencies + deps=(libcrypt1:"${arch}") + ;; + powerpc64le) + arch=ppc64el + kernel="${kversion}-powerpc64le" + ;; + s390x) + arch=s390x + kernel="${kversion}-s390x" + ;; + sparc64) + # there is no stable port + # https://packages.debian.org/en/sid/linux-image-sparc64 + kernel='*-sparc64' + libgcc="libgcc-s1" + debsource="deb http://ftp.ports.debian.org/debian-ports unstable main" + debsource="${debsource}\ndeb http://ftp.ports.debian.org/debian-ports unreleased main" + # sid version of dropbear requires these dependencies + deps=(libcrypt1:"${arch}") + ;; + x86_64) + arch=amd64 + kernel="${kversion}-amd64" + ;; + *) + echo "Invalid arch: ${arch}" + exit 1 + ;; + esac + + install_packages ca-certificates \ + curl \ + cpio \ + sharutils \ + gnupg + + # Download packages + mv /etc/apt/sources.list /etc/apt/sources.list.bak + echo -e "${debsource}" > /etc/apt/sources.list + + # Old ubuntu does not support --add-architecture, so we directly change multiarch file + if [ -f /etc/dpkg/dpkg.cfg.d/multiarch ]; then + cp /etc/dpkg/dpkg.cfg.d/multiarch /etc/dpkg/dpkg.cfg.d/multiarch.bak + fi + dpkg --add-architecture "${arch}" || echo "foreign-architecture ${arch}" > /etc/dpkg/dpkg.cfg.d/multiarch + + # Add Debian keys. + curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{7.0,8,9,10}.asc' -O + curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/archive-key-{8,9,10}-security.asc' -O + curl --retry 3 -sSfL 'https://ftp-master.debian.org/keys/release-{7,8,9,10}.asc' -O + curl --retry 3 -sSfL 'https://www.ports.debian.org/archive_{2020,2021,2022}.key' -O + + for key in *.asc *.key; do + apt-key add "${key}" + rm "${key}" + done + + # allow apt-get to retry downloads + echo 'APT::Acquire::Retries "3";' > /etc/apt/apt.conf.d/80-retries + + apt-get update + + mkdir -p "/qemu/${arch}" + chmod 777 /qemu "/qemu/${arch}" + + cd "/qemu/${arch}" + apt-get -d --no-install-recommends download \ + ${deps[@]+"${deps[@]}"} \ + "busybox:${arch}" \ + "${dropbear}:${arch}" \ + "libtommath1:${arch}" \ + "libtomcrypt1:${arch}" \ + "libgmp10:${arch}" \ + "libc6:${arch}" \ + "${libgcc}:${arch}" \ + "libstdc++6:${arch}" \ + "linux-image-${kernel}:${arch}" \ + ncurses-base \ + "zlib1g:${arch}" + cd /qemu + + # Install packages + root="root-${arch}" + mkdir -p "${root}"/{bin,etc/dropbear,root,sys,dev,proc,sbin,tmp,usr/{bin,sbin},var/log} + for deb in "${arch}"/*deb; do + dpkg -x "${deb}" "${root}"/ + done + + cp "${root}/boot/vmlinu"* kernel + + # initrd + mkdir -p "${root}/modules" + cp -v \ + "${root}/lib/modules"/*/kernel/drivers/net/net_failover.ko \ + "${root}/lib/modules"/*/kernel/drivers/net/virtio_net.ko \ + "${root}/lib/modules"/*/kernel/drivers/virtio/* \ + "${root}/lib/modules"/*/kernel/fs/netfs/netfs.ko \ + "${root}/lib/modules"/*/kernel/fs/9p/9p.ko \ + "${root}/lib/modules"/*/kernel/fs/fscache/fscache.ko \ + "${root}/lib/modules"/*/kernel/net/9p/9pnet.ko \ + "${root}/lib/modules"/*/kernel/net/9p/9pnet_virtio.ko \ + "${root}/lib/modules"/*/kernel/net/core/failover.ko \ + "${root}/modules" || true # some file may not exist + rm -rf "${root:?}/boot" + rm -rf "${root:?}/lib/modules" + + cat << 'EOF' > "${root}/etc/hosts" +127.0.0.1 localhost qemu +EOF + + cat << 'EOF' > $root/etc/hostname +qemu +EOF + + cat << 'EOF' > $root/etc/passwd +root::0:0:root:/root:/bin/sh +EOF + +cat << 'EOF' | uudecode -o $root/etc/dropbear/dropbear_rsa_host_key +begin 600 dropbear_rsa_host_key +M````!W-S:"UR+3[X=QMH,B*4$RYULV,V3X6]K:7@Q?80"#WXGGQZNFN6CZ7LTDX(F6J[\]F5<0`HEOF:Z +MX;^53`L'4I/A```!``$L:$Z*#6<^3@+O%.[-#/5H+.C'3\#QQZN[1;J>L`8I +MZ_&T'!"J'/Y+?R?55G:M^=]R*-&I3TOJYZA8@&H51ZOAF59'1_>>Z@?E4#)$ +MQU)X/RWH51ZB5KSDWJS:D'7GD(!?NAY`C'7\)I:_4)J")QBV/P"RJQGHG'%B +M1BT2LE6676>`1K,0\NIMZTKQNB(IC+88<7#8%_-=P<&6<"9LH>60TSS?3?-C +MN`T36YB/3^<(Q;`N1NT>I9EZS`BAC^-?.:,R\7EL"<4>7E=]^1]B\K9])AQU +MBM\]M;4V(S(6KH-I.4[6>9E+@\UEM.J6:[2LUEEJDG:G:+:/EVF^Y75@(S$` +M``"!`.O+KW=&*CBCHL"11&SVO4/K]$R-]7MV7,3RR)Q[X'0;6.?4JHW!3VR6 +M*FGBY--37ZD-+UV.8_+"$6PH9)(/E.\G19#G0K`LRM?JWS!58&;D0C1```` +M@0"\[@NYWSTW(?Q@:_A*1Y3/AKYO5?S=0"<2>#V-AH6W-NCSDTSRP=2D79FS +M"D?[;.)V>8'#9&I3"MU@+:2\Z%$0-MG0+J'(0>T1_C6?*C=4U0I$DI<=@D]1 +H_&DE8Y(OT%%EPG]!$H&5HX*),_D1A2\P=R.7G'`0L%YM-79Y"T">$0`` +` +end +EOF + + # dropbear complains when this file is missing + touch "${root}/var/log/lastlog" + + cat << 'EOF' > $root/init +#!/bin/busybox sh + +set -e + +/bin/busybox --install + +mount -t devtmpfs devtmpfs /dev +mount -t proc none /proc +mount -t sysfs none /sys +mkdir /dev/pts +mount -t devpts none /dev/pts/ + +# some archs does not have virtio modules +insmod /modules/failover.ko || true +insmod /modules/net_failover.ko || true +insmod /modules/virtio.ko || true +insmod /modules/virtio_ring.ko || true +insmod /modules/virtio_mmio.ko || true +insmod /modules/virtio_pci_legacy_dev.ko || true +insmod /modules/virtio_pci_modern_dev.ko || true +insmod /modules/virtio_pci.ko || true +insmod /modules/virtio_net.ko || true +insmod /modules/netfs.ko || true +insmod /modules/fscache.ko +insmod /modules/9pnet.ko +insmod /modules/9pnet_virtio.ko || true +insmod /modules/9p.ko + +ifconfig lo 127.0.0.1 +ifconfig eth0 10.0.2.15 +route add default gw 10.0.2.2 eth0 + +mkdir /target +mount -t 9p -o trans=virtio target /target -oversion=9p2000.u || true + +exec dropbear -F -E -B +EOF + + chmod +x "${root}/init" + cd "${root}" + find . | cpio --create --format='newc' --quiet | gzip > ../initrd.gz + cd - + + # Clean up + rm -rf "/qemu/${root}" "/qemu/${arch}" + mv -f /etc/apt/sources.list.bak /etc/apt/sources.list + if [ -f /etc/dpkg/dpkg.cfg.d/multiarch.bak ]; then + mv /etc/dpkg/dpkg.cfg.d/multiarch.bak /etc/dpkg/dpkg.cfg.d/multiarch + fi + # can fail if arch is used (amd64 and/or i386) + dpkg --remove-architecture "${arch}" || true + apt-get update + + purge_packages + + ls -lh /qemu +} + +main "${@}" diff --git a/.docker/cross/linux-runner b/.docker/cross/linux-runner new file mode 100755 index 000000000000..2ef0efc674d4 --- /dev/null +++ b/.docker/cross/linux-runner @@ -0,0 +1,173 @@ +#!/usr/bin/env bash + +set -e + +LOG=/tmp/qemu.log +LOCK=/tmp/qemu.lock + +if [ -n "${CROSS_DEBUG}" ]; then + set -x +fi + +# arch in the rust target +arch="${1}" +shift + +if [ "${CROSS_RUNNER}" = "" ]; then + if [[ "${arch}" == i?86 ]] || [[ "${arch}" == x86_64 ]]; then + CROSS_RUNNER=native + else + CROSS_RUNNER=qemu-user + fi +fi + +# select qemu arch +qarch="${arch}" +case "${arch}" in + armv7) + qarch="arm" + ;; + i686) + qarch="i386" + ;; + powerpc) + qarch="ppc" + ;; + powerpc64) + qarch="ppc64" + ;; + powerpc64le) + if [ "${CROSS_RUNNER}" = "qemu-user" ]; then + qarch="ppc64le" + else + qarch="ppc64" + fi + ;; +esac + +case "${CROSS_RUNNER}" in + native) + exec "${@}" + ;; + qemu-user) + exec "qemu-${qarch}" "${@}" + ;; + qemu-system) + true + ;; + *) + echo "Invalid runner: \"${CROSS_RUNNER}\""; + echo "Valid runners are: native, qemu-user and qemu-system" + exit 1 + ;; +esac + +n="$(nproc)" +memory=1G +driver9p="virtio-9p-pci" +drivernet="virtio-net-pci" + +# select qemu parameters +case "${arch}" in + aarch64) + # 8 is the max number of cpu supported by qemu-aarch64 + n=$(( n > 8 ? 8 : n )) + opt="-machine virt -cpu cortex-a57" + ;; + armv7) + opt="-machine virt" + driver9p="virtio-9p-device" + drivernet="virtio-net-device" + ;; + i686) + opt="-append console=ttyS0" + ;; + mips|mipsel) + # avoid kernel error + # https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/ + opt="-append nokaslr" + n=1 + ;; + mips64el) + # avoid kernel error + # https://blahcat.github.io/2017/07/14/building-a-debian-stretch-qemu-image-for-mipsel/ + opt="-append nokaslr -cpu MIPS64R2-generic" + n=1 + ;; + powerpc) + opt="-append console=ttyPZ0" + n=1 + ;; + powerpc64|powerpc64le) + opt="-append console=hvc0 --nodefaults -serial stdio" + ;; + s390x) + n=1 + driver9p="virtio-9p-ccw" + drivernet="virtio-net-ccw" + ;; + sparc64) + n=1 + driver9p+=",bus=pciB" + drivernet+=",bus=pciB" + ;; + x86_64) + opt="-append console=ttyS0" + ;; +esac + +( + flock -n 200 || exit 0 + + echo Booting QEMU virtual machine with $n cpus... + + QEMU_CMD="qemu-system-${qarch} \ + -m ${memory} \ + -smp ${n} \ + -nographic \ + -monitor none \ + -netdev user,id=net0,hostfwd=tcp::10022-:22 \ + -device ${drivernet},netdev=net0 \ + -kernel /qemu/kernel \ + -initrd /qemu/initrd.gz \ + ${opt} \ + -fsdev local,id=fs0,path=/target,security_model=mapped \ + -device ${driver9p},fsdev=fs0,mount_tag=target" + + touch "${LOG}" + if [[ -n "${CROSS_DEBUG}" ]]; then + (${QEMU_CMD} 2>&1 | tee -a "${LOG}") & + else + ${QEMU_CMD} >> "${LOG}" 2>&1 & + fi + + # wait for dropbear + for _ in $(seq 240); do + if grep -q "Not backgrounding" "${LOG}"; then + READY=1 + break + fi + sleep 0.5s + done + + if [ -z "${READY}" ]; then + if [ -n "${CROSS_DEBUG}" ]; then + echo "Not ready but continuing because CROSS_DEBUG is set" + else + echo "Qemu is not ready after ${SECONDS} seconds..." + echo "Set the environment variable CROSS_DEBUG=1 to debug" + echo "Last 100 lines of qemu output:" + tail -n 100 "${LOG}" + exit 1 + fi + fi + + echo "Booted in ${SECONDS} seconds" + +) 200>"${LOCK}" + +if [[ -t 1 ]] && [[ -t 2 ]]; then + tty_flag='-t' +fi + +exec dbclient ${tty_flag} -p 10022 -y -y root@localhost "${@}" diff --git a/.docker/cross/qemu.sh b/.docker/cross/qemu.sh new file mode 100755 index 000000000000..75626c55cb35 --- /dev/null +++ b/.docker/cross/qemu.sh @@ -0,0 +1,233 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +build_static_libffi () { + local version=3.0.13 + + local td + td="$(mktemp -d)" + + pushd "${td}" + + + curl --retry 3 -sSfL "https://github.com/libffi/libffi/archive/refs/tags/v${version}.tar.gz" -O -L + tar --strip-components=1 -xzf "v${version}.tar.gz" + ./configure --prefix="$td"/lib --disable-builddir --disable-shared --enable-static + make "-j$(nproc)" + install -m 644 ./.libs/libffi.a /usr/lib64/ + + popd + + rm -rf "${td}" +} + +build_static_libmount () { + local version_spec=2.23.2 + local version=2.23 + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://kernel.org/pub/linux/utils/util-linux/v${version}/util-linux-${version_spec}.tar.xz" -O -L + tar --strip-components=1 -xJf "util-linux-${version_spec}.tar.xz" + ./configure --disable-shared --enable-static --without-ncurses + make "-j$(nproc)" mount blkid + install -m 644 ./.libs/*.a /usr/lib64/ + + popd + + rm -rf "${td}" +} + + +build_static_libattr() { + local version=2.4.46 + + local td + td="$(mktemp -d)" + + pushd "${td}" + + yum install -y gettext + + curl --retry 3 -sSfL "https://download.savannah.nongnu.org/releases/attr/attr-${version}.src.tar.gz" -O + tar --strip-components=1 -xzf "attr-${version}.src.tar.gz" + cp /usr/share/automake*/config.* . + + ./configure + make "-j$(nproc)" + install -m 644 ./libattr/.libs/libattr.a /usr/lib64/ + + yum remove -y gettext + + popd + + rm -rf "${td}" +} + +build_static_libcap() { + local version=2.22 + + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://www.kernel.org/pub/linux/libs/security/linux-privs/libcap2/libcap-${version}.tar.xz" -O + tar --strip-components=1 -xJf "libcap-${version}.tar.xz" + make "-j$(nproc)" + install -m 644 libcap/libcap.a /usr/lib64/ + + popd + + rm -rf "${td}" +} + +build_static_pixman() { + local version=0.34.0 + + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://www.cairographics.org/releases/pixman-${version}.tar.gz" -O + tar --strip-components=1 -xzf "pixman-${version}.tar.gz" + ./configure + make "-j$(nproc)" + install -m 644 ./pixman/.libs/libpixman-1.a /usr/lib64/ + + popd + + rm -rf "${td}" +} + +main() { + local version=5.1.0 + + if_centos version=4.2.1 + + local arch="${1}" \ + softmmu="${2:-}" + + install_packages \ + autoconf \ + automake \ + bison \ + bzip2 \ + curl \ + flex \ + libtool \ + make \ + patch \ + python3 \ + + if_centos install_packages \ + gcc-c++ \ + pkgconfig \ + xz \ + glib2-devel \ + glib2-static \ + glibc-static \ + libattr-devel \ + libcap-devel \ + libfdt-devel \ + pcre-static \ + pixman-devel \ + libselinux-devel \ + libselinux-static \ + libffi \ + libuuid-devel \ + libblkid-devel \ + libmount-devel \ + zlib-devel \ + zlib-static + + if_centos 'curl --retry 3 -sSfL "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD" -o /usr/share/automake*/config.guess' + if_centos 'curl --retry 3 -sSfL "https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD" -o /usr/share/automake*/config.sub' + + # these are not packaged as static libraries in centos; build them manually + if_centos build_static_libffi + if_centos build_static_libmount + if_centos build_static_libattr + if_centos build_static_libcap + if_centos build_static_pixman + + if_ubuntu install_packages \ + g++ \ + pkg-config \ + xz-utils \ + libattr1-dev \ + libcap-ng-dev \ + libffi-dev \ + libglib2.0-dev \ + libpixman-1-dev \ + libselinux1-dev \ + zlib1g-dev + + # if we have python3.6+, we can install qemu 6.1.0, which needs ninja-build + # ubuntu 16.04 only provides python3.5, so remove when we have a newer qemu. + is_ge_python36=$(python3 -c "import sys; print(int(sys.version_info >= (3, 6)))") + if [[ "${is_ge_python36}" == "1" ]]; then + if_ubuntu version=6.1.0 + if_ubuntu install_packages ninja-build + fi + + local td + td="$(mktemp -d)" + + pushd "${td}" + + curl --retry 3 -sSfL "https://download.qemu.org/qemu-${version}.tar.xz" -O + tar --strip-components=1 -xJf "qemu-${version}.tar.xz" + + local targets="${arch}-linux-user" + local virtfs="" + case "${softmmu}" in + softmmu) + if [ "${arch}" = "ppc64le" ]; then + targets="${targets},ppc64-softmmu" + else + targets="${targets},${arch}-softmmu" + fi + virtfs="--enable-virtfs" + ;; + "") + true + ;; + *) + echo "Invalid softmmu option: ${softmmu}" + exit 1 + ;; + esac + + ./configure \ + --disable-kvm \ + --disable-vnc \ + --disable-guest-agent \ + --enable-linux-user \ + --static \ + ${virtfs} \ + --target-list="${targets}" + make "-j$(nproc)" + make install + + # HACK the binfmt_misc interpreter we'll use expects the QEMU binary to be + # in /usr/bin. Create an appropriate symlink + ln -s "/usr/local/bin/qemu-${arch}" "/usr/bin/qemu-${arch}-static" + + purge_packages + + popd + + rm -rf "${td}" + rm "${0}" +} + +main "${@}" diff --git a/.docker/cross/xargo.sh b/.docker/cross/xargo.sh new file mode 100755 index 000000000000..5f7e2dcd623b --- /dev/null +++ b/.docker/cross/xargo.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -x +set -euo pipefail + +# shellcheck disable=SC1091 +. lib.sh + +main() { + install_packages ca-certificates curl + + export RUSTUP_HOME=/tmp/rustup + export CARGO_HOME=/tmp/cargo + + curl --retry 3 -sSfL https://sh.rustup.rs -o rustup-init.sh + sh rustup-init.sh -y --no-modify-path --profile minimal + rm rustup-init.sh + + PATH="${CARGO_HOME}/bin:${PATH}" cargo install xargo --root /usr/local + + rm -r "${RUSTUP_HOME}" "${CARGO_HOME}" + + purge_packages + + rm "${0}" +} + +main "${@}" diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index dfe16ecf0f15..a5296b46d1ea 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1,24 +1,8 @@ # Current WG Code Sub Teams: -# @tauri-apps/admins -# @tauri-apps/bundler -# @tauri-apps/core -# @tauri-apps/js-cli -# @tauri-apps/testing +# @tauri-apps/wg-tauri +# @tauri-apps/wg-devops -# admins default to review # Order is important; the last matching pattern takes the most precedence. -* @tauri-apps/admins +* @tauri-apps/wg-tauri -.github @tauri-apps/admins @tauri-apps/testing - -/examples/ @tauri-apps/testing - -/tooling/api/ @tauri-apps/core - -/tooling/bundler/ @tauri-apps/bundler - -/tooling/cli/ @tauri-apps/core - -/tooling/cli/node/ @tauri-apps/js-cli - -/core/** @tauri-apps/core +.github @tauri-apps/wg-devops diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md index 4ead0e1daf29..aa35f0f842ac 100644 --- a/.github/CODE_OF_CONDUCT.md +++ b/.github/CODE_OF_CONDUCT.md @@ -1,13 +1,132 @@ -# Contributor Code of Conduct +# Contributor Covenant Code of Conduct -As contributors and maintainers of this project, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. +## Our Pledge -We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, age, or religion. +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. -Examples of unacceptable behavior by participants include the use of sexual language or imagery, derogatory comments or personal attacks, trolling, public or private harassment, insults, or other unprofessional conduct. +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed from the project team. +## Our Standards -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by opening an issue or contacting one or more of the project maintainers. +Examples of behavior that contributes to a positive environment for our +community include: -This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.0.0, available at [http://contributor-covenant.org/version/1/0/0/](http://contributor-covenant.org/version/1/0/0/) +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +[contact@tauri.app](mailto:contact@tauri.app). +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 07ffcc1dd443..bf5fd16860e2 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -22,7 +22,7 @@ Hi! We, the maintainers, are really excited that you are interested in contribut - Issues with no clear repro steps will not be triaged. If an issue labeled "need repro" receives no further input from the issue author for more than 5 days, it will be closed. -- If your issue is resolved but still open, don’t hesitate to close it. In case you found a solution by yourself, it could be helpful to explain how you fixed it. +- If your issue is resolved but still open, don't hesitate to close it. In case you found a solution by yourself, it could be helpful to explain how you fixed it. - Most importantly, we beg your patience: the team must balance your request against many other responsibilities — fixing other bugs, answering other questions, new features, new documentation, etc. The issue list is not paid support and we cannot make guarantees about how fast your issue can be resolved. @@ -37,54 +37,52 @@ Hi! We, the maintainers, are really excited that you are interested in contribut - Provide convincing reason to add this feature. Ideally you should open a suggestion issue first and have it greenlighted before working on it. - If fixing a bug: + - If you are resolving a special issue, add `(fix: #xxxx[,#xxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`. - Provide detailed description of the bug in the PR, or link to an issue that does. +- If the PR is meant to be released, follow the instructions in `.changes/readme.md` to log your changes. ie. [readme.md](https://github.com/tauri-apps/tauri/blob/dev/.changes/README.md) + ## Development Guide -**NOTE: Tauri is undergoing rapid development right now, and the docs match the latest published version of Tauri. They are horribly out of date when compared with the code in the dev branch. This contributor guide is up-to-date, but it doesn't cover all of Tauri's functions in depth. If you have any questions, don't hesitate to ask in our Discord server.** +**NOTE: If you have any question don't hesitate to ask in our Discord server. We try to keep this guide to up guide, but if something doesn't work let us know.** ### General Setup First, [join our Discord server](https://discord.gg/SpmNs4S) and let us know that you want to contribute. This way we can point you in the right direction and help ensure your contribution will be as helpful as possible. -To set up your machine for development, follow the [Tauri setup guide](https://tauri.studio/en/docs/get-started/intro#setting-up-your-environment) to get all the tools you need to develop Tauri apps. The only additional tool you may need is [Yarn](https://yarnpkg.com/), it is only required if you are developing the Node CLI or API packages (`tooling/cli/node` and `tooling/api`). Next, fork and clone this repo. It is structured as a monorepo, which means that all the various Tauri packages are under the same repository. The development process varies depending on what part of Tauri you are contributing to, see the guides below for per-package instructions. +To set up your machine for development, follow the [Tauri setup guide](https://v2.tauri.app/start/prerequisites/) to get all the tools you need to develop Tauri apps. The only additional tool you may need is [PNPM](https://pnpm.io/), it is only required if you are developing the Node CLI or API packages (`packages/cli` and `packages/api`). Next, fork and clone this repo. It is structured as a monorepo, which means that all the various Tauri packages are under the same repository. The development process varies depending on what part of Tauri you are contributing to, see the guides below for per-package instructions. -Some Tauri packages will be automatically built when running one of the examples. Others, however, will need to be built beforehand. To build these automatically, run the `.scripts/setup.sh` (Linux and macOS) or `.scripts/setup.ps1` (Windows) script. This will install the Rust and Node.js CLI and build the JS API. After that, you should be able to run all the examples. Note that the setup script should be executed from the root folder of the respository in order to run correctly. +Some Tauri packages will be automatically built when running one of the examples. Others, however, will need to be built beforehand. To build these automatically, run the `.scripts/setup.sh` (Linux and macOS) or `.scripts/setup.ps1` (Windows) script. This will install the Rust and Node.js CLI and build the JS API. After that, you should be able to run all the examples. Note that the setup script should be executed from the root folder of the repository in order to run correctly. -### Packages Overview +### Overview -- The JS API (`/tooling/api`) contains JS bindings to the builtin Rust functions in the Rust API. -- cli.rs (`/tooling/cli`) is the primary CLI for creating and developing Tauri apps. -- cli.js (`/tooling/cli/node`) is a Node.js CLI wrapper for `cli.rs`. -- Tauri Bundler (`/tooling/bundler`) is used by the Rust CLI to package executables into installers. -- Tauri Core (`/core/tauri`) is the heart of Tauri. It contains the code that starts the app, configures communication between Rust and the Webview, and ties all the other packages together. -- The Macros (`/core/tauri-macros`) are used by Tauri Core for various functions. +See [Architecture](../ARCHITECTURE.md#major-components) for an overview of the packages in this repository. -### Developing The Node.js CLI (cli.js) +### Developing Tauri Bundler and Rust CLI -`cli.js` is a wrapper to `cli.rs` so most changes should be written on the Rust CLI. The `[Tauri repo root]/tooling/cli/node` folder contains only packaging scripts to properly publish the Rust CLI binaries to NPM. +The code for the bundler is located in `[Tauri repo root]/crates/tauri-bundler`, and the code for the Rust CLI is located in `[Tauri repo root]/crates/tauri-cli`. If you are using your local copy of `@tauri-apps/cli` (see above), any changes you make to the bundler and CLI will be automatically built and applied when running the build or dev command. Otherwise, running `cargo install --path .` in the Rust CLI directory will allow you to run `cargo tauri build` and `cargo tauri dev` anywhere, using the updated copy of the bundler and cli. You will have to run this command each time you make a change in either package. -### Developing Tauri Bundler and Rust CLI +### Developing The Node.js CLI (`@tauri-apps/cli`) -The code for the bundler is located in `[Tauri repo root]/tooling/bundler`, and the code for the Rust CLI is located in `[Tauri repo root]/tooling/cli`. If you are using your local copy of cli.js (see above), any changes you make to the bundler and CLI will be automatically built and applied when running the build or dev command. Otherwise, running `cargo install --path .` in the Rust CLI directory will allow you to run `cargo tauri build` and `cargo tauri dev` anywhere, using the updated copy of the bundler and cli. You will have to run this command each time you make a change in either package. +`@tauri-apps/cli` is a wrapper to `tauri-cli` so most changes should be written on the Rust CLI. The `[Tauri repo root]/crates/tauri-cli` folder contains only packaging scripts to properly publish the Rust CLI binaries to NPM. ### Developing Tauri Core and Related Components (Rust API, Macros, Codegen, and Utils) -The code for Tauri Core is located in `[Tauri repo root]/core/tauri`, and the Rust API, Macros, and Utils are in `[Tauri repo root]/core/tauri-(api/macros/utils)`. The easiest way to test your changes is to use the `[Tauri repo root]/examples/helloworld` app. It automatically rebuilds and uses your local copy of the Tauri core packages. Just run `yarn tauri build` or `yarn tauri dev` in the helloworld app directory after making changes to test them out. To use your local changes in another project, edit its `src-tauri/Cargo.toml` file so that the `tauri` key looks like `tauri = { path = "PATH", features = [ "api-all", "cli" ] }`, where `PATH` is the relative path to `[Tauri repo root]/core/tauri`. Then, your local copy of the Tauri core packages will be rebuilt and used whenever you build that project. +The code for the Rust crates, including the Core, Macros, Utils, WRY runtime, and a few more are located in `[Tauri repo root]/crates/tauri-(macros/utils)`. The easiest way to test your changes is to use the `[Tauri repo root]/examples/helloworld` app. It automatically rebuilds and uses your local copy of the Tauri core packages. Just run `cargo run --example helloworld` after making changes to test them out. #### Building the documentation locally You can build the Rust documentation locally running the following script: ```bash -$ RUSTDOCFLAGS="--cfg doc_cfg" cargo +nightly doc --all-features --open +$ RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --open ``` ### Developing the JS API -The JS API provides bindings between the developer's JS in the Webview and the builtin Tauri APIs, written in Rust. Its code is located in `[Tauri repo root]/tooling/api`. After making changes to the code, run `yarn build` to build it. To test your changes, we recommend using the API example app, located in `[Tauri repo root]/examples/api`. It will automatically use your local copy of the JS API and provides a helpful UI to test the various commands. +The JS API provides bindings between the developer's JS in the Webview and the builtin Tauri APIs, written in Rust. Its code is located in `[Tauri repo root]/packages/api`. After making changes to the code, run `pnpm build` to build it. To test your changes, we recommend using the API example app, located in `[Tauri repo root]/examples/api`. It will automatically use your local copy of the JS API and provides a helpful UI to test the various commands. ## Financial Contribution -Tauri is an MIT-licensed open source project. Its ongoing development can be supported via [Github Sponsors](https://github.com/sponsors/nothingismagick) or [Open Collective](https://opencollective.com/tauri). We prefer Github Sponsors as donations made are doubled through the matching fund program. +Tauri is an MIT-licensed open source project. Its ongoing development can be supported via [GitHub Sponsors](https://github.com/sponsors/tauri-apps) or [Open Collective](https://opencollective.com/tauri). We prefer GitHub Sponsors as donations made are doubled through the matching fund program. diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 0c0d6c42e1e3..062d6b94131d 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,6 +1,10 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + # These are supported funding model platforms -github: nothingismagick +github: tauri-apps patreon: # open_collective: tauri ko_fi: # Replace with a single Ko-fi username diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index b2a5c15882b9..6e51eff58720 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,7 +1,11 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + name: 🐞 Bug Report title: '[bug] ' description: Report a bug -labels: 'type: bug' +labels: ['type: bug', 'status: needs triage'] body: - type: markdown @@ -26,11 +30,10 @@ body: id: reproduction attributes: label: Reproduction - description: Steps to reproduce the behavior. + description: A link to a reproduction repo or steps to reproduce the behaviour. placeholder: | - 1. Go to ... - 2. Click on ... - 3. See error + Please provide a minimal reproduction or steps to reproduce, see this guide https://stackoverflow.com/help/minimal-reproducible-example + Why reproduction is required? see this article https://antfu.me/posts/why-reproductions-are-required - type: textarea id: expected-behavior @@ -41,9 +44,9 @@ body: - type: textarea id: info attributes: - label: Platform and versions - description: "Output of `npm run tauri info` or `cargo tauri info`" - render: shell + label: Full `tauri info` output + description: 'Output of `npm run tauri info` or `cargo tauri info`' + render: text validations: required: true @@ -51,8 +54,8 @@ body: id: logs attributes: label: Stack trace - render: shell - + render: text + - type: textarea id: context attributes: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index de285b08c7b5..dabd032899be 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,3 +1,7 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + contact_links: - name: 💬 Discord Chat url: https://discord.com/invite/tauri diff --git a/.github/ISSUE_TEMPLATE/docs_report.md b/.github/ISSUE_TEMPLATE/docs_report.md index 25350673ca78..27df742bda04 100644 --- a/.github/ISSUE_TEMPLATE/docs_report.md +++ b/.github/ISSUE_TEMPLATE/docs_report.md @@ -1,8 +1,7 @@ --- name: 📚 Docs Report about: Create a report to help us improve the docs -title: "[docs] " +title: '[docs] ' labels: 'type: documentation' assignees: '' - --- diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index 0b611fafba94..266eb27e76b1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,7 +1,11 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + name: 💡 Feature Request title: '[feat] ' description: Suggest an idea -labels: 'type: feature request' +labels: ['type: feature request'] body: - type: textarea @@ -18,7 +22,7 @@ body: attributes: label: "Describe the solution you'd like" description: A clear description of what change you would like - placeholder: "I would like to..." + placeholder: 'I would like to...' validations: required: true @@ -27,7 +31,7 @@ body: attributes: label: Alternatives considered description: "Any alternative solutions you've considered" - + - type: textarea id: context attributes: diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7cb3c1f282e8..bd297e82a5a4 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,30 +1,21 @@ - -### What kind of change does this PR introduce? - - -- [ ] Bugfix -- [ ] Feature -- [ ] Docs -- [ ] New Binding issue #___ -- [ ] Code style update -- [ ] Refactor -- [ ] Build-related changes -- [ ] Other, please describe: +1. Give the PR a descriptive title. -### Does this PR introduce a breaking change? - + Examples of good title: + - fix(windows): fix race condition in event loop + - docs: update example for `App::show` + - feat: add `Window::set_fullscreen` -- [ ] Yes, and the changes were approved in issue #___ -- [ ] No + Examples of bad title: + - fix #7123 + - update docs + - fix bugs -### Checklist -- [ ] When resolving issues, they are referenced in the PR's title (e.g `fix: remove a typo, closes #___, #___`) -- [ ] A change file is added if any packages will require a version bump due to this PR per [the instructions in the readme](https://github.com/tauri-apps/tauri/blob/dev/.changes/readme.md). -- [ ] I have added a convincing reason for adding this feature, if necessary - -### Other information +2. If there is a related issue, reference it in the PR text, e.g. closes #123. +3. If this change requires a new version, then add a change file in `.changes` directory with the appropriate bump, see https://github.com/tauri-apps/tauri/blob/dev/.changes/README.md +4. Ensure that all your commits are signed https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-commits +5. Ensure `cargo test` and `cargo clippy` passes. +6. Propose your changes as a draft PR if your work is still in progress. +--> diff --git a/.github/RELEASING.md b/.github/RELEASING.md new file mode 100644 index 000000000000..4732509891a4 --- /dev/null +++ b/.github/RELEASING.md @@ -0,0 +1,62 @@ +# Tauri Releasing Handbook + +This handbook contains information about our release pipeline and how to deal with common issues. +This document is mainly intended for team members responsible for maintaining the project. + +- [Covector](#covector) +- [Version Pull Request](#version-pull-request) +- [Releasing and Publishing](#releasing-and-publishing) +- [Publishing failed, what to do?](#publishing-failed-what-to-do) + +## Covector + +We use [`covector`](https://github.com/jbolda/covector) to manage our version bumps and release pipeline. +It can be configured in [`.changes/config.json`](../.changes/config.json) which includes how each package should be published step by step. + +Some packages can't be published directly using `covector` as it requires to be built on a matrix of platforms +such as `tauri-cli` prebuilt binaries which is published using [publish-cli-rs.yml](./workflows/publish-cli-rs.yml) +and `@tauri-apps/cli` native Node.js modules which is published using using [publish-cli-js.yml](./workflows/publish-cli-js.yml) +both of which are triggered after `covector` has created a github release for both of them, see `Trigger @tauri-apps/cli publishing workflow` +and `Trigger tauri-cli publishing workflow` steps in [covector-version-or-publish.yml](./workflows/covector-version-or-publish.yml) + +## Version Pull Request + +On each pull request merged, [covector-version-or-publish.yml](./workflows/covector-version-or-publish.yml) workflow will run, and: + +When there're change files inside `.changes` folder and they're not all included in `pre.json` (usually this is only when we are in `-alpha` to `-rc` phase), it will open/update an `Apply Version Updates From Current Changes` PR (https://github.com/tauri-apps/tauri/pull/11029 for example) that bumps all packages based on current existing change files and generate `CHANGELOG.md` entries. see `Create Pull Request With Versions Bumped` step in [covector-version-or-publish.yml](./workflows/covector-version-or-publish.yml). + +Otherwise, covector will start to publish packages configured in [`.changes/config.json`](../.changes/config.json). + +## Releasing and Publishing + +Releasing can be as easy as merging the version pull request but here is a checklist to follow: + +- [ ] Double check that every package is bumped correctly and there are no accidental major or minor being released unless that is indeed the intention. +- [ ] Make sure that there are no pending or unfinished [covector-version-or-publish.yml](./workflows/covector-version-or-publish.yml) workflow runs. +- [ ] Sign the Version PR before merging as we require signed commits + - [ ] `git fetch --all` + - [ ] `git checkout release/version-updates` + - [ ] `git commit --amend -S` + - [ ] `git push --force` +- [ ] Approve and merge the version pull request + +## Publishing failed, what to do? + +It is possible and due to many factors that one or many packages release can fail to release, there is no reason to panic, we can fix this. + +Did all of the packages fail to release? + +- yes? + - [ ] `git checkout -b revert-branch` + - [ ] `git revert HEAD~1` +- no? + - [ ] `git checkout -b revert-branch` + - [ ] `git revert HEAD~1 --no-commit` + - [ ] Edit the commit and revert only changes related to packages that failed to publish + - [ ] `git revert --continue` + +Then: + +- [ ] Make a pull request with reverted changes, get it approved and merged +- [ ] Fix the issue that caused releases to fail in another PR, get it approved and merged +- [ ] Repeat the release process again. diff --git a/app-icon.png b/.github/icon.png similarity index 100% rename from app-icon.png rename to .github/icon.png diff --git a/.github/sponsors/crabnebula.svg b/.github/sponsors/crabnebula.svg new file mode 100644 index 000000000000..40e24131b51e --- /dev/null +++ b/.github/sponsors/crabnebula.svg @@ -0,0 +1,31 @@ + \ No newline at end of file diff --git a/.github/workflows/artifacts-updater.yml b/.github/workflows/artifacts-updater.yml deleted file mode 100644 index ac1bdf6b8dbe..000000000000 --- a/.github/workflows/artifacts-updater.yml +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: updater test artifacts -on: - push: - branches: - - dev - - next - pull_request: - paths: - - '.github/workflows/artifacts-updater.yml' - - 'core/tauri/**' - - 'tooling/cli/**' - - 'tooling/bundler/**' - - 'examples/updater/**' - -env: - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache - CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. - -jobs: - build-artifacs: - runs-on: ${{ matrix.platform }} - - strategy: - fail-fast: false - matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] - - steps: - - uses: actions/checkout@v2 - - name: install stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - - name: install webkit2gtk (ubuntu only) - if: matrix.platform == 'ubuntu-latest' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache core cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-core - with: - path: target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache CLI cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-cli - with: - path: tooling/cli/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: build and install cli.rs - run: cargo install --path tooling/cli --force - - name: Check whether code signing should be enabled - id: enablecodesigning - env: - ENABLE_CODE_SIGNING: ${{ secrets.APPLE_CERTIFICATE }} - run: | - echo "Enable code signing: ${{ env.ENABLE_CODE_SIGNING != '' }}" - echo "::set-output name=enabled::${{ env.ENABLE_CODE_SIGNING != '' }}" - # run only on tauri-apps/tauri repo (require secrets) - - name: build sample artifacts + code signing (updater) - if: steps.enablecodesigning.outputs.enabled == 'true' - working-directory: ./examples/updater - run: | - yarn install - cargo tauri build - env: - # Notarization (disabled) - # FIXME: enable only on `dev` push maybe? as it take some times... - # - # APPLE_ID: ${{ secrets.APPLE_ID }} - # APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} - - # Apple code signing testing - APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} - # Updater signature is exposed here to make sure it works in PR's - TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg== - # run on PRs and forks - - name: build sample artifacts (updater) - if: steps.enablecodesigning.outputs.enabled != 'true' - working-directory: ./examples/updater - run: | - yarn install - cargo tauri build - env: - TAURI_PRIVATE_KEY: dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5YTBGV3JiTy9lRDZVd3NkL0RoQ1htZmExNDd3RmJaNmRMT1ZGVjczWTBKZ0FBQkFBQUFBQUFBQUFBQUlBQUFBQWdMekUzVkE4K0tWQ1hjeGt1Vkx2QnRUR3pzQjVuV0ZpM2czWXNkRm9hVUxrVnB6TUN3K1NheHJMREhQbUVWVFZRK3NIL1VsMDBHNW5ET1EzQno0UStSb21nRW4vZlpTaXIwZFh5ZmRlL1lSN0dKcHdyOUVPclVvdzFhVkxDVnZrbHM2T1o4Tk1NWEU9Cg== - # upload assets - - uses: actions/upload-artifact@v2 - if: matrix.platform == 'ubuntu-latest' - with: - name: linux-updater-artifacts - path: ./examples/updater/src-tauri/target/release/bundle/appimage/updater-example_*.AppImage.* - - uses: actions/upload-artifact@v2 - if: matrix.platform == 'windows-latest' - with: - name: windows-updater-artifacts - path: ./examples/updater/src-tauri/target/release/bundle/msi/* - - uses: actions/upload-artifact@v2 - if: matrix.platform == 'macos-latest' - with: - name: macos-updater-artifacts - path: ./examples/updater/src-tauri/target/release/bundle/macos/updater-example.app.tar.* diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 361ab4585269..fa0bb5b37c6a 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -1,4 +1,4 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -10,25 +10,32 @@ on: - cron: '0 0 * * *' push: paths: + - '.github/workflows/audit.yml' - '**/Cargo.lock' - '**/Cargo.toml' - '**/package.json' - - '**/yarn.lock' + - '**/pnpm-lock.yaml' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: audit-rust: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: rust audit - uses: actions-rs/audit-check@v1 + uses: rustsec/audit-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} audit-js: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: yarn audit - working-directory: tooling/cli/node - run: yarn audit + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + - run: pnpm audit diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index bfca38dfd669..b36e525b2d3c 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -1,16 +1,27 @@ -name: benches +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: bench on: push: branches: - dev - - next workflow_dispatch: + pull_request: + paths: + - '.github/workflows/bench.yml' + - 'bench/**' env: RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. + LC_ALL: en_US.UTF-8 # This prevents strace from changing its number format to use commas. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: bench: @@ -24,87 +35,45 @@ jobs: runs-on: ${{ matrix.platform.os }} steps: - - uses: actions/checkout@v2 - - name: install ${{ matrix.rust }} - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + + - name: install Rust ${{ matrix.rust }} + uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} - override: true components: rust-src - target: ${{ matrix.platform.target }} + targets: ${{ matrix.platform.target }} - name: setup python - uses: actions/setup-python@v2 + uses: actions/setup-python@v5 with: - python-version: '3.x' + python-version: '3.10' architecture: x64 - - name: install depedencies + - name: install dependencies run: | python -m pip install --upgrade pip sudo apt-get update - sudo apt-get install -y webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf xvfb - wget https://github.com/sharkdp/hyperfine/releases/download/v1.11.0/hyperfine_1.11.0_amd64.deb - sudo dpkg -i hyperfine_1.11.0_amd64.deb + sudo apt-get install -y --no-install-recommends \ + webkit2gtk-4.1 libayatana-appindicator3-dev \ + xvfb \ + at-spi2-core + wget https://github.com/sharkdp/hyperfine/releases/download/v1.18.0/hyperfine_1.18.0_amd64.deb + sudo dpkg -i hyperfine_1.18.0_amd64.deb pip install memory_profiler - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache core cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-core - with: - path: target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }} - ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}- - ${{ matrix.platform }}-${{ matrix.rust }}- - ${{ matrix.platform }}- - - - name: cache cargo `tooling/bench/tests` target - uses: actions/cache@v2 - env: - cache-name: cargo-benches - with: - path: tooling/bench/tests/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}-${{ hashFiles('tooling/bench/tests/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}-${{ hashFiles('tooling/bench/tests/Cargo.lock') }} - ${{ matrix.platform }}-${{ matrix.rust }}-${{ env.cache-name }}- - ${{ matrix.platform }}-${{ matrix.rust }}- - ${{ matrix.platform }}- + - uses: Swatinem/rust-cache@v2 - name: run benchmarks run: | - cargo build --release -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${{ matrix.platform.target }} --manifest-path tooling/bench/tests/Cargo.toml - xvfb-run --auto-servernum cargo run --manifest-path tooling/bench/Cargo.toml --bin run_benchmark + cargo build --manifest-path bench/tests/cpu_intensive/src-tauri/Cargo.toml --release -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${{ matrix.platform.target }} + cargo build --manifest-path bench/tests/files_transfer/src-tauri/Cargo.toml --release -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${{ matrix.platform.target }} + cargo build --manifest-path bench/tests/helloworld/src-tauri/Cargo.toml --release -Z build-std=std,panic_abort -Z build-std-features=panic_immediate_abort --target ${{ matrix.platform.target }} + xvfb-run --auto-servernum cargo run --manifest-path bench/Cargo.toml --bin run_benchmark - name: clone benchmarks_results if: github.repository == 'tauri-apps/tauri' && github.ref == 'refs/heads/dev' - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: token: ${{ secrets.BENCH_PAT }} path: gh-pages @@ -113,7 +82,7 @@ jobs: - name: push new benchmarks if: github.repository == 'tauri-apps/tauri' && github.ref == 'refs/heads/dev' run: | - cargo run --manifest-path tooling/bench/Cargo.toml --bin build_benchmark_jsons + cargo run --manifest-path bench/Cargo.toml --bin build_benchmark_jsons cd gh-pages git pull git config user.name "tauri-bench" @@ -122,7 +91,7 @@ jobs: git commit --message "Update Tauri benchmarks" git push origin gh-pages - - name: Worker info + - name: Print worker info run: | cat /proc/cpuinfo cat /proc/meminfo diff --git a/.github/workflows/change-status-on-PR.yml b/.github/workflows/change-status-on-PR.yml deleted file mode 100644 index bc0080203675..000000000000 --- a/.github/workflows/change-status-on-PR.yml +++ /dev/null @@ -1,20 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: covector status -on: [pull_request] - -jobs: - covector: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - name: covector status - uses: jbolda/covector/packages/action@covector-v0 - id: covector - with: - command: "status" diff --git a/.github/workflows/check-change-tags.yml b/.github/workflows/check-change-tags.yml new file mode 100644 index 000000000000..d10c5a09912b --- /dev/null +++ b/.github/workflows/check-change-tags.yml @@ -0,0 +1,44 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: check change tags + +on: + pull_request: + paths: + - '.changes/*.md' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: check change files end with .md + run: | + for file in .changes/* + do + if [[ ! "$file" =~ \.(md|json)$ ]]; then + echo ".changes directory should only contain files that end with .md" + echo "found an invalid file in .changes directory:" + echo "$file" + exit 1 + fi + done + + - uses: dorny/paths-filter@v3 + id: filter + with: + list-files: shell + filters: | + changes: + - added|modified: '.changes/*.md' + + - name: check + run: node ./.scripts/ci/check-change-tags.js ${{ steps.filter.outputs.changes_files }} + if: ${{ steps.filter.outputs.changes == 'true' }} diff --git a/.github/workflows/check-generated-files.yml b/.github/workflows/check-generated-files.yml new file mode 100644 index 000000000000..b2ee3bb6d3b4 --- /dev/null +++ b/.github/workflows/check-generated-files.yml @@ -0,0 +1,82 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: check generated files + +on: + pull_request: + paths: + - '.github/workflows/check-generated-files.yml' + - 'packages/api/src/**' + - 'crates/tauri/scripts/bundle.global.js' + - 'crates/tauri-utils/src/config.rs' + - 'crates/tauri-cli/config.schema.json' + - 'crates/tauri-schema-generator/schemas/*.json' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + api: ${{ steps.filter.outputs.api }} + schema: ${{ steps.filter.outputs.schema }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + api: + - 'packages/api/src/**' + - 'crates/tauri/scripts/bundle.global.js' + schema: + - 'crates/tauri-utils/src/config.rs' + - 'crates/tauri-cli/config.schema.json' + - 'crates/tauri-schema-generator/schemas/*.json' + + api: + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.api == 'true' + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'pnpm' + + - name: install deps + run: pnpm i --frozen-lockfile + - name: build api + run: pnpm build + working-directory: packages/api + - name: check api + run: ./.scripts/ci/has-diff.sh + + schema: + runs-on: ubuntu-latest + needs: changes + if: needs.changes.outputs.schema == 'true' + steps: + - uses: actions/checkout@v4 + + - name: install stable + uses: dtolnay/rust-toolchain@stable + + - name: install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev + + - uses: Swatinem/rust-cache@v2 + + - name: generate schemas + run: cargo build --manifest-path ./crates/tauri-schema-generator/Cargo.toml + + - name: check schemas + run: ./.scripts/ci/has-diff.sh diff --git a/.github/workflows/check-license-header.yml b/.github/workflows/check-license-header.yml new file mode 100644 index 000000000000..9b850deccb17 --- /dev/null +++ b/.github/workflows/check-license-header.yml @@ -0,0 +1,28 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: check license headers + +on: + pull_request: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + check: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + list-files: shell + filters: | + added: + - added: '**' + - name: check header license on new files + if: ${{ steps.filter.outputs.added == 'true' }} + run: node ./.scripts/ci/check-license-header.js ${{ steps.filter.outputs.added_files }} diff --git a/.github/workflows/covector-comment-on-fork.yml b/.github/workflows/covector-comment-on-fork.yml new file mode 100644 index 000000000000..86b8cdf30f0c --- /dev/null +++ b/.github/workflows/covector-comment-on-fork.yml @@ -0,0 +1,30 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector comment +on: + workflow_run: + workflows: [covector status] # the `name` of the workflow run on `pull_request` running `status` with `comment: true` + types: + - completed + +# note all other permissions are set to none if not specified +# and these set the permissions for `secrets.GITHUB_TOKEN` +permissions: + # to read the action artifacts on `covector status` workflows + actions: read + # to write the comment + pull-requests: write + +jobs: + comment: + runs-on: ubuntu-latest + if: github.event.workflow_run.conclusion == 'success' && + (github.event.workflow_run.head_repository.full_name != github.repository || github.actor == 'dependabot[bot]') + steps: + - name: covector status + uses: jbolda/covector/packages/action@covector-v0 + with: + token: ${{ secrets.GITHUB_TOKEN }} + command: 'status' diff --git a/.github/workflows/covector-status.yml b/.github/workflows/covector-status.yml new file mode 100644 index 000000000000..9b13dc2215d8 --- /dev/null +++ b/.github/workflows/covector-status.yml @@ -0,0 +1,22 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: covector status +on: [pull_request] + +jobs: + covector: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: covector status + uses: jbolda/covector/packages/action@covector-v0 + id: covector + with: + command: 'status' + token: ${{ secrets.GITHUB_TOKEN }} + comment: true diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index 15d7404a503c..afc07f94768a 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -1,8 +1,8 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT -name: version or publish +name: covector version or publish on: push: @@ -10,44 +10,108 @@ on: - dev jobs: + run-integration-tests: + runs-on: ${{ matrix.platform }} + + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + + - name: install stable + uses: dtolnay/rust-toolchain@stable + + - name: install Linux dependencies + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev libfuse2 librsvg2-dev + + - uses: Swatinem/rust-cache@v2 + + - name: build CLI + run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml + + - name: run integration tests + run: cargo test --test '*' -- --ignored + + - name: run CLI tests + timeout-minutes: 30 + run: | + cd ./packages/cli + pnpm i --frozen-lockfile + pnpm build + pnpm test + version-or-publish: runs-on: ubuntu-latest timeout-minutes: 65 + permissions: + actions: write # required for workflow_dispatch + contents: write # required to create new releases + pull-requests: write # required to open version update pr + id-token: write # pnpm provenance outputs: change: ${{ steps.covector.outputs.change }} commandRan: ${{ steps.covector.outputs.commandRan }} successfulPublish: ${{ steps.covector.outputs.successfulPublish }} + needs: + - run-integration-tests steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 - - uses: actions/setup-node@v2 + - run: corepack enable + - uses: actions/setup-node@v4 with: - node-version: 14 + node-version: 20 registry-url: 'https://registry.npmjs.org' - cache: yarn - cache-dependency-path: tooling/*/yarn.lock + cache: 'pnpm' - name: cargo login - run: cargo login ${{ secrets.crate_token }} + run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }} - name: git config run: | git config --global user.name "${{ github.event.pusher.name }}" git config --global user.email "${{ github.event.pusher.email }}" + + - name: install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + - name: covector version or publish (publish when no change files present) uses: jbolda/covector/packages/action@covector-v0 id: covector env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} CARGO_AUDIT_OPTIONS: ${{ secrets.CARGO_AUDIT_OPTIONS }} + NPM_CONFIG_PROVENANCE: true with: - token: ${{ secrets.GITHUB_TOKEN }} command: 'version-or-publish' + token: ${{ secrets.GITHUB_TOKEN }} createRelease: true + recognizeContributors: true + + - name: Sync Cargo.lock + if: steps.covector.outputs.commandRan == 'version' + run: cargo tree --depth 0 + - name: Create Pull Request With Versions Bumped if: steps.covector.outputs.commandRan == 'version' - uses: tauri-apps/create-pull-request@v3.4.1 + uses: tauri-apps/create-pull-request@v3 with: token: ${{ secrets.GITHUB_TOKEN }} branch: release/version-updates @@ -57,19 +121,27 @@ jobs: body: ${{ steps.covector.outputs.change }} - name: Trigger doc update - if: steps.covector.outputs.successfulPublish == 'true' + if: | + steps.covector.outputs.successfulPublish == 'true' && + steps.covector.outputs.packagesPublished != '' uses: peter-evans/repository-dispatch@v1 with: - token: ${{ secrets.TAURI_BOT_PAT }} + token: ${{ secrets.ORG_TAURI_BOT_PAT }} repository: tauri-apps/tauri-docs event-type: update-docs - - name: Trigger cli.js publishing workflow + - name: Trigger `@tauri-apps/cli` publishing workflow if: | steps.covector.outputs.successfulPublish == 'true' && - contains(steps.covector.outputs.packagesPublished, 'cli.rs') - uses: peter-evans/repository-dispatch@v1 - with: - token: ${{ secrets.TAURI_BOT_PAT }} - repository: tauri-apps/tauri - event-type: publish-clijs + contains(steps.covector.outputs.packagesPublished, '@tauri-apps/cli') + run: gh workflow run 31554138 -r dev -f releaseId=${{ steps.covector.outputs['-tauri-apps-cli-releaseId'] }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Trigger `tauri-cli` publishing workflow + if: | + steps.covector.outputs.successfulPublish == 'true' && + contains(steps.covector.outputs.packagesPublished, 'tauri-cli') + run: gh workflow run 31554139 -r dev + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/deploy-schema-worker.yml b/.github/workflows/deploy-schema-worker.yml new file mode 100644 index 000000000000..6a8297bb44cd --- /dev/null +++ b/.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@v3 + with: + command: deploy + workingDirectory: 'crates/tauri-schema-worker' + apiToken: ${{ secrets.SCHEMA_WORKER_CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.SCHEMA_WORKER_CLOUDFLARE_ACCOUNT_ID }} diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 000000000000..4c0eae17642c --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,130 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: docker + +on: + workflow_dispatch: + #pull_request: + # paths: + # - '.docker/**' + # - '.github/workflows/docker.yml' + +jobs: + setup: + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: install stable + uses: dtolnay/rust-toolchain@stable + + - name: install Linux dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev + + - name: install cross + run: cargo install cross --git https://github.com/cross-rs/cross + + - name: Upload cross + uses: actions/upload-artifact@v4 + with: + name: cross + path: '~/.cargo/bin/cross' + if-no-files-found: error + + - name: build CLI + run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml + + - name: Upload CLI + uses: actions/upload-artifact@v4 + with: + name: cargo-tauri + path: crates/tauri-cli/target/debug/cargo-tauri + if-no-files-found: error + + docker: + needs: setup + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + target: + - { name: 'aarch64-unknown-linux-gnu', filename: 'aarch64' } + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: install stable + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.target.name }} + + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + + - name: Download cross + uses: actions/download-artifact@v4.1.7 + with: + name: cross + path: '~/.cargo/bin' + + - name: Download CLI + uses: actions/download-artifact@v4.1.7 + with: + name: cargo-tauri + path: 'examples/api' + + - name: Set up QEMU + uses: docker/setup-qemu-action@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and export to Docker + uses: docker/build-push-action@v3 + with: + context: .docker/cross + file: .docker/cross/${{ matrix.target.filename }}.Dockerfile + load: true + tags: ${{ matrix.target.name }}:latest + + - name: install dependencies + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev + + - name: Test + run: | + cd packages/api + pnpm i --frozen-lockfile && pnpm build + cd ../../examples/api + pnpm i --frozen-lockfile + . .setup-cross.sh + chmod +x cargo-tauri + chmod +x $HOME/.cargo/bin/cross + ./cargo-tauri build --runner cross --bundles deb --target ${{ matrix.target.name }} --verbose + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: .docker/cross + file: .docker/cross/${{ matrix.target.filename }}.Dockerfile + push: true + tags: ghcr.io/${{ github.repository }}/${{ matrix.target.name }}:latest diff --git a/.github/workflows/fmt.yml b/.github/workflows/fmt.yml new file mode 100644 index 000000000000..a02819a2676d --- /dev/null +++ b/.github/workflows/fmt.yml @@ -0,0 +1,51 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: check formatting + +on: + pull_request: + +jobs: + rustfmt: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: install Rust stable and rustfmt + uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + + - name: run cargo fmt + run: cargo fmt --all -- --check + + prettier: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'pnpm' + - run: pnpm i --frozen-lockfile + - run: pnpm format:check + + taplo: + name: taplo (.toml files) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: install Rust stable + uses: dtolnay/rust-toolchain@stable + + - name: install taplo-cli + uses: taiki-e/install-action@v2 + with: + tool: taplo-cli + + - run: taplo fmt --check --diff diff --git a/.github/workflows/lint-fmt-cli.yml b/.github/workflows/lint-fmt-cli.yml deleted file mode 100644 index 1267dbc9cfd6..000000000000 --- a/.github/workflows/lint-fmt-cli.yml +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: cli clippy and fmt check - -on: - push: - branches: - - dev - - next - pull_request: - paths: - - '.github/workflows/lint-fmt-cli.yml' - - 'tooling/cli/**' - -env: - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache - CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. - -jobs: - fmt_check: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt - - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path ./tooling/cli/Cargo.toml --all -- --check - - cli_clippy_check: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ubuntu-latest-stable-${{ env.cache-name }}- - ubuntu-latest-stable- - ubuntu-latest- - - - name: Cache CLI cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-cli - with: - path: tooling/cli/target - # Add date to the cache to keep it up to date - key: ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }} - ubuntu-latest-stable-${{ env.cache-name }}- - ubuntu-latest-stable- - ubuntu-latest- - - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --manifest-path ./tooling/cli/Cargo.toml --all-targets --all-features -- -D warnings - name: cli diff --git a/.github/workflows/lint-fmt-core.yml b/.github/workflows/lint-fmt-core.yml deleted file mode 100644 index f29f86c6d5b5..000000000000 --- a/.github/workflows/lint-fmt-core.yml +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: core clippy and fmt check - -on: - push: - branches: - - dev - - next - pull_request: - paths: - - '.github/workflows/lint-fmt-core.yml' - - 'core/**' - - 'examples/**' - -env: - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache - CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. - -jobs: - fmt_check: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt - - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - core_clippy_check: - runs-on: ubuntu-latest - strategy: - matrix: - clippy: - - { args: '', key: 'empty' } - - { - args: '--features compression,wry,isolation,custom-protocol,api-all,cli,updater,system-tray', - key: 'all' - } - - { args: '--no-default-features', key: 'no-default' } - - { args: '--features custom-protocol', key: 'custom-protocol' } - - { args: '--features api-all', key: 'api-all' } - - steps: - - uses: actions/checkout@v2 - - name: install webkit2gtk - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: clippy - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ubuntu-latest-stable-${{ env.cache-name }}- - ubuntu-latest-stable- - ubuntu-latest- - - - name: Cache core cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-core - with: - path: target - # Add date to the cache to keep it up to date - key: ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ubuntu-latest-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }} - ubuntu-latest-stable-${{ env.cache-name }}- - ubuntu-latest-stable- - ubuntu-latest- - - - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --manifest-path ./core/tauri/Cargo.toml --all-targets ${{ matrix.clippy.args }} -- -D warnings - name: ${{ matrix.clippy.key }} diff --git a/.github/workflows/lint-js.yml b/.github/workflows/lint-js.yml index 5eadd0a0a87d..6d6b6ac8c7d9 100644 --- a/.github/workflows/lint-js.yml +++ b/.github/workflows/lint-js.yml @@ -1,43 +1,40 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT -name: api and cli.js lint check +name: lint js on: pull_request: paths: - '.github/workflows/lint-js.yml' - - 'tooling/cli/node/**' - - 'tooling/api/**' + - 'packages/**' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: - eslint-check: + eslint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v4 with: - node-version: '12' - cache: yarn - cache-dependency-path: tooling/*/yarn.lock - - name: install cli.js deps via yarn - working-directory: ./tooling/cli/node/ - run: yarn - # nothing to lint - #- name: run cli.js lint - # working-directory: ./tooling/cli/node/ - # run: yarn lint - - name: run cli.js format - working-directory: ./tooling/cli/node/ - run: yarn format:check + node-version: 'lts/*' + cache: 'pnpm' + - run: pnpm i --frozen-lockfile + - run: pnpm eslint:check - - name: install api deps via yarn - working-directory: ./tooling/api/ - run: yarn - - name: run api lint - working-directory: ./tooling/api/ - run: yarn lint - - name: run api format - working-directory: ./tooling/api/ - run: yarn format:check + typescript: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'pnpm' + - run: pnpm i --frozen-lockfile + - run: pnpm ts:check diff --git a/.github/workflows/lint-rust.yml b/.github/workflows/lint-rust.yml new file mode 100644 index 000000000000..18baf97d02e0 --- /dev/null +++ b/.github/workflows/lint-rust.yml @@ -0,0 +1,43 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: lint rust + +on: + push: + branches: + - dev + pull_request: + paths: + - '.github/workflows/lint-cli.yml' + - 'crates/**' + +env: + RUST_BACKTRACE: 1 + CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + clippy: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: install rust stable and clippy + uses: dtolnay/rust-toolchain@stable + with: + components: clippy + + - name: install dependencies + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev + + - uses: Swatinem/rust-cache@v2 + + - run: cargo clippy --all-targets --all-features -- -D warnings diff --git a/.github/workflows/publish-cli-js.yml b/.github/workflows/publish-cli-js.yml new file mode 100644 index 000000000000..d12a8c490090 --- /dev/null +++ b/.github/workflows/publish-cli-js.yml @@ -0,0 +1,389 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: publish `@tauri-apps/cli` +env: + DEBUG: napi:* + APP_NAME: cli + MACOSX_DEPLOYMENT_TARGET: '10.13' +on: + workflow_dispatch: + inputs: + releaseId: + description: 'ID of the `@tauri-apps/cli` release' + required: true + repository_dispatch: + types: [publish-js-cli] + +defaults: + run: + working-directory: packages/cli/ + +jobs: + build: + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: x86_64-apple-darwin + architecture: x64 + build: | + pnpm build --target=x86_64-apple-darwin + strip -x *.node + - host: windows-latest + build: pnpm build + target: x86_64-pc-windows-msvc + architecture: x64 + - host: windows-latest + build: pnpm build --target i686-pc-windows-msvc + target: i686-pc-windows-msvc + architecture: x64 + - host: windows-latest + architecture: x64 + target: aarch64-pc-windows-msvc + build: pnpm build --target aarch64-pc-windows-msvc --features native-tls-vendored --cargo-flags="--no-default-features" + - host: ubuntu-20.04 + target: x86_64-unknown-linux-gnu + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian + build: | + cd packages/cli + pnpm build --target x86_64-unknown-linux-gnu + strip *.node + - host: ubuntu-20.04 + target: x86_64-unknown-linux-musl + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine + build: | + cd packages/cli + pnpm build + strip *.node + - host: macos-latest + target: aarch64-apple-darwin + build: | + pnpm build --features native-tls-vendored --target=aarch64-apple-darwin + strip -x *.node + - host: ubuntu-20.04 + target: aarch64-unknown-linux-gnu + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-debian-aarch64 + build: | + cd packages/cli + pnpm build --target aarch64-unknown-linux-gnu + aarch64-unknown-linux-gnu-strip *.node + - host: ubuntu-20.04 + architecture: x64 + target: armv7-unknown-linux-gnueabihf + setup: | + sudo apt-get update + sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y + build: | + pnpm build --target=armv7-unknown-linux-gnueabihf + arm-linux-gnueabihf-strip *.node + - host: ubuntu-20.04 + architecture: x64 + target: aarch64-unknown-linux-musl + docker: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine + build: | + cd packages/cli + rustup target add aarch64-unknown-linux-musl + pnpm build --target aarch64-unknown-linux-musl + /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node + name: stable - ${{ matrix.settings.target }} - node@20 + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + if: ${{ !matrix.settings.docker }} + with: + node-version: 20 + cache: 'pnpm' + architecture: ${{ matrix.settings.architecture }} + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + if: ${{ !matrix.settings.docker }} + with: + targets: ${{ matrix.settings.target }} + - uses: Swatinem/rust-cache@v1 + with: + key: ${{ matrix.settings.target }} + if: ${{ matrix.settings.docker }} + - name: Setup toolchain + run: ${{ matrix.settings.setup }} + if: ${{ matrix.settings.setup }} + shell: bash + - name: Install dependencies + run: pnpm i --frozen-lockfile --ignore-scripts + + - name: Build in docker + uses: addnab/docker-run-action@v3 + if: ${{ matrix.settings.docker }} + with: + image: ${{ matrix.settings.docker }} + options: --user 0:0 -v ${{ github.workspace }}/.cargo-cache/git/db:/root/.cargo/git/db -v ${{ github.workspace }}/.cargo/registry/cache:/root/.cargo/registry/cache -v ${{ github.workspace }}/.cargo/registry/index:/root/.cargo/registry/index -v ${{ github.workspace }}:/build -w /build + run: ${{ matrix.settings.build }} + + - name: Build + run: ${{ matrix.settings.build }} + if: ${{ !matrix.settings.docker }} + shell: bash + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: bindings-${{ matrix.settings.target }} + path: packages/cli/${{ env.APP_NAME }}.*.node + if-no-files-found: error + # build-freebsd: + # runs-on: macos-10.15 + # name: Build FreeBSD + # steps: + # - uses: actions/checkout@v4 + # - name: Build + # id: build + # uses: vmactions/freebsd-vm@v0.1.6 + # env: + # DEBUG: napi:* + # RUSTUP_HOME: /usr/local/rustup + # CARGO_HOME: /usr/local/cargo + # RUSTUP_IO_THREADS: 1 + # with: + # envs: DEBUG RUSTUP_HOME CARGO_HOME RUSTUP_IO_THREADS + # usesh: true + # mem: 3000 + # prepare: | + # pkg install -y curl node14 python2 + # curl -qL https://www.npmjs.com/install.sh | sh + # npm install -g pnpm + # curl https://sh.rustup.rs -sSf --output rustup.sh + # sh rustup.sh -y --profile minimal --default-toolchain stable + # export PATH="/usr/local/cargo/bin:$PATH" + # echo "~~~~ rustc --version ~~~~" + # rustc --version + # echo "~~~~ node -v ~~~~" + # node -v + # echo "~~~~ pnpm --version ~~~~" + # pnpm --version + # run: | + # export PATH="/usr/local/cargo/bin:$PATH" + # pwd + # ls -lah + # whoami + # env + # freebsd-version + # cd ./packages/cli/ + # pnpm i --frozen-lockfile --ignore-scripts + # pnpm build + # strip -x *.node + # rm -rf node_modules + # rm -rf ../../target + # - name: Upload artifact + # uses: actions/upload-artifact@v4 + # with: + # name: bindings-freebsd + # path: packages/cli/${{ env.APP_NAME }}.*.node + # if-no-files-found: error + test-macOS-windows-binding: + name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + settings: + - host: macos-latest + target: aarch64-apple-darwin + - host: windows-latest + target: x86_64-pc-windows-msvc + node: + - '18' + - '20' + runs-on: ${{ matrix.settings.host }} + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'pnpm' + - name: Install dependencies + run: pnpm i --frozen-lockfile --ignore-scripts + - name: Download artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: bindings-${{ matrix.settings.target }} + path: 'packages/cli/' + - name: List packages + run: ls -R . + shell: bash + - name: Test bindings + run: pnpm test + test-linux-x64-gnu-binding: + name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + node: + - '18' + - '20' + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'pnpm' + - name: Install dependencies + run: pnpm i --frozen-lockfile --ignore-scripts + - name: Download artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: bindings-x86_64-unknown-linux-gnu + path: 'packages/cli' + - name: List packages + run: ls -R . + shell: bash + - name: install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev librsvg2-dev + - name: Test bindings + run: pnpm test + test-linux-x64-musl-binding: + name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + node: + - '18' + - '20' + runs-on: ubuntu-latest + container: + image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node }} + cache: 'pnpm' + - name: Install dependencies + run: pnpm i --frozen-lockfile --ignore-scripts + - name: Download artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: bindings-x86_64-unknown-linux-musl + path: 'packages/cli/' + - name: List packages + run: ls -R . + shell: bash + - name: Setup and run tests + run: | + pnpm tauri --help + ls -la + #- name: Setup and run tests + # run: | + # rustup install stable + # rustup default stable + # pnpm test + # ls -la + test-linux-arm-bindings: + name: Test bindings on ${{ matrix.image }} - node@${{ matrix.node }} + needs: + - build + strategy: + fail-fast: false + matrix: + node: + - '18' + - '20' + image: + - ghcr.io/napi-rs/napi-rs/nodejs:aarch64-16 + - ghcr.io/napi-rs/napi-rs/nodejs:armhf-16 + runs-on: ubuntu-latest + steps: + - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset + working-directory: ${{ github.workspace }} + - uses: actions/checkout@v4 + - name: List packages + run: ls -R . + shell: bash + - name: Download aarch64-gnu artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: bindings-aarch64-unknown-linux-gnu + path: 'packages/cli' + - name: Download armv7-gnueabihf artifacts + uses: actions/download-artifact@v4.1.7 + with: + name: bindings-armv7-unknown-linux-gnueabihf + path: 'packages/cli/' + # TODO: actually run test, blocked by https://github.com/rust-lang/cargo/issues/8719 + - uses: addnab/docker-run-action@v3 + with: + image: ${{ matrix.image }} + options: '-v ${{ github.workspace }}:/build -w /build -e RUSTUP_HOME=/usr/local/rustup -e CARGO_HOME=/usr/local/cargo' + shell: bash + run: | + set -e + export PATH=/usr/local/cargo/bin/:/usr/local/fnm:$PATH + apt-get update + DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install --no-install-recommends -y unzip libayatana-appindicator3-dev + bash + curl https://sh.rustup.rs -sSf | bash -s -- -y + curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "/usr/local/fnm" --skip-shell + eval "$(fnm env --use-on-cd)" + fnm install ${{ matrix.node }} + fnm use ${{ matrix.node }} + cd packages/cli + node tauri.js --help + ls -la + publish: + name: Publish + runs-on: ubuntu-latest + needs: + #- build-freebsd + - test-macOS-windows-binding + - test-linux-x64-gnu-binding + - test-linux-x64-musl-binding + #- test-linux-arm-bindings + permissions: + contents: write # update release + id-token: write # npm provenance + steps: + - uses: actions/checkout@v4 + - run: corepack enable + - name: Setup node + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: 'pnpm' + - name: Install dependencies + run: pnpm i --frozen-lockfile --ignore-scripts + - name: Download all artifacts + uses: actions/download-artifact@v4.1.7 + with: + path: packages/cli/artifacts + - name: Move artifacts + run: pnpm artifacts + - name: List packages + run: ls -R ./npm + shell: bash + - name: Publish + run: | + echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc + npm publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} + RELEASE_ID: ${{ github.event.client_payload.releaseId || inputs.releaseId }} + NPM_CONFIG_PROVENANCE: true diff --git a/.github/workflows/publish-cli-rs.yml b/.github/workflows/publish-cli-rs.yml new file mode 100644 index 000000000000..e8bf7b673288 --- /dev/null +++ b/.github/workflows/publish-cli-rs.yml @@ -0,0 +1,95 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: publish `tauri-cli` +env: + MACOSX_DEPLOYMENT_TARGET: '10.13' +on: + workflow_dispatch: + repository_dispatch: + types: [publish-clirs] + +jobs: + build: + runs-on: ${{ matrix.config.os }} + + strategy: + fail-fast: false + matrix: + config: + - os: ubuntu-20.04 + rust_target: x86_64-unknown-linux-gnu + ext: '' + args: '' + - os: macos-latest + rust_target: x86_64-apple-darwin + ext: '' + args: '' + - os: macos-latest + rust_target: aarch64-apple-darwin + ext: '' + args: '' + - os: windows-latest + rust_target: x86_64-pc-windows-msvc + ext: '.exe' + args: '' + - os: windows-latest + rust_target: aarch64-pc-windows-msvc + ext: '.exe' + args: '--no-default-features --features native-tls-vendored' + + steps: + - uses: actions/checkout@v4 + + - name: 'Setup Rust' + uses: dtolnay/rust-toolchain@stable + with: + targets: ${{ matrix.config.rust_target }} + + - uses: Swatinem/rust-cache@v2 + with: + key: ${{ matrix.config.rust_target }} + + - name: install Linux dependencies + if: matrix.config.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev + + - name: Build CLI + run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml --profile release-size-optimized ${{ matrix.config.args }} + + - name: Upload CLI + uses: actions/upload-artifact@v4 + with: + name: cargo-tauri-${{ matrix.config.rust_target }}${{ matrix.config.ext }} + path: target/release-size-optimized/cargo-tauri${{ matrix.config.ext }} + if-no-files-found: error + + upload: + needs: build + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download built CLIs + uses: actions/download-artifact@v4.1.7 + with: + path: outputs + + - name: Pack archives + run: ./.scripts/ci/pack-cli.sh + + - name: Get CLI version + run: echo "CLI_VERSION=$(cat crates/tauri-cli/metadata-v2.json | jq '."cli.js".version' -r)" >> $GITHUB_ENV + + - name: Publish release + uses: softprops/action-gh-release@50195ba7f6f93d1ac97ba8332a178e008ad176aa + with: + tag_name: tauri-cli-v${{ env.CLI_VERSION }} + files: | + outputs/cargo-tauri-*.zip + outputs/cargo-tauri-*.tgz diff --git a/.github/workflows/publish-cli.yml b/.github/workflows/publish-cli.yml deleted file mode 100644 index a9404751ba67..000000000000 --- a/.github/workflows/publish-cli.yml +++ /dev/null @@ -1,394 +0,0 @@ -name: publish cli.js -env: - DEBUG: napi:* - APP_NAME: cli - MACOSX_DEPLOYMENT_TARGET: '10.13' -on: - workflow_dispatch: - repository_dispatch: - types: [publish-clijs] - -defaults: - run: - working-directory: tooling/cli/node/ - -jobs: - build: - strategy: - fail-fast: false - matrix: - settings: - - host: macos-latest - target: x86_64-apple-darwin - architecture: x64 - build: | - yarn build - strip -x *.node - - host: windows-latest - build: yarn build - target: x86_64-pc-windows-msvc - architecture: x64 - - host: windows-latest - build: yarn build --target i686-pc-windows-msvc - target: i686-pc-windows-msvc - architecture: x64 - - host: ubuntu-18.04 - target: x86_64-unknown-linux-gnu - architecture: x64 - docker: | - docker pull $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-debian - docker tag $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-debian builder - build: | - docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd)/../../../:/build -w /build builder sh -c "cd tooling/cli/node && yarn build && strip *.node" - - host: ubuntu-18.04 - target: x86_64-unknown-linux-musl - architecture: x64 - docker: | - docker pull $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-alpine - docker tag $DOCKER_REGISTRY_URL/napi-rs/napi-rs/nodejs-rust:lts-alpine builder - build: docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd)/../../../:/build -w /build builder sh -c "cd tooling/cli/node && yarn build && strip *.node" - - host: macos-latest - target: aarch64-apple-darwin - build: | - yarn build --target=aarch64-apple-darwin - strip -x *.node - - host: ubuntu-18.04 - architecture: x64 - target: aarch64-unknown-linux-gnu - setup: | - sudo apt-get update - sudo apt-get install g++-aarch64-linux-gnu gcc-aarch64-linux-gnu -y - build: | - yarn build --target=aarch64-unknown-linux-gnu - aarch64-linux-gnu-strip *.node - - host: ubuntu-18.04 - architecture: x64 - target: armv7-unknown-linux-gnueabihf - setup: | - sudo apt-get update - sudo apt-get install gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf -y - build: | - yarn build --target=armv7-unknown-linux-gnueabihf - arm-linux-gnueabihf-strip *.node - - host: ubuntu-18.04 - architecture: x64 - target: aarch64-unknown-linux-musl - downloadTarget: aarch64-unknown-linux-musl - docker: | - docker pull ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine - docker tag ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine builder - build: | - docker run --rm -v ~/.cargo/git:/root/.cargo/git -v ~/.cargo/registry:/root/.cargo/registry -v $(pwd)/../../../:/build -w /build builder sh -c "cd tooling/cli/node && yarn build --target=aarch64-unknown-linux-musl && /aarch64-linux-musl-cross/bin/aarch64-linux-musl-strip *.node" - #- host: windows-latest - # architecture: x64 - # target: aarch64-pc-windows-msvc - # build: yarn build --target aarch64-pc-windows-msvc - name: stable - ${{ matrix.settings.target }} - node@16 - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v2 - - name: Setup node - uses: actions/setup-node@v2 - with: - node-version: 16 - check-latest: true - cache: yarn - cache-dependency-path: 'tooling/cli/node/yarn.lock' - architecture: ${{ matrix.settings.architecture }} - - name: Install - uses: actions-rs/toolchain@v1 - with: - profile: minimal - override: true - toolchain: stable - target: ${{ matrix.settings.target }} - # should be committed - #- name: Generate Cargo.lock - # uses: actions-rs/cargo@v1 - # with: - # command: generate-lockfile - - uses: Swatinem/rust-cache@v1 - with: - key: ${{ matrix.settings.target }} - working-directory: 'tooling/cli/' - - name: Pull latest image - run: ${{ matrix.settings.docker }} - env: - DOCKER_REGISTRY_URL: ghcr.io - if: ${{ matrix.settings.docker }} - - name: Setup toolchain - run: ${{ matrix.settings.setup }} - if: ${{ matrix.settings.setup }} - shell: bash - - name: Install dependencies - run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Build - run: ${{ matrix.settings.build }} - shell: bash - - name: Upload artifact - uses: actions/upload-artifact@v2 - with: - name: bindings-${{ matrix.settings.target }} - path: tooling/cli/node/${{ env.APP_NAME }}.*.node - if-no-files-found: error - # build-freebsd: - # runs-on: macos-10.15 - # name: Build FreeBSD - # steps: - # - uses: actions/checkout@v2 - # - name: Build - # id: build - # uses: vmactions/freebsd-vm@v0.1.5 - # env: - # DEBUG: napi:* - # RUSTUP_HOME: /usr/local/rustup - # CARGO_HOME: /usr/local/cargo - # RUSTUP_IO_THREADS: 1 - # with: - # envs: DEBUG RUSTUP_HOME CARGO_HOME RUSTUP_IO_THREADS - # usesh: true - # mem: 3000 - # prepare: | - # pkg install -y curl node14 python2 - # curl -qL https://www.npmjs.com/install.sh | sh - # npm install -g yarn - # curl https://sh.rustup.rs -sSf --output rustup.sh - # sh rustup.sh -y --profile minimal --default-toolchain stable - # export PATH="/usr/local/cargo/bin:$PATH" - # echo "~~~~ rustc --version ~~~~" - # rustc --version - # echo "~~~~ node -v ~~~~" - # node -v - # echo "~~~~ yarn --version ~~~~" - # yarn --version - # run: | - # export PATH="/usr/local/cargo/bin:$PATH" - # pwd - # ls -lah - # whoami - # env - # freebsd-version - # cd ./tooling/cli/node/ - # yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - # yarn build - # strip -x *.node - # rm -rf node_modules - # rm -rf ../target - # - name: Upload artifact - # uses: actions/upload-artifact@v2 - # with: - # name: bindings-freebsd - # path: tooling/cli/node/${{ env.APP_NAME }}.*.node - # if-no-files-found: error - test-macOS-windows-binding: - name: Test bindings on ${{ matrix.settings.target }} - node@${{ matrix.node }} - needs: - - build - strategy: - fail-fast: false - matrix: - settings: - - host: macos-latest - target: 'x86_64-apple-darwin' - - host: windows-latest - target: x86_64-pc-windows-msvc - node: - - '12' - - '14' - - '16' - runs-on: ${{ matrix.settings.host }} - steps: - - uses: actions/checkout@v2 - - name: Setup node - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - check-latest: true - cache: yarn - cache-dependency-path: 'tooling/cli/node/yarn.lock' - - name: Install dependencies - run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Download artifacts - uses: actions/download-artifact@v2 - with: - name: bindings-${{ matrix.settings.target }} - path: 'tooling/cli/node/' - - name: List packages - run: ls -R . - shell: bash - - name: Test bindings - run: yarn test - test-linux-x64-gnu-binding: - name: Test bindings on Linux-x64-gnu - node@${{ matrix.node }} - needs: - - build - strategy: - fail-fast: false - matrix: - node: - - '12' - - '14' - - '16' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Setup node - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - check-latest: true - cache: yarn - cache-dependency-path: 'tooling/cli/node/yarn.lock' - - name: Install dependencies - run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Download artifacts - uses: actions/download-artifact@v2 - with: - name: bindings-x86_64-unknown-linux-gnu - path: 'tooling/cli/node/' - - name: List packages - run: ls -R . - shell: bash - - name: install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - - name: Test bindings - run: yarn test - test-linux-x64-musl-binding: - name: Test bindings on x86_64-unknown-linux-musl - node@${{ matrix.node }} - needs: - - build - strategy: - fail-fast: false - matrix: - node: - - '12' - - '14' - - '16' - runs-on: ubuntu-latest - container: - image: ghcr.io/napi-rs/napi-rs/nodejs-rust:lts-alpine - steps: - - uses: actions/checkout@v2 - - name: Setup node - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - check-latest: true - cache: yarn - cache-dependency-path: 'tooling/cli/node/yarn.lock' - - name: Install dependencies - run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Download artifacts - uses: actions/download-artifact@v2 - with: - name: bindings-x86_64-unknown-linux-musl - path: 'tooling/cli/node/' - - name: List packages - run: ls -R . - shell: bash - - name: Install system dependencies - run: | - apk add openssl-dev musl-dev glib-dev cairo-dev pkgconfig gdk-pixbuf-dev webkit2gtk-dev curl libappindicator-dev patchelf librsvg-dev gtk+3.0-dev - - name: Setup and run tests - run: | - yarn tauri --help - ls -la - # TODO: fix this test: https://github.com/tauri-apps/tauri/runs/5145729140?check_suite_focus=true#step:9:704 - #- name: Setup and run tests - # run: | - # rustup install stable - # rustup default stable - # yarn test - # ls -la - test-linux-arm-bindings: - name: Test bindings on ${{ matrix.image }} - node@${{ matrix.node }} - needs: - - build - strategy: - fail-fast: false - matrix: - node: - - '12' - - '14' - - '16' - image: - - ghcr.io/napi-rs/napi-rs/nodejs:aarch64-16 - - ghcr.io/napi-rs/napi-rs/nodejs:armhf-16 - runs-on: ubuntu-latest - steps: - - run: docker run --rm --privileged multiarch/qemu-user-static:register --reset - working-directory: ${{ github.workspace }} - - uses: actions/checkout@v2 - - name: List packages - run: ls -R . - shell: bash - - name: Install dependencies - run: yarn install --ignore-scripts --ignore-platform --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Download aarch64-gnu artifacts - uses: actions/download-artifact@v2 - with: - name: bindings-aarch64-unknown-linux-gnu - path: 'tooling/cli/node/' - - name: Download armv7-gnueabihf artifacts - uses: actions/download-artifact@v2 - with: - name: bindings-armv7-unknown-linux-gnueabihf - path: 'tooling/cli/node/' - # TODO: actually run test, blocked by https://github.com/rust-lang/cargo/issues/8719 - - uses: addnab/docker-run-action@v3 - with: - image: ${{ matrix.image }} - options: '-v ${{ github.workspace }}:/build -w /build -e RUSTUP_HOME=/usr/local/rustup -e CARGO_HOME=/usr/local/cargo' - shell: bash - run: | - set -e - export PATH=/usr/local/cargo/bin/:/usr/local/fnm:$PATH - apt-get update - DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC apt-get install --no-install-recommends -y unzip libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - bash - curl https://sh.rustup.rs -sSf | bash -s -- -y - curl -fsSL https://fnm.vercel.app/install | bash -s -- --install-dir "/usr/local/fnm" --skip-shell - eval "$(fnm env --use-on-cd)" - fnm install ${{ matrix.node }} - fnm use ${{ matrix.node }} - cd tooling/cli/node - yarn tauri --help - ls -la - publish: - name: Publish - runs-on: ubuntu-latest - needs: - #- build-freebsd - - test-macOS-windows-binding - - test-linux-x64-gnu-binding - - test-linux-x64-musl-binding - #- test-linux-arm-bindings - steps: - - uses: actions/checkout@v2 - - name: Setup node - uses: actions/setup-node@v2 - with: - node-version: 16 - check-latest: true - cache: yarn - cache-dependency-path: 'tooling/cli/node/yarn.lock' - - name: Install dependencies - run: yarn install --ignore-scripts --frozen-lockfile --registry https://registry.npmjs.org --network-timeout 300000 - - name: Download all artifacts - uses: actions/download-artifact@v2 - with: - path: tooling/cli/node/artifacts - - name: Move artifacts - run: yarn artifacts - - name: List packages - run: ls -R ./npm - shell: bash - - name: Publish - run: | - echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc - npm publish - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/supply-chain.yml b/.github/workflows/supply-chain.yml new file mode 100644 index 000000000000..cab9b8b5a8bc --- /dev/null +++ b/.github/workflows/supply-chain.yml @@ -0,0 +1,44 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: supply chain health status +on: + workflow_dispatch: + schedule: + - cron: '0 0 * * *' + push: + branches: + - dev + paths: + - '.github/workflows/supply-chain.yml' + - '**/Cargo.lock' + - '**/Cargo.toml' +jobs: + cargo-vet: + name: check rust dependencies with cargo vet + runs-on: ubuntu-latest + env: + CARGO_VET_VERSION: 0.9.1 + steps: + - uses: actions/checkout@master + - name: Install Rust + run: rustup update stable && rustup default stable + + - uses: actions/cache@v4 + with: + path: ${{ runner.tool_cache }}/cargo-vet + key: cargo-vet-bin-${{ env.CARGO_VET_VERSION }} + + - name: Add the tool cache directory to the search path + run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH + + - name: Ensure that the tool cache is populated with the cargo-vet binary + run: cargo install --root ${{ runner.tool_cache }}/cargo-vet --version ${{ env.CARGO_VET_VERSION }} cargo-vet + + # Enable this again to break the workflow once we have a reasonable amount of suggestions to get to a clean base line + # - name: Invoke cargo-vet + # run: cargo vet --locked + + - name: Provide audit suggestions + run: cargo vet suggest diff --git a/.github/workflows/test-android.yml b/.github/workflows/test-android.yml new file mode 100644 index 000000000000..2acf3c272ce7 --- /dev/null +++ b/.github/workflows/test-android.yml @@ -0,0 +1,106 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: test android + +on: + pull_request: + paths: + - '.github/workflows/test-android.yml' + - 'crates/tauri-cli/templates/mobile/android/**' + - 'crates/tauri-cli/src/mobile/**' + - '!crates/tauri-cli/src/mobile/ios.rs' + - '!crates/tauri-cli/src/mobile/ios/**' + - 'crates/tauri-build/src/mobile.rs' + - 'crates/tauri/mobile/android/**' + - 'crates/tauri/mobile/android-codegen/**' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ${{ matrix.platform }} + + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + + - name: install Rust 1.77.2 + uses: dtolnay/rust-toolchain@1.77.2 + + - name: install Linux dependencies + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 + + - run: corepack enable + - name: setup node + uses: actions/setup-node@v4 + with: + node-version: lts/* + cache: 'pnpm' + + - uses: actions/setup-java@v3 + with: + distribution: temurin + java-version: 17 + cache: 'gradle' + + - name: Setup NDK + uses: nttld/setup-ndk@v1 + id: setup-ndk + with: + ndk-version: r25b + local-cache: true + + # TODO check after https://github.com/nttld/setup-ndk/issues/518 is fixed + - name: Restore Android Symlinks + if: matrix.platform == 'ubuntu-latest' || matrix.platform == 'macos-latest' + run: | + directory="${{ steps.setup-ndk.outputs.ndk-path }}/toolchains/llvm/prebuilt/linux-x86_64/bin" + find "$directory" -type l | while read link; do + current_target=$(readlink "$link") + new_target="$directory/$(basename "$current_target")" + ln -sf "$new_target" "$link" + echo "Changed $(basename "$link") from $current_target to $new_target" + done + + - uses: Swatinem/rust-cache@v2 + + - name: build CLI + run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml + + - name: move CLI to cargo bin dir + if: matrix.platform != 'windows-latest' + run: mv ./target/debug/cargo-tauri $HOME/.cargo/bin + + - name: move CLI to cargo bin dir + if: matrix.platform == 'windows-latest' + run: mv ./target/debug/cargo-tauri.exe $HOME/.cargo/bin + + - run: pnpm i --frozen-lockfile + + - name: build Tauri API + working-directory: ./packages/api + run: pnpm build + + - name: init Android Studio project + working-directory: ./examples/api + run: cargo tauri android init + env: + NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} + + - name: build APK + working-directory: ./examples/api + run: cargo tauri android build + env: + NDK_HOME: ${{ steps.setup-ndk.outputs.ndk-path }} diff --git a/.github/workflows/test-bundler.yml b/.github/workflows/test-bundler.yml deleted file mode 100644 index 76ace77333d6..000000000000 --- a/.github/workflows/test-bundler.yml +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: test bundler - -on: - push: - branches: - - dev - - next - pull_request: - paths: - - '.github/workflows/test-bundler.yml' - - 'tooling/bundler/**' - -env: - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache - CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. - -jobs: - build-tauri-bundler: - runs-on: ${{ matrix.platform }} - - strategy: - fail-fast: false - matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] - - steps: - - uses: actions/checkout@v2 - - name: install stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache bundler cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-bundler - with: - path: tooling/bundler/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: test - run: | - cd ./tooling/bundler - cargo test - - fmt_check: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - components: rustfmt - - - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path ./tooling/bundler/Cargo.toml --all -- --check - - clippy-check: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - name: install minimal stable with clippy and rustfmt - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - components: rustfmt, clippy - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache bundler cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-bundler - with: - path: tooling/bundler/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: clippy check - uses: actions-rs/clippy-check@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - args: --manifest-path ./tooling/bundler/Cargo.toml --all-targets -- -D warnings - name: bundler diff --git a/.github/workflows/test-cli-js.yml b/.github/workflows/test-cli-js.yml new file mode 100644 index 000000000000..2f556f421638 --- /dev/null +++ b/.github/workflows/test-cli-js.yml @@ -0,0 +1,61 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: test `@tauri-apps/cli` + +on: + push: + branches: + - dev + pull_request: + paths: + - '.github/workflows/test-cli-js.yml' + # currently` @tauri-apps/cli` only tests the template + - 'crates/tauri-cli/templates/app/**' + +env: + RUST_BACKTRACE: 1 + CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ${{ matrix.platform }} + + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + steps: + - uses: actions/checkout@v4 + + - name: install Rust stable + uses: dtolnay/rust-toolchain@stable + + - run: corepack enable + - name: setup node + uses: actions/setup-node@v4 + with: + node-version: 'lts/*' + cache: 'pnpm' + + - name: install Linux dependencies + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev + + - uses: Swatinem/rust-cache@v2 + + - name: test + timeout-minutes: 30 + run: | + cd ./packages/cli + pnpm i --frozen-lockfile + pnpm build + pnpm test diff --git a/.github/workflows/test-cli-rs.yml b/.github/workflows/test-cli-rs.yml new file mode 100644 index 000000000000..2d97c55b2645 --- /dev/null +++ b/.github/workflows/test-cli-rs.yml @@ -0,0 +1,60 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +name: test `tauri-cli` + +on: + push: + branches: + - dev + pull_request: + paths: + - '.github/workflows/test-cli-rs.yml' + - 'crates/tauri-utils/**' + - 'crates/tauri-bundler/**' + - 'crates/tauri-cli/**' + +env: + RUST_BACKTRACE: 1 + CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + runs-on: ${{ matrix.platform.os }} + + strategy: + fail-fast: false + matrix: + platform: + - { target: x86_64-pc-windows-msvc, os: windows-latest } + - { + target: aarch64-pc-windows-msvc, + os: windows-latest, + args: --no-default-features --features native-tls-vendored + } + - { target: x86_64-unknown-linux-gnu, os: ubuntu-latest } + - { target: x86_64-apple-darwin, os: macos-latest } + + steps: + - uses: actions/checkout@v4 + + - name: 'Setup Rust' + uses: dtolnay/rust-toolchain@1.77.2 + with: + targets: ${{ matrix.platform.target }} + + - name: install Linux dependencies + if: matrix.platform.os == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y libgtk-3-dev webkit2gtk-4.1 libayatana-appindicator3-dev + + - uses: Swatinem/rust-cache@v2 + + - name: test CLI + run: cargo test --manifest-path ./crates/tauri-cli/Cargo.toml ${{ matrix.platform.args }} diff --git a/.github/workflows/test-cli.yml b/.github/workflows/test-cli.yml deleted file mode 100644 index 3bd5001563f6..000000000000 --- a/.github/workflows/test-cli.yml +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -name: test CLI - -on: - push: - branches: - - dev - - next - pull_request: - paths: - - '.github/workflows/test-cli.yml' - - 'tooling/cli/**' - -env: - RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache - CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. - -jobs: - test-tauri-cli: - runs-on: ${{ matrix.platform }} - - strategy: - fail-fast: false - matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] - - steps: - - uses: actions/checkout@v2 - - name: install stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache CLI cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-cli - with: - path: tooling/cli/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: build CLI - uses: actions-rs/cargo@v1 - with: - command: build - args: --manifest-path ./tooling/cli/Cargo.toml - - test-tauri-js-cli: - runs-on: ${{ matrix.platform }} - - strategy: - fail-fast: false - matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] - - steps: - - uses: actions/checkout@v2 - - name: install Rust stable - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - override: true - - name: setup node - uses: actions/setup-node@v2 - with: - node-version: 14 - cache: yarn - cache-dependency-path: tooling/cli/node/yarn.lock - - name: install webkit2gtk (ubuntu only) - if: matrix.platform == 'ubuntu-latest' - run: | - sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' - - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache CLI cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-cli - with: - path: tooling/cli/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache template cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-template - with: - path: tooling/cli/node/test/jest/fixtures/empty/src-tauri/target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/templates/app/**') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('tooling/cli/templates/app/**') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: test - timeout-minutes: 30 - run: | - cd ./tooling/cli/node - yarn - yarn build - yarn test diff --git a/.github/workflows/test-core.yml b/.github/workflows/test-core.yml index 62a35f3d5e39..dac4465d7f2b 100644 --- a/.github/workflows/test-core.yml +++ b/.github/workflows/test-core.yml @@ -1,4 +1,4 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT @@ -8,81 +8,97 @@ on: push: branches: - dev - - next pull_request: paths: - '.github/workflows/test-core.yml' - - 'core/**' - - 'examples/**' - - 'tooling/cli/**' + - 'crates/**' + - '!crates/tauri/scripts/**' + - '!crates/tauri-cli/**' + - '!crates/tauri-bundler/**' + - '!crates/tauri-macos-sign/**' + - '!crates/tauri-schema-generator/**' env: RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - test-tauri-core: - runs-on: ${{ matrix.platform }} + test: + runs-on: ${{ matrix.platform.os }} strategy: fail-fast: false matrix: - platform: [ubuntu-latest, macos-latest, windows-latest] + platform: + - { + target: x86_64-pc-windows-msvc, + os: windows-latest, + toolchain: '1.77.2', + cross: false, + command: 'test' + } + - { + target: x86_64-unknown-linux-gnu, + os: ubuntu-latest, + toolchain: '1.77.2', + cross: false, + command: 'test' + } + - { + target: aarch64-apple-darwin, + os: macos-14, + toolchain: '1.77.2', + cross: false, + command: 'test' + } + - { + target: aarch64-apple-ios, + os: macos-latest, + toolchain: '1.77.2', + cross: false, + command: 'build' + } + - { + target: aarch64-linux-android, + os: ubuntu-latest, + toolchain: '1.77.2', + cross: true, + command: 'build' + } + features: + - { args: --no-default-features, key: no-default } + - { args: --all-features, key: all } steps: - - uses: actions/checkout@v2 - - name: install stable - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + + - name: install Rust + uses: dtolnay/rust-toolchain@master with: - toolchain: stable - - name: install webkit2gtk (ubuntu only) - if: matrix.platform == 'ubuntu-latest' + toolchain: ${{ matrix.platform.toolchain }} + targets: ${{ matrix.platform.target }} + + - name: install Linux dependencies + if: contains(matrix.platform.target, 'unknown-linux') run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf - - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV - if: matrix.platform == 'macos-latest' || matrix.platform == 'ubuntu-latest' + sudo apt-get install -y webkit2gtk-4.1 libxdo-dev libayatana-appindicator3-dev - - name: Get current date - if: matrix.platform == 'windows-latest' - run: echo "CURRENT_DATE=$(Get-Date -Format "yyyy-MM-dd")" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- - - - name: Cache core cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-core + - uses: Swatinem/rust-cache@v2 with: - path: target - # Add date to the cache to keep it up to date - key: ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ${{ matrix.platform }}-stable-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }} - ${{ matrix.platform }}-stable-${{ env.cache-name }}- - ${{ matrix.platform }}-stable- - ${{ matrix.platform }}- + prefix-key: v2 + save-if: ${{ matrix.features.key == 'all' }} - name: test + if: ${{ !matrix.platform.cross }} + run: cargo ${{ matrix.platform.command }} --target ${{ matrix.platform.target }} ${{ matrix.features.args }} --manifest-path crates/tauri/Cargo.toml + + - name: test (using cross) + if: ${{ matrix.platform.cross }} run: | - cargo test - cargo test --features api-all - cargo test --features compression,wry,isolation,custom-protocol,api-all,cli,updater,system-tray + cargo install cross --git https://github.com/cross-rs/cross --rev ac4c11cedc97cd7c27faed36e55377a90e6ed618 --locked + cross ${{ matrix.platform.command }} --target ${{ matrix.platform.target }} ${{ matrix.features.args }} --manifest-path crates/tauri/Cargo.toml diff --git a/.github/workflows/udeps.yml b/.github/workflows/udeps.yml index cb072fafb41b..155f09eb4333 100644 --- a/.github/workflows/udeps.yml +++ b/.github/workflows/udeps.yml @@ -1,119 +1,154 @@ -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy # SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: MIT name: Udeps on: - pull_request: - paths: - - '.github/workflows/udeps.yml' - - 'core/**' - - 'tooling/bundler/**' - - 'tooling/cli/**' + push: + branches: + - dev env: RUST_BACKTRACE: 1 - CARGO_INCREMENTAL: 0 # This is set to 0 by the https://github.com/Swatinem/rust-cache CARGO_PROFILE_DEV_DEBUG: 0 # This would add unnecessary bloat to the target folder, decreasing cache efficiency. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - udeps: + changes: runs-on: ubuntu-latest + outputs: + tauri: ${{ steps.filter.outputs.tauri }} + build: ${{ steps.filter.outputs.build }} + codegen: ${{ steps.filter.outputs.codegen }} + macros: ${{ steps.filter.outputs.macros }} + runtime: ${{ steps.filter.outputs.runtime }} + wry: ${{ steps.filter.outputs.wry }} + utils: ${{ steps.filter.outputs.utils }} + bundler: ${{ steps.filter.outputs.bundler }} + cli: ${{ steps.filter.outputs.cli }} steps: - - uses: actions/checkout@v2 - - - uses: actions-rs/toolchain@v1 + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter with: - profile: minimal - toolchain: nightly - override: true + filters: | + tauri: + - 'crates/tauri/**' + - '!crates/tauri/scripts/**' + build: + - 'crates/tauri-build/**' + codegen: + - 'crates/tauri-codegen/**' + macros: + - 'crates/tauri-macros/**' + runtime: + - 'crates/tauri-runtime/**' + wry: + - 'crates/tauri-runtime-wry/**' + utils: + - 'crates/tauri-utils/**' + bundler: + - 'crates/tauri-bundler/**' + cli: + - 'crates/tauri-cli/**' + macossign: + - 'crates/tauri-macos-sign/**' - - name: Get current date - run: echo "CURRENT_DATE=$(date +'%Y-%m-%d')" >> $GITHUB_ENV + setup: + runs-on: ubuntu-latest + needs: changes + if: | + needs.changes.outputs.tauri == 'true' || + needs.changes.outputs.build == 'true' || + needs.changes.outputs.codegen == 'true' || + needs.changes.outputs.macros == 'true' || + needs.changes.outputs.runtime == 'true' || + needs.changes.outputs.wry == 'true' || + needs.changes.outputs.utils == 'true' || + needs.changes.outputs.bundler == 'true' || + needs.changes.outputs.cli == 'true' || + needs.changes.outputs.macossign == 'true' - - name: Cache cargo state - uses: actions/cache@v2 - env: - cache-name: cargo-state - with: - path: | - ~/.cargo/registry - ~/.cargo/git - ~/.cargo/bin - key: ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - restore-keys: | - ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('**/Cargo.toml') }}- - ubuntu-latest-nightly-${{ env.cache-name }}- - ubuntu-latest-nightly- - ubuntu-latest- - - - name: Cache core cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-core - with: - path: target - # Add date to the cache to keep it up to date - key: ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('core/**/Cargo.toml') }} - ubuntu-latest-nightly-${{ env.cache-name }}- - ubuntu-latest-nightly- - ubuntu-latest- - - - name: Cache bundler cargo target - uses: actions/cache@v2 - env: - cache-name: cargo-bundler + steps: + - uses: actions/checkout@v4 + + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@nightly + + - name: Install udeps + run: cargo install cargo-udeps --locked --force + + - name: Upload udeps + uses: actions/upload-artifact@v4 with: - path: tooling/bundler/target - # Add date to the cache to keep it up to date - key: ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('tooling/bundler/Cargo.lock') }} - ubuntu-latest-nightly-${{ env.cache-name }}- - ubuntu-latest-nightly- - ubuntu-latest- - - - name: Cache CLI cargo target - uses: actions/cache@v2 + name: udeps + path: '~/.cargo/bin/cargo-udeps' + if-no-files-found: error + + - name: Create udeps matrix + id: create-matrix env: - cache-name: cargo-cli - with: - path: tooling/cli/target - # Add date to the cache to keep it up to date - key: ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }}-${{ env.CURRENT_DATE }} - # Restore from outdated cache for speed - restore-keys: | - ubuntu-latest-nightly-${{ env.cache-name }}-${{ hashFiles('tooling/cli/Cargo.lock') }} - ubuntu-latest-nightly-${{ env.cache-name }}- - ubuntu-latest-nightly- - ubuntu-latest- - - - uses: actions-rs/cargo@v1 - with: - command: install - args: cargo-udeps --locked --force + TAURI: ${{ needs.changes.outputs.tauri == 'true' }} + BUILD: ${{ needs.changes.outputs.build == 'true' }} + CODEGEN: ${{ needs.changes.outputs.codegen == 'true' }} + MACROS: ${{ needs.changes.outputs.macros == 'true' }} + RUNTIME: ${{ needs.changes.outputs.runtime == 'true' }} + WRY: ${{ needs.changes.outputs.wry == 'true' }} + UTILS: ${{ needs.changes.outputs.utils == 'true' }} + BUNDLER: ${{ needs.changes.outputs.bundler == 'true' }} + CLI: ${{ needs.changes.outputs.cli == 'true' }} + MACOSSIGN: ${{ needs.changes.outputs.macossign == 'true' }} + run: | + crates=() + if [ "${TAURI}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri\""; fi + if [ "${BUILD}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-build\""; fi + if [ "${CODEGEN}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-codegen\""; fi + if [ "${MACROS}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-macros\""; fi + if [ "${RUNTIME}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-runtime\""; fi + if [ "${WRY}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-runtime-wry\""; fi + if [ "${UTILS}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-utils\""; fi + if [ "${BUNDLER}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-bundler\""; fi + if [ "${CLI}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-cli\""; fi + if [ "${MACOSSIGN}" == "true" ]; then crates[${#crates[@]}]="\"./crates/tauri-macos-sign\""; fi + echo "matrix=[$crates]" >> "$GITHUB_OUTPUT" + outputs: + matrix: ${{ steps.create-matrix.outputs.matrix }} - - name: Install required packages + udeps: + runs-on: ubuntu-latest + needs: setup + strategy: + matrix: + path: ${{ fromJson(needs.setup.outputs.matrix) }} + steps: + - uses: actions/checkout@v4 + + - name: Install Rust nightly + uses: dtolnay/rust-toolchain@nightly + + - name: install dependencies run: | sudo apt-get update - sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf + sudo apt-get install -y libgtk-3-dev - - uses: actions-rs/cargo@v1 - with: - command: udeps - args: --all-targets --all-features + - uses: Swatinem/rust-cache@v2 - - uses: actions-rs/cargo@v1 + - name: Download udeps + uses: actions/download-artifact@v4.1.7 with: - command: udeps - args: --manifest-path ./tooling/bundler/Cargo.toml --all-targets --all-features + name: udeps + path: '~/.cargo/bin' - - uses: actions-rs/cargo@v1 - with: - command: udeps - args: --manifest-path ./tooling/cli/Cargo.toml --all-targets --all-features + - run: chmod +x $HOME/.cargo/bin/cargo-udeps + + - name: Install required packages + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 libayatana-appindicator3-dev + + - name: Run udeps + run: cargo udeps --manifest-path ${{ matrix.path }}/Cargo.toml --all-targets --all-features diff --git a/.gitignore b/.gitignore index 4fb1d3064239..3f71763c93fa 100644 --- a/.gitignore +++ b/.gitignore @@ -1,89 +1,52 @@ -# Logs -logs -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# smoke-tests repo -/smoke-tests - -# Runtime data -pids -*.pid -*.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover -lib-cov - -# Coverage directory used by tools like istanbul -coverage - -# nyc test coverage -.nyc_output - -# node-waf configuration -.lock-wscript +# dependency directories +node_modules/ -# Compiled binary addons (http://nodejs.org/api/addons.html) -build/Release +# Optional npm and yarn cache directory +.npm/ +.yarn/ -# Dependency directories -node_modules/ -jspm_packages/ +# Output of 'npm pack' +*.tgz -# Typescript v1 declaration files -typings/ +# dotenv environment variables file +.env -# Optional npm cache directory -.npm +# .vscode workspace settings file +.vscode/settings.json -# Optional yarn cache directory -.yarn +# npm, yarn and bun lock files +package-lock.json +yarn.lock +bun.lockb -# Optional eslint cache -.eslintcache +# rust compiled folders +target/ -# Optional REPL history -.node_repl_history +# test video for streaming example +streaming_example_test_video.mp4 -# Output of 'npm pack' -*.tgz +# examples /gen directory +/examples/**/src-tauri/gen/ +/bench/**/src-tauri/gen/ -# Yarn Integrity file -.yarn-integrity +# logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* -# dotenv environment variables file -.env +# runtime data +pids +*.pid +*.seed +*.pid.lock +# miscellaneous /.vs .DS_Store .Thumbs.db *.sublime* .idea debug.log -package-lock.json -.vscode/settings.json -*/.vscode/ -proptest-regressions/ TODO.md - -# rust compiled folders -target - -# lock for libs -/Cargo.lock -/tooling/bench/tests/Cargo.lock -/yarn.lock - -# ignore frida handlers -__handlers__/ - -# benches -gh-pages -test_video.mp4 - -# old cli directories -/tooling/cli.js -/tooling/cli.rs diff --git a/.husky/.gitignore b/.husky/.gitignore deleted file mode 100644 index 31354ec13899..000000000000 --- a/.husky/.gitignore +++ /dev/null @@ -1 +0,0 @@ -_ diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index c9d98ed21814..000000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -. "$(dirname "$0")/_/husky.sh" - -if [ -z "$(git diff --name-only tooling/api)" ]; then - echo "skipping api - no changes detected" -else - cd tooling/api - yarn format - yarn lint-fix - cd ../.. -fi - -if [ -z "$(git diff --name-only tooling/cli/node)" ]; then - echo "skipping cli.js - no changes detected" -else - cd tooling/cli/node - yarn format - cd ../../.. -fi diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000000..3494710b79e3 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,40 @@ +/audits +/.vscode + +# change files are hand-written and shouldn't be formatted +/.changes/* +!/.changes/config.json + +# dependcies and artifacts directories +node_modules/ +target/ +dist/ + +# lock files +pnpm-lock.yaml + +# autogenerated and minimized js file +crates/tauri/scripts/bundle.global.js + +# this file is an IIFE, shouldn't be formatted +crates/tauri/scripts/process-ipc-message-fn.js + +# cli templates should be formatted manually +# it also includes invalid json files that +# prettier can't handle +crates/tauri-cli/templates + +# autogenerated files +**/autogenerated/**/*.md +packages/cli/index.js +packages/cli/index.d.ts +crates/tauri-schema-worker/.wrangler +CHANGELOG.md +*schema.json + +# WiX templates +*.wxs + +# examples /gen directory +examples/**/src-tauri/gen +bench/**/src-tauri/gen diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000000..299b9e14e8ab --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "semi": false, + "trailingComma": "none" +} diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 2be2f932702c..000000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - singleQuote: true, - semi: false, - trailingComma: 'none' -} diff --git a/.scripts/cargo-check.ps1 b/.scripts/cargo-check.ps1 deleted file mode 100755 index 30459bf41ae6..000000000000 --- a/.scripts/cargo-check.ps1 +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env pwsh -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -# note: you can pass in the cargo sub-commands used to check manually. -# allowed commands: check, clippy, fmt, test -# default: clippy, fmt, test - -# set the script arguments if none are found -if(-Not $args) { - $args=@("clippy","fmt","test") -} - -# exit the script early if the last command returned an error -function check_error { - if($LASTEXITCODE -ne 0 ) { - Exit $LASTEXITCODE - } -} - -function run { - $command, $_args = $args - - Write-Output "[$command]" - cargo $command --workspace --all-targets --all-features $_args - check_error -} - -foreach ($command in $args) { - Switch ($command) { - "check" { - run check - break - } - "test" { - run test - break - } - "clippy" { - run clippy "--" -D warnings - break - } - "fmt" { - Write-Output "[$command] checking formatting" - cargo +nightly fmt "--" --check - check_error - } - default { - Write-Output "[cargo-check.ps1] Unknown cargo sub-command: $command" - Exit 1 - } - } -} diff --git a/.scripts/cargo-check.sh b/.scripts/cargo-check.sh deleted file mode 100755 index 0f6a431edd12..000000000000 --- a/.scripts/cargo-check.sh +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env sh -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -# note: you can pass in the cargo sub-commands used to check manually. -# allowed commands: check, clippy, fmt, test -# default: clippy, fmt, test - -# exit the script early if any of the commands return an error -set -e - -# set the script arguments if none are found -if [ -z "$*" ]; then - set -- "clippy" "fmt" "test" -fi - -# run n+1 times, where n is the amount of mutually exclusive features. -# the extra run is for all the crates without mutually exclusive features. -# as many features as possible are enabled at for each command -run() { - command=$1 - shift 1 - cargo "$command" --workspace --all-targets --all-features "$@" -} - -for command in "$@"; do - case "$command" in - check | test) - run "$command" - ;; - clippy) - run clippy -- -D warnings - ;; - fmt) - echo "[$command] checking formatting" - cargo +nightly fmt -- --check - ;; - *) - echo "[cargo-check.sh] Unknown cargo sub-command: $command" - exit 1 - ;; - esac -done diff --git a/.scripts/ci/check-change-tags.js b/.scripts/ci/check-change-tags.js new file mode 100644 index 000000000000..1cd7de3d9d98 --- /dev/null +++ b/.scripts/ci/check-change-tags.js @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +const fs = require('fs') +const path = require('path') +const ignorePackages = [ + 'tauri-macros', + 'tauri-codegen', + 'tauri-runtime', + 'tauri-runtime-wry', + 'tauri-driver' +] + +const covectorConfig = JSON.parse( + fs.readFileSync('.changes/config.json', 'utf8') +) +const tags = Object.keys(covectorConfig.changeTags) + +const missingTagsFiles = {} +const unknownTagsFiles = {} + +function checkChangeFiles(changeFiles) { + for (const file of changeFiles) { + const content = fs.readFileSync(file, 'utf8') + const [frontMatter] = /^---[\s\S.]*---\n/i.exec(content) + const packages = frontMatter + .split('\n') + .filter((l) => !(l === '---' || !l)) + .map((l) => l.replace(/('|")/g, '').split(':')) + + for (const [package, _, tag] of packages) { + if (!tag) { + if (ignorePackages.includes(package)) continue + + if (!missingTagsFiles[file]) missingTagsFiles[file] = [] + missingTagsFiles[file].push(package) + } else if (!tags.includes(tag)) { + if (!unknownTagsFiles[file]) unknownTagsFiles[file] = [] + unknownTagsFiles[file].push({ package, tag }) + } + } + } + const missingTagsEntries = Object.entries(missingTagsFiles) + const unknownTagsEntries = Object.entries(unknownTagsFiles) + if (missingTagsEntries.length > 0 || unknownTagsEntries.length > 0) { + for (const [file, packages] of missingTagsEntries) { + for (const package of packages) { + console.error( + `Package \`${package}\` is missing a change tag in ${file} ` + ) + } + } + + for (const [file, packages] of unknownTagsEntries) { + for (const { package, tag } of packages) { + console.error( + `Package \`${package}\` has an uknown change tag ${tag} in ${file} ` + ) + } + } + + process.exit(1) + } +} + +const [_bin, _script, ...files] = process.argv + +if (files.length > 0) { + checkChangeFiles( + files.filter((f) => f.toLowerCase() !== '.changes/readme.md') + ) +} else { + const changeFiles = fs + .readdirSync('.changes') + .filter((f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md') + .map((p) => path.join('.changes', p)) + checkChangeFiles(changeFiles) +} diff --git a/.scripts/ci/check-license-header.js b/.scripts/ci/check-license-header.js new file mode 100644 index 000000000000..5afd062f81a2 --- /dev/null +++ b/.scripts/ci/check-license-header.js @@ -0,0 +1,123 @@ +#!/usr/bin/env node + +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +const fs = require('fs') +const path = require('path') +const readline = require('readline') + +const header = `Copyright 2019-2024 Tauri Programme within The Commons Conservancy +SPDX-License-Identifier: Apache-2.0 +SPDX-License-Identifier: MIT` +const bundlerLicense = + '// Copyright 2016-2019 Cargo-Bundle developers ' +const denoLicense = + '// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.' + +const extensions = ['.rs', '.js', '.ts', '.yml', '.swift', '.kt'] +const ignore = [ + 'target', + 'templates', + 'node_modules', + 'gen', + 'dist', + 'bundle.global.js' +] + +async function checkFile(file) { + if ( + extensions.some((e) => file.endsWith(e)) && + !ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) == i) + ) { + const fileStream = fs.createReadStream(file) + const rl = readline.createInterface({ + input: fileStream, + crlfDelay: Infinity + }) + + let contents = `` + let i = 0 + for await (let line of rl) { + // ignore empty lines, allow shebang and bundler license + if ( + line.length === 0 || + line.startsWith('#!') || + line.startsWith('// swift-tools-version:') || + line === bundlerLicense || + line === denoLicense + ) { + continue + } + + // strip comment marker + if (line.startsWith('// ')) { + line = line.substring(3) + } else if (line.startsWith('# ')) { + line = line.substring(2) + } + + contents += line + if (++i === 3) { + break + } + contents += '\n' + } + if (contents !== header) { + return true + } + } + return false +} + +async function check(src) { + const missingHeader = [] + + for (const entry of fs.readdirSync(src, { withFileTypes: true })) { + const p = path.join(src, entry.name) + + if (entry.isSymbolicLink() || ignore.includes(entry.name)) { + continue + } + + if (entry.isDirectory()) { + const missing = await check(p) + missingHeader.push(...missing) + } else { + const isMissing = await checkFile(p) + if (isMissing) { + missingHeader.push(p) + } + } + } + + return missingHeader +} + +const [_bin, _script, ...files] = process.argv + +if (files.length > 0) { + async function run() { + const missing = [] + for (const f of files) { + const isMissing = await checkFile(f) + if (isMissing) { + missing.push(f) + } + } + if (missing.length > 0) { + console.log(missing.join('\n')) + process.exit(1) + } + } + + run() +} else { + check('.').then((missing) => { + if (missing.length > 0) { + console.log(missing.join('\n')) + process.exit(1) + } + }) +} diff --git a/.scripts/ci/has-diff.sh b/.scripts/ci/has-diff.sh new file mode 100755 index 000000000000..91f9a0fc1066 --- /dev/null +++ b/.scripts/ci/has-diff.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +git_output=$(git diff --ignore-submodules --name-only HEAD) +if [ -z "$git_output" ]; +then + echo "✔ working directory is clean" +else + echo "✘ found diff:" + echo "$git_output" + exit 1 +fi diff --git a/.scripts/ci/pack-cli.sh b/.scripts/ci/pack-cli.sh new file mode 100755 index 000000000000..3658f3d4314d --- /dev/null +++ b/.scripts/ci/pack-cli.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +set -euxo pipefail + +for o in outputs/*; do + pushd "$o" + + chmod +x cargo-tauri* + cp ../../crates/tauri-cli/LICENSE* ../../crates/tauri-cli/README.md . + + target=$(basename "$o" | cut -d. -f1) + if grep -qE '(apple|windows)' <<< "$target"; then + zip "../${target}.zip" * + else + tar cv * | gzip -9 > "../${target}.tgz" + fi + + popd +done diff --git a/.scripts/ci/sync-cli-metadata.js b/.scripts/ci/sync-cli-metadata.js new file mode 100644 index 000000000000..b47212d929f0 --- /dev/null +++ b/.scripts/ci/sync-cli-metadata.js @@ -0,0 +1,74 @@ +#!/usr/bin/env node + +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +/* +This script is solely intended to be run as part of the `covector version` step to +keep the `../../crates/tauri-cli/metadata-v2.json` up to date with other version bumps. Long term +we should look to find a more "rusty way" to import / "pin" a version value in our tauri-cli +rust binaries. +*/ + +const { readFileSync, writeFileSync } = require('fs') +const { resolve } = require('path') + +const packageNickname = process.argv[2] +const filePath = resolve(__dirname, '../../crates/tauri-cli/metadata-v2.json') +const bump = process.argv[3] +let index = null + +switch (bump) { + case 'major': + case 'premajor': + index = 0 + break + case 'minor': + index = 1 + break + case 'patch': + index = 2 + break + case 'prerelease': + case 'prepatch': + index = 3 + break + default: + throw new Error('unexpected bump ' + bump) +} + +const inc = (version) => { + const v = version.split('.') + for (let i = 0; i < v.length; i++) { + if (i === index) { + v[i] = String(Number(v[i]) + 1) + } else if (i > index) { + v[i] = 0 + } + } + if (bump === 'premajor') { + const pre = JSON.parse( + readFileSync(resolve(__dirname, '../../.changes/pre.json'), 'utf-8') + ) + return `${v.join('.')}-${pre.tag}.0` + } + return v.join('.') +} + +// read file into js object +const metadata = JSON.parse(readFileSync(filePath, 'utf-8')) + +// set field version +let version +if (packageNickname === '@tauri-apps/cli') { + version = inc(metadata['cli.js'].version) + metadata['cli.js'].version = version +} else { + version = inc(metadata[packageNickname]) + metadata[packageNickname] = version +} + +writeFileSync(filePath, JSON.stringify(metadata, null, 2) + '\n') +console.log(`wrote ${version} for ${packageNickname} into metadata-v2.json`) +console.dir(metadata) diff --git a/.scripts/covector/sync-cli-metadata.js b/.scripts/covector/sync-cli-metadata.js deleted file mode 100644 index c3af1e5bf454..000000000000 --- a/.scripts/covector/sync-cli-metadata.js +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env node - // Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -/* -This script is solely intended to be run as part of the `covector version` step to -keep the `../tooling/cli/metadata.json` up to date with other version bumps. Long term -we should look to find a more "rusty way" to import / "pin" a version value in our cli.rs -rust binaries. -*/ - -const { - readFileSync, - writeFileSync -} = require('fs') - -const packageNickname = process.argv[2] -const filePath = packageNickname === 'cli.js' ? `../../../tooling/cli/metadata.json` : `../../tooling/cli/metadata.json` -const bump = process.argv[3] -if (bump !== 'prerelease') { - throw new Error( - `We don't handle anything except prerelease right now. Exiting.` - ) -} - -const inc = (version) => { - const v = version.split('.') - const n = v[v.length - 1] - v[v.length - 1] = String(Number(n) + 1) - return v.join('.') -} - -// read file into js object -const metadata = JSON.parse(readFileSync(filePath, 'utf-8')) - -// set field version -let version -if (packageNickname === 'cli.js') { - version = inc(metadata[packageNickname].version) - metadata[packageNickname].version = version -} else { - version = inc(metadata[packageNickname]) - metadata[packageNickname] = version -} - -writeFileSync(filePath, JSON.stringify(metadata, null, 2) + '\n') -console.log(`wrote ${version} for ${packageNickname} into metadata.json`) -console.dir(metadata) diff --git a/.scripts/covector/sync-prerelease.js b/.scripts/covector/sync-prerelease.js deleted file mode 100644 index b7a9c3c63d2a..000000000000 --- a/.scripts/covector/sync-prerelease.js +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env node - // Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -/* -This script is solely intended to be run as part of the `covector version` step to -keep the `tauri-runtime`, `tauri-runtime-wry` and `tauri-driver` crates version without the `beta` or `rc` suffix. -*/ - -const { - readFileSync, - writeFileSync -} = require('fs') - -const packageNickname = process.argv[2] -const bump = process.argv[3] - -let manifestPath -let dependencyManifestPaths -let changelogPath - -if (packageNickname === 'tauri-runtime') { - manifestPath = '../../core/tauri-runtime/Cargo.toml' - dependencyManifestPaths = [ - '../../core/tauri/Cargo.toml', - '../../core/tauri-runtime-wry/Cargo.toml' - ] - changelogPath = '../../core/tauri-runtime/CHANGELOG.md' -} else if (packageNickname === 'tauri-runtime-wry') { - manifestPath = '../../core/tauri-runtime-wry/Cargo.toml' - dependencyManifestPaths = ['../../core/tauri/Cargo.toml'] - changelogPath = '../../core/tauri-runtime-wry/CHANGELOG.md' -} else if (packageNickname === 'tauri-driver') { - manifestPath = '../../tooling/webdriver/Cargo.toml' - dependencyManifestPaths = [] - changelogPath = '../../tooling/webdriver/CHANGELOG.md' -} else { - throw new Error(`Unexpected package ${packageNickname}`) -} - -let manifest = readFileSync(manifestPath, 'utf-8') -manifest = manifest.replace( - /version = "(\d+\.\d+\.\d+)-[^0-9\.]+\.0"/, - 'version = "$1"' -) -writeFileSync(manifestPath, manifest) - -let changelog = readFileSync(changelogPath, 'utf-8') -changelog = changelog.replace(/(\d+\.\d+\.\d+)-[^0-9\.]+\.0/, '$1') -writeFileSync(changelogPath, changelog) - -for (const dependencyManifestPath of dependencyManifestPaths) { - let dependencyManifest = readFileSync(dependencyManifestPath, 'utf-8') - dependencyManifest = dependencyManifest.replace( - new RegExp( - packageNickname + ' = { version = "(\\d+\\.\\d+.\\d+)-[^0-9.]+.0"' - ), - `${packageNickname} = { version = "$1"` - ) - writeFileSync(dependencyManifestPath, dependencyManifest) -} diff --git a/.scripts/setup.ps1 b/.scripts/setup.ps1 deleted file mode 100644 index 4d435d46534b..000000000000 --- a/.scripts/setup.ps1 +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env pwsh -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -echo "Building API definitions..." -cd tooling\api -yarn; yarn build -cd ..\.. - -echo "Installing the Tauri Rust CLI..." -cd tooling\cli -cargo install --path . -cd ..\.. -echo "Tauri Rust CLI installed. Run it with '$ cargo tauri [COMMAND]'." - -$yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes" -$no = New-Object System.Management.Automation.Host.ChoiceDescription "&No" -$options = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no) - -$result = $host.ui.PromptForChoice("Node.js CLI", "Do you want to install the Node.js CLI?", $options, 1) -switch ($result) { - 0{ - cd tooling\cli\node - yarn; yarn build; yarn link - cd ..\.. - echo "Tauri Node.js CLI installed. use `yarn link @tauri-apps/cli` and run it with '$ yarn tauri [COMMAND]'." - } -} diff --git a/.scripts/setup.sh b/.scripts/setup.sh deleted file mode 100755 index 0f2410946da8..000000000000 --- a/.scripts/setup.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/usr/bin/env bash -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -echo "Building API definitions..." -cd tooling/api -yarn && yarn build -cd ../.. - -echo "Building the Tauri Rust CLI..." -cd tooling/cli -cargo install --path . -cd ../.. -echo "Tauri Rust CLI installed. Run it with '$ cargo tauri [COMMAND]'." - -echo "Do you want to install the Node.js CLI?" -select yn in "Yes" "No"; do - case $yn in - Yes ) - cd tooling/cli/node - yarn && yarn build && yarn link - cd ../../.. - echo "Tauri Node.js CLI installed. use `yarn link @tauri-apps/cli` and run it with '$ yarn tauri [COMMAND]'." - break;; - No ) break;; - esac -done diff --git a/.scripts/update-lockfiles.sh b/.scripts/update-lockfiles.sh deleted file mode 100755 index 37929e2050f3..000000000000 --- a/.scripts/update-lockfiles.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env sh -# Copyright 2019-2021 Tauri Programme within The Commons Conservancy -# SPDX-License-Identifier: Apache-2.0 -# SPDX-License-Identifier: MIT - -declare -a examples=("api" "sidecar" "updater" "resources", "isolation") -declare -a tooling=("bench" "cli" "webdriver") - -for example in "${examples[@]}" -do - cd examples/$example/src-tauri - cargo update - cargo build - cd ../../.. -done - -for tooling in "${tooling[@]}" -do - cd tooling/$tooling - cargo update - cargo build - cd ../.. -done diff --git a/.scripts/utils/batch_to_exe.cmd b/.scripts/utils/batch_to_exe.cmd deleted file mode 100644 index 44b207b4f801..000000000000 --- a/.scripts/utils/batch_to_exe.cmd +++ /dev/null @@ -1,62 +0,0 @@ -@ECHO OFF - -REM Copyright 2019-2021 Tauri Programme within The Commons Conservancy -REM SPDX-License-Identifier: Apache-2.0 -REM SPDX-License-Identifier: MIT - -ECHO Make EXE From BAT -ECHO. -ECHO. - -REM Usage: -REM MakeExeFromBat BatFileToConvert [IncludeFile1] [IncludeFile2] [...] -REM -REM Required Parameters: -REM BatFileToConvert -REM Source batch file to use to produce the output Exe file. -REM -REM Optional Parameters: -REM IncludeFile -REM Additional files to include in the Exe file. -REM You can include external tools used by the batch file so they are available on the executing machine. - -SETLOCAL - -REM Configuration (no quotes needed): -SET PathTo7Zip= - - -REM ---- Do not modify anything below this line ---- - -SET OutputFile="%~n1.exe" -SET SourceFiles="%TEMP%MakeEXE_files.txt" -SET Config="%TEMP%MakeEXE_config.txt" -SET Source7ZFile="%Temp%MakeEXE.7z" - -REM Remove existing files -IF EXIST %OutputFile% DEL %OutputFile% - -REM Build source archive -ECHO "%~dpnx1" > %SourceFiles% -:AddInclude -IF {%2}=={} GOTO EndInclude -ECHO "%~dpnx2" >> %SourceFiles% -SHIFT /2 -GOTO AddInclude -:EndInclude -"%PathTo7Zip%7za.exe" a %Source7ZFile% @%SourceFiles% - -REM Build config file -ECHO ;!@Install@!UTF-8! > %Config% -ECHO RunProgram="%~nx1" >> %Config% -ECHO ;!@InstallEnd@! >> %Config% - -REM Build EXE -COPY /B "%PathTo7Zip%7zsd.sfx" + %Config% + %Source7ZFile% %OutputFile% - -REM Clean up -IF EXIST %SourceFiles% DEL %SourceFiles% -IF EXIST %Config% DEL %Config% -IF EXIST %Source7ZFile% DEL %Source7ZFile% - -ENDLOCAL \ No newline at end of file diff --git a/.taurignore b/.taurignore new file mode 100644 index 000000000000..6e49b1ea8a6b --- /dev/null +++ b/.taurignore @@ -0,0 +1,16 @@ +.changes +.devcontainer +.docker +.github +.scripts +.vscode +audits +bench +packages/api +packages/cli +crates/tauri-cli +crates/tauri-bundler +crates/tauri-driver +crates/tauri-macos-sign +crates/tauri-schema-generator +crates/tests diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 000000000000..68acfc90a362 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "rust-lang.rust-analyzer", + "EditorConfig.EditorConfig", + "esbenp.prettier-vscode", + "tamasfe.even-better-toml" + ] +} diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index cfff480fbd80..56630ea06c76 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -1,107 +1,134 @@ # The Tauri Architecture -https://tauri.studio -https://github.com/tauri-apps/tauri + + + + ## Introduction + Tauri is a polyglot and generic toolkit that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the OS's webview. They do not ship a runtime, since the final binary is compiled from Rust. This makes the reversing of Tauri apps not a trivial task. ## What Tauri is NOT + - Tauri is not a lightweight kernel wrapper...instead it directly uses [WRY](#wry) and [TAO](#tao) to do the heavy-lifting in making system calls to the OS. - Tauri is not a VM or virtualized environment...instead it is an application toolkit that allows making Webview OS applications. ## Major Components + The following section briefly describes the roles of the various parts of Tauri. + ### Tauri Core [STABLE RUST] -#### [tauri](https://github.com/tauri-apps/tauri/tree/dev/core/tauri) + +#### [tauri](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri) + This is the major crate that holds everything together. It brings the runtimes, macros, utilities and API into one final product. It reads the `tauri.conf.json` file at compile time in order to bring in features and undertake actual configuration of the app (and even the `Cargo.toml` file in the project's folder). It handles script injection (for polyfills / prototype revision) at runtime, hosts the API for systems interaction, and even manages updating. -#### [tauri-build](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-build) +#### [tauri-build](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-build) + Apply the macros at build-time in order to rig some special features needed by `cargo`. -#### [tauri-codegen](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-codegen) +#### [tauri-codegen](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-codegen) + - Embed, hash, and compress assets, including icons for the app as well as the system-tray. - Parse `tauri.conf.json` at compile time and generate the Config struct. -#### [tauri-macros](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-macros) +#### [tauri-macros](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-macros) + Create macros for the context, handler, and commands by leveraging the `tauri-codegen` crate. -#### [tauri-runtime](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-runtime) +#### [tauri-runtime](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime) + This is the glue layer between tauri itself and lower level webview libraries. -#### [tauri-runtime-wry](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-runtime-wry) +#### [tauri-runtime-wry](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-runtime-wry) + This crate opens up direct systems-level interactions specifically for WRY, such as printing, monitor detection, and other windowing related tasks. `tauri-runtime` implementation for WRY. -#### [tauri-utils](https://github.com/tauri-apps/tauri/tree/dev/core/tauri-utils) -This is common code that is reused in many places and offers useful utilities like parsing configuration files, detecting platform triples, injecting the CSP, and managing assets. +#### [tauri-utils](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-utils) +This is common code that is reused in many places and offers useful utilities like parsing configuration files, detecting platform triples, injecting the CSP, and managing assets. ### Tauri Tooling -#### [api](https://github.com/tauri-apps/tauri/tree/dev/tooling/api) [TS -> JS] -A typescript library that creates `cjs` and `esm` Javascript endpoints for you to import into your Frontend framework so that the Webview can call and listen to backend activity. We also ship the pure typescript, because for some frameworks this is more optimal. It uses the message passing of webviews to their hosts. -#### [bundler](https://github.com/tauri-apps/tauri/tree/dev/tooling/bundler) [RUST / SHELL] +#### [@tauri-apps/api](https://github.com/tauri-apps/tauri/tree/dev/packages/api) [TS -> JS] + +A TypeScript library that creates `cjs` and `esm` JavaScript endpoints for you to import into your Frontend framework so that the Webview can call and listen to backend activity. We also ship the pure TypeScript, because for some frameworks this is more optimal. It uses the message passing of webviews to their hosts. + +#### [bundler](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-bundler) [RUST / SHELL] + The bundler is a library that builds a Tauri App for the platform triple it detects / is told. At the moment it currently supports macOS, Windows and Linux - but in the near future will support mobile platforms as well. May be used outside of Tauri projects. -#### [cli.js](https://github.com/tauri-apps/tauri/tree/dev/tooling/cli/node) [JS] -It is a wrapper around [cli.rs](https://github.com/tauri-apps/tauri/blob/dev/tooling/cli) using [napi-rs](https://github.com/napi-rs/napi-rs) to produce NPM packages for each platform. +#### [@tauri-apps/cli](https://github.com/tauri-apps/tauri/tree/dev/packages/cli) [JS] + +It is a wrapper around [tauri-cli](https://github.com/tauri-apps/tauri/blob/dev/crates/tauri-cli) using [napi-rs](https://github.com/napi-rs/napi-rs) to produce NPM packages for each platform. + +#### [tauri-cli](https://github.com/tauri-apps/tauri/tree/dev/crates/tauri-cli) [RUST] -#### [cli.rs](https://github.com/tauri-apps/tauri/tree/dev/tooling/cli) [RUST] This rust executable provides the full interface to all of the required activities for which the CLI is required. It will run on macOS, Windows, and Linux. #### [create-tauri-app](https://github.com/tauri-apps/create-tauri-app) [JS] + This is a toolkit that will enable engineering teams to rapidly scaffold out a new tauri-apps project using the frontend framework of their choice (as long as it has been configured). # External Crates + The Tauri-Apps organisation maintains two "upstream" crates from Tauri, namely TAO for creating and managing application windows, and WRY for interfacing with the Webview that lives within the window. ## [TAO](https://github.com/tauri-apps/tao) -Cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android. Written in Rust, it is a fork of [winit](https://github.com/rust-windowing/winit) that we have extended for our own needs like menu bar and system tray. +Cross-platform application window creation library in Rust that supports all major platforms like Windows, macOS, Linux, iOS and Android. Written in Rust, it is a fork of [winit](https://github.com/rust-windowing/winit) that we have extended for our own needs like menu bar and system tray. ## [WRY](https://github.com/tauri-apps/wry) + WRY is a cross-platform WebView rendering library in Rust that supports all major desktop platforms like Windows, macOS, and Linux. Tauri uses WRY as the abstract layer responsible to determine which webview is used (and how interactions are made). # Additional tooling -## [binary-releases](https://github.com/tauri-apps/binary-releases) -This is the delivery mechanism for tauri prebuilt binaries: currently the cli.rs (used by cli.js) and rustup binaries (used by the deps install command of cli.js). These artifacts are automatically created on release. - ## [tauri-action](https://github.com/tauri-apps/tauri-action) + This is a github workflow that builds tauri binaries for all platforms. It is not the fastest out there, but it gets the job done and is highly configurable. Even allowing you to create a (very basic) tauri app even if tauri is not setup. ## [create-pull-request](https://github.com/tauri-apps/create-pull-request) + Because this is a very risky (potentially destructive) github action, we forked it in order to have strong guarantees that the code we think is running is actually the code that is running. ## [vue-cli-plugin-tauri](https://github.com/tauri-apps/vue-cli-plugin-tauri) + This plugin allows you to very quickly install tauri in a vue-cli project. ## [tauri-vscode](https://github.com/tauri-apps/tauri-vscode) + This project enhances the VS Code interface with several nice-to-have features. -# Tauri Plugins [documentation](https://tauri.studio/en/docs/guides/plugin) +# Tauri Plugins [documentation](https://v2.tauri.app/develop/plugins/) Generally speaking, plugins are authored by third parties (even though there may be official, supported plugins). A plugin generally does 3 things: + 1. It provides rust code to do "something". 2. It provides interface glue to make it easy to integrate into an app. 3. It provides a JS API for interfacing with the rust code. Here are several examples of Tauri Plugins: -- https://github.com/tauri-apps/tauri-plugin-sql -- https://github.com/tauri-apps/tauri-plugin-stronghold -- https://github.com/tauri-apps/tauri-plugin-authenticator + +- +- +- # Workflows + ## What does the Development flow look like? + A developer must first install the prerequisite toolchains for creating a Tauri app. At the very least this will entail installing rust & cargo, and most likely also a modern version of node.js and potentially another package manager. Some platforms may also require other tooling and libraries, but this has been documented carefully in the respective platform docs. Because of the many ways to build front-ends, we will stick with a common node.js based approach for development. (Note: Tauri does not by default ship a node.js runtime.) The easiest way to do this is to run the following: + ``` -npx create-tauri-app +npm create tauri-app ``` Which will ask you a bunch of questions about the framework you want to install and then create everything you need in a single folder - some via the placement of template files and some through normal installation procedures of your framework. @@ -109,16 +136,21 @@ Which will ask you a bunch of questions about the framework you want to install > If you don't use this process, you will have to manually install the tauri cli, initialise tauri and manually configure the `tauri.conf.json` file. Once everything is installed, you can run: + ``` +pnpm tauri dev +-or- yarn tauri dev -or- npm run tauri dev ``` + This will do several things: + 1. start the JS Framework devserver 2. begin the long process of downloading and compiling the rust libraries 3. open an application window with devtools enabled -4. keep a long-lived console alive +4. keep a long-lived console alive If you change your HTML/CSS/TS/JS, your framework devserver should give you its best shot at instant hot module reloading and you will see the changes instantly. @@ -127,10 +159,9 @@ If you modify your rust code or anything in the Cargo.toml, the window will clos If you need to get deeper insight into your current project, or triage requires investigation of installed components, just run: ``` -yarn tauri info +pnpm tauri info ``` - ## What does the Release flow look like? The release flow begins with proper configuration in the `tauri.conf.json` file. In this file, the developer can configure not only the basic behaviour of the application (like window size and decoration), they can also provide settings for signing and updating. @@ -138,21 +169,25 @@ The release flow begins with proper configuration in the `tauri.conf.json` file. Depending upon the operating system that the developer (or CI) is building the application on, there will be an app built for them for that system. (Cross compilation is not currently available, however there is an official [GitHub Action](https://github.com/tauri-apps/tauri-action) that can be used to build for all platforms.) To kick off this process, just: + ``` -yarn tauri build +pnpm tauri build ``` After some time, the process will end and you can see the results in the `./src-tauri/target/release` folder. ## What does the End-User flow look like? + End users will be provided with binaries in ways that are appropriate for their systems. Whether macOS, Linux, or Windows, direct download or store installations - they will be able to follow procedures for installing and removing that they are used to. ## What does the Updating flow look like? -When a new version is ready, the developer publishes the new signed artifacts to a server (that they have configured within `tauri.conf.json`). + +When a new version is ready, the developer publishes the new signed artifacts to a server (that they have configured within `tauri.conf.json`). The application can poll this server to see if there is a new release. When there is a new release, the user is prompted to update. The application update is downloaded, verified (checksum & signature), updated, closed, and restarted. ## License + Tauri itself is licensed under MIT or Apache-2.0. If you repackage it and modify any source code, it is your responsibility to verify that you are complying with all upstream licenses. Tauri is provided AS-IS with no explicit claim for suitability for any purpose. Here you may peruse our [Software Bill of Materials](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri). diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 000000000000..3f73948c1b92 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,11662 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + +[[package]] +name = "acl-tests" +version = "0.1.0" +dependencies = [ + "insta", + "serde_json", + "tauri-utils 2.1.0", +] + +[[package]] +name = "addr2line" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "ghash", + "subtle", +] + +[[package]] +name = "ahash" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "getrandom 0.2.15", + "once_cell", + "serde", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "aligned-vec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa90d7ce82d4be67b64039a3d588d38dbcc6736577de4a847025ce5b0c468d1" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + +[[package]] +name = "allocator-api2" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_log-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ecc8056bf6ab9892dcd53216c83d1597487d7dacac16c8df6b877d127df9937" + +[[package]] +name = "android_logger" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b07e8e73d720a1f2e4b6014766e6039fd2e96a4fa44e2a78d0e1fa2ff49826" +dependencies = [ + "android_log-sys", + "env_filter", + "log", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.94" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" + +[[package]] +name = "api" +version = "0.1.0" +dependencies = [ + "log", + "serde", + "serde_json", + "tauri", + "tauri-build", + "tauri-plugin-log", + "tauri-plugin-sample", + "tiny_http", +] + +[[package]] +name = "app-store-connect" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33fb5489b9bfcfa3aec2f68cc79eafb999b5af9b9d9d70ca8dfe36acdd1b2b05" +dependencies = [ + "anyhow", + "base64 0.21.7", + "clap", + "dirs", + "env_logger 0.10.2", + "jsonwebtoken", + "log", + "pem", + "rand 0.8.5", + "reqwest 0.11.27", + "rsa", + "serde", + "serde_json", + "thiserror 1.0.68", + "x509-certificate", +] + +[[package]] +name = "apple-bundles" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb7c27ee2ca7826adfdc84228cd4c5a84ab57b0a11d269d1d7cd0615238e5a2" +dependencies = [ + "anyhow", + "plist", + "simple-file-manifest", + "walkdir", +] + +[[package]] +name = "apple-codesign" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "329820aac7259ca0529d3cc21dd3b4c11651225dfce9e0ce25b121b23f923164" +dependencies = [ + "anyhow", + "app-store-connect", + "apple-bundles", + "apple-flat-package", + "apple-xar", + "aws-config", + "aws-sdk-s3", + "aws-smithy-http", + "aws-smithy-types", + "base64 0.21.7", + "bcder", + "bitflags 2.6.0", + "bytes", + "chrono", + "clap", + "cryptographic-message-syntax", + "der 0.7.9", + "dialoguer", + "difference", + "digest", + "dirs", + "elliptic-curve 0.13.8", + "env_logger 0.10.2", + "figment", + "filetime", + "glob", + "goblin", + "hex", + "log", + "md-5", + "minicbor", + "num-traits", + "object 0.32.2", + "oid-registry", + "once_cell", + "p12", + "p256 0.13.2", + "pem", + "pkcs1", + "pkcs8 0.10.2", + "plist", + "rand 0.8.5", + "rasn", + "rayon", + "regex", + "reqwest 0.11.27", + "ring", + "rsa", + "scroll", + "security-framework", + "security-framework-sys", + "semver", + "serde", + "serde_json", + "serde_yaml", + "sha2", + "signature 2.2.0", + "simple-file-manifest", + "spake2", + "spki 0.7.3", + "subtle", + "tempfile", + "thiserror 1.0.68", + "tokio", + "tungstenite 0.21.0", + "uuid", + "walkdir", + "widestring", + "windows-sys 0.52.0", + "x509", + "x509-certificate", + "xml-rs", + "yasna", + "zeroize", + "zip 0.6.6", + "zip_structs", +] + +[[package]] +name = "apple-flat-package" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6adc520e05304de5ec383487786fa20e9c636fe972e59719cdd93621a2db6f1" +dependencies = [ + "apple-xar", + "cpio-archive", + "flate2", + "scroll", + "serde", + "serde-xml-rs", + "thiserror 1.0.68", +] + +[[package]] +name = "apple-xar" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "844e00dc1e665b3cf0bba745aa9c6464292ca512db0c11384511586701eb0335" +dependencies = [ + "base64 0.21.7", + "bcder", + "bzip2", + "chrono", + "cryptographic-message-syntax", + "digest", + "flate2", + "log", + "md-5", + "rand 0.8.5", + "reqwest 0.11.27", + "scroll", + "serde", + "serde-xml-rs", + "sha1", + "sha2", + "signature 2.2.0", + "thiserror 1.0.68", + "url", + "x509-certificate", + "xml-rs", + "xz2", +] + +[[package]] +name = "ar" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d67af77d68a931ecd5cbd8a3b5987d63a1d1d1278f7f6a60ae33db485cdebb69" + +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + +[[package]] +name = "arg_enum_proc_macro" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror 1.0.68", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure 0.12.6", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "assert-unchecked" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7330592adf847ee2e3513587b4db2db410a0d751378654e7e993d9adcbe5c795" + +[[package]] +name = "async-trait" +version = "0.1.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "atk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4af014b17dd80e8af9fa689b2d4a211ddba6eb583c1622f35d0cb543f6b17e4" +dependencies = [ + "atk-sys", + "glib", + "libc", +] + +[[package]] +name = "atk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "251e0b7d90e33e0ba930891a505a9a35ece37b2dd37a14f3ffc306c13b980009" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "atomic" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "av1-grain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6678909d8c5d46a42abcf571271e15fdbc0a225e3646cf23762cd415046c78bf" +dependencies = [ + "anyhow", + "arrayvec", + "log", + "nom", + "num-rational", + "v_frame", +] + +[[package]] +name = "avif-serialize" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876c75a42f6364451a033496a14c44bffe41f5f4a8236f697391f11024e596d2" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "aws-config" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e95816a168520d72c0e7680c405a5a8c1fb6a035b4bc4b9d7b0de8e1a941697" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-sdk-sso", + "aws-sdk-ssooidc", + "aws-sdk-sts", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "hex", + "http 0.2.12", + "ring", + "time", + "tokio", + "tracing", + "url", + "zeroize", +] + +[[package]] +name = "aws-credential-types" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e8f6b615cb5fc60a98132268508ad104310f0cfb25a1c22eee76efdf9154da" +dependencies = [ + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "zeroize", +] + +[[package]] +name = "aws-runtime" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a10d5c055aa540164d9561a0e2e74ad30f0dcf7393c3a92f6733ddf9c5762468" +dependencies = [ + "aws-credential-types", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "fastrand", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "tracing", + "uuid", +] + +[[package]] +name = "aws-sdk-s3" +version = "1.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abf69a87be33b6f125a93d5046b5f7395c26d1f449bf8d3927f5577463b6de0" +dependencies = [ + "ahash 0.8.11", + "aws-credential-types", + "aws-runtime", + "aws-sigv4", + "aws-smithy-async", + "aws-smithy-checksums", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "bytes", + "fastrand", + "hex", + "hmac", + "http 0.2.12", + "http-body 0.4.6", + "lru", + "once_cell", + "percent-encoding", + "regex-lite", + "sha2", + "tracing", + "url", +] + +[[package]] +name = "aws-sdk-sso" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11822090cf501c316c6f75711d77b96fba30658e3867a7762e5e2f5d32d31e81" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-ssooidc" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78a2a06ff89176123945d1bbe865603c4d7101bea216a550bb4d2e4e9ba74d74" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-types", + "bytes", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sdk-sts" +version = "1.39.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a20a91795850826a6f456f4a48eff1dfa59a0e69bdbf5b8c50518fd372106574" +dependencies = [ + "aws-credential-types", + "aws-runtime", + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-json", + "aws-smithy-query", + "aws-smithy-runtime", + "aws-smithy-runtime-api", + "aws-smithy-types", + "aws-smithy-xml", + "aws-types", + "http 0.2.12", + "once_cell", + "regex-lite", + "tracing", +] + +[[package]] +name = "aws-sigv4" +version = "1.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc8db6904450bafe7473c6ca9123f88cc11089e41a025408f992db4e22d3be68" +dependencies = [ + "aws-credential-types", + "aws-smithy-eventstream", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "crypto-bigint 0.5.5", + "form_urlencoded", + "hex", + "hmac", + "http 0.2.12", + "http 1.1.0", + "once_cell", + "p256 0.11.1", + "percent-encoding", + "ring", + "sha2", + "subtle", + "time", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-async" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62220bc6e97f946ddd51b5f1361f78996e704677afc518a4ff66b7a72ea1378c" +dependencies = [ + "futures-util", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "aws-smithy-checksums" +version = "0.60.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598b1689d001c4d4dc3cb386adb07d37786783aee3ac4b324bcadac116bf3d23" +dependencies = [ + "aws-smithy-http", + "aws-smithy-types", + "bytes", + "crc32c", + "crc32fast", + "hex", + "http 0.2.12", + "http-body 0.4.6", + "md-5", + "pin-project-lite", + "sha1", + "sha2", + "tracing", +] + +[[package]] +name = "aws-smithy-eventstream" +version = "0.60.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cef7d0a272725f87e51ba2bf89f8c21e4df61b9e49ae1ac367a6d69916ef7c90" +dependencies = [ + "aws-smithy-types", + "bytes", + "crc32fast", +] + +[[package]] +name = "aws-smithy-http" +version = "0.60.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8bc3e8fdc6b8d07d976e301c02fe553f72a39b7a9fea820e023268467d7ab6" +dependencies = [ + "aws-smithy-eventstream", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http-body 0.4.6", + "once_cell", + "percent-encoding", + "pin-project-lite", + "pin-utils", + "tracing", +] + +[[package]] +name = "aws-smithy-json" +version = "0.60.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4683df9469ef09468dad3473d129960119a0d3593617542b7d52086c8486f2d6" +dependencies = [ + "aws-smithy-types", +] + +[[package]] +name = "aws-smithy-query" +version = "0.60.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fbd61ceb3fe8a1cb7352e42689cec5335833cd9f94103a61e98f9bb61c64bb" +dependencies = [ + "aws-smithy-types", + "urlencoding", +] + +[[package]] +name = "aws-smithy-runtime" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be28bd063fa91fd871d131fc8b68d7cd4c5fa0869bea68daca50dcb1cbd76be2" +dependencies = [ + "aws-smithy-async", + "aws-smithy-http", + "aws-smithy-runtime-api", + "aws-smithy-types", + "bytes", + "fastrand", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "http-body 1.0.1", + "httparse", + "hyper 0.14.30", + "hyper-rustls 0.24.2", + "once_cell", + "pin-project-lite", + "pin-utils", + "rustls 0.21.12", + "tokio", + "tracing", +] + +[[package]] +name = "aws-smithy-runtime-api" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e086682a53d3aa241192aa110fa8dfce98f2f5ac2ead0de84d41582c7e8fdb96" +dependencies = [ + "aws-smithy-async", + "aws-smithy-types", + "bytes", + "http 0.2.12", + "http 1.1.0", + "pin-project-lite", + "tokio", + "tracing", + "zeroize", +] + +[[package]] +name = "aws-smithy-types" +version = "1.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fbd94a32b3a7d55d3806fe27d98d3ad393050439dd05eb53ece36ec5e3d3510" +dependencies = [ + "base64-simd", + "bytes", + "bytes-utils", + "futures-core", + "http 0.2.12", + "http 1.1.0", + "http-body 0.4.6", + "http-body 1.0.1", + "http-body-util", + "itoa 1.0.11", + "num-integer", + "pin-project-lite", + "pin-utils", + "ryu", + "serde", + "time", + "tokio", + "tokio-util", +] + +[[package]] +name = "aws-smithy-xml" +version = "0.60.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab0b0166827aa700d3dc519f72f8b3a91c35d0b8d042dc5d643a91e6f80648fc" +dependencies = [ + "xmlparser", +] + +[[package]] +name = "aws-types" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5221b91b3e441e6675310829fd8984801b772cb1546ef6c0e54dec9f1ac13fef" +dependencies = [ + "aws-credential-types", + "aws-smithy-async", + "aws-smithy-runtime-api", + "aws-smithy-types", + "rustc_version", + "tracing", +] + +[[package]] +name = "axum" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +dependencies = [ + "async-trait", + "axum-core", + "base64 0.22.1", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "itoa 1.0.11", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sha1", + "sync_wrapper 1.0.1", + "tokio", + "tokio-tungstenite", + "tower 0.5.1", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper 1.0.1", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "backtrace" +version = "0.3.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" +dependencies = [ + "addr2line", + "cfg-if", + "libc", + "miniz_oxide 0.8.0", + "object 0.36.5", + "rustc-demangle", + "windows-targets 0.52.6", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64-simd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339abbe78e73178762e23bea9dfd08e697eb3f3301cd4be981c0f78ba5859195" +dependencies = [ + "outref", + "vsimd", +] + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bcder" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c627747a6774aab38beb35990d88309481378558875a41da1a4b2e373c906ef0" +dependencies = [ + "bytes", + "smallvec", +] + +[[package]] +name = "bench_cpu_intensive" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "bench_files_transfer" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "bench_helloworld" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" + +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] + +[[package]] +name = "bitness" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57792b99d555ebf109c83169228076f7d997e2b37ba1a653850ccd703ac7bab0" +dependencies = [ + "sysctl", + "thiserror 1.0.68", + "uname", + "winapi", +] + +[[package]] +name = "bitstream-io" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c12d1856e42f0d817a835fe55853957c85c8c8a470114029143d3f12671446e" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "bitvec-nom2" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d988fcc40055ceaa85edc55875a08f8abd29018582647fd82ad6128dba14a5f0" +dependencies = [ + "bitvec", + "nom", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.90", + "syn_derive", +] + +[[package]] +name = "brotli" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + +[[package]] +name = "bstr" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40723b8fb387abc38f4f4a37c09073622e41dd12327033091ef8950659e6dc0c" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "buffer-redux" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e8acf87c5b9f5897cd3ebb9a327f420e0cae9dd4e5c1d2e36f2c84c571a58f1" +dependencies = [ + "memchr", +] + +[[package]] +name = "built" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "236e6289eda5a812bc6b53c3b024039382a2895fbbeef2d748b2931546d392c4" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "byte-unit" +version = "5.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ac19bdf0b2665407c39d82dbc937e951e7e2001609f0fb32edd0af45a2d63e" +dependencies = [ + "rust_decimal", + "serde", + "utf8-width", +] + +[[package]] +name = "bytecheck" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23cdc57ce23ac53c931e88a43d06d070a6fd142f2617be5855eb75efc9beb1c2" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db406d29fbcd95542e92559bed4d8ad92636d1ca8b3b72ede10b4bcc010e659" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytecount" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" + +[[package]] +name = "bytemuck" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94bbb0ad554ad961ddc5da507a12a29b14e4ae5bda06b19f575a3e6079d2e2ae" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +dependencies = [ + "serde", +] + +[[package]] +name = "bytes-utils" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dafe3a8757b027e2be6e4e5601ed563c55989fcf1546e933c66c8eb3a058d35" +dependencies = [ + "bytes", + "either", +] + +[[package]] +name = "bytesize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc" + +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "cairo-rs" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca26ef0159422fb77631dc9d17b102f253b876fe1586b03b803e63a309b4ee2" +dependencies = [ + "bitflags 2.6.0", + "cairo-sys-rs", + "glib", + "libc", + "once_cell", + "thiserror 1.0.68", +] + +[[package]] +name = "cairo-sys-rs" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685c9fa8e590b8b3d678873528d83411db17242a73fccaed827770ea0fedda51" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "camino" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-mobile2" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c8052fc43184dc6c572437c2f8dae83e4ca9a5b27c790e269b90b080c1b9301" +dependencies = [ + "colored", + "core-foundation 0.10.0", + "deunicode", + "duct", + "dunce", + "embed-resource", + "english-numbers", + "freedesktop_entry_parser", + "handlebars", + "heck 0.5.0", + "home", + "ignore", + "java-properties", + "libc", + "log", + "once-cell-regex", + "os_info", + "os_pipe", + "path_abs", + "serde", + "serde_json", + "textwrap", + "thiserror 1.0.68", + "toml 0.8.19", + "ureq", + "which 6.0.3", + "windows", + "x509-certificate", +] + +[[package]] +name = "cargo-platform" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "cargo_toml" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a969e13a7589e9e3e4207e153bae624ade2b5622fb4684a4923b23ec3d57719" +dependencies = [ + "serde", + "toml 0.8.19", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + +[[package]] +name = "castaway" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" +dependencies = [ + "rustversion", +] + +[[package]] +name = "cbc" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b52a9543ae338f279b96b0b9fed9c8093744685043739079ce85cd58f289a6" +dependencies = [ + "cipher", +] + +[[package]] +name = "cc" +version = "1.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" +dependencies = [ + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfb" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f" +dependencies = [ + "byteorder", + "fnv", + "uuid", +] + +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + +[[package]] +name = "cfg-expr" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02" +dependencies = [ + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", + "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.6", +] + +[[package]] +name = "chunked_transfer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e4de3bc4ea267985becf712dc6d9eed8b04c953b3fcfb339ebc87acd9804901" + +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "clap" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_complete" +version = "4.5.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_derive" +version = "4.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "cmac" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" +dependencies = [ + "cipher", + "dbl", + "digest", +] + +[[package]] +name = "cocoa" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6140449f97a6e97f9511815c5632d84c8aacf8ac271ad77c559218161a1373c" +dependencies = [ + "bitflags 1.3.2", + "block", + "cocoa-foundation 0.1.2", + "core-foundation 0.9.4", + "core-graphics 0.23.2", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2" +dependencies = [ + "bitflags 2.6.0", + "block", + "cocoa-foundation 0.2.0", + "core-foundation 0.10.0", + "core-graphics 0.24.0", + "foreign-types 0.5.0", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c6234cbb2e4c785b456c0644748b1ac416dd045799740356f8363dfe00c93f7" +dependencies = [ + "bitflags 1.3.2", + "block", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "libc", + "objc", +] + +[[package]] +name = "cocoa-foundation" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d" +dependencies = [ + "bitflags 2.6.0", + "block", + "core-foundation 0.10.0", + "core-graphics-types 0.2.0", + "libc", + "objc", +] + +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys 0.48.0", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "common-path" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2382f75942f4b3be3690fe4f86365e9c853c1587d6ee58212cebf6e2a9ccd101" + +[[package]] +name = "compact_str" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6050c3a16ddab2e412160b31f2c871015704239bca62f72f6e5f0be631d3f644" +dependencies = [ + "castaway", + "cfg-if", + "itoa 1.0.11", + "rustversion", + "ryu", + "static_assertions", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "const_panic" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "013b6c2c3a14d678f38cd23994b02da3a1a1b6a5d1eedddfe63a5a5f11b13a81" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "cookie" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" +dependencies = [ + "time", + "version_check", +] + +[[package]] +name = "cookie-factory" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9885fa71e26b8ab7855e2ec7cae6e9b380edff76cd052e07c683a0319d51b3a2" +dependencies = [ + "futures", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types 0.1.3", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", + "core-graphics-types 0.2.0", + "foreign-types 0.5.0", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.10.0", + "libc", +] + +[[package]] +name = "core_maths" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b02505ccb8c50b0aa21ace0fc08c3e53adebd4e58caa18a36152803c7709a3" +dependencies = [ + "libm", +] + +[[package]] +name = "cpio" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e3adec7390c7643049466136117057188edf5f23efc5c8b4fc8079c8dc34a6" + +[[package]] +name = "cpio-archive" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63d5133d716d3d82da8c76367ddb0ab1733e2629f1462e4f39947e13b8b4b741" +dependencies = [ + "chrono", + "is_executable", + "simple-file-manifest", + "thiserror 1.0.68", +] + +[[package]] +name = "cpufeatures" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +dependencies = [ + "libc", +] + +[[package]] +name = "crc24" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" + +[[package]] +name = "crc32c" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a47af21622d091a8f0fb295b88bc886ac74efcc613efc19f5d0b21de5c89e47" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "cryptographic-message-syntax" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c324ba1028cef7e3a71a00cbf585637bb0215dec2f6a2b566d094190a1309b" +dependencies = [ + "bcder", + "bytes", + "chrono", + "hex", + "pem", + "reqwest 0.11.27", + "ring", + "signature 2.2.0", + "x509-certificate", +] + +[[package]] +name = "css-color" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42aaeae719fd78ce501d77c6cdf01f7e96f26bcd5617a4903a1c2b97e388543a" + +[[package]] +name = "cssparser" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" +dependencies = [ + "cssparser-macros", + "dtoa-short", + "itoa 0.4.8", + "matches", + "phf 0.8.0", + "proc-macro2", + "quote", + "smallvec", + "syn 1.0.109", +] + +[[package]] +name = "cssparser-macros" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" +dependencies = [ + "quote", + "syn 2.0.90", +] + +[[package]] +name = "ctor" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edb49164822f3ee45b17acd4a208cfc1251410cf0cad9a833234c9890774dd9f" +dependencies = [ + "quote", + "syn 2.0.90", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "darling" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.90", +] + +[[package]] +name = "darling_macro" +version = "0.20.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "data-encoding" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" + +[[package]] +name = "data-url" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c297a1c74b71ae29df00c3e22dd9534821d60eb9af5a0192823fa2acea70c2a" + +[[package]] +name = "dbl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" +dependencies = [ + "generic-array", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "der" +version = "0.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "derive_builder" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +dependencies = [ + "derive_builder_core", + "syn 2.0.90", +] + +[[package]] +name = "derive_more" +version = "0.99.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" +dependencies = [ + "convert_case 0.4.0", + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.90", +] + +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + +[[package]] +name = "deunicode" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "339544cc9e2c4dc3fc7149fd630c5f22263a4fdf18a98afd0075784968b5cf00" + +[[package]] +name = "dialoguer" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" +dependencies = [ + "console", + "shell-words", + "tempfile", + "thiserror 1.0.68", + "zeroize", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "difference" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-next" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +dependencies = [ + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "dlopen2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1297103d2bbaea85724fcee6294c2d50b1081f9ad47d0f6f6f61eda65315a6" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b99bf03862d7f545ebc28ddd33a665b50865f4dfd84031a393823879bd4c54" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "doc-comment" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" + +[[package]] +name = "dpi" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f25c0e292a7ca6d6498557ff1df68f32c99850012b6ea401cf8daf771f22ff53" +dependencies = [ + "serde", +] + +[[package]] +name = "dsa" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8 0.10.2", + "rfc6979 0.4.0", + "sha2", + "signature 2.2.0", + "zeroize", +] + +[[package]] +name = "dtoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" + +[[package]] +name = "dtoa-short" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd1511a7b6a56299bd043a9c167a6d2bfb37bf84a6dfceaba651168adfb43c87" +dependencies = [ + "dtoa", +] + +[[package]] +name = "duct" +version = "0.13.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4ab5718d1224b63252cd0c6f74f6480f9ffeb117438a2e0f5cf6d9a4798929c" +dependencies = [ + "libc", + "once_cell", + "os_pipe", + "shared_child", +] + +[[package]] +name = "dunce" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" + +[[package]] +name = "dyn-clone" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" + +[[package]] +name = "eax" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" +dependencies = [ + "aead", + "cipher", + "cmac", + "ctr", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der 0.6.1", + "elliptic-curve 0.12.3", + "rfc6979 0.3.1", + "signature 1.6.4", +] + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der 0.7.9", + "digest", + "elliptic-curve 0.13.8", + "rfc6979 0.4.0", + "signature 2.2.0", + "spki 0.7.3", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8 0.10.2", + "signature 2.2.0", +] + +[[package]] +name = "ed25519-dalek" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" +dependencies = [ + "curve25519-dalek", + "ed25519", + "serde", + "sha2", + "subtle", + "zeroize", +] + +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct 0.1.1", + "crypto-bigint 0.4.9", + "der 0.6.1", + "digest", + "ff 0.12.1", + "generic-array", + "group 0.12.1", + "pkcs8 0.9.0", + "rand_core 0.6.4", + "sec1 0.3.0", + "subtle", + "zeroize", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct 0.2.0", + "crypto-bigint 0.5.5", + "digest", + "ff 0.13.0", + "generic-array", + "group 0.13.0", + "hkdf", + "pem-rfc7468", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "sec1 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "embed-resource" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e24052d7be71f0efb50c201557f6fe7d237cfd5a64fd5bcd7fd8fe32dbbffa" +dependencies = [ + "cc", + "memchr", + "rustc_version", + "toml 0.8.19", + "vswhom", + "winreg 0.52.0", +] + +[[package]] +name = "embed_plist" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" + +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "english-numbers" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4f5d6e192964d498b45abee72ca445e91909094bc8e8791259e82c2a0d1aa6" + +[[package]] +name = "enum-display-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f16ef37b2a9b242295d61a154ee91ae884afff6b8b933b486b12481cc58310ca" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "enum-primitive-derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba7795da175654fe16979af73f81f26a8ea27638d8d9823d317016888a63dc4c" +dependencies = [ + "num-traits", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "env_filter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2c92ceda6ceec50f43169f9ee8424fe2db276791afde7b2cd8bc084cb376ab" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580" +dependencies = [ + "humantime", + "is-terminal", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "erased-serde" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +dependencies = [ + "serde", + "typeid", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "exr" +version = "1.72.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "887d93f60543e9a9362ef8a21beedd0a833c5d9610e18c67abe15a5963dcb1a4" +dependencies = [ + "bit_field", + "flume", + "half", + "lebe", + "miniz_oxide 0.7.4", + "rayon-core", + "smallvec", + "zune-inflate", +] + +[[package]] +name = "fancy-regex" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2" +dependencies = [ + "bit-set", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + +[[package]] +name = "fdeflate" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8090f921a24b04994d9929e204f50b498a33ea6ba559ffaa05e04f7ee7fb5ab" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "fern" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9f0c14694cbd524c8720dd69b0e3179344f04ebb5f90f2e4a440c6ea3b2f1ee" +dependencies = [ + "log", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "field-offset" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38e2275cc4e4fc009b0669731a1e5ab7ebf11f469eaede2bab9309a5b4d6057f" +dependencies = [ + "memoffset", + "rustc_version", +] + +[[package]] +name = "figment" +version = "0.10.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb01cd46b0cf372153850f4c6c272d9cbea2da513e07538405148f95bd789f3" +dependencies = [ + "atomic", + "pear", + "serde", + "toml 0.8.19", + "uncased", + "version_check", +] + +[[package]] +name = "filetime" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" +dependencies = [ + "cfg-if", + "libc", + "libredox", + "windows-sys 0.59.0", +] + +[[package]] +name = "flate2" +version = "1.0.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1b589b4dc103969ad3cf85c950899926ec64300a1a46d76c03a6072957036f0" +dependencies = [ + "crc32fast", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" + +[[package]] +name = "fluent-uri" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17c704e9dbe1ddd863da1e6ff3567795087b1eb201ce80d8fa81162e1516500d" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "flume" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ac459de2512911e4b674ce33cf20befaba382d05b62b008afc1c8b57cbf181" +dependencies = [ + "spin", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "fontconfig-parser" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1fcfcd44ca6e90c921fee9fa665d530b21ef1327a4c1a6c5250ea44b776ada7" +dependencies = [ + "roxmltree", +] + +[[package]] +name = "fontdb" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37be9fc20d966be438cd57a45767f73349477fb0f85ce86e000557f787298afb" +dependencies = [ + "fontconfig-parser", + "log", + "memmap2", + "slotmap", + "tinyvec", + "ttf-parser", +] + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared 0.1.1", +] + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared 0.3.1", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fraction" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f158e3ff0a1b334408dc9fb811cd99b446986f4d8b741bb08f9df1604085ae7" +dependencies = [ + "lazy_static", + "num", +] + +[[package]] +name = "freedesktop_entry_parser" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db9c27b72f19a99a895f8ca89e2d26e4ef31013376e56fdafef697627306c3e4" +dependencies = [ + "nom", + "thiserror 1.0.68", +] + +[[package]] +name = "fsevent-sys" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2" +dependencies = [ + "libc", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" +dependencies = [ + "mac", + "new_debug_unreachable", +] + +[[package]] +name = "futures" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-executor" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "futures-sink" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" + +[[package]] +name = "futures-task" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" + +[[package]] +name = "futures-util" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gdk" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5ba081bdef3b75ebcdbfc953699ed2d7417d6bd853347a42a37d76406a33646" +dependencies = [ + "cairo-rs", + "gdk-pixbuf", + "gdk-sys", + "gio", + "glib", + "libc", + "pango", +] + +[[package]] +name = "gdk-pixbuf" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50e1f5f1b0bfb830d6ccc8066d18db35c487b1b2b1e8589b5dfe9f07e8defaec" +dependencies = [ + "gdk-pixbuf-sys", + "gio", + "glib", + "libc", + "once_cell", +] + +[[package]] +name = "gdk-pixbuf-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9839ea644ed9c97a34d129ad56d38a25e6756f99f3a88e15cd39c20629caf7" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "gdk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31ff856cb3386dae1703a920f803abafcc580e9b5f711ca62ed1620c25b51ff2" +dependencies = [ + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkwayland-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a90fbf5c033c65d93792192a49a8efb5bb1e640c419682a58bb96f5ae77f3d4a" +dependencies = [ + "gdk-sys", + "glib-sys", + "gobject-sys", + "libc", + "pkg-config", + "system-deps", +] + +[[package]] +name = "gdkx11" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2ea8a4909d530f79921290389cbd7c34cb9d623bfe970eaae65ca5f9cd9cce" +dependencies = [ + "gdk", + "gdkx11-sys", + "gio", + "glib", + "libc", + "x11", +] + +[[package]] +name = "gdkx11-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee8f00f4ee46cad2939b8990f5c70c94ff882c3028f3cc5abf950fa4ab53043" +dependencies = [ + "gdk-sys", + "glib-sys", + "libc", + "system-deps", + "x11", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "ghash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" +dependencies = [ + "opaque-debug", + "polyval", +] + +[[package]] +name = "gif" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fb2d69b19215e18bb912fa30f7ce15846e301408695e44e0ef719f1da9e19f2" +dependencies = [ + "color_quant", + "weezl", +] + +[[package]] +name = "gimli" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" + +[[package]] +name = "gio" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fc8f532f87b79cbc51a79748f16a6828fb784be93145a322fa14d06d354c73" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-util", + "gio-sys", + "glib", + "libc", + "once_cell", + "pin-project-lite", + "smallvec", + "thiserror 1.0.68", +] + +[[package]] +name = "gio-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37566df850baf5e4cb0dfb78af2e4b9898d817ed9263d1090a2df958c64737d2" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", + "winapi", +] + +[[package]] +name = "glib" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5" +dependencies = [ + "bitflags 2.6.0", + "futures-channel", + "futures-core", + "futures-executor", + "futures-task", + "futures-util", + "gio-sys", + "glib-macros", + "glib-sys", + "gobject-sys", + "libc", + "memchr", + "once_cell", + "smallvec", + "thiserror 1.0.68", +] + +[[package]] +name = "glib-macros" +version = "0.18.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb0228f477c0900c880fd78c8759b95c7636dbd7842707f49e132378aa2acdc" +dependencies = [ + "heck 0.4.1", + "proc-macro-crate 2.0.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "glib-sys" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063ce2eb6a8d0ea93d2bf8ba1957e78dbab6be1c2220dd3daca57d5a9d869898" +dependencies = [ + "libc", + "system-deps", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "gobject-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0850127b514d1c4a4654ead6dedadb18198999985908e6ffe4436f53c785ce44" +dependencies = [ + "glib-sys", + "libc", + "system-deps", +] + +[[package]] +name = "goblin" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" +dependencies = [ + "log", + "plain", + "scroll", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff 0.13.0", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "gtk" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93c4f5e0e20b60e10631a5f06da7fe3dda744b05ad0ea71fee2f47adf865890c" +dependencies = [ + "atk", + "cairo-rs", + "field-offset", + "futures-channel", + "gdk", + "gdk-pixbuf", + "gio", + "glib", + "gtk-sys", + "gtk3-macros", + "libc", + "pango", + "pkg-config", +] + +[[package]] +name = "gtk-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771437bf1de2c1c0b496c11505bdf748e26066bbe942dfc8f614c9460f6d7722" +dependencies = [ + "atk-sys", + "cairo-sys-rs", + "gdk-pixbuf-sys", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "pango-sys", + "system-deps", +] + +[[package]] +name = "gtk3-macros" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6063efb63db582968fb7df72e1ae68aa6360dcfb0a75143f34fc7d616bad75e" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "h2" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e8ac6999421f49a846c2d4411f337e53497d8ec55d67753beffa43c5d9205" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http 1.1.0", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" +dependencies = [ + "cfg-if", + "crunchy", +] + +[[package]] +name = "handlebars" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315" +dependencies = [ + "log", + "num-order", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +dependencies = [ + "ahash 0.8.11", + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hermit-abi" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf6a919d6cf397374f7dfeeea91d974c7c0a7221d0d0f4f20d859d329e53fcc" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "html5ever" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bea68cab48b8459f17cf1c944c67ddc572d272d9f2b274140f223ecb1da4a3b7" +dependencies = [ + "log", + "mac", + "markup5ever", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.11", +] + +[[package]] +name = "http" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b9ddb458710bc376481b842f5da65cdf31522de232c1ca8146abce2a358258" +dependencies = [ + "bytes", + "fnv", + "itoa 1.0.11", +] + +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + +[[package]] +name = "http-body" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.1.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" +dependencies = [ + "bytes", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "pin-project-lite", +] + +[[package]] +name = "http-range" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" + +[[package]] +name = "httparse" +version = "1.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" + +[[package]] +name = "httpdate" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa 1.0.11", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "h2 0.4.6", + "http 1.1.0", + "http-body 1.0.1", + "httparse", + "httpdate", + "itoa 1.0.11", + "pin-project-lite", + "smallvec", + "tokio", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http 0.2.12", + "hyper 0.14.30", + "log", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.27.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.4.1", + "hyper-util", + "rustls 0.23.13", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.26.0", + "tower-service", + "webpki-roots 0.26.6", +] + +[[package]] +name = "hyper-tls" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" +dependencies = [ + "bytes", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "native-tls", + "tokio", + "tokio-native-tls", + "tower-service", +] + +[[package]] +name = "hyper-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" +dependencies = [ + "bytes", + "futures-channel", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.4.1", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core 0.52.0", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ico" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3804960be0bb5e4edb1e1ad67afd321a9ecfd875c3e65c099468fd2717d7cae" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "icu_collections" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_locid_transform" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_locid_transform_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_locid_transform_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdc8ff3388f852bede6b579ad4e978ab004f139284d7b28715f773507b946f6e" + +[[package]] +name = "icu_normalizer" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "utf16_iter", + "utf8_iter", + "write16", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8cafbf7aa791e9b22bec55a167906f9e1215fd475cd22adfcf660e03e989516" + +[[package]] +name = "icu_properties" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" +dependencies = [ + "displaydoc", + "icu_collections", + "icu_locid_transform", + "icu_properties_data", + "icu_provider", + "tinystr", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67a8effbc3dd3e4ba1afa8ad918d5684b8868b3b26500753effea8d2eed19569" + +[[package]] +name = "icu_provider" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" +dependencies = [ + "displaydoc", + "icu_locid", + "icu_provider_macros", + "stable_deref_trait", + "tinystr", + "writeable", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_provider_macros" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "ignore" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "image" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc144d44a31d753b02ce64093d532f55ff8dc4ebf2ffb8a63c0dda691385acae" +dependencies = [ + "bytemuck", + "byteorder-lite", + "color_quant", + "exr", + "gif", + "image-webp 0.2.0", + "num-traits", + "png", + "qoi", + "ravif", + "rayon", + "rgb", + "tiff", + "zune-core", + "zune-jpeg", +] + +[[package]] +name = "image-webp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f79afb8cbee2ef20f59ccd477a218c12a93943d075b492015ecb1bb81f8ee904" +dependencies = [ + "byteorder-lite", + "quick-error 2.0.1", +] + +[[package]] +name = "image-webp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e031e8e3d94711a9ccb5d6ea357439ef3dcbed361798bd4071dc4d9793fbe22f" +dependencies = [ + "byteorder-lite", + "quick-error 2.0.1", +] + +[[package]] +name = "imagesize" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edcd27d72f2f071c64249075f42e205ff93c9a4c5f6c6da53e79ed9f9832c285" + +[[package]] +name = "imgref" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44feda355f4159a7c757171a77de25daf6411e217b4cabd03bd6650690468126" + +[[package]] +name = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" +dependencies = [ + "equivalent", + "hashbrown 0.15.0", + "serde", +] + +[[package]] +name = "infer" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f551f8c3a39f68f986517db0d1759de85881894fdc7db798bd2a9df9cb04b7fc" +dependencies = [ + "cfb", +] + +[[package]] +name = "infer" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc150e5ce2330295b8616ce0e3f53250e53af31759a9dbedad1621ba29151847" +dependencies = [ + "cfb", +] + +[[package]] +name = "inlinable_string" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" + +[[package]] +name = "inotify" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8069d3ec154eb856955c1c0fbffefbf5f3c40a104ec912d4797314c1801abff" +dependencies = [ + "bitflags 1.3.2", + "inotify-sys", + "libc", +] + +[[package]] +name = "inotify-sys" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +dependencies = [ + "libc", +] + +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "insta" +version = "1.40.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6593a41c7a73841868772495db7dc1e8ecab43bb5c0b6da2059246c4b506ab60" +dependencies = [ + "console", + "lazy_static", + "linked-hash-map", + "similar", +] + +[[package]] +name = "interpolate_name" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" + +[[package]] +name = "is-terminal" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +dependencies = [ + "hermit-abi 0.4.0", + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "is_executable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4a1b5bad6f9072935961dfbf1cced2f3d129963d091b6f69f007fe04e758ae2" +dependencies = [ + "winapi", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "iso8601" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924e5d73ea28f59011fec52a0d12185d496a9b075d360657aed2a5707f701153" +dependencies = [ + "nom", +] + +[[package]] +name = "iter-read" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071ed4cc1afd86650602c7b11aa2e1ce30762a1c27193201cb5cee9c6ebb1294" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "java-properties" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37bf6f484471c451f2b51eabd9e66b3fa7274550c5ec4b6c3d6070840945117f" +dependencies = [ + "encoding_rs", + "lazy_static", + "regex", +] + +[[package]] +name = "javascriptcore-rs" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca5671e9ffce8ffba57afc24070e906da7fc4b1ba66f2cabebf61bf2ea257fcc" +dependencies = [ + "bitflags 1.3.2", + "glib", + "javascriptcore-rs-sys", +] + +[[package]] +name = "javascriptcore-rs-sys" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1be78d14ffa4b75b66df31840478fef72b51f8c2465d4ca7c194da9f7a5124" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.68", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" +dependencies = [ + "libc", +] + +[[package]] +name = "jpeg-decoder" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "json-patch" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec9ad60d674508f3ca8f380a928cfe7b096bc729c4e2dbfe3852bc45da3ab30b" +dependencies = [ + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "json-patch" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" +dependencies = [ + "jsonptr 0.4.7", + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "json-patch" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08" +dependencies = [ + "jsonptr 0.6.3", + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + +[[package]] +name = "jsonptr" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c6e529149475ca0b2820835d3dce8fcc41c6b943ca608d32f35b449255e4627" +dependencies = [ + "fluent-uri", + "serde", + "serde_json", +] + +[[package]] +name = "jsonptr" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "jsonrpsee" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126b48a5acc3c52fbd5381a77898cb60e145123179588a29e7ac48f9c06e401b" +dependencies = [ + "jsonrpsee-core", + "jsonrpsee-server", + "jsonrpsee-types", + "tokio", +] + +[[package]] +name = "jsonrpsee-client-transport" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf679a8e0e083c77997f7c4bb4ca826577105906027ae462aac70ff348d02c6a" +dependencies = [ + "base64 0.22.1", + "futures-util", + "http 1.1.0", + "jsonrpsee-core", + "pin-project", + "soketto", + "thiserror 1.0.68", + "tokio", + "tokio-util", + "tracing", + "url", +] + +[[package]] +name = "jsonrpsee-core" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0e503369a76e195b65af35058add0e6900b794a4e9a9316900ddd3a87a80477" +dependencies = [ + "async-trait", + "bytes", + "futures-timer", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "jsonrpsee-types", + "parking_lot", + "pin-project", + "rand 0.8.5", + "rustc-hash", + "serde", + "serde_json", + "thiserror 1.0.68", + "tokio", + "tokio-stream", + "tracing", +] + +[[package]] +name = "jsonrpsee-server" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af6e6c9b6d975edcb443565d648b605f3e85a04ec63aa6941811a8894cc9cded" +dependencies = [ + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-util", + "jsonrpsee-core", + "jsonrpsee-types", + "pin-project", + "route-recognizer", + "serde", + "serde_json", + "soketto", + "thiserror 1.0.68", + "tokio", + "tokio-stream", + "tokio-util", + "tower 0.4.13", + "tracing", +] + +[[package]] +name = "jsonrpsee-types" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb16314327cbc94fdf7965ef7e4422509cd5597f76d137bd104eb34aeede67" +dependencies = [ + "http 1.1.0", + "serde", + "serde_json", + "thiserror 1.0.68", +] + +[[package]] +name = "jsonrpsee-ws-client" +version = "0.24.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39aabf5d6c6f22da8d5b808eea1fab0736059f11fb42f71f141b14f404e5046a" +dependencies = [ + "http 1.1.0", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-types", + "url", +] + +[[package]] +name = "jsonschema" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0f4bea31643be4c6a678e9aa4ae44f0db9e5609d5ca9dc9083d06eb3e9a27a" +dependencies = [ + "ahash 0.8.11", + "anyhow", + "base64 0.22.1", + "bytecount", + "clap", + "fancy-regex", + "fraction", + "getrandom 0.2.15", + "iso8601", + "itoa 1.0.11", + "memchr", + "num-cmp", + "once_cell", + "parking_lot", + "percent-encoding", + "regex", + "reqwest 0.12.9", + "serde", + "serde_json", + "time", + "url", + "uuid", +] + +[[package]] +name = "jsonwebtoken" +version = "9.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" +dependencies = [ + "base64 0.21.7", + "js-sys", + "pem", + "ring", + "serde", + "serde_json", + "simple_asn1", +] + +[[package]] +name = "jzon" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ab85f84ca42c5ec520e6f3c9966ba1fd62909ce260f8837e248857d2560509" + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "once_cell", + "sha2", + "signature 2.2.0", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keyboard-types" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a" +dependencies = [ + "bitflags 2.6.0", + "serde", + "unicode-segmentation", +] + +[[package]] +name = "konst" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50a0ba6de5f7af397afff922f22c149ff605c766cd3269cf6c1cd5e466dbe3b9" +dependencies = [ + "const_panic", + "konst_kernel", + "typewit", +] + +[[package]] +name = "konst_kernel" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0a455a1719220fd6adf756088e1c69a85bf14b6a9e24537a5cc04f503edb2b" +dependencies = [ + "typewit", +] + +[[package]] +name = "kqueue" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c" +dependencies = [ + "kqueue-sys", + "libc", +] + +[[package]] +name = "kqueue-sys" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9625ffda8729b85e45cf04090035ac368927b8cebc34898e7c120f52e4838b" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "kuchikiki" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e4755b7b995046f510a7520c42b2fed58b77bd94d5a87a8eb43d2fd126da8" +dependencies = [ + "cssparser", + "html5ever", + "indexmap 1.9.3", + "matches", + "selectors", +] + +[[package]] +name = "kurbo" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89234b2cc610a7dd927ebde6b41dd1a5d4214cffaef4cf1fb2195d592f92518f" +dependencies = [ + "arrayvec", + "smallvec", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] + +[[package]] +name = "lebe" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8" + +[[package]] +name = "libappindicator" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03589b9607c868cc7ae54c0b2a22c8dc03dd41692d48f2d7df73615c6a95dc0a" +dependencies = [ + "glib", + "gtk", + "gtk-sys", + "libappindicator-sys", + "log", +] + +[[package]] +name = "libappindicator-sys" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e9ec52138abedcc58dc17a7c6c0c00a2bdb4f3427c7f63fa97fd0d859155caf" +dependencies = [ + "gtk-sys", + "libloading 0.7.4", + "once_cell", +] + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "libfuzzer-sys" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96cfd5557eb82f2b83fed4955246c988d331975a002961b07c81584d107e7f7" +dependencies = [ + "arbitrary", + "cc", + "once_cell", +] + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libloading" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +dependencies = [ + "cfg-if", + "windows-targets 0.52.6", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] + +[[package]] +name = "libxdo" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00333b8756a3d28e78def82067a377de7fa61b24909000aeaa2b446a948d14db" +dependencies = [ + "libxdo-sys", +] + +[[package]] +name = "libxdo-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db23b9e7e2b7831bbd8aac0bbeeeb7b68cbebc162b227e7052e8e55829a09212" +dependencies = [ + "libc", + "x11", +] + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "litemap" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" + +[[package]] +name = "local-ip-address" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3669cf5561f8d27e8fc84cc15e58350e70f557d4d65f70e3154e54cd2f8e1782" +dependencies = [ + "libc", + "neli", + "thiserror 1.0.68", + "windows-sys 0.59.0", +] + +[[package]] +name = "lock_api" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "lockfree-object-pool" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +dependencies = [ + "value-bag", +] + +[[package]] +name = "loop9" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fae87c125b03c1d2c0150c90365d7d6bcc53fb73a9acaef207d2d065860f062" +dependencies = [ + "imgref", +] + +[[package]] +name = "lru" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +dependencies = [ + "hashbrown 0.14.5", +] + +[[package]] +name = "lzma-sys" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fda04ab3764e6cde78b9974eec4f779acaba7c4e84b36eca3cf77c581b85d27" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" + +[[package]] +name = "magic_string" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c8033ce8c43f7ccb207e4699f30eed50d7526379ee08fab47159f80b7934e18" +dependencies = [ + "base64 0.13.1", + "regex", + "serde", + "serde_json", + "vlq", +] + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "markup5ever" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2629bb1404f3d34c2e921f21fd34ba00b206124c81f65c50b43b6aaefeb016" +dependencies = [ + "log", + "phf 0.10.1", + "phf_codegen 0.10.0", + "string_cache", + "string_cache_codegen", + "tendril", +] + +[[package]] +name = "matches" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" + +[[package]] +name = "matchit" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest", +] + +[[package]] +name = "md5" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miette" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edc8853320c2a0dab800fbda86253c8938f6ea88510dc92c5f1ed20e794afc1" +dependencies = [ + "cfg-if", + "miette-derive", + "owo-colors", + "textwrap", + "thiserror 1.0.68", + "unicode-width", +] + +[[package]] +name = "miette-derive" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09caffaac8068c346b6df2a7fc27a177fd20b39421a39ce0a211bde679a6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "minicbor" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d15f4203d71fdf90903c2696e55426ac97a363c67b218488a73b534ce7aca10" +dependencies = [ + "minicbor-derive", +] + +[[package]] +name = "minicbor-derive" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1154809406efdb7982841adb6311b3d095b46f78342dd646736122fe6b19e267" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "minisign" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b23ef13ff1d745b1e52397daaa247e333c607f3cff96d4df2b798dc252db974b" +dependencies = [ + "getrandom 0.2.15", + "rpassword", + "scrypt", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "mio" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +dependencies = [ + "hermit-abi 0.3.9", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.52.0", +] + +[[package]] +name = "muda" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8123dfd4996055ac9b15a60ad263b44b01e539007523ad7a4a533a3d93b0591" +dependencies = [ + "crossbeam-channel", + "dpi", + "gtk", + "keyboard-types", + "libxdo", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 1.0.68", + "windows-sys 0.59.0", +] + +[[package]] +name = "napi" +version = "2.16.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53575dfa17f208dd1ce3a2da2da4659aae393b256a472f2738a8586a6c4107fd" +dependencies = [ + "bitflags 2.6.0", + "ctor", + "napi-derive", + "napi-sys", + "once_cell", +] + +[[package]] +name = "napi-build" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1c0f5d67ee408a4685b61f5ab7e58605c8ae3f2b4189f0127d804ff13d5560a" + +[[package]] +name = "napi-derive" +version = "2.16.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17435f7a00bfdab20b0c27d9c56f58f6499e418252253081bfff448099da31d1" +dependencies = [ + "cfg-if", + "convert_case 0.6.0", + "napi-derive-backend", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "napi-derive-backend" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "967c485e00f0bf3b1bdbe510a38a4606919cf1d34d9a37ad41f25a81aa077abe" +dependencies = [ + "convert_case 0.6.0", + "once_cell", + "proc-macro2", + "quote", + "regex", + "semver", + "syn 2.0.90", +] + +[[package]] +name = "napi-sys" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" +dependencies = [ + "libloading 0.8.5", +] + +[[package]] +name = "native-tls" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +dependencies = [ + "libc", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.6.0", + "jni-sys", + "log", + "ndk-sys", + "num_enum", + "raw-window-handle", + "thiserror 1.0.68", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "neli" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1100229e06604150b3becd61a4965d5c70f3be1759544ea7274166f4be41ef43" +dependencies = [ + "byteorder", + "libc", + "log", + "neli-proc-macros", +] + +[[package]] +name = "neli-proc-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c168194d373b1e134786274020dae7fc5513d565ea2ebb9bc9ff17ffb69106d4" +dependencies = [ + "either", + "proc-macro2", + "quote", + "serde", + "syn 1.0.109", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nodrop" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nonmax" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "610a5acd306ec67f907abe5567859a3c693fb9886eb1f012ab8f2a47bef3db51" + +[[package]] +name = "noop_proc_macro" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8" + +[[package]] +name = "notify" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6205bd8bb1e454ad2e27422015fb5e4f2bcc7e08fa8f27058670d208324a4d2d" +dependencies = [ + "bitflags 2.6.0", + "crossbeam-channel", + "filetime", + "fsevent-sys", + "inotify", + "kqueue", + "libc", + "log", + "mio 0.8.11", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "notify-debouncer-mini" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43" +dependencies = [ + "crossbeam-channel", + "log", + "notify", +] + +[[package]] +name = "num" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand 0.8.5", + "serde", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-cmp" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63335b2e2c34fae2fb0aa2cecfd9f0832a1e24b3b32ecec612c3426d46dc8aaa" + +[[package]] +name = "num-complex" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + +[[package]] +name = "num-rational" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" +dependencies = [ + "cc", +] + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2", + "objc2-contacts", + "objc2-foundation", +] + +[[package]] +name = "objc2-encode" +version = "4.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.6.0", + "block2", + "libc", + "objc2", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-foundation", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2", + "objc2-foundation", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-core-location", + "objc2-foundation", +] + +[[package]] +name = "objc2-web-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65" +dependencies = [ + "bitflags 2.6.0", + "block2", + "objc2", + "objc2-app-kit", + "objc2-foundation", +] + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "crc32fast", + "flate2", + "hashbrown 0.14.5", + "indexmap 2.6.0", + "memchr", + "ruzstd", +] + +[[package]] +name = "object" +version = "0.36.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +dependencies = [ + "memchr", +] + +[[package]] +name = "ocb3" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + +[[package]] +name = "once-cell-regex" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de7e389a5043420c8f2b95ed03f3f104ad6f4c41f7d7e27298f033abc253e8" +dependencies = [ + "once_cell", + "regex", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "openssl" +version = "0.10.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "foreign-types 0.3.2", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "300.3.2+3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a211a18d945ef7e648cc6e0058f4c548ee46aab922ea203e0d30e966ea23647b" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "ordered-float" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" +dependencies = [ + "num-traits", +] + +[[package]] +name = "os_info" +version = "3.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092" +dependencies = [ + "log", + "serde", + "windows-sys 0.52.0", +] + +[[package]] +name = "os_pipe" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "outref" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4030760ffd992bef45b0ae3f10ce1aba99e33464c90d14dd7c039884963ddc7a" + +[[package]] +name = "owo-colors" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb37767f6569cd834a413442455e0f066d0d522de8630436e2a1761d9726ba56" + +[[package]] +name = "oxc_allocator" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "466379b9ab2e05996bfedfae9c96753a633bb5a53aaf0898eb0e0ab09e169514" +dependencies = [ + "allocator-api2", + "bumpalo", +] + +[[package]] +name = "oxc_ast" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34bd4f56fe32adea489153f6d681d9ee01f0336b9b6a89f062611488d8f80797" +dependencies = [ + "bitflags 2.6.0", + "num-bigint", + "oxc_allocator", + "oxc_ast_macros", + "oxc_span", + "oxc_syntax", +] + +[[package]] +name = "oxc_ast_macros" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "197b36739db0e80919e19a90785233eea5664697d4cd829bd49af34838ec43d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "oxc_diagnostics" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cd4bb48b9527f5825c84acb688ec1485df4a5edadc17b3582626bb49736752b" +dependencies = [ + "miette", + "owo-colors", + "textwrap", + "unicode-width", +] + +[[package]] +name = "oxc_index" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc9aa9446f6d2a64d0baa02fe20dc3d64e3e112083854b84fdacb82261be2b84" + +[[package]] +name = "oxc_parser" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3432e80a58cfb38f9a138203e64d0f9a621d4c4e9d18e3e3bd870b51ce1f0e" +dependencies = [ + "assert-unchecked", + "bitflags 2.6.0", + "memchr", + "num-bigint", + "num-traits", + "oxc_allocator", + "oxc_ast", + "oxc_diagnostics", + "oxc_regular_expression", + "oxc_span", + "oxc_syntax", + "rustc-hash", + "seq-macro", +] + +[[package]] +name = "oxc_regular_expression" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc6d05fec98ad6cc864ba8cfe7ece2e258106059a9a57e35b02450650b06979" +dependencies = [ + "oxc_allocator", + "oxc_diagnostics", + "oxc_span", + "phf 0.11.2", + "rustc-hash", + "unicode-id-start", +] + +[[package]] +name = "oxc_span" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a862a896ac3abd269863a19d4f77302b019458d90513705c7a017b138c8449b" +dependencies = [ + "compact_str", + "miette", + "oxc_allocator", + "oxc_ast_macros", +] + +[[package]] +name = "oxc_syntax" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d50c7ea034fb12f65376cfffc8ae4bfde3cda0a1e14407f82ffba1d26431703d" +dependencies = [ + "bitflags 2.6.0", + "dashmap", + "nonmax", + "oxc_allocator", + "oxc_ast_macros", + "oxc_index", + "oxc_span", + "phf 0.11.2", + "rustc-hash", + "unicode-id-start", +] + +[[package]] +name = "p12" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4873306de53fe82e7e484df31e1e947d61514b6ea2ed6cd7b45d63006fd9224" +dependencies = [ + "cbc", + "cipher", + "des", + "getrandom 0.2.15", + "hmac", + "lazy_static", + "rc2", + "sha1", + "yasna", +] + +[[package]] +name = "p256" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f44edd08f51e2ade572f141051021c5af22677e42b7dd28a88155151c33594" +dependencies = [ + "ecdsa 0.14.8", + "elliptic-curve 0.12.3", + "sha2", +] + +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct 0.2.0", + "ecdsa 0.16.9", + "elliptic-curve 0.13.8", + "primeorder", + "rand_core 0.6.4", + "sha2", +] + +[[package]] +name = "pango" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ca27ec1eb0457ab26f3036ea52229edbdb74dee1edd29063f5b9b010e7ebee4" +dependencies = [ + "gio", + "glib", + "libc", + "once_cell", + "pango-sys", +] + +[[package]] +name = "pango-sys" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436737e391a843e5933d6d9aa102cb126d501e815b83601365a948a518555dc5" +dependencies = [ + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "parking_lot" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.52.6", +] + +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "path_abs" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05ef02f6342ac01d8a93b65f96db53fe68a92a15f41144f97fb00a9e669633c3" +dependencies = [ + "serde", + "serde_derive", + "std_prelude", + "stfu8", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest", + "hmac", +] + +[[package]] +name = "pear" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdeeaa00ce488657faba8ebf44ab9361f9365a97bd39ffb8a60663f57ff4b467" +dependencies = [ + "inlinable_string", + "pear_codegen", + "yansi", +] + +[[package]] +name = "pear_codegen" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bab5b985dc082b345f812b7df84e1bef27e7207b39e448439ba8bd69c93f147" +dependencies = [ + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "pem" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e459365e590736a54c3fa561947c84837534b8e9af6fc5bf781307e82658fae" +dependencies = [ + "base64 0.22.1", + "serde", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "pest" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9" +dependencies = [ + "memchr", + "thiserror 1.0.68", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "pest_meta" +version = "2.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pgp" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6c842436d5fa2b59eac1e9b3d142b50bfff99c1744c816b1f4c2ac55a20754" +dependencies = [ + "aes", + "aes-gcm", + "argon2", + "base64 0.22.1", + "bitfield", + "block-padding", + "blowfish", + "bstr", + "buffer-redux", + "byteorder", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "const-oid", + "crc24", + "curve25519-dalek", + "derive_builder", + "des", + "digest", + "dsa", + "eax", + "ecdsa 0.16.9", + "ed25519-dalek", + "elliptic-curve 0.13.8", + "flate2", + "generic-array", + "hex", + "hkdf", + "idea", + "iter-read", + "k256", + "log", + "md-5", + "nom", + "num-bigint-dig", + "num-traits", + "num_enum", + "ocb3", + "p256 0.13.2", + "p384", + "p521", + "rand 0.8.5", + "ripemd", + "rsa", + "sha1", + "sha1-checked", + "sha2", + "sha3", + "signature 2.2.0", + "smallvec", + "thiserror 1.0.68", + "twofish", + "x25519-dalek", + "zeroize", +] + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +dependencies = [ + "phf_macros 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", +] + +[[package]] +name = "phf" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" +dependencies = [ + "phf_shared 0.10.0", +] + +[[package]] +name = "phf" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +dependencies = [ + "phf_macros 0.11.2", + "phf_shared 0.11.2", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", +] + +[[package]] +name = "phf_codegen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb1c3a8bc4dd4e5cfce29b44ffc14bedd2ee294559a294e2a4d4c9e9a6a13cd" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +dependencies = [ + "phf_shared 0.8.0", + "rand 0.7.3", +] + +[[package]] +name = "phf_generator" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" +dependencies = [ + "phf_shared 0.10.0", + "rand 0.8.5", +] + +[[package]] +name = "phf_generator" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +dependencies = [ + "phf_shared 0.11.2", + "rand 0.8.5", +] + +[[package]] +name = "phf_macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" +dependencies = [ + "phf_generator 0.8.0", + "phf_shared 0.8.0", + "proc-macro-hack", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "phf_macros" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +dependencies = [ + "phf_generator 0.11.2", + "phf_shared 0.11.2", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "phf_shared" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +dependencies = [ + "siphasher 0.3.11", +] + +[[package]] +name = "pico-args" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" + +[[package]] +name = "pico-args" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be167a7af36ee22fe3115051bc51f6e6c7054c9348e28deb4f49bd6f705a315" + +[[package]] +name = "pin-project" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der 0.7.9", + "pkcs8 0.10.2", + "spki 0.7.3", +] + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der 0.6.1", + "spki 0.6.0", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der 0.7.9", + "spki 0.7.3", +] + +[[package]] +name = "pkg-config" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + +[[package]] +name = "plist" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" +dependencies = [ + "base64 0.22.1", + "indexmap 2.6.0", + "quick-xml", + "serde", + "time", +] + +[[package]] +name = "png" +version = "0.17.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67582bd5b65bdff614270e2ea89a1cf15bef71245cc1e5f7ea126977144211d" +dependencies = [ + "bitflags 1.3.2", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide 0.8.0", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "ppv-lite86" +version = "0.2.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + +[[package]] +name = "pretty_assertions" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" +dependencies = [ + "diff", + "yansi", +] + +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve 0.13.8", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8" +dependencies = [ + "toml_edit 0.20.7", +] + +[[package]] +name = "proc-macro-crate" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" +dependencies = [ + "toml_edit 0.22.22", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-hack" +version = "0.5.20+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc375e1527247fe1a97d8b7156678dfe7c1af2fc075c9a4db3690ecd2a148068" + +[[package]] +name = "proc-macro2" +version = "1.0.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proc-macro2-diagnostics" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "version_check", + "yansi", +] + +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn 2.0.90", +] + +[[package]] +name = "proptest" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +dependencies = [ + "bit-set", + "bit-vec", + "bitflags 2.6.0", + "lazy_static", + "num-traits", + "rand 0.8.5", + "rand_chacha 0.3.1", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "qoi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6d64c71eb498fe9eae14ce4ec935c555749aef511cca85b5568910d6e48001" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d3a6e5838b60e0e8fa7a43f22ade549a37d61f8bdbe636d0d7816191de969c2" +dependencies = [ + "memchr", +] + +[[package]] +name = "quickcheck" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "588f6378e4dd99458b60ec275b4477add41ce4fa9f64dcba6f15adccb19b50d6" +dependencies = [ + "env_logger 0.8.4", + "log", + "rand 0.8.5", +] + +[[package]] +name = "quickcheck_macros" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b22a693222d716a9587786f37ac3f6b4faedb5b80c23914e7303ff5a1d8016e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quinn" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls 0.23.13", + "socket2", + "thiserror 1.0.68", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring", + "rustc-hash", + "rustls 0.23.13", + "slab", + "thiserror 1.0.68", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" +dependencies = [ + "libc", + "once_cell", + "socket2", + "tracing", + "windows-sys 0.59.0", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", + "rand_pcg", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rasn" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9b0d03fbc7d2dcfdd35086c43ce30ac5ff62ed7eff4397e4f4f2995a2b0e2a" +dependencies = [ + "arrayvec", + "bitvec", + "bitvec-nom2", + "bytes", + "chrono", + "either", + "jzon", + "konst", + "nom", + "num-bigint", + "num-integer", + "num-traits", + "once_cell", + "rasn-derive", + "snafu", +] + +[[package]] +name = "rasn-derive" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbaf7105cd254b632f4732fbcc243ce750cef87d8335826125ef6df5733b5a0c" +dependencies = [ + "either", + "itertools 0.10.5", + "proc-macro2", + "quote", + "rayon", + "syn 1.0.109", + "uuid", +] + +[[package]] +name = "rav1e" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd87ce80a7665b1cce111f8a16c1f3929f6547ce91ade6addf4ec86a8dda5ce9" +dependencies = [ + "arbitrary", + "arg_enum_proc_macro", + "arrayvec", + "av1-grain", + "bitstream-io", + "built", + "cfg-if", + "interpolate_name", + "itertools 0.12.1", + "libc", + "libfuzzer-sys", + "log", + "maybe-rayon", + "new_debug_unreachable", + "noop_proc_macro", + "num-derive", + "num-traits", + "once_cell", + "paste", + "profiling", + "rand 0.8.5", + "rand_chacha 0.3.1", + "simd_helpers", + "system-deps", + "thiserror 1.0.68", + "v_frame", + "wasm-bindgen", +] + +[[package]] +name = "ravif" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc13288f5ab39e6d7c9d501759712e6969fcc9734220846fc9ed26cae2cc4234" +dependencies = [ + "avif-serialize", + "imgref", + "loop9", + "quick-error 2.0.1", + "rav1e", + "rayon", + "rgb", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "rc2" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62c64daa8e9438b84aaae55010a93f396f8e60e3911590fcba770d04643fc1dd" +dependencies = [ + "cipher", +] + +[[package]] +name = "redox_syscall" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +dependencies = [ + "bitflags 2.6.0", +] + +[[package]] +name = "redox_users" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" +dependencies = [ + "getrandom 0.2.15", + "libredox", + "thiserror 1.0.68", +] + +[[package]] +name = "regex" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-lite" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a" + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "rend" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71fe3824f5629716b1589be05dacd749f6aa084c87e00e016714a8cdfccc997c" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.11.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" +dependencies = [ + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.30", + "hyper-rustls 0.24.2", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.12", + "rustls-native-certs 0.6.3", + "rustls-pemfile 1.0.4", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 0.1.2", + "system-configuration", + "tokio", + "tokio-rustls 0.24.1", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg 0.50.0", +] + +[[package]] +name = "reqwest" +version = "0.12.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.4.1", + "hyper-rustls 0.27.3", + "hyper-tls", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls 0.23.13", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.1", + "tokio", + "tokio-native-tls", + "tokio-rustls 0.26.0", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots 0.26.6", + "windows-registry 0.2.0", +] + +[[package]] +name = "resources" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", +] + +[[package]] +name = "restart" +version = "0.1.0" +dependencies = [ + "tauri", + "tempfile", +] + +[[package]] +name = "resvg" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7314563c59c7ce31c18e23ad3dd092c37b928a0fa4e1c0a1a6504351ab411d1" +dependencies = [ + "gif", + "image-webp 0.1.3", + "log", + "pico-args 0.5.0", + "rgb", + "svgtypes", + "tiny-skia", + "usvg", + "zune-jpeg", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint 0.4.9", + "hmac", + "zeroize", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rgb" +version = "0.8.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin", + "untrusted", + "windows-sys 0.52.0", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + +[[package]] +name = "rkyv" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +dependencies = [ + "bitvec", + "bytecheck", + "bytes", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "route-recognizer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afab94fb28594581f62d981211a9a4d53cc8130bbcbbb89a0440d9b8e81a7746" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rpassword" +version = "7.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] + +[[package]] +name = "rpm" +version = "0.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95c49b6baaa0e8fa864b2069d1e94e7a132471da3ac26a132f3fa7e71416772c" +dependencies = [ + "bitflags 2.6.0", + "bzip2", + "chrono", + "cpio", + "digest", + "enum-display-derive", + "enum-primitive-derive", + "flate2", + "hex", + "itertools 0.13.0", + "log", + "md-5", + "nom", + "num", + "num-derive", + "num-traits", + "pgp", + "sha1", + "sha2", + "thiserror 1.0.68", + "xz2", + "zstd", +] + +[[package]] +name = "rsa" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8 0.10.2", + "rand_core 0.6.4", + "signature 2.2.0", + "spki 0.7.3", + "subtle", + "zeroize", +] + +[[package]] +name = "rtoolbox" +version = "0.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "rust_decimal" +version = "1.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b082d80e3e3cc52b2ed634388d436fe1f4de6af5786cc2de9ba9737527bdf555" +dependencies = [ + "arrayvec", + "borsh", + "bytes", + "num-traits", + "rand 0.8.5", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" + +[[package]] +name = "rustc-hash" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rusticata-macros" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" +dependencies = [ + "nom", +] + +[[package]] +name = "rustix" +version = "0.37.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea8ca367a3a01fe35e6943c400addf443c0f57670e6ec51196f71a4b8762dd2" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.52.0", +] + +[[package]] +name = "rustls" +version = "0.21.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" +dependencies = [ + "log", + "ring", + "rustls-webpki 0.101.7", + "sct", +] + +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls" +version = "0.23.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +dependencies = [ + "log", + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.102.8", + "subtle", + "zeroize", +] + +[[package]] +name = "rustls-native-certs" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +dependencies = [ + "openssl-probe", + "rustls-pemfile 1.0.4", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-native-certs" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +dependencies = [ + "openssl-probe", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "schannel", + "security-framework", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + +[[package]] +name = "rustls-pemfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "rustls-pki-types" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e696e35370c65c9c541198af4543ccd580cf17fc25d8e05c5a242b202488c55" + +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.102.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "rustybuzz" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85d1ccd519e61834798eb52c4e886e8c2d7d698dd3d6ce0b1b47eb8557f1181" +dependencies = [ + "bitflags 2.6.0", + "bytemuck", + "core_maths", + "log", + "smallvec", + "ttf-parser", + "unicode-bidi-mirroring", + "unicode-ccc", + "unicode-properties", + "unicode-script", +] + +[[package]] +name = "ruzstd" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" +dependencies = [ + "byteorder", + "derive_more", + "twox-hash", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scc" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836f1e0f4963ef5288b539b643b35e043e76a32d0f4e47e67febf69576527f50" +dependencies = [ + "sdd", +] + +[[package]] +name = "schannel" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "schemars" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09c024468a378b7e36765cd36702b7a90cc3cba11654f6685c8f233408e89e92" +dependencies = [ + "dyn-clone", + "indexmap 1.9.3", + "schemars_derive", + "serde", + "serde_json", + "url", + "uuid", +] + +[[package]] +name = "schemars_derive" +version = "0.8.21" +source = "git+https://github.com/tauri-apps/schemars.git?branch=feat/preserve-description-newlines#c30f98480e6e4742aa72202d55d5264c6b2e6476" +dependencies = [ + "proc-macro2", + "quote", + "serde_derive_internals", + "syn 2.0.90", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "scroll" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +dependencies = [ + "scroll_derive", +] + +[[package]] +name = "scroll_derive" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "scrypt" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0516a385866c09368f0b5bcd1caff3366aace790fcd46e2bb032697bb172fd1f" +dependencies = [ + "pbkdf2", + "salsa20", + "sha2", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "sdd" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a7b59a5d9b0099720b417b6325d91a52cbf5b3dcb5041d864be53eefa58abc" + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct 0.1.1", + "der 0.6.1", + "generic-array", + "pkcs8 0.9.0", + "subtle", + "zeroize", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct 0.2.0", + "der 0.7.9", + "generic-array", + "pkcs8 0.10.2", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +dependencies = [ + "bitflags 2.6.0", + "core-foundation 0.9.4", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "selectors" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" +dependencies = [ + "bitflags 1.3.2", + "cssparser", + "derive_more", + "fxhash", + "log", + "matches", + "phf 0.8.0", + "phf_codegen 0.8.0", + "precomputed-hash", + "servo_arc", + "smallvec", + "thin-slice", +] + +[[package]] +name = "semver" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +dependencies = [ + "serde", +] + +[[package]] +name = "seq-macro" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" + +[[package]] +name = "serde" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-untagged" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2676ba99bd82f75cae5cbd2c8eda6fa0b8760f18978ea840e980dd5567b5c5b6" +dependencies = [ + "erased-serde", + "serde", + "typeid", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "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-xml-rs" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" +dependencies = [ + "log", + "serde", + "thiserror 1.0.68", + "xml-rs", +] + +[[package]] +name = "serde_derive" +version = "1.0.216" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_derive_internals" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d26a20a969b9e3fdf2fc2d9f21eda6c40e2de84c9408bb5d3b05d499aae711" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_fmt" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1d4ddca14104cd60529e8c7f7ba71a2c8acd8f7f5cfcdc2faf97eeb7c3010a4" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_json" +version = "1.0.133" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +dependencies = [ + "indexmap 2.6.0", + "itoa 1.0.11", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "serde_path_to_error" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af99884400da37c88f5e9146b7f1fd0fbcae8f6eec4e9da38b67d05486f814a6" +dependencies = [ + "itoa 1.0.11", + "serde", +] + +[[package]] +name = "serde_repr" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_spanned" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa 1.0.11", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc" +dependencies = [ + "base64 0.22.1", + "chrono", + "hex", + "indexmap 1.9.3", + "indexmap 2.6.0", + "serde", + "serde_derive", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap 2.6.0", + "itoa 1.0.11", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "serial_test" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "serialize-to-javascript" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" +dependencies = [ + "serde", + "serde_json", + "serialize-to-javascript-impl", +] + +[[package]] +name = "serialize-to-javascript-impl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "servo_arc" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" +dependencies = [ + "nodrop", + "stable_deref_trait", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest", + "sha1", +] + +[[package]] +name = "sha1_smol" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbfa15b3dddfee50a0fff136974b3e1bde555604ba463834a7eb7deb6417705d" + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest", + "keccak", +] + +[[package]] +name = "shared_child" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09fa9338aed9a1df411814a5b2252f7cd206c55ae9bf2fa763f8de84603aa60c" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + +[[package]] +name = "signal-hook-tokio" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e" +dependencies = [ + "futures-core", + "libc", + "signal-hook", + "tokio", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + +[[package]] +name = "simd_helpers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95890f873bec569a0362c235787f3aca6e1e887302ba4840839bcc6459c42da6" +dependencies = [ + "quote", +] + +[[package]] +name = "simdutf8" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" + +[[package]] +name = "similar" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" + +[[package]] +name = "simple-file-manifest" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd19be0257552dd56d1bb6946f89f193c6e5b9f13cc9327c4bc84a357507c74" + +[[package]] +name = "simple_asn1" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" +dependencies = [ + "num-bigint", + "num-traits", + "thiserror 1.0.68", + "time", +] + +[[package]] +name = "simplecss" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a11be7c62927d9427e9f40f3444d5499d868648e2edbc4e2116de69e7ec0e89d" +dependencies = [ + "log", +] + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "siphasher" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slotmap" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbff4acf519f630b3a3ddcfaea6c06b42174d9a44bc70c620e9ed1649d58b82a" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "smawk" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" + +[[package]] +name = "snafu" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4de37ad025c587a29e8f3f5605c00f70b98715ef90b9061a815b9e59e9042d6" +dependencies = [ + "backtrace", + "doc-comment", + "snafu-derive", +] + +[[package]] +name = "snafu-derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990079665f075b699031e9c08fd3ab99be5029b96f3b78dc0709e8f77e4efebf" +dependencies = [ + "heck 0.4.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "socket2" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "socks" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0c3dbbd9ae980613c6dd8e28a9407b50509d3803b57624d5dfe8315218cd58b" +dependencies = [ + "byteorder", + "libc", + "winapi", +] + +[[package]] +name = "softbuffer" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18051cdd562e792cad055119e0cdb2cfc137e44e3987532e0f9659a77931bb08" +dependencies = [ + "bytemuck", + "cfg_aliases", + "core-graphics 0.24.0", + "foreign-types 0.5.0", + "js-sys", + "log", + "objc2", + "objc2-foundation", + "objc2-quartz-core", + "raw-window-handle", + "redox_syscall", + "wasm-bindgen", + "web-sys", + "windows-sys 0.59.0", +] + +[[package]] +name = "soketto" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37468c595637c10857701c990f93a40ce0e357cedb0953d1c26c8d8027f9bb53" +dependencies = [ + "base64 0.22.1", + "bytes", + "futures", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", +] + +[[package]] +name = "soup3" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "471f924a40f31251afc77450e781cb26d55c0b650842efafc9c6cbd2f7cc4f9f" +dependencies = [ + "futures-channel", + "gio", + "glib", + "libc", + "soup3-sys", +] + +[[package]] +name = "soup3-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ebe8950a680a12f24f15ebe1bf70db7af98ad242d9db43596ad3108aab86c27" +dependencies = [ + "gio-sys", + "glib-sys", + "gobject-sys", + "libc", + "system-deps", +] + +[[package]] +name = "spake2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5482afe85a0b6ce956c945401598dbc527593c77ba51d0a87a586938b1b893a" +dependencies = [ + "curve25519-dalek", + "hkdf", + "rand_core 0.6.4", + "sha2", +] + +[[package]] +name = "specta" +version = "2.0.0-rc.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccbb212565d2dc177bc15ecb7b039d66c4490da892436a4eee5b394d620c9bc" +dependencies = [ + "paste", + "specta-macros", + "thiserror 1.0.68", +] + +[[package]] +name = "specta-macros" +version = "2.0.0-rc.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68999d29816965eb9e5201f60aec02a76512139811661a7e8e653abc810b8f72" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "specta-util" +version = "0.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8113d65b58a6de3184b01d6df9e50b6d4bbe7f724251f576d84f23228824456" +dependencies = [ + "ctor", + "serde", + "specta", + "specta-macros", +] + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der 0.6.1", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der 0.7.9", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "std_prelude" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8207e78455ffdf55661170876f88daf85356e4edd54e0a3dbc79586ca1e50cbe" + +[[package]] +name = "stfu8" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51f1e89f093f99e7432c491c382b88a6860a5adbe6bf02574bf0a08efff1978" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" +dependencies = [ + "float-cmp", +] + +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot", + "phf_shared 0.10.0", + "precomputed-hash", + "serde", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bb30289b722be4ff74a408c3cc27edeaad656e06cb1fe8fa9231fa59c728988" +dependencies = [ + "phf_generator 0.10.0", + "phf_shared 0.10.0", + "proc-macro2", + "quote", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "sublime_fuzzy" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7986063f7c0ab374407e586d7048a3d5aac94f103f751088bf398e07cd5400" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "sval" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf38d1fa2ce984086ea42fb856a9f374d94680a4f796831a7fc868d7f2af1b9" + +[[package]] +name = "sval_buffer" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81682ff859964ca1d7cf3d3d0f9ec7204ea04c2c32acb8cc2cf68ecbd3127354" +dependencies = [ + "sval", + "sval_ref", +] + +[[package]] +name = "sval_dynamic" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a213b93bb4c6f4c9f9b17f2e740e077fd18746bbf7c80c72bbadcac68fa7ee4" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_fmt" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6902c6d3fb52c89206fe0dc93546c0123f7d48b5997fd14e61c9e64ff0b63275" +dependencies = [ + "itoa 1.0.11", + "ryu", + "sval", +] + +[[package]] +name = "sval_json" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a28041ea78cdc394b930ae6b897d36246dc240a29a6edf82d76562487fb0b4" +dependencies = [ + "itoa 1.0.11", + "ryu", + "sval", +] + +[[package]] +name = "sval_nested" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850346e4b0742a7f2fd2697d703ff80084d0b658f0f2e336d71b8a06abf9b68e" +dependencies = [ + "sval", + "sval_buffer", + "sval_ref", +] + +[[package]] +name = "sval_ref" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824afd97a8919f28a35b0fdea979845cc2ae461a8a3aaa129455cb89c88bb77a" +dependencies = [ + "sval", +] + +[[package]] +name = "sval_serde" +version = "2.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ada7520dd719ed672c786c7db7de4f5230f4d504b0821bd8305cd30ca442315" +dependencies = [ + "serde", + "sval", + "sval_nested", +] + +[[package]] +name = "svgtypes" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794de53cc48eaabeed0ab6a3404a65f40b3e38c067e4435883a65d2aa4ca000e" +dependencies = [ + "kurbo", + "siphasher 1.0.1", +] + +[[package]] +name = "swift-rs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7" +dependencies = [ + "base64 0.21.7", + "serde", + "serde_json", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "sync_wrapper" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "synstructure" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "sysctl" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225e483f02d0ad107168dc57381a8a40c3aeea6abe47f37506931f861643cfa8" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "libc", + "thiserror 1.0.68", + "walkdir", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "system-deps" +version = "6.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e535eb8dded36d55ec13eddacd30dec501792ff23a0b1682c38601b8cf2349" +dependencies = [ + "cfg-expr", + "heck 0.5.0", + "pkg-config", + "toml 0.8.19", + "version-compare", +] + +[[package]] +name = "tao" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc6b53216f32e60efc27dfa111268481e4dfba53e553e4cdebcaed9db36c11bb" +dependencies = [ + "bitflags 2.6.0", + "cocoa 0.26.0", + "core-foundation 0.10.0", + "core-graphics 0.24.0", + "crossbeam-channel", + "dispatch", + "dlopen2", + "dpi", + "gdkwayland-sys", + "gdkx11-sys", + "gtk", + "jni", + "lazy_static", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys", + "objc", + "once_cell", + "parking_lot", + "raw-window-handle", + "scopeguard", + "tao-macros", + "unicode-segmentation", + "url", + "windows", + "windows-core 0.58.0", + "windows-version", + "x11-dl", +] + +[[package]] +name = "tao-macros" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tar" +version = "0.4.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ff6c40d3aedb5e06b57c6f669ad17ab063dd1e63d977c6a88e7f4dfa4f04020" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "target-lexicon" +version = "0.12.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" + +[[package]] +name = "tauri" +version = "2.1.1" +dependencies = [ + "anyhow", + "bytes", + "cargo_toml", + "data-url", + "dirs", + "dunce", + "embed_plist", + "futures-util", + "getrandom 0.2.15", + "glob", + "gtk", + "heck 0.5.0", + "http 1.1.0", + "http-range", + "image", + "jni", + "libc", + "log", + "mime", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-web-kit", + "percent-encoding", + "plist", + "proptest", + "quickcheck", + "quickcheck_macros", + "raw-window-handle", + "reqwest 0.12.9", + "serde", + "serde_json", + "serde_repr", + "serialize-to-javascript", + "specta", + "specta-util", + "swift-rs", + "tauri", + "tauri-build", + "tauri-macros", + "tauri-runtime", + "tauri-runtime-wry", + "tauri-utils 2.1.0", + "thiserror 2.0.8", + "tokio", + "tracing", + "tray-icon", + "url", + "urlpattern", + "uuid", + "webkit2gtk", + "webview2-com", + "window-vibrancy", + "windows", +] + +[[package]] +name = "tauri-build" +version = "2.0.3" +dependencies = [ + "anyhow", + "cargo_toml", + "dirs", + "glob", + "heck 0.5.0", + "json-patch 3.0.1", + "quote", + "schemars", + "semver", + "serde", + "serde_json", + "tauri-codegen", + "tauri-utils 2.1.0", + "tauri-winres", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "tauri-bundler" +version = "2.1.0" +dependencies = [ + "anyhow", + "ar", + "bitness", + "dirs", + "dunce", + "flate2", + "glob", + "handlebars", + "heck 0.5.0", + "hex", + "image", + "log", + "md5", + "native-tls", + "os_pipe", + "plist", + "regex", + "rpm", + "semver", + "serde", + "serde_json", + "sha1", + "sha2", + "strsim", + "tar", + "tauri-icns", + "tauri-macos-sign", + "tauri-utils 2.1.0", + "tempfile", + "thiserror 2.0.8", + "time", + "ureq", + "url", + "uuid", + "walkdir", + "windows-registry 0.3.0", + "windows-sys 0.59.0", + "zip 2.2.0", +] + +[[package]] +name = "tauri-cli" +version = "2.1.0" +dependencies = [ + "anyhow", + "ar", + "axum", + "base64 0.22.1", + "cargo-mobile2", + "clap", + "clap_complete", + "colored", + "common-path", + "css-color", + "ctrlc", + "dialoguer", + "duct", + "dunce", + "elf", + "env_logger 0.11.5", + "glob", + "handlebars", + "heck 0.5.0", + "html5ever", + "ignore", + "image", + "include_dir", + "insta", + "itertools 0.13.0", + "json-patch 3.0.1", + "jsonrpsee", + "jsonrpsee-client-transport", + "jsonrpsee-core", + "jsonrpsee-ws-client", + "jsonschema", + "kuchikiki", + "libc", + "local-ip-address", + "log", + "magic_string", + "memchr", + "minisign", + "notify", + "notify-debouncer-mini", + "object 0.36.5", + "os_info", + "os_pipe", + "oxc_allocator", + "oxc_ast", + "oxc_parser", + "oxc_span", + "phf 0.11.2", + "plist", + "pretty_assertions", + "rand 0.8.5", + "regex", + "resvg", + "semver", + "serde", + "serde-value", + "serde_json", + "shared_child", + "sublime_fuzzy", + "tauri-bundler", + "tauri-icns", + "tauri-macos-sign", + "tauri-utils 1.6.0", + "tauri-utils 2.1.0", + "tempfile", + "tokio", + "toml 0.8.19", + "toml_edit 0.22.22", + "ureq", + "url", + "uuid", + "walkdir", + "windows-sys 0.59.0", +] + +[[package]] +name = "tauri-cli-node" +version = "0.0.0" +dependencies = [ + "log", + "napi", + "napi-build", + "napi-derive", + "tauri-cli", +] + +[[package]] +name = "tauri-codegen" +version = "2.0.3" +dependencies = [ + "base64 0.22.1", + "brotli", + "ico", + "json-patch 3.0.1", + "plist", + "png", + "proc-macro2", + "quote", + "regex", + "semver", + "serde", + "serde_json", + "sha2", + "syn 2.0.90", + "tauri-utils 2.1.0", + "thiserror 2.0.8", + "time", + "url", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-driver" +version = "2.0.1" +dependencies = [ + "anyhow", + "futures", + "futures-util", + "hyper 0.14.30", + "pico-args 0.4.2", + "serde", + "serde_json", + "signal-hook", + "signal-hook-tokio", + "tokio", + "which 4.4.2", +] + +[[package]] +name = "tauri-file-associations-demo" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", + "tauri", + "tauri-build", + "url", +] + +[[package]] +name = "tauri-icns" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b7eb4d0d43724ba9ba6a6717420ee68aee377816a3edbb45db8c18862b1431" +dependencies = [ + "byteorder", + "png", +] + +[[package]] +name = "tauri-macos-sign" +version = "2.0.1" +dependencies = [ + "anyhow", + "apple-codesign", + "chrono", + "dirs-next", + "log", + "once-cell-regex", + "os_pipe", + "p12", + "plist", + "rand 0.8.5", + "serde", + "serde_json", + "tempfile", + "x509-certificate", +] + +[[package]] +name = "tauri-macros" +version = "2.0.3" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.90", + "tauri-codegen", + "tauri-utils 2.1.0", +] + +[[package]] +name = "tauri-plugin" +version = "2.0.0-rc.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6de7ffe64afa61c4cc13d450d64643b8db6cbb177a802beb88bf595594505ddf" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils 2.0.0-rc.13", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "tauri-plugin" +version = "2.0.3" +dependencies = [ + "anyhow", + "glob", + "plist", + "schemars", + "serde", + "serde_json", + "tauri-utils 2.1.0", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "tauri-plugin-log" +version = "2.0.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b57e4666c4a5d81f81b7bb8eacf51ae32c4e69c35071aabb480ad20a80836e4e" +dependencies = [ + "android_logger", + "byte-unit", + "cocoa 0.25.0", + "fern", + "log", + "objc", + "serde", + "serde_json", + "serde_repr", + "swift-rs", + "tauri", + "tauri-plugin 2.0.0-rc.13", + "thiserror 1.0.68", + "time", +] + +[[package]] +name = "tauri-plugin-sample" +version = "0.1.0" +dependencies = [ + "log", + "serde", + "tauri", + "tauri-plugin 2.0.3", + "thiserror 2.0.8", +] + +[[package]] +name = "tauri-runtime" +version = "2.2.0" +dependencies = [ + "dpi", + "gtk", + "http 1.1.0", + "jni", + "raw-window-handle", + "serde", + "serde_json", + "tauri-utils 2.1.0", + "thiserror 2.0.8", + "url", + "windows", +] + +[[package]] +name = "tauri-runtime-wry" +version = "2.2.0" +dependencies = [ + "gtk", + "http 1.1.0", + "jni", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "percent-encoding", + "raw-window-handle", + "softbuffer", + "tao", + "tauri-runtime", + "tauri-utils 2.1.0", + "tracing", + "url", + "webkit2gtk", + "webview2-com", + "windows", + "wry", +] + +[[package]] +name = "tauri-schema-generator" +version = "0.0.0" +dependencies = [ + "schemars", + "serde", + "serde_json", + "tauri-utils 2.1.0", + "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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2826db448309d382dac14d520f0c0a40839b87b57b977e59cf5f296b3ace6a93" +dependencies = [ + "aes-gcm", + "ctor", + "dunce", + "getrandom 0.2.15", + "heck 0.5.0", + "html5ever", + "infer 0.13.0", + "json-patch 1.4.0", + "json5", + "kuchikiki", + "log", + "memchr", + "phf 0.11.2", + "schemars", + "semver", + "serde", + "serde_json", + "serde_with", + "serialize-to-javascript", + "thiserror 1.0.68", + "toml 0.7.8", + "url", + "windows-version", +] + +[[package]] +name = "tauri-utils" +version = "2.0.0-rc.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a271545e4c25b36b922d98cf7e0c1755f64e92355705f656893e352aef0331e3" +dependencies = [ + "cargo_metadata", + "ctor", + "dunce", + "glob", + "html5ever", + "infer 0.16.0", + "json-patch 2.0.0", + "kuchikiki", + "log", + "memchr", + "phf 0.11.2", + "proc-macro2", + "quote", + "regex", + "schemars", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "swift-rs", + "thiserror 1.0.68", + "toml 0.8.19", + "url", + "urlpattern", + "uuid", +] + +[[package]] +name = "tauri-utils" +version = "2.1.0" +dependencies = [ + "aes-gcm", + "brotli", + "cargo_metadata", + "ctor", + "dunce", + "getrandom 0.2.15", + "glob", + "html5ever", + "http 1.1.0", + "infer 0.16.0", + "json-patch 3.0.1", + "json5", + "kuchikiki", + "log", + "memchr", + "phf 0.11.2", + "proc-macro2", + "quote", + "regex", + "schemars", + "semver", + "serde", + "serde-untagged", + "serde_json", + "serde_with", + "serial_test", + "serialize-to-javascript", + "swift-rs", + "thiserror 2.0.8", + "toml 0.8.19", + "url", + "urlpattern", + "uuid", + "walkdir", +] + +[[package]] +name = "tauri-winres" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5993dc129e544393574288923d1ec447c857f3f644187f4fbf7d9a875fbfc4fb" +dependencies = [ + "embed-resource", + "toml 0.7.8", +] + +[[package]] +name = "tauri_bench" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", + "serde_json", + "tempfile", + "time", +] + +[[package]] +name = "tempfile" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +dependencies = [ + "cfg-if", + "fastrand", + "once_cell", + "rustix 0.38.37", + "windows-sys 0.59.0", +] + +[[package]] +name = "tendril" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24a120c5fc464a3458240ee02c299ebcb9d67b5249c8848b09d639dca8d7bb0" +dependencies = [ + "futf", + "mac", + "utf-8", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix 0.37.27", + "windows-sys 0.48.0", +] + +[[package]] +name = "textwrap" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" +dependencies = [ + "smawk", + "terminal_size", + "unicode-linebreak", + "unicode-width", +] + +[[package]] +name = "thin-slice" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" + +[[package]] +name = "thiserror" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +dependencies = [ + "thiserror-impl 1.0.68", +] + +[[package]] +name = "thiserror" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a" +dependencies = [ + "thiserror-impl 2.0.8", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tiff" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba1310fcea54c6a9a4fd1aad794ecc02c31682f6bfbecdf460bf19533eed1e3e" +dependencies = [ + "flate2", + "jpeg-decoder", + "weezl", +] + +[[package]] +name = "time" +version = "0.3.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" +dependencies = [ + "deranged", + "itoa 1.0.11", + "libc", + "num-conv", + "num_threads", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" +dependencies = [ + "num-conv", + "time-core", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "png", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tiny_http" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d6ef4e10d23c1efb862eecad25c5054429a71958b4eeef85eb5e7170b477ca" +dependencies = [ + "ascii", + "chunked_transfer", + "log", + "time", + "url", +] + +[[package]] +name = "tinystr" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.41.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +dependencies = [ + "backtrace", + "bytes", + "libc", + "mio 1.0.2", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.52.0", +] + +[[package]] +name = "tokio-macros" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tokio-native-tls" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2" +dependencies = [ + "native-tls", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +dependencies = [ + "rustls 0.23.13", + "rustls-pki-types", + "tokio", +] + +[[package]] +name = "tokio-stream" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edc5f74e248dc973e0dbb7b74c7e0d6fcc301c694ff50049504004ef4d0cdcd9" +dependencies = [ + "futures-util", + "log", + "tokio", + "tungstenite 0.24.0", +] + +[[package]] +name = "tokio-util" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e7c3654c13bcd040d4a03abee2c75b1d14a37b423cf5a813ceae1cc903ec6a" +dependencies = [ + "bytes", + "futures-core", + "futures-io", + "futures-sink", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "toml" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd79e69d3b627db300ff956027cc6c3798cef26d22526befdfcd12feeb6d2257" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.19.15", +] + +[[package]] +name = "toml" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +dependencies = [ + "indexmap 2.6.0", + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.22", +] + +[[package]] +name = "toml_datetime" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.6.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.20.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +dependencies = [ + "indexmap 2.6.0", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.20", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + +[[package]] +name = "tower-service" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tray-icon" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "533fc2d4105e0e3d96ce1c71f2d308c9fbbe2ef9c587cab63dd627ab5bde218f" +dependencies = [ + "core-graphics 0.24.0", + "crossbeam-channel", + "dirs", + "libappindicator", + "muda", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "once_cell", + "png", + "serde", + "thiserror 1.0.68", + "windows-sys 0.59.0", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "ttf-parser" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be21190ff5d38e8b4a2d3b6a3ae57f612cc39c96e83cedeaf7abc338a8bac4a" +dependencies = [ + "core_maths", +] + +[[package]] +name = "tungstenite" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "rustls 0.22.4", + "rustls-native-certs 0.7.3", + "rustls-pki-types", + "sha1", + "thiserror 1.0.68", + "url", + "utf-8", +] + +[[package]] +name = "tungstenite" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18e5b8366ee7a95b16d32197d0b2604b43a0be89dc5fac9f8e96ccafbaedda8a" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http 1.1.0", + "httparse", + "log", + "rand 0.8.5", + "sha1", + "thiserror 1.0.68", + "utf-8", +] + +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + +[[package]] +name = "typeid" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e13db2e0ccd5e14a544e8a246ba2312cd25223f616442d7f2cb0e3db614236e" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "typewit" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6fb9ae6a3cafaf0a5d14c2302ca525f9ae8e07a0f0e6949de88d882c37a6e24" +dependencies = [ + "typewit_proc_macros", +] + +[[package]] +name = "typewit_proc_macros" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e36a83ea2b3c704935a01b4642946aadd445cea40b10935e3f8bd8052b8193d6" + +[[package]] +name = "ucd-trie" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971" + +[[package]] +name = "uname" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b72f89f0ca32e4db1c04e2a72f5345d59796d4866a1ee0609084569f73683dc8" +dependencies = [ + "libc", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "uncased" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" +dependencies = [ + "version_check", +] + +[[package]] +name = "unic-char-property" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221" +dependencies = [ + "unic-char-range", +] + +[[package]] +name = "unic-char-range" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc" + +[[package]] +name = "unic-common" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc" + +[[package]] +name = "unic-ucd-ident" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987" +dependencies = [ + "unic-char-property", + "unic-char-range", + "unic-ucd-version", +] + +[[package]] +name = "unic-ucd-version" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4" +dependencies = [ + "unic-common", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" + +[[package]] +name = "unicode-bidi-mirroring" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64af057ad7466495ca113126be61838d8af947f41d93a949980b2389a118082f" + +[[package]] +name = "unicode-ccc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "260bc6647b3893a9a90668360803a15f96b85a5257b1c3a0c3daf6ae2496de42" + +[[package]] +name = "unicode-id-start" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97e2a3c5fc9de285c0e805d98eba666adb4b2d9e1049ce44821ff7707cc34e91" + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "unicode-linebreak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" + +[[package]] +name = "unicode-properties" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" + +[[package]] +name = "unicode-script" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fb421b350c9aff471779e262955939f565ec18b86c15364e6bdf0d662ca7c1f" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-vo" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1d386ff53b415b7fe27b50bb44679e2cc4660272694b7b6f3326d8480823a94" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + +[[package]] +name = "ureq" +version = "2.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b74fc6b57825be3373f7054754755f03ac3a8f5d70015ccad699ba2029956f4a" +dependencies = [ + "base64 0.22.1", + "flate2", + "log", + "native-tls", + "once_cell", + "rustls 0.23.13", + "rustls-pki-types", + "socks", + "url", + "webpki-roots 0.26.6", +] + +[[package]] +name = "url" +version = "2.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "urlencoding" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" + +[[package]] +name = "urlpattern" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d" +dependencies = [ + "regex", + "serde", + "unic-ucd-ident", + "url", +] + +[[package]] +name = "usvg" +version = "0.43.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6803057b5cbb426e9fb8ce2216f3a9b4ca1dd2c705ba3cbebc13006e437735fd" +dependencies = [ + "base64 0.22.1", + "data-url", + "flate2", + "fontdb", + "imagesize", + "kurbo", + "log", + "pico-args 0.5.0", + "roxmltree", + "rustybuzz", + "simplecss", + "siphasher 1.0.1", + "strict-num", + "svgtypes", + "tiny-skia-path", + "unicode-bidi", + "unicode-script", + "unicode-vo", + "xmlwriter", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "utf16_iter" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" + +[[package]] +name = "utf8-width" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86bd8d4e895da8537e5315b8254664e6b769c4ff3db18321b297a1e7004392e3" + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +dependencies = [ + "getrandom 0.2.15", + "serde", + "sha1_smol", +] + +[[package]] +name = "v_frame" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f32aaa24bacd11e488aa9ba66369c7cd514885742c9fe08cfe85884db3e92b" +dependencies = [ + "aligned-vec", + "num-traits", + "wasm-bindgen", +] + +[[package]] +name = "value-bag" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a84c137d37ab0142f0f2ddfe332651fdbf252e7b7dbb4e67b6c1f1b2e925101" +dependencies = [ + "value-bag-serde1", + "value-bag-sval2", +] + +[[package]] +name = "value-bag-serde1" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccacf50c5cb077a9abb723c5bcb5e0754c1a433f1e1de89edc328e2760b6328b" +dependencies = [ + "erased-serde", + "serde", + "serde_fmt", +] + +[[package]] +name = "value-bag-sval2" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1785bae486022dfb9703915d42287dcb284c1ee37bd1080eeba78cc04721285b" +dependencies = [ + "sval", + "sval_buffer", + "sval_dynamic", + "sval_fmt", + "sval_json", + "sval_ref", + "sval_serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version-compare" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "vlq" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65dd7eed29412da847b0f78bcec0ac98588165988a8cfe41d4ea1d429f8ccfff" + +[[package]] +name = "vsimd" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c3082ca00d5a5ef149bb8b555a72ae84c9c59f7250f013ac822ac2e49b19c64" + +[[package]] +name = "vswhom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be979b7f07507105799e854203b470ff7c78a1639e330a58f183b5fea574608b" +dependencies = [ + "libc", + "vswhom-sys", +] + +[[package]] +name = "vswhom-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3b17ae1f6c8a2b28506cd96d412eebf83b4a0ff2cbefeeb952f2f9dfa44ba18" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "wasm-streams" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e072d4e72f700fb3443d8fe94a39315df013eef1104903cdb0a2abd322bbecd" +dependencies = [ + "futures-util", + "js-sys", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webkit2gtk" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +dependencies = [ + "bitflags 1.3.2", + "cairo-rs", + "gdk", + "gdk-sys", + "gio", + "gio-sys", + "glib", + "glib-sys", + "gobject-sys", + "gtk", + "gtk-sys", + "javascriptcore-rs", + "libc", + "once_cell", + "soup3", + "webkit2gtk-sys", +] + +[[package]] +name = "webkit2gtk-sys" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +dependencies = [ + "bitflags 1.3.2", + "cairo-sys-rs", + "gdk-sys", + "gio-sys", + "glib-sys", + "gobject-sys", + "gtk-sys", + "javascriptcore-rs-sys", + "libc", + "pkg-config", + "soup3-sys", + "system-deps", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "0.26.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "webview2-com" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c" +dependencies = [ + "webview2-com-macros", + "webview2-com-sys", + "windows", + "windows-core 0.58.0", + "windows-implement", + "windows-interface", +] + +[[package]] +name = "webview2-com-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d228f15bba3b9d56dde8bddbee66fa24545bd17b48d5128ccf4a8742b18e431" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "webview2-com-sys" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" +dependencies = [ + "thiserror 1.0.68", + "windows", + "windows-core 0.58.0", +] + +[[package]] +name = "weezl" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53a85b86a771b1c87058196170769dd264f66c0782acf1ae6cc51bfd64b39082" + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix 0.38.37", +] + +[[package]] +name = "which" +version = "6.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" +dependencies = [ + "either", + "home", + "rustix 0.38.37", + "winsafe", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +dependencies = [ + "windows-sys 0.59.0", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "window-vibrancy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ea403deff7b51fff19e261330f71608ff2cdef5721d72b64180bb95be7c4150" +dependencies = [ + "objc2", + "objc2-app-kit", + "objc2-foundation", + "raw-window-handle", + "windows-sys 0.59.0", + "windows-version", +] + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-result", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-registry" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bafa604f2104cf5ae2cc2db1dee84b7e6a5d11b05f737b60def0ffdc398cbc0a" +dependencies = [ + "windows-result", + "windows-strings 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978d65aedf914c664c510d9de43c8fd85ca745eaff1ed53edf409b479e441663" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-version" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6998aa457c9ba8ff2fb9f13e9d2a930dabcea28f1d0ab94d687d8b3654844515" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "winreg" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + +[[package]] +name = "winsafe" +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 1.0.68", + "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.90", + "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 = "write16" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" + +[[package]] +name = "writeable" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" + +[[package]] +name = "wry" +version = "0.47.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553ca1ce149982123962fac2506aa75b8b76288779a77e72b12fa2fc34938647" +dependencies = [ + "base64 0.22.1", + "block2", + "cookie", + "crossbeam-channel", + "dpi", + "dunce", + "gdkx11", + "gtk", + "html5ever", + "http 1.1.0", + "javascriptcore-rs", + "jni", + "kuchikiki", + "libc", + "ndk", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "objc2-ui-kit", + "objc2-web-kit", + "once_cell", + "percent-encoding", + "raw-window-handle", + "sha2", + "soup3", + "tao-macros", + "thiserror 1.0.68", + "tracing", + "url", + "webkit2gtk", + "webkit2gtk-sys", + "webview2-com", + "windows", + "windows-core 0.58.0", + "windows-version", + "x11-dl", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "x11" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "502da5464ccd04011667b11c435cb992822c2c0dbde1770c988480d312a0db2e" +dependencies = [ + "libc", + "pkg-config", +] + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x25519-dalek" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7e468321c81fb07fa7f4c636c3972b9100f0346e5b6a9f2bd0603a52f7ed277" +dependencies = [ + "curve25519-dalek", + "rand_core 0.6.4", + "serde", + "zeroize", +] + +[[package]] +name = "x509" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3cec94c3999f31341553f358ef55f65fc031291a022cd42ec0ce7219560c76" +dependencies = [ + "chrono", + "cookie-factory", +] + +[[package]] +name = "x509-certificate" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66534846dec7a11d7c50a74b7cdb208b9a581cad890b7866430d438455847c85" +dependencies = [ + "bcder", + "bytes", + "chrono", + "der 0.7.9", + "hex", + "pem", + "ring", + "signature 2.2.0", + "spki 0.7.3", + "thiserror 1.0.68", + "zeroize", +] + +[[package]] +name = "xattr" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +dependencies = [ + "libc", + "linux-raw-sys 0.4.14", + "rustix 0.38.37", +] + +[[package]] +name = "xml-rs" +version = "0.8.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af4e2e2f7cba5a093896c1e150fbfe177d1883e7448200efb81d40b9d339ef26" + +[[package]] +name = "xmlparser" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66fee0b777b0f5ac1c69bb06d361268faafa61cd4682ae064a171c16c433e9e4" + +[[package]] +name = "xmlwriter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec7a2a501ed189703dba8b08142f057e887dfc4b2cc4db2d343ac6376ba3e0b9" + +[[package]] +name = "xz2" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388c44dc09d76f1536602ead6d325eb532f5c122f17782bd57fb47baeeb767e2" +dependencies = [ + "lzma-sys", +] + +[[package]] +name = "yansi" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" + +[[package]] +name = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" + +[[package]] +name = "yoke" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +dependencies = [ + "serde", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "byteorder", + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zerofrom" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", + "synstructure 0.13.1", +] + +[[package]] +name = "zeroize" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zerovec" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "byteorder", + "crc32fast", + "crossbeam-utils", + "flate2", +] + +[[package]] +name = "zip" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc5e4288ea4057ae23afc69a4472434a87a2495cafce6632fd1c4ec9f5cf3494" +dependencies = [ + "arbitrary", + "crc32fast", + "crossbeam-utils", + "displaydoc", + "flate2", + "indexmap 2.6.0", + "memchr", + "thiserror 1.0.68", + "zopfli", +] + +[[package]] +name = "zip_structs" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce824a6bfffe8942820fa36d24973b7c83a40896749a42e33de0abdd11750ee5" +dependencies = [ + "byteorder", + "bytesize", + "thiserror 1.0.68", +] + +[[package]] +name = "zopfli" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5019f391bac5cf252e93bbcc53d039ffd62c7bfb7c150414d61369afe57e946" +dependencies = [ + "bumpalo", + "crc32fast", + "lockfree-object-pool", + "log", + "once_cell", + "simd-adler32", +] + +[[package]] +name = "zstd" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf2b778a664581e31e389454a7072dab1647606d44f7feea22cd5abb9c9f3f9" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "7.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a3ab4db68cea366acc5c897c7b4d4d1b8994a9cd6e6f841f8964566a419059" +dependencies = [ + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.13+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-inflate" +version = "0.2.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73ab332fe2f6680068f3582b16a24f90ad7096d5d39b974d1c0aff0125116f02" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "zune-jpeg" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16099418600b4d8f028622f73ff6e3deaabdff330fb9a2a131dea781ee8b0768" +dependencies = [ + "zune-core", +] diff --git a/Cargo.toml b/Cargo.toml index c95d732b27c5..963894b5910b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,22 +1,49 @@ [workspace] members = [ - # core - "core/tauri", - "core/tauri-runtime", - "core/tauri-runtime-wry", - "core/tauri-macros", - "core/tauri-utils", - "core/tauri-build", - "core/tauri-codegen" -] -exclude = [ - # examples that can be compiled with the tauri CLI - "examples/api/src-tauri", - "examples/updater/src-tauri", + "crates/tauri", + "crates/tauri-runtime", + "crates/tauri-runtime-wry", + "crates/tauri-macros", + "crates/tauri-utils", + "crates/tauri-build", + "crates/tauri-codegen", + "crates/tauri-plugin", + "crates/tauri-schema-generator", + "crates/tauri-schema-worker", + "crates/tauri-cli", + "crates/tauri-bundler", + "crates/tauri-macos-sign", + "crates/tauri-driver", + + # @tauri-apps/cli rust project + "packages/cli", + + # integration tests + "crates/tests/restart", + "crates/tests/acl", + + # bench + "bench", + "bench/tests/cpu_intensive/src-tauri", + "bench/tests/files_transfer/src-tauri", + "bench/tests/helloworld/src-tauri", + + # examples + "examples/file-associations/src-tauri", "examples/resources/src-tauri", - "examples/sidecar/src-tauri", - "examples/isolation/src-tauri" + "examples/api/src-tauri", + "examples/api/src-tauri/tauri-plugin-sample", ] +resolver = "2" + +[workspace.package] +authors = ["Tauri Programme within The Commons Conservancy"] +homepage = "https://tauri.app/" +repository = "https://github.com/tauri-apps/tauri" +categories = ["gui", "web-programming"] +license = "Apache-2.0 OR MIT" +edition = "2021" +rust-version = "1.77.2" # default to small, optimized workspace release binaries [profile.release] @@ -25,3 +52,21 @@ codegen-units = 1 lto = true incremental = false opt-level = "s" +strip = true + +# profiles for tauri-cli +[profile.dev.package.miniz_oxide] +opt-level = 3 + +[profile.release-size-optimized] +inherits = "release" +codegen-units = 1 +lto = true +incremental = false +opt-level = "s" + +# Temporary patch to schemars to preserve newlines in docstrings for our reference docs schemas +# See https://github.com/GREsau/schemars/issues/120 for reference +[patch.crates-io] +schemars_derive = { git = 'https://github.com/tauri-apps/schemars.git', branch = 'feat/preserve-description-newlines' } +tauri = { path = "./crates/tauri" } diff --git a/LICENSE.spdx b/LICENSE.spdx index 4a4518460ea9..978d1d4223d3 100644 --- a/LICENSE.spdx +++ b/LICENSE.spdx @@ -6,7 +6,7 @@ PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy PackageHomePage: https://tauri.app PackageLicenseDeclared: Apache-2.0 PackageLicenseDeclared: MIT -PackageCopyrightText: 2019-2021, The Tauri Programme in the Commons Conservancy +PackageCopyrightText: 2019-2024, The Tauri Programme in the Commons Conservancy PackageSummary: Tauri is a rust project that enables developers to make secure and small desktop applications using a web frontend. @@ -17,4 +17,4 @@ Created: 2019-05-20T09:00:00Z PackageDownloadLocation: git://github.com/tauri-apps/tauri PackageDownloadLocation: git+https://github.com/tauri-apps/tauri.git PackageDownloadLocation: git+ssh://github.com/tauri-apps/tauri.git -Creator: Person: Daniel Thompson-Yvetot \ No newline at end of file +Creator: Person: Daniel Thompson-Yvetot diff --git a/README.md b/README.md index f8f976feeef0..99624ebd89b2 100644 --- a/README.md +++ b/README.md @@ -1,161 +1,96 @@ Tauri -[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri/tree/dev) +[![status](https://img.shields.io/badge/status-stable-blue.svg)](https://github.com/tauri-apps/tauri/tree/dev) [![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri) -[![test library](https://img.shields.io/github/workflow/status/tauri-apps/tauri/test%20library?label=test%20library)](https://github.com/tauri-apps/tauri/actions?query=workflow%3A%22test+library%22) +[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_shield) - -[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) -[![devto](https://img.shields.io/badge/blog-dev.to-black.svg)](https://dev.to/tauri) -[![devto](https://img.shields.io/badge/documentation-tauri.studio-purple.svg)](https://tauri.studio/docs/get-started/intro) +[![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S) +[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app) [![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) -[![support](https://img.shields.io/badge/sponsor-open%20collective-blue.svg)](https://opencollective.com/tauri) - -## Current Releases - -| Component | Description | Version | Lin | Win | Mac | -| ------------------------------------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------- | --- | --- | --- | -| [**cli.rs**](https://github.com/tauri-apps/tauri/tree/dev/tooling/cli) | create, develop and build apps | [![](https://img.shields.io/crates/v/tauri-cli.svg)](https://crates.io/crates/tauri-cli) | ✅ | ✅ | ✅ | -| [**cli.js**](https://github.com/tauri-apps/tauri/tree/dev/tooling/cli/node) | Node.js CLI wrapper for cli.rs | [![](https://img.shields.io/npm/v/@tauri-apps/cli.svg)](https://www.npmjs.com/package/@tauri-apps/cli) | ✅ | ✅ | ✅ | -| [**api.js**](https://github.com/tauri-apps/tauri/tree/dev/tooling/api) | JS API for interaction with Rust backend | [![](https://img.shields.io/npm/v/@tauri-apps/api.svg)](https://www.npmjs.com/package/@tauri-apps/api) | ✅ | ✅ | ✅ | -| [**create-tauri-app**](https://github.com/tauri-apps/create-tauri-app) | Get started with your first Tauri app | [![](https://img.shields.io/npm/v/create-tauri-app.svg)](https://www.npmjs.com/package/create-tauri-app) | ✅ | ✅ | ✅ | -| [**vue-cli-plugin-tauri**](https://github.com/tauri-apps/vue-cli-plugin-tauri/) | Vue CLI plugin for Tauri | [![](https://img.shields.io/npm/v/vue-cli-plugin-tauri.svg)](https://www.npmjs.com/package/vue-cli-plugin-tauri) | ✅ | ✅ | ✅ | -| [**core**](https://github.com/tauri-apps/tauri/tree/dev/core/tauri) | runtime core | [![](https://img.shields.io/crates/v/tauri.svg)](https://crates.io/crates/tauri) | ✅ | ✅ | ✅ | -| [**bundler**](https://github.com/tauri-apps/tauri/tree/dev/tooling/bundler) | manufacture the final binaries | [![](https://img.shields.io/crates/v/tauri-bundler.svg)](https://crates.io/crates/tauri-bundler) | ✅ | ✅ | ✅ | +[![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri) ## Introduction -Tauri is a framework for building tiny, blazing fast binaries for all major desktop platforms. Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface. The backend of the application is a rust-sourced binary with an API that the front-end can interact with. -The user interface in Tauri apps currently leverages [`tao`](https://docs.rs/tao) as a window handling library on macOS and Windows, and [`gtk`](https://gtk-rs.org/docs/gtk/) on Linux via the **Tauri-team** incubated and maintained [WRY](https://github.com/tauri-apps/wry), which creates a unified interface to the system webview (and other goodies like Menu and Taskbar), leveraging WebKit on macOS, WebView2 on Windows and WebKitGTK on Linux. +Tauri is a framework for building tiny, blazingly fast binaries for all major desktop platforms. Developers can integrate any front-end framework that compiles to HTML, JS and CSS for building their user interface. The backend of the application is a rust-sourced binary with an API that the front-end can interact with. + +The user interface in Tauri apps currently leverages [`tao`](https://docs.rs/tao) as a window handling library on macOS, Windows, Linux, Android and iOS. To render your application, Tauri uses [WRY](https://github.com/tauri-apps/wry), a library which provides a unified interface to the system webview, leveraging WKWebView on macOS & iOS, WebView2 on Windows, WebKitGTK on Linux and Android System WebView on Android. To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. -## Get Started -If you are interested in making a tauri-app, please visit the [documentation website](https://tauri.studio). This README is directed towards those who are interested in contributing to the core library. But if you just want a quick overview about where `tauri` is at in its development, here's a quick burndown: +## Getting Started + +If you are interested in making a tauri app, please visit the [documentation website](https://tauri.app). + +The quickest way to get started is to install the [prerequisites](https://v2.tauri.app/start/prerequisites/) for your system and create a new project with [`create-tauri-app`](https://github.com/tauri-apps/create-tauri-app/#usage). For example with `npm`: + +```sh +npm create tauri-app@latest +``` + +## Features + +The list of Tauri's features includes, but is not limited to: + +- Built-in app bundler to create app bundles in formats like `.app`, `.dmg`, `.deb`, `.rpm`, `.AppImage` and Windows installers like `.exe` (via NSIS) and `.msi` (via WiX). +- Built-in self updater (desktop only) +- System tray icons +- Native notifications +- [Localhost free (🔥)](https://github.com/tauri-apps/tauri/issues/10510) +- GitHub action for streamlined CI +- VS Code extension ### Platforms -- [x] Windows 7,8,10 -- [x] Linux -- [x] macOS -- [ ] iOS (in progress) -- [ ] android (soon) - -### App Bundles -- [x] App Icons -- [x] Build on MacOS (.app, .dmg) -- [x] Build on Linux (.deb, AppImage) -- [x] Build on Windows (.exe, .msi) -- [x] Copy Buffer -- [x] Device Notifications (toast) -- [x] Self Updater -- [x] App Signing -- [x] Frameless Mode -- [x] Transparent Mode -- [x] Multiwindow Mode -- [x] Tray -- [ ] deeplink RPC (in progress) -- [ ] One-Time commands (coming soon) - -### Security Features -- [x] localhost-free (:fire:) -- [x] custom protocol for secure mode -- [x] Dynamic ahead of Time Compilation (dAoT) with functional tree-shaking -- [x] functional Address Space Layout Randomization -- [x] OTP salting of function names and messages at runtime -- [x] CSP Injection - -### Utilities -- [x] GH Action for creating binaries for all platforms -- [x] VS Code Extension -- [x] Tauri Core Plugins -- [x] Update core dependencies automatically from the command line -- [x] Rust-based CLI - -### Comparison between Tauri and Electron - -| Detail | Tauri | Electron | -| -------------------------- | ------ | -------------------- | -| Installer Size Linux | 3.1 MB | 52.1 MB | -| Memory Consumption Linux | 180 MB | 462 MB | -| Launch Time Linux | 0.39s | 0.80s | -| Interface Service Provider | WRY | Chromium | -| Backend Binding | Rust | Node.js (ECMAScript) | -| Underlying Engine | Rust | V8 (C/C++) | -| FLOSS | Yes | No | -| Multithreading | Yes | Yes | -| Bytecode Delivery | Yes | No | -| Multiple Windows | Yes | Yes | -| Auto Updater | Yes | Yes1 | -| Custom App Icon | Yes | Yes | -| Windows Binary | Yes | Yes | -| MacOS Binary | Yes | Yes | -| Linux Binary | Yes | Yes | -| iOS Binary | Soon | No | -| Android Binary | Soon | No | -| Desktop Tray | Yes | Yes | -| Sidecar Binaries | Yes | No | - -#### Notes -1. Electron has no native auto updater on Linux, but is offered by electron-packager - -## Development - -Tauri is a system composed of a number of moving pieces: - -### Infrastructure -- Git for code management -- GitHub for project management -- GitHub actions for CI and CD -- Discord for discussions -- Netlify-hosted documentation website -- DigitalOcean meilisearch instance - -### Major Runtimes -- Node.js for running the CLI (deno and pure rust are on the roadmap) -- Cargo for testing, running the dev service, building binaries and as the runtime harness for the webview - -### Major Languages -- Rust for the CLI -- EcmaScript bindings to the Rust API, written in typescript -- Rust for bindings, rust side of the API, harnesses -- Rust plugins to Tauri backend - -### Operating systems -Tauri core can be developed on Mac, Linux and Windows, but you are encouraged to use the latest possible operating systems and build tools for your OS. - -### Contributing -Before you start working on something, it's best to check if there is an existing issue first. It's also is a good idea to stop by the Discord server and confirm with the team if it makes sense or if someone is already working on it. + +Tauri currently supports development and distribution on the following platforms: + +| Platform | Versions | +| :---------------- | :-------------------------------------------------------------------------------------------------------------- | +| Windows | 7 and above | +| macOS | 10.15 and above | +| Linux | webkit2gtk 4.0 for Tauri v1 (for example Ubuntu 18.04). webkit2gtk 4.1 for Tauri v2 (for example Ubuntu 22.04). | +| iOS/iPadOS (beta) | 9 and above | +| Android (beta) | 7 and above | + +## Contributing + +Before you start working on something, it's best to check if there is an existing issue first. It's also a good idea to stop by the Discord server and confirm with the team if it makes sense or if someone else is already working on it. Please make sure to read the [Contributing Guide](./.github/CONTRIBUTING.md) before making a pull request. Thank you to everyone contributing to Tauri! ### Documentation -Documentation in a polyglot system is a tricky proposition. To this end, we prefer to use inline documentation of Rust code and at JSDoc in typescript / javascript code. We autocollect these and publish them using Docusaurus v2 and netlify. Here is the hosting repository for the documentation site: https://github.com/tauri-apps/tauri-docs -### Testing & Linting -Test all the things! We have a number of test suites, but are always looking to improve our coverage: -- Rust (`cargo test`) => sourced via inline `#[cfg(test)]` declarations -- TS (`jest`) => via spec files -- Smoke Tests (run on merges to latest) -- eslint, clippy +Documentation in a polyglot system is a tricky proposition. To this end, we prefer to use inline documentation in the Rust & JS source code as much as possible. Check out the hosting repository for the documentation site for further information: + +## Partners + + + + + + + +
+ + CrabNebula + +
-### CI/CD -We recommend you read this article to understand better how we run our pipelines: https://www.jacobbolda.com/setting-up-ci-and-cd-for-tauri/ +For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri). ## Organization -Tauri aims to be a sustainable collective based on principles that guide [sustainable free and open software communities](https://sfosc.org). To this end it has become a Programme within the [Commons Conservancy](https://commonsconservancy.org/), and you can contribute financially via [Open Collective](https://opencollective.com/tauri). -## Semver -**tauri** is following [Semantic Versioning 2.0](https://semver.org/). +Tauri aims to be a sustainable collective based on principles that guide [sustainable free and open software communities](https://sfosc.org). To this end it has become a Programme within the [Commons Conservancy](https://commonsconservancy.org/), and you can contribute financially via [Open Collective](https://opencollective.com/tauri). ## Licenses -Code: (c) 2015 - 2021 - The Tauri Programme within The Commons Conservancy. + +Code: (c) 2015 - Present - The Tauri Programme within The Commons Conservancy. MIT or MIT/Apache 2.0 where applicable. Logo: CC-BY-NC-ND -- Original Tauri Logo Designs by [Alve Larsson](https://alve.io/), [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) +- Original Tauri Logo Designs by [Alve Larsson](https://alve.io/), [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_large) diff --git a/SECURITY.md b/SECURITY.md index cbd06ded3472..9c941968c38b 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -10,10 +10,19 @@ ## Reporting a Vulnerability If you have found a potential security threat, vulnerability or exploit in Tauri -or one of its upstream dependencies, please DON’T create a pull-request, DON’T -file an issue on GitHub, DON’T mention it on Discord and DON’T create a forum thread. +or one of its upstream dependencies, please DON'T create a pull-request, DON'T +file an issue on GitHub, DON'T mention it on Discord and DON'T create a forum thread. -We will be adding contact information to this page very soon. +Please submit your report via the GitHub Private Vulnerability Disclosure functionality. -At the current time we do not have the financial ability to reward bounties, +Find out more about the reporting process [here](https://docs.github.com/en/code-security/security-advisories/guidance-on-reporting-and-writing/privately-reporting-a-security-vulnerability#privately-reporting-a-security-vulnerability). + +Our team will triage your report and keep you informed about the progress. +We may ask questions or request further guidance on reproduction of the vulnerability in the comments of the advisory, which will be publicized. + +Additionally, we may ask you to independently verify our patch, which will be available in the private advisory branch. Please do not publish your vulnerability during the process or before coordinated public disclosure from our side. We try to adhere to common standards of publication within 90-Days of disclosure. + +Depending on your decision to accept or deny credit for the vulnerability, you will be publicly attributed to the vulnerability and may be mentioned in our announcements. + +At the current time we do not have the financial ability to reward bounties, but in extreme cases will at our discretion consider a reward. diff --git a/audits/Radically_Open_Security-v2-report.pdf b/audits/Radically_Open_Security-v2-report.pdf new file mode 100644 index 000000000000..bd654e4543e5 Binary files /dev/null and b/audits/Radically_Open_Security-v2-report.pdf differ diff --git a/bench/Cargo.toml b/bench/Cargo.toml new file mode 100644 index 000000000000..7b9b36e334cb --- /dev/null +++ b/bench/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "tauri_bench" +version = "0.1.0" +authors = ["Tauri Programme within The Commons Conservancy"] +edition = "2021" +rust-version = "1.77.2" +license = "Apache-2.0 OR MIT" +description = "Cross-platform WebView rendering library" +repository = "https://github.com/tauri-apps/wry" + +[dependencies] +anyhow = "1.0.40" +time = { version = "0.3", features = ["formatting"] } +tempfile = "3.2.0" +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } + +[[bin]] +name = "run_benchmark" +path = "src/run_benchmark.rs" + +[[bin]] +name = "build_benchmark_jsons" +path = "src/build_benchmark_jsons.rs" diff --git a/bench/README.md b/bench/README.md new file mode 100644 index 000000000000..b6894f04aeaa --- /dev/null +++ b/bench/README.md @@ -0,0 +1,38 @@ +# Tauri Bench + + + +[![status](https://img.shields.io/badge/Status-beta-green.svg)](https://github.com/tauri-apps/tauri) +[![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri) +[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_shield) +[![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S) +[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app) +[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) +[![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri) + +## About Tauri + +Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. + +Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. + +## This module + +This rust module run on CI, provides internal metrics results of Tauri. To learn more see [benchmark_results](https://github.com/tauri-apps/benchmark_results) repository. + +**\*_Internal use only_** + +## Semver + +**tauri** is following [Semantic Versioning 2.0](https://semver.org/). + +## Licenses + +Code: (c) 2015 - 2021 - The Tauri Programme within The Commons Conservancy. + +MIT or MIT/Apache 2.0 where applicable. + +Logo: CC-BY-NC-ND + +- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/bench/src/build_benchmark_jsons.rs b/bench/src/build_benchmark_jsons.rs new file mode 100644 index 000000000000..71a6e32cdf6f --- /dev/null +++ b/bench/src/build_benchmark_jsons.rs @@ -0,0 +1,64 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! This Rust binary runs on CI and provides internal metrics results of Tauri. To learn more see [benchmark_results](https://github.com/tauri-apps/benchmark_results) repository. +//! +//! ***_Internal use only_** + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +use std::{fs::File, io::BufReader}; +mod utils; + +fn main() { + let tauri_data = &utils::tauri_root_path() + .join("gh-pages") + .join("tauri-data.json"); + let tauri_recent = &utils::tauri_root_path() + .join("gh-pages") + .join("tauri-recent.json"); + + // current data + let current_data_buffer = BufReader::new( + File::open(utils::target_dir().join("bench.json")).expect("Unable to read current data file"), + ); + let current_data: utils::BenchResult = + serde_json::from_reader(current_data_buffer).expect("Unable to read current data buffer"); + + // all data's + let all_data_buffer = + BufReader::new(File::open(tauri_data).expect("Unable to read all data file")); + let mut all_data: Vec = + serde_json::from_reader(all_data_buffer).expect("Unable to read all data buffer"); + + // add current data to all data + all_data.push(current_data); + + // use only latest 20 elements from all data + let recent: Vec = if all_data.len() > 20 { + all_data[all_data.len() - 20..].to_vec() + } else { + all_data.clone() + }; + + // write json's + utils::write_json( + tauri_data + .to_str() + .expect("Something wrong with tauri_data"), + &serde_json::to_value(all_data).expect("Unable to build final json (all)"), + ) + .unwrap_or_else(|_| panic!("Unable to write {:?}", tauri_data)); + + utils::write_json( + tauri_recent + .to_str() + .expect("Something wrong with tauri_recent"), + &serde_json::to_value(recent).expect("Unable to build final json (recent)"), + ) + .unwrap_or_else(|_| panic!("Unable to write {:?}", tauri_recent)); +} diff --git a/tooling/bench/src/run_benchmark.rs b/bench/src/run_benchmark.rs similarity index 85% rename from tooling/bench/src/run_benchmark.rs rename to bench/src/run_benchmark.rs index 8319e008b5e0..d55d8ee03ab3 100644 --- a/tooling/bench/src/run_benchmark.rs +++ b/bench/src/run_benchmark.rs @@ -1,7 +1,16 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +//! This Rust binary runs on CI and provides internal metrics results of Tauri. To learn more see [benchmark_results](https://github.com/tauri-apps/benchmark_results) repository. +//! +//! ***_Internal use only_** + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + use anyhow::Result; use std::{ collections::{HashMap, HashSet}, @@ -17,22 +26,19 @@ fn get_all_benchmarks() -> Vec<(String, String)> { vec![ ( "tauri_hello_world".into(), - format!( - "tests/target/{}/release/bench_helloworld", - utils::get_target() - ), + format!("../target/{}/release/bench_helloworld", utils::get_target()), ), ( "tauri_cpu_intensive".into(), format!( - "tests/target/{}/release/bench_cpu_intensive", + "../target/{}/release/bench_cpu_intensive", utils::get_target() ), ), ( "tauri_3mb_transfer".into(), format!( - "tests/target/{}/release/bench_files_transfer", + "../target/{}/release/bench_files_transfer", utils::get_target() ), ), @@ -49,7 +55,7 @@ fn run_strace_benchmarks(new_data: &mut utils::BenchResult) -> Result<()> { let mut file = tempfile::NamedTempFile::new()?; Command::new("strace") - .args(&[ + .args([ "-c", "-f", "-o", @@ -64,7 +70,10 @@ fn run_strace_benchmarks(new_data: &mut utils::BenchResult) -> Result<()> { file.as_file_mut().read_to_string(&mut output)?; let strace_result = utils::parse_strace_output(&output); - let clone = strace_result.get("clone").map(|d| d.calls).unwrap_or(0) + 1; + // Note, we always have 1 thread. Use cloneX calls as counter for additional threads created. + let clone = 1 + + strace_result.get("clone").map(|d| d.calls).unwrap_or(0) + + strace_result.get("clone3").map(|d| d.calls).unwrap_or(0); let total = strace_result.get("total").unwrap().calls; thread_count.insert(name.to_string(), clone); syscall_count.insert(name.to_string(), total); @@ -84,7 +93,7 @@ fn run_max_mem_benchmark() -> Result> { let benchmark_file = benchmark_file.to_str().unwrap(); let proc = Command::new("mprof") - .args(&[ + .args([ "run", "-C", "-o", @@ -99,7 +108,7 @@ fn run_max_mem_benchmark() -> Result> { println!("{:?}", proc_result); results.insert( name.to_string(), - utils::parse_max_mem(&benchmark_file).unwrap(), + utils::parse_max_mem(benchmark_file).unwrap(), ); } @@ -132,7 +141,7 @@ fn rlib_size(target_dir: &std::path::Path, prefix: &str) -> u64 { fn get_binary_sizes(target_dir: &Path) -> Result> { let mut sizes = HashMap::::new(); - let wry_size = rlib_size(&target_dir, "libwry"); + let wry_size = rlib_size(target_dir, "libwry"); println!("wry {} bytes", wry_size); sizes.insert("wry_rlib".to_string(), wry_size); @@ -174,10 +183,10 @@ fn cargo_deps() -> HashMap { let mut cmd = Command::new("cargo"); cmd.arg("tree"); cmd.arg("--no-dedupe"); - cmd.args(&["--edges", "normal"]); - cmd.args(&["--prefix", "none"]); - cmd.args(&["--target", target]); - cmd.current_dir(&utils::tauri_root_path()); + cmd.args(["--edges", "normal"]); + cmd.args(["--prefix", "none"]); + cmd.args(["--target", target]); + cmd.current_dir(utils::tauri_root_path()); let full_deps = cmd.output().expect("failed to run cargo tree").stdout; let full_deps = String::from_utf8(full_deps).expect("cargo tree output not utf-8"); @@ -262,13 +271,13 @@ fn main() -> Result<()> { let target_dir = utils::target_dir(); - env::set_current_dir(&utils::bench_root_path())?; + env::set_current_dir(utils::bench_root_path())?; let format = time::format_description::parse("[year]-[month]-[day]T[hour]:[minute]:[second]Z").unwrap(); let now = time::OffsetDateTime::now_utc(); let mut new_data = utils::BenchResult { - created_at: format!("{}", now.format(&format).unwrap()), + created_at: now.format(&format).unwrap(), sha1: utils::run_collect(&["git", "rev-parse", "HEAD"]) .0 .trim() diff --git a/bench/src/utils.rs b/bench/src/utils.rs new file mode 100644 index 000000000000..6571f5f2df6a --- /dev/null +++ b/bench/src/utils.rs @@ -0,0 +1,245 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use anyhow::Result; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use std::{ + collections::HashMap, + fs, + io::{BufRead, BufReader}, + path::PathBuf, + process::{Command, Output, Stdio}, +}; + +#[derive(Default, Clone, Serialize, Deserialize, Debug)] +pub struct BenchResult { + pub created_at: String, + pub sha1: String, + pub exec_time: HashMap>, + pub binary_size: HashMap, + pub max_memory: HashMap, + pub thread_count: HashMap, + pub syscall_count: HashMap, + pub cargo_deps: HashMap, +} + +#[allow(dead_code)] +#[derive(Debug, Clone, Serialize)] +pub struct StraceOutput { + pub percent_time: f64, + pub seconds: f64, + pub usecs_per_call: Option, + pub calls: u64, + pub errors: u64, +} + +pub fn get_target() -> &'static str { + #[cfg(target_os = "macos")] + return if cfg!(target_arch = "aarch64") { + "aarch64-apple-darwin" + } else { + "x86_64-apple-darwin" + }; + #[cfg(target_os = "ios")] + return if cfg!(target_arch = "aarch64") { + "aarch64-apple-ios" + } else { + "x86_64-apple-ios" + }; + #[cfg(target_os = "linux")] + return "x86_64-unknown-linux-gnu"; + #[cfg(target_os = "windows")] + unimplemented!(); +} + +pub fn target_dir() -> PathBuf { + bench_root_path() + .join("..") + .join("target") + .join(get_target()) + .join("release") +} + +pub fn bench_root_path() -> PathBuf { + PathBuf::from(env!("CARGO_MANIFEST_DIR")) +} + +#[allow(dead_code)] +pub fn home_path() -> PathBuf { + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "linux"))] + return PathBuf::from(env!("HOME")); + #[cfg(target_os = "windows")] + return PathBuf::from(env!("HOMEPATH")); +} + +#[allow(dead_code)] +pub fn tauri_root_path() -> PathBuf { + bench_root_path().parent().unwrap().to_path_buf() +} + +#[allow(dead_code)] +pub fn run_collect(cmd: &[&str]) -> (String, String) { + let mut process_builder = Command::new(cmd[0]); + process_builder + .args(&cmd[1..]) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()); + let prog = process_builder.spawn().expect("failed to spawn script"); + let Output { + stdout, + stderr, + status, + } = prog.wait_with_output().expect("failed to wait on child"); + let stdout = String::from_utf8_lossy(&stdout).to_string(); + let stderr = String::from_utf8_lossy(&stderr).to_string(); + if !status.success() { + eprintln!("stdout: <<<{}>>>", stdout); + eprintln!("stderr: <<<{}>>>", stderr); + panic!("Unexpected exit code: {:?}", status.code()); + } + (stdout, stderr) +} + +#[allow(dead_code)] +pub fn parse_max_mem(file_path: &str) -> Option { + let file = fs::File::open(file_path).unwrap(); + let output = BufReader::new(file); + let mut highest: u64 = 0; + // MEM 203.437500 1621617192.4123 + for line in output.lines().map_while(Result::ok) { + // split line by space + let split = line.split(' ').collect::>(); + if split.len() == 3 { + // mprof generate result in MB + let current_bytes = str::parse::(split[1]).unwrap() as u64 * 1024 * 1024; + if current_bytes > highest { + highest = current_bytes; + } + } + } + + fs::remove_file(file_path).unwrap(); + + if highest > 0 { + return Some(highest); + } + + None +} + +#[allow(dead_code)] +pub fn parse_strace_output(output: &str) -> HashMap { + let mut summary = HashMap::new(); + + let mut lines = output + .lines() + .filter(|line| !line.is_empty() && !line.contains("detached ...")); + let count = lines.clone().count(); + + if count < 4 { + return summary; + } + + let total_line = lines.next_back().unwrap(); + lines.next_back(); // Drop separator + let data_lines = lines.skip(2); + + for line in data_lines { + let syscall_fields = line.split_whitespace().collect::>(); + let len = syscall_fields.len(); + let syscall_name = syscall_fields.last().unwrap(); + + if (5..=6).contains(&len) { + summary.insert( + syscall_name.to_string(), + StraceOutput { + percent_time: str::parse::(syscall_fields[0]).unwrap(), + seconds: str::parse::(syscall_fields[1]).unwrap(), + usecs_per_call: Some(str::parse::(syscall_fields[2]).unwrap()), + calls: str::parse::(syscall_fields[3]).unwrap(), + errors: if syscall_fields.len() < 6 { + 0 + } else { + str::parse::(syscall_fields[4]).unwrap() + }, + }, + ); + } + } + + let total_fields = total_line.split_whitespace().collect::>(); + + summary.insert( + "total".to_string(), + match total_fields.len() { + // Old format, has no usecs/call + 5 => StraceOutput { + percent_time: str::parse::(total_fields[0]).unwrap(), + seconds: str::parse::(total_fields[1]).unwrap(), + usecs_per_call: None, + calls: str::parse::(total_fields[2]).unwrap(), + errors: str::parse::(total_fields[3]).unwrap(), + }, + 6 => StraceOutput { + percent_time: str::parse::(total_fields[0]).unwrap(), + seconds: str::parse::(total_fields[1]).unwrap(), + usecs_per_call: Some(str::parse::(total_fields[2]).unwrap()), + calls: str::parse::(total_fields[3]).unwrap(), + errors: str::parse::(total_fields[4]).unwrap(), + }, + _ => panic!("Unexpected total field count: {}", total_fields.len()), + }, + ); + + summary +} + +#[allow(dead_code)] +pub fn run(cmd: &[&str]) { + let mut process_builder = Command::new(cmd[0]); + process_builder.args(&cmd[1..]).stdin(Stdio::piped()); + let mut prog = process_builder.spawn().expect("failed to spawn script"); + let status = prog.wait().expect("failed to wait on child"); + if !status.success() { + panic!("Unexpected exit code: {:?}", status.code()); + } +} + +#[allow(dead_code)] +pub fn read_json(filename: &str) -> Result { + let f = fs::File::open(filename)?; + Ok(serde_json::from_reader(f)?) +} + +#[allow(dead_code)] +pub fn write_json(filename: &str, value: &Value) -> Result<()> { + let f = fs::File::create(filename)?; + serde_json::to_writer(f, value)?; + Ok(()) +} + +#[allow(dead_code)] +pub fn download_file(url: &str, filename: PathBuf) { + if !url.starts_with("http:") && !url.starts_with("https:") { + fs::copy(url, filename).unwrap(); + return; + } + + // Downloading with curl this saves us from adding + // a Rust HTTP client dependency. + println!("Downloading {}", url); + let status = Command::new("curl") + .arg("-L") + .arg("-s") + .arg("-o") + .arg(&filename) + .arg(url) + .status() + .unwrap(); + + assert!(status.success()); + assert!(filename.exists()); +} diff --git a/tooling/bench/tests/cpu_intensive/public/index.css b/bench/tests/cpu_intensive/public/index.css similarity index 100% rename from tooling/bench/tests/cpu_intensive/public/index.css rename to bench/tests/cpu_intensive/public/index.css diff --git a/bench/tests/cpu_intensive/public/index.html b/bench/tests/cpu_intensive/public/index.html new file mode 100644 index 000000000000..b4efd24aa5e9 --- /dev/null +++ b/bench/tests/cpu_intensive/public/index.html @@ -0,0 +1,16 @@ + + + + + Hello World! + + + +

Calculate prime numbers

+

+ +

+

+ + + diff --git a/tooling/bench/tests/cpu_intensive/public/site.js b/bench/tests/cpu_intensive/public/site.js similarity index 85% rename from tooling/bench/tests/cpu_intensive/public/site.js rename to bench/tests/cpu_intensive/public/site.js index 11ae51702fb9..cb38661c7a87 100644 --- a/tooling/bench/tests/cpu_intensive/public/site.js +++ b/bench/tests/cpu_intensive/public/site.js @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + // Create web worker const THRESHOLD = 10000000 const worker = new Worker('worker.js') @@ -17,7 +21,7 @@ const onMessage = (message) => { if (message.data.status === 'done') { // tell tauri that we are done - window.__TAURI__.invoke('app_completed_successfully') + window.__TAURI__.core.invoke('app_completed_successfully') } status.innerHTML = `${prefix} Found ${message.data.count} prime numbers in ${message.data.time}ms` diff --git a/tooling/bench/tests/cpu_intensive/public/worker.js b/bench/tests/cpu_intensive/public/worker.js similarity index 85% rename from tooling/bench/tests/cpu_intensive/public/worker.js rename to bench/tests/cpu_intensive/public/worker.js index 3b2eb05d7410..ae779bbf7e5e 100644 --- a/tooling/bench/tests/cpu_intensive/public/worker.js +++ b/bench/tests/cpu_intensive/public/worker.js @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + const isPrime = (number) => { if (number % 2 === 0 && number > 2) { return false diff --git a/bench/tests/cpu_intensive/src-tauri/.gitignore b/bench/tests/cpu_intensive/src-tauri/.gitignore new file mode 100644 index 000000000000..aba21e242c95 --- /dev/null +++ b/bench/tests/cpu_intensive/src-tauri/.gitignore @@ -0,0 +1,3 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ diff --git a/bench/tests/cpu_intensive/src-tauri/Cargo.toml b/bench/tests/cpu_intensive/src-tauri/Cargo.toml new file mode 100644 index 000000000000..e4471b07a7dd --- /dev/null +++ b/bench/tests/cpu_intensive/src-tauri/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bench_cpu_intensive" +version = "0.1.0" +description = "A very simple Tauri Application" +edition = "2021" +rust-version = "1.77.2" + +[build-dependencies] +tauri-build = { path = "../../../../crates/tauri-build", features = [ + "codegen", +] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { path = "../../../../crates/tauri", features = [] } diff --git a/bench/tests/cpu_intensive/src-tauri/build.rs b/bench/tests/cpu_intensive/src-tauri/build.rs new file mode 100644 index 000000000000..e43a276ec2ae --- /dev/null +++ b/bench/tests/cpu_intensive/src-tauri/build.rs @@ -0,0 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() { + tauri_build::build() +} diff --git a/bench/tests/cpu_intensive/src-tauri/src/main.rs b/bench/tests/cpu_intensive/src-tauri/src/main.rs new file mode 100644 index 000000000000..5734d4606446 --- /dev/null +++ b/bench/tests/cpu_intensive/src-tauri/src/main.rs @@ -0,0 +1,17 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +#[tauri::command] +fn app_completed_successfully() { + std::process::exit(0); +} + +fn main() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![app_completed_successfully]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/bench/tests/cpu_intensive/src-tauri/tauri.conf.json b/bench/tests/cpu_intensive/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..09054263452b --- /dev/null +++ b/bench/tests/cpu_intensive/src-tauri/tauri.conf.json @@ -0,0 +1,33 @@ +{ + "$schema": "../../../../crates/tauri-schema-generator/schemas/config.schema.json", + "identifier": "com.tauri.dev", + "build": { + "frontendDist": "../public" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "Welcome to Tauri!", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; connect-src ipc: http://ipc.localhost" + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "../../../../examples/.icons/32x32.png", + "../../../../examples/.icons/128x128.png", + "../../../../examples/.icons/128x128@2x.png", + "../../../../examples/.icons/icon.icns", + "../../../../examples/.icons/icon.ico" + ] + } +} diff --git a/bench/tests/files_transfer/public/index.html b/bench/tests/files_transfer/public/index.html new file mode 100644 index 000000000000..c0f5b44b90b1 --- /dev/null +++ b/bench/tests/files_transfer/public/index.html @@ -0,0 +1,30 @@ + + + + + + Welcome to Tauri! + + +

Welcome to Tauri!

+ + + + diff --git a/bench/tests/files_transfer/src-tauri/.gitignore b/bench/tests/files_transfer/src-tauri/.gitignore new file mode 100644 index 000000000000..aba21e242c95 --- /dev/null +++ b/bench/tests/files_transfer/src-tauri/.gitignore @@ -0,0 +1,3 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ diff --git a/bench/tests/files_transfer/src-tauri/Cargo.toml b/bench/tests/files_transfer/src-tauri/Cargo.toml new file mode 100644 index 000000000000..247a671e3043 --- /dev/null +++ b/bench/tests/files_transfer/src-tauri/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bench_files_transfer" +version = "0.1.0" +description = "A very simple Tauri Application" +edition = "2021" +rust-version = "1.77.2" + +[build-dependencies] +tauri-build = { path = "../../../../crates/tauri-build", features = [ + "codegen", +] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { path = "../../../../crates/tauri", features = [] } diff --git a/bench/tests/files_transfer/src-tauri/build.rs b/bench/tests/files_transfer/src-tauri/build.rs new file mode 100644 index 000000000000..e43a276ec2ae --- /dev/null +++ b/bench/tests/files_transfer/src-tauri/build.rs @@ -0,0 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() { + tauri_build::build() +} diff --git a/bench/tests/files_transfer/src-tauri/src/main.rs b/bench/tests/files_transfer/src-tauri/src/main.rs new file mode 100644 index 000000000000..9ac64be2d4b7 --- /dev/null +++ b/bench/tests/files_transfer/src-tauri/src/main.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +use std::fs::read; +use tauri::{command, ipc::Response, path::BaseDirectory, AppHandle, Manager, Runtime}; + +#[command] +fn app_should_close(exit_code: i32) { + std::process::exit(exit_code); +} + +#[command] +async fn read_file(app: AppHandle) -> Result { + let path = app + .path() + .resolve(".tauri_3mb.json", BaseDirectory::Home) + .map_err(|e| e.to_string())?; + let contents = read(&path).map_err(|e| e.to_string())?; + Ok(Response::new(contents)) +} + +fn main() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![app_should_close, read_file]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/bench/tests/files_transfer/src-tauri/tauri.conf.json b/bench/tests/files_transfer/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..09054263452b --- /dev/null +++ b/bench/tests/files_transfer/src-tauri/tauri.conf.json @@ -0,0 +1,33 @@ +{ + "$schema": "../../../../crates/tauri-schema-generator/schemas/config.schema.json", + "identifier": "com.tauri.dev", + "build": { + "frontendDist": "../public" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "Welcome to Tauri!", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; connect-src ipc: http://ipc.localhost" + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "../../../../examples/.icons/32x32.png", + "../../../../examples/.icons/128x128.png", + "../../../../examples/.icons/128x128@2x.png", + "../../../../examples/.icons/icon.icns", + "../../../../examples/.icons/icon.ico" + ] + } +} diff --git a/bench/tests/helloworld/public/index.html b/bench/tests/helloworld/public/index.html new file mode 100644 index 000000000000..938a5be9a486 --- /dev/null +++ b/bench/tests/helloworld/public/index.html @@ -0,0 +1,17 @@ + + + + + + Welcome to Tauri! + + +

Welcome to Tauri!

+ + + + diff --git a/bench/tests/helloworld/src-tauri/.gitignore b/bench/tests/helloworld/src-tauri/.gitignore new file mode 100644 index 000000000000..aba21e242c95 --- /dev/null +++ b/bench/tests/helloworld/src-tauri/.gitignore @@ -0,0 +1,3 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ diff --git a/bench/tests/helloworld/src-tauri/Cargo.toml b/bench/tests/helloworld/src-tauri/Cargo.toml new file mode 100644 index 000000000000..e8d1ad8d9668 --- /dev/null +++ b/bench/tests/helloworld/src-tauri/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "bench_helloworld" +version = "0.1.0" +description = "A very simple Tauri Application" +edition = "2021" +rust-version = "1.77.2" + +[build-dependencies] +tauri-build = { path = "../../../../crates/tauri-build", features = [ + "codegen", +] } + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +tauri = { path = "../../../../crates/tauri", features = [] } diff --git a/bench/tests/helloworld/src-tauri/build.rs b/bench/tests/helloworld/src-tauri/build.rs new file mode 100644 index 000000000000..e43a276ec2ae --- /dev/null +++ b/bench/tests/helloworld/src-tauri/build.rs @@ -0,0 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() { + tauri_build::build() +} diff --git a/bench/tests/helloworld/src-tauri/src/main.rs b/bench/tests/helloworld/src-tauri/src/main.rs new file mode 100644 index 000000000000..bbfcf1e3c710 --- /dev/null +++ b/bench/tests/helloworld/src-tauri/src/main.rs @@ -0,0 +1,17 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +#[tauri::command] +fn app_loaded_successfully() { + std::process::exit(0); +} + +fn main() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![app_loaded_successfully]) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/bench/tests/helloworld/src-tauri/tauri.conf.json b/bench/tests/helloworld/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..af5ff5db8846 --- /dev/null +++ b/bench/tests/helloworld/src-tauri/tauri.conf.json @@ -0,0 +1,35 @@ +{ + "$schema": "../../../../crates/tauri-schema-generator/schemas/config.schema.json", + "identifier": "com.tauri.dev", + "build": { + "frontendDist": "../public", + "beforeDevCommand": "", + "beforeBuildCommand": "" + }, + "app": { + "withGlobalTauri": true, + "windows": [ + { + "title": "Welcome to Tauri!", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; connect-src ipc: http://ipc.localhost" + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "../../../../examples/.icons/32x32.png", + "../../../../examples/.icons/128x128.png", + "../../../../examples/.icons/128x128@2x.png", + "../../../../examples/.icons/icon.icns", + "../../../../examples/.icons/icon.ico" + ] + } +} diff --git a/core/tauri-build/.license_template b/core/tauri-build/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/core/tauri-build/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/core/tauri-build/CHANGELOG.md b/core/tauri-build/CHANGELOG.md deleted file mode 100644 index 93f8d950f211..000000000000 --- a/core/tauri-build/CHANGELOG.md +++ /dev/null @@ -1,94 +0,0 @@ -# Changelog - -## \[1.0.0-rc.4] - -- Parse window icons at compile time. - - Bumped due to a bump in tauri-codegen. - - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 - -## \[1.0.0-rc.3] - -- Automatically emit `cargo:rustc-env=MACOSX_DEPLOYMENT_TARGET` with the value set on `tauri.conf.json > tauri > bundle > macos > minimumSystemVersion`. - - [4bacea5b](https://www.github.com/tauri-apps/tauri/commit/4bacea5bf48ea5ca6c9bdd10e28e85e67a0c6ef9) feat(core): set `MACOSX_DEPLOYMENT_TARGET` environment variable, closes [#2732](https://www.github.com/tauri-apps/tauri/pull/2732) ([#3496](https://www.github.com/tauri-apps/tauri/pull/3496)) on 2022-02-17 - -## \[1.0.0-rc.2] - -- Rerun if sidecar or resource change. - - [afcc3ec5](https://www.github.com/tauri-apps/tauri/commit/afcc3ec50148074293350aaa26a05812207716be) fix(build): rerun if resource or sidecar change ([#3460](https://www.github.com/tauri-apps/tauri/pull/3460)) on 2022-02-14 - -## \[1.0.0-rc.1] - -- Remove `cargo:rerun-if-changed` check for non-existent file that caused projects to *always* rebuild. - - [65287cd6](https://www.github.com/tauri-apps/tauri/commit/65287cd6148feeba91df86217b261770fed34608) remove non-existent cargo rerun check ([#3412](https://www.github.com/tauri-apps/tauri/pull/3412)) on 2022-02-11 - -## \[1.0.0-rc.0] - -- Allow user to specify windows sdk path in build.rs. - - [59b6ee87](https://www.github.com/tauri-apps/tauri/commit/59b6ee87932d341433032befe3babd897ed8f7d0) fix(tauri-build): allow user to specify win sdk path (fix: [#2871](https://www.github.com/tauri-apps/tauri/pull/2871)) ([#2893](https://www.github.com/tauri-apps/tauri/pull/2893)) on 2021-11-16 -- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. - -Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: - -1. Check if `tauri.conf.json` exists - a. Parse it with `serde_json` - b. Parse it with `json5` if `serde_json` fails - c. Return original `serde_json` error if all above steps failed -2. Check if `tauri.conf.json5` exists - a. Parse it with `json5` - b. Return error if all above steps failed -3. Return error if all above steps failed - -- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 -- Move the copying of resources and sidecars from `cli.rs` to `tauri-build` so using the Cargo CLI directly processes the files for the application execution in development. - - [5eb72c24](https://www.github.com/tauri-apps/tauri/commit/5eb72c24deddf5a01093bea96b90c0d8806afc3f) refactor: copy resources and sidecars on the Cargo build script ([#3357](https://www.github.com/tauri-apps/tauri/pull/3357)) on 2022-02-08 -- The minimum Rust version is now `1.56`. - - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 -- Validate `tauri` dependency `features` under `Cargo.toml` matching `tauri.conf.json`'s `allowlist`. - - [4de285c3](https://www.github.com/tauri-apps/tauri/commit/4de285c3967d32250d73acdd5d171a6fd332d2b3) feat(core): validate Cargo features matching allowlist \[TRI-023] on 2022-01-09 - -## \[1.0.0-beta.4] - -- Implement `Debug` on public API structs and enums. - - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 - -## \[1.0.0-beta.3] - -- Improve ESM detection with regexes. - - Bumped due to a bump in tauri-codegen. - - [4b0ec018](https://www.github.com/tauri-apps/tauri/commit/4b0ec0188078a8fefd4119fe5e19ebc30191f802) fix(core): improve JS ESM detection ([#2139](https://www.github.com/tauri-apps/tauri/pull/2139)) on 2021-07-02 -- Inject invoke key on `script` tags with `type="module"`. - - Bumped due to a bump in tauri-codegen. - - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on ``). Maps a HTML path to a list of hashes. - pub(crate) inline_scripts: HashMap>, - /// A list of hashes of the contents of all `style` elements. - pub(crate) styles: Vec, -} - -impl CspHashes { - /// Only add a CSP hash to the appropriate category if we think the file matches - /// - /// Note: this only checks the file extension, much like how a browser will assume a .js file is - /// a JavaScript file unless HTTP headers tell it otherwise. - pub fn add_if_applicable(&mut self, entry: &DirEntry) -> Result<(), EmbeddedAssetsError> { - let path = entry.path(); - - // we only hash JavaScript files for now, may expand to other CSP hashable types in the future - if let Some("js") | Some("mjs") = path.extension().and_then(|os| os.to_str()) { - let mut hasher = Sha256::new(); - hasher.update( - &std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead { - path: path.to_path_buf(), - error, - })?, - ); - let hash = hasher.finalize(); - self - .scripts - .push(format!("'sha256-{}'", base64::encode(hash))) - } - - Ok(()) - } -} - -/// Options used to embed assets. -#[derive(Default)] -pub struct AssetOptions { - pub(crate) csp: bool, - pub(crate) pattern: PatternKind, - pub(crate) freeze_prototype: bool, - #[cfg(any(feature = "isolation", feature = "__isolation-docs"))] - pub(crate) isolation_schema: String, -} - -impl AssetOptions { - /// Creates the default asset options. - pub fn new(pattern: PatternKind) -> Self { - Self { - csp: false, - pattern, - freeze_prototype: false, - #[cfg(any(feature = "isolation", feature = "__isolation-docs"))] - isolation_schema: format!("isolation-{}", uuid::Uuid::new_v4()), - } - } - - /// Instruct the asset handler to inject the CSP token to HTML files. - #[must_use] - pub fn with_csp(mut self) -> Self { - self.csp = true; - self - } - - /// Instruct the asset handler to include a script to freeze the `Object.prototype` on all HTML files. - #[must_use] - pub fn freeze_prototype(mut self, freeze: bool) -> Self { - self.freeze_prototype = freeze; - self - } -} - -impl EmbeddedAssets { - /// Compress a collection of files and directories, ready to be generated into [`Assets`]. - /// - /// [`Assets`]: tauri_utils::assets::Assets - pub fn new( - input: impl Into, - map: impl Fn(&AssetKey, &Path, &mut Vec, &mut CspHashes) -> Result<(), EmbeddedAssetsError>, - ) -> Result { - // we need to pre-compute all files now, so that we can inject data from all files into a few - let RawEmbeddedAssets { paths, csp_hashes } = RawEmbeddedAssets::new(input.into())?; - - struct CompressState { - csp_hashes: CspHashes, - assets: HashMap, - } - - let CompressState { assets, csp_hashes } = paths.into_iter().try_fold( - CompressState { - csp_hashes, - assets: HashMap::new(), - }, - move |mut state, (prefix, entry)| { - let (key, asset) = Self::compress_file(&prefix, entry.path(), &map, &mut state.csp_hashes)?; - state.assets.insert(key, asset); - Ok(state) - }, - )?; - - Ok(Self { assets, csp_hashes }) - } - - /// Use highest compression level for release, the fastest one for everything else - #[cfg(feature = "compression")] - fn compression_level() -> i32 { - let levels = zstd::compression_level_range(); - if cfg!(debug_assertions) { - *levels.start() - } else { - *levels.end() - } - } - - /// Compress a file and spit out the information in a [`HashMap`] friendly form. - fn compress_file( - prefix: &Path, - path: &Path, - map: &impl Fn(&AssetKey, &Path, &mut Vec, &mut CspHashes) -> Result<(), EmbeddedAssetsError>, - csp_hashes: &mut CspHashes, - ) -> Result { - let mut input = std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead { - path: path.to_owned(), - error, - })?; - - // get a key to the asset path without the asset directory prefix - let key = path - .strip_prefix(prefix) - .map(AssetKey::from) // format the path for use in assets - .map_err(|_| EmbeddedAssetsError::PrefixInvalid { - prefix: prefix.to_owned(), - path: path.to_owned(), - })?; - - // perform any caller-requested input manipulation - map(&key, path, &mut input, csp_hashes)?; - - // we must canonicalize the base of our paths to allow long paths on windows - let out_dir = std::env::var("OUT_DIR") - .map_err(|_| EmbeddedAssetsError::OutDir) - .map(PathBuf::from) - .and_then(|p| p.canonicalize().map_err(|_| EmbeddedAssetsError::OutDir)) - .map(|p| p.join(TARGET_PATH))?; - - // make sure that our output directory is created - std::fs::create_dir_all(&out_dir).map_err(|_| EmbeddedAssetsError::OutDir)?; - - // get a hash of the input - allows for caching existing files - let hash = { - let mut hasher = blake3::Hasher::new(); - if input.len() < MULTI_HASH_SIZE_LIMIT { - hasher.update(&input); - } else { - hasher.update_rayon(&input); - } - hasher.finalize().to_hex() - }; - - // use the content hash to determine filename, keep extensions that exist - let out_path = if let Some(ext) = path.extension().and_then(|e| e.to_str()) { - out_dir.join(format!("{}.{}", hash, ext)) - } else { - out_dir.join(hash.to_string()) - }; - - // only compress and write to the file if it doesn't already exist. - if !out_path.exists() { - #[allow(unused_mut)] - let mut out_file = - File::create(&out_path).map_err(|error| EmbeddedAssetsError::AssetWrite { - path: out_path.clone(), - error, - })?; - - #[cfg(not(feature = "compression"))] - { - use std::io::Write; - out_file - .write_all(&input) - .map_err(|error| EmbeddedAssetsError::AssetWrite { - path: path.to_owned(), - error, - })?; - } - - #[cfg(feature = "compression")] - // entirely write input to the output file path with compression - zstd::stream::copy_encode(&*input, out_file, Self::compression_level()).map_err(|error| { - EmbeddedAssetsError::AssetWrite { - path: path.to_owned(), - error, - } - })?; - } - - Ok((key, (path.into(), out_path))) - } -} - -impl ToTokens for EmbeddedAssets { - fn to_tokens(&self, tokens: &mut TokenStream) { - let mut assets = TokenStream::new(); - for (key, (input, output)) in &self.assets { - let key: &str = key.as_ref(); - let input = input.display().to_string(); - let output = output.display().to_string(); - - // add original asset as a compiler dependency, rely on dead code elimination to clean it up - assets.append_all(quote!(#key => { - const _: &[u8] = include_bytes!(#input); - include_bytes!(#output) - },)); - } - - let mut global_hashes = TokenStream::new(); - for script_hash in &self.csp_hashes.scripts { - let hash = script_hash.as_str(); - global_hashes.append_all(quote!(CspHash::Script(#hash),)); - } - - for style_hash in &self.csp_hashes.styles { - let hash = style_hash.as_str(); - global_hashes.append_all(quote!(CspHash::Style(#hash),)); - } - - let mut html_hashes = TokenStream::new(); - for (path, hashes) in &self.csp_hashes.inline_scripts { - let key = path.as_str(); - let mut value = TokenStream::new(); - for script_hash in hashes { - let hash = script_hash.as_str(); - value.append_all(quote!(CspHash::Script(#hash),)); - } - html_hashes.append_all(quote!(#key => &[#value],)); - } - - // we expect phf related items to be in path when generating the path code - tokens.append_all(quote! {{ - use ::tauri::utils::assets::{CspHash, EmbeddedAssets, phf, phf::phf_map}; - EmbeddedAssets::new(phf_map! { #assets }, &[#global_hashes], phf_map! { #html_hashes }) - }}); - } -} diff --git a/core/tauri-codegen/src/lib.rs b/core/tauri-codegen/src/lib.rs deleted file mode 100644 index 4eedaa1434ee..000000000000 --- a/core/tauri-codegen/src/lib.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -pub use self::context::{context_codegen, ContextData}; -use std::{ - borrow::Cow, - path::{Path, PathBuf}, -}; -pub use tauri_utils::config::{parse::ConfigError, Config}; - -mod context; -pub mod embedded_assets; - -/// Represents all the errors that can happen while reading the config during codegen. -#[derive(Debug, thiserror::Error)] -#[non_exhaustive] -pub enum CodegenConfigError { - #[error("unable to access current working directory: {0}")] - CurrentDir(std::io::Error), - - // this error should be "impossible" because we use std::env::current_dir() - cover it anyways - #[error("Tauri config file has no parent, this shouldn't be possible. file an issue on https://github.com/tauri-apps/tauri - target {0}")] - Parent(PathBuf), - - #[error("unable to parse inline JSON TAURI_CONFIG env var: {0}")] - FormatInline(serde_json::Error), - - #[error("{0}")] - ConfigError(#[from] ConfigError), -} - -/// Get the [`Config`] from the `TAURI_CONFIG` environmental variable, or read from the passed path. -/// -/// If the passed path is relative, it should be relative to the current working directory of the -/// compiling crate. -pub fn get_config(path: &Path) -> Result<(Config, PathBuf), CodegenConfigError> { - let path = if path.is_relative() { - let cwd = std::env::current_dir().map_err(CodegenConfigError::CurrentDir)?; - Cow::Owned(cwd.join(path)) - } else { - Cow::Borrowed(path) - }; - - // in the future we may want to find a way to not need the TAURI_CONFIG env var so that - // it is impossible for the content of two separate configs to get mixed up. The chances are - // already unlikely unless the developer goes out of their way to run the cli on a different - // project than the target crate. - let config = if let Ok(env) = std::env::var("TAURI_CONFIG") { - serde_json::from_str(&env).map_err(CodegenConfigError::FormatInline)? - } else { - tauri_utils::config::parse(path.to_path_buf())? - }; - - // this should be impossible because of the use of `current_dir()` above, but handle it anyways - let parent = path - .parent() - .map(ToOwned::to_owned) - .ok_or_else(|| CodegenConfigError::Parent(path.into_owned()))?; - - Ok((config, parent)) -} diff --git a/core/tauri-macros/.license_template b/core/tauri-macros/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/core/tauri-macros/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/core/tauri-macros/CHANGELOG.md b/core/tauri-macros/CHANGELOG.md deleted file mode 100644 index df919c83d2df..000000000000 --- a/core/tauri-macros/CHANGELOG.md +++ /dev/null @@ -1,144 +0,0 @@ -# Changelog - -## \[1.0.0-rc.3] - -- Parse window icons at compile time. - - Bumped due to a bump in tauri-codegen. - - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 - -## \[1.0.0-rc.2] - -- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. - - Bumped due to a bump in tauri-utils. - - [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17 - -## \[1.0.0-rc.1] - -- Change default value for the `freezePrototype` configuration to `false`. - - Bumped due to a bump in tauri-utils. - - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 - -## \[1.0.0-rc.0] - -- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. - -Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: - -1. Check if `tauri.conf.json` exists - a. Parse it with `serde_json` - b. Parse it with `json5` if `serde_json` fails - c. Return original `serde_json` error if all above steps failed -2. Check if `tauri.conf.json5` exists - a. Parse it with `json5` - b. Return error if all above steps failed -3. Return error if all above steps failed - -- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 -- The minimum Rust version is now `1.56`. - - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 - -## \[1.0.0-beta.5] - -- Embed Info.plist file contents on binary on dev. - - Bumped due to a bump in tauri-codegen. - - [537ab1b6](https://www.github.com/tauri-apps/tauri/commit/537ab1b6d5a792c550a535619965c9e4126292e6) feat(core): inject src-tauri/Info.plist file on dev and merge on bundle, closes [#1570](https://www.github.com/tauri-apps/tauri/pull/1570) [#2338](https://www.github.com/tauri-apps/tauri/pull/2338) ([#2444](https://www.github.com/tauri-apps/tauri/pull/2444)) on 2021-08-15 -- Fix ES Module detection for default imports with relative paths or scoped packages and exporting of async functions. - - Bumped due to a bump in tauri-codegen. - - [b2b36cfe](https://www.github.com/tauri-apps/tauri/commit/b2b36cfe8dfcccb341638a4cb6dc23a514c54148) fix(core): fixes ES Module detection for default imports with relative paths or scoped packages ([#2380](https://www.github.com/tauri-apps/tauri/pull/2380)) on 2021-08-10 - - [fbf8caf5](https://www.github.com/tauri-apps/tauri/commit/fbf8caf5c419cb4fc3d123be910e094a8e8c4bef) fix(core): ESM detection when using `export async function` ([#2425](https://www.github.com/tauri-apps/tauri/pull/2425)) on 2021-08-14 - -## \[1.0.0-beta.4] - -- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those - associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If - you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the - explicit type and let the compiler infer it instead. - -`tauri`: - -- See `Params` note -- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a - simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition - of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type - to these functions. -- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all - methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already - required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change - affects you. - -`tauri-macros`: - -- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when - the specified feature is enabled. - -`tauri-runtime`: - -- See `Params` note -- Removed `Params`, `MenuId`, `Tag`, `TagRef`. -- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. - - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. -- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the - `Runtime` type directly -- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. -- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. - -`tauri-runtime-wry`: - -- See `Params` note -- update menu and runtime related types to the ones changed in `tauri-runtime`. - -`tauri-utils`: - -- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object - safe. -- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 - -## \[1.0.0-beta.3] - -- Detect ESM scripts and inject the invoke key directly instead of using an IIFE. - - Bumped due to a bump in tauri-codegen. - - [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27 -- Improve invoke key code injection performance time rewriting code at compile time. - - Bumped due to a bump in tauri-codegen. - - [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27 - -## \[1.0.0-beta.2] - -- internal: Refactor all macro code that expects specific bindings to be passed Idents - - [39f8f269](https://www.github.com/tauri-apps/tauri/commit/39f8f269164d2fda3d5b614a193b12bb266e4b4b) refactor(macros): explicitly pass idents ([#1812](https://www.github.com/tauri-apps/tauri/pull/1812)) on 2021-05-13 - -## \[1.0.0-beta.1] - -- Fixes a name collision when the command function is named `invoke`. - - [7862ec5](https://www.github.com/tauri-apps/tauri/commit/7862ec562fa70e3733263ce1f690d6cd2943c0b4) fix(macros): change invoke binding in generate handler ([#1804](https://www.github.com/tauri-apps/tauri/pull/1804)) on 2021-05-12 -- Fixes a name collision when the command function is named `message` or `resolver`. - - [0b87532](https://www.github.com/tauri-apps/tauri/commit/0b875327067ca825ff6f6f26c9b2ce6fcb001e79) fix(macros): fix rest of command collisons ([#1805](https://www.github.com/tauri-apps/tauri/pull/1805)) on 2021-05-12 -- Fixes a name collision when the command function is named `cmd`. - - [d36b726](https://www.github.com/tauri-apps/tauri/commit/d36b7269261d329dd7d7fcd4d5098f3fca167364) fix(macros): collision when command is named `cmd` ([#1802](https://www.github.com/tauri-apps/tauri/pull/1802)) on 2021-05-12 - -## \[1.0.0-beta.0] - -- Only commands with a `async fn` are executed on a separate task. `#[command] fn command_name` runs on the main thread. - - [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09 -- `#[command]` now generates a macro instead of a function to allow passing through `Params` and other generics. - `generate_handler!` has been changed to consume the generated `#[command]` macro - - [1453d4b](https://www.github.com/tauri-apps/tauri/commit/1453d4bf842ed6891ec604e0635344c930282189) feat(core): support generics (especially Param) in #\[command] ([#1622](https://www.github.com/tauri-apps/tauri/pull/1622)) on 2021-05-05 -- Improves support for commands returning `Result`. - - [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09 -- Adds support to command state, triggered when a command argument is `arg: State<'_, StateType>`. - - [8b6f3de](https://www.github.com/tauri-apps/tauri/commit/8b6f3de0ad47684e72a2ae5f884d8675acfaeeac) feat(core): add state management, closes [#1655](https://www.github.com/tauri-apps/tauri/pull/1655) ([#1665](https://www.github.com/tauri-apps/tauri/pull/1665)) on 2021-05-02 - -## \[1.0.0-beta-rc.1] - -- Fixes the Message `command` name value on plugin invoke handler. - - [422dd5e](https://www.github.com/tauri-apps/tauri/commit/422dd5e2a0a03bb1556915c78f110bfab092c874) fix(core): command name on plugin invoke handler ([#1577](https://www.github.com/tauri-apps/tauri/pull/1577)) on 2021-04-21 - - [f575aaa](https://www.github.com/tauri-apps/tauri/commit/f575aaad71f23d44b2f89cf9ee5d84817dc3bb7a) fix: change files not referencing core packages ([#1619](https://www.github.com/tauri-apps/tauri/pull/1619)) on 2021-04-25 - -## \[1.0.0-beta-rc.0] - -- Update all code files to have our license header. - - [bf82136](https://www.github.com/tauri-apps/tauri/commit/bf8213646689175f8a158b956911f3a43e360690) feat(license): SPDX Headers ([#1449](https://www.github.com/tauri-apps/tauri/pull/1449)) on 2021-04-11 - - [a6def70](https://www.github.com/tauri-apps/tauri/commit/a6def7066eec19c889b0f14cc1e475bf209a332e) Refactor(tauri): move tauri-api and tauri-updater to tauri ([#1455](https://www.github.com/tauri-apps/tauri/pull/1455)) on 2021-04-11 - - [aea6145](https://www.github.com/tauri-apps/tauri/commit/aea614587bddab930d552512b54e18624fbf573e) refactor(repo): add /tooling folder ([#1457](https://www.github.com/tauri-apps/tauri/pull/1457)) on 2021-04-12 -- Added new macros to simplify the creation of commands that can be called by the webview. - - [1f2e7a3](https://www.github.com/tauri-apps/tauri/commit/1f2e7a3226ccf0ee3e30ae0cba3c67f7e219d1f2) feat(core): improved command matching with macros, fixes [#1157](https://www.github.com/tauri-apps/tauri/pull/1157) ([#1301](https://www.github.com/tauri-apps/tauri/pull/1301)) on 2021-02-28 diff --git a/core/tauri-macros/Cargo.toml b/core/tauri-macros/Cargo.toml deleted file mode 100644 index 5508996adbb3..000000000000 --- a/core/tauri-macros/Cargo.toml +++ /dev/null @@ -1,32 +0,0 @@ -[package] -name = "tauri-macros" -version = "1.0.0-rc.3" -authors = [ "Tauri Programme within The Commons Conservancy" ] -categories = [ "gui", "os", "filesystem", "web-programming" ] -license = "Apache-2.0 OR MIT" -homepage = "https://tauri.studio" -repository = "https://github.com/tauri-apps/tauri" -description = "Macros for the tauri crate." -edition = "2021" -rust-version = "1.57" -exclude = [ ".license_template", "CHANGELOG.md", "/target" ] -readme = "README.md" - -[lib] -proc-macro = true - -[dependencies] -proc-macro2 = "1" -quote = "1" -syn = { version = "1", features = [ "full" ] } -heck = "0.4" -tauri-codegen = { version = "1.0.0-rc.3", default-features = false, path = "../tauri-codegen" } -tauri-utils = { version = "1.0.0-rc.3", path = "../tauri-utils" } - -[features] -custom-protocol = [ ] -compression = [ "tauri-codegen/compression" ] -isolation = [ "tauri-codegen/isolation" ] -__isolation-docs = [ "tauri-codegen/__isolation-docs" ] -shell-scope = [ "tauri-codegen/shell-scope" ] -config-json5 = [ "tauri-codegen/config-json5", "tauri-utils/config-json5" ] diff --git a/core/tauri-macros/README.md b/core/tauri-macros/README.md deleted file mode 100644 index a66ba454cbb1..000000000000 --- a/core/tauri-macros/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# tauri-macros - - - -[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri) -[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) -[![devto](https://img.shields.io/badge/blog-dev.to-black.svg)](https://dev.to/tauri) - -![](https://img.shields.io/github/workflow/status/tauri-apps/tauri/test%20library?label=test%20library -) -[![devto](https://img.shields.io/badge/documentation-site-purple.svg)](https://tauri.studio) - -[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) -[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri) - -| Component | Version | -| --------- | ------------------------------------------- | -| tauri-macros | [![](https://img.shields.io/crates/v/tauri-macros?style=flat-square)](https://crates.io/crates/tauri-macros) | - -## About Tauri -Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. - -Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. - -## This module -Create macros for the context, handler, and commands by leveraging the `tauri-codegen` crate. - -To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. - -## Semver -**tauri** is following [Semantic Versioning 2.0](https://semver.org/). -## Licenses -Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. - -MIT or MIT/Apache 2.0 where applicable. - -Logo: CC-BY-NC-ND -- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/core/tauri-macros/src/command/handler.rs b/core/tauri-macros/src/command/handler.rs deleted file mode 100644 index 75e882442527..000000000000 --- a/core/tauri-macros/src/command/handler.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use quote::format_ident; -use syn::{ - parse::{Parse, ParseBuffer}, - Ident, Path, Token, -}; - -/// The items parsed from [`generate_handle!`](crate::generate_handle). -pub struct Handler { - paths: Vec, - commands: Vec, - wrappers: Vec, -} - -impl Parse for Handler { - fn parse(input: &ParseBuffer<'_>) -> syn::Result { - let paths = input.parse_terminated::(Path::parse)?; - - // parse the command names and wrappers from the passed paths - let (commands, wrappers) = paths - .iter() - .map(|path| { - let mut wrapper = path.clone(); - let last = super::path_to_command(&mut wrapper); - - // the name of the actual command function - let command = last.ident.clone(); - - // set the path to the command function wrapper - last.ident = super::format_command_wrapper(&command); - - (command, wrapper) - }) - .unzip(); - - Ok(Self { - paths: paths.into_iter().collect(), // remove punctuation separators - commands, - wrappers, - }) - } -} - -impl From for proc_macro::TokenStream { - fn from( - Handler { - paths, - commands, - wrappers, - }: Handler, - ) -> Self { - let cmd = format_ident!("__tauri_cmd__"); - let invoke = format_ident!("__tauri_invoke__"); - quote::quote!(move |#invoke| { - let #cmd = #invoke.message.command(); - match #cmd { - #(stringify!(#commands) => #wrappers!(#paths, #invoke),)* - _ => { - #invoke.resolver.reject(format!("command {} not found", #cmd)) - }, - } - }) - .into() - } -} diff --git a/core/tauri-macros/src/command/mod.rs b/core/tauri-macros/src/command/mod.rs deleted file mode 100644 index 9acbb0bda519..000000000000 --- a/core/tauri-macros/src/command/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use proc_macro2::Ident; -use syn::{Path, PathSegment}; - -pub use self::{handler::Handler, wrapper::wrapper}; - -mod handler; -mod wrapper; - -/// The autogenerated wrapper ident. -fn format_command_wrapper(function: &Ident) -> Ident { - quote::format_ident!("__cmd__{}", function) -} - -/// This function will panic if the passed [`syn::Path`] does not have any segments. -fn path_to_command(path: &mut Path) -> &mut PathSegment { - path - .segments - .last_mut() - .expect("parsed syn::Path has no segment") -} diff --git a/core/tauri-macros/src/command/wrapper.rs b/core/tauri-macros/src/command/wrapper.rs deleted file mode 100644 index 9d27962feb45..000000000000 --- a/core/tauri-macros/src/command/wrapper.rs +++ /dev/null @@ -1,218 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use proc_macro::TokenStream; -use proc_macro2::TokenStream as TokenStream2; -use quote::{format_ident, quote}; -use syn::{ - parse::{Parse, ParseBuffer}, - parse_macro_input, - spanned::Spanned, - FnArg, Ident, ItemFn, Pat, Token, Visibility, -}; - -/// The execution context of the command. -enum ExecutionContext { - Async, - Blocking, -} - -impl Parse for ExecutionContext { - fn parse(input: &ParseBuffer<'_>) -> syn::Result { - if input.is_empty() { - return Ok(Self::Blocking); - } - - input - .parse::() - .map(|_| Self::Async) - .map_err(|_| { - syn::Error::new( - input.span(), - "only a single item `async` is currently allowed", - ) - }) - } -} - -/// The bindings we attach to `tauri::Invoke`. -struct Invoke { - message: Ident, - resolver: Ident, -} - -/// Create a new [`Wrapper`] from the function and the generated code parsed from the function. -pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { - let function = parse_macro_input!(item as ItemFn); - let wrapper = super::format_command_wrapper(&function.sig.ident); - let visibility = &function.vis; - - // macros used with `pub use my_macro;` need to be exported with `#[macro_export]` - let maybe_macro_export = match &function.vis { - Visibility::Public(_) => quote!(#[macro_export]), - _ => Default::default(), - }; - - let invoke = Invoke { - message: format_ident!("__tauri_message__"), - resolver: format_ident!("__tauri_resolver__"), - }; - - // body to the command wrapper or a `compile_error!` of an error occurred while parsing it. - let body = syn::parse::(attributes) - .map(|context| match function.sig.asyncness { - Some(_) => ExecutionContext::Async, - None => context, - }) - .and_then(|context| match context { - ExecutionContext::Async => body_async(&function, &invoke), - ExecutionContext::Blocking => body_blocking(&function, &invoke), - }) - .unwrap_or_else(syn::Error::into_compile_error); - - let Invoke { message, resolver } = invoke; - - // Rely on rust 2018 edition to allow importing a macro from a path. - quote!( - #function - - #maybe_macro_export - macro_rules! #wrapper { - // double braces because the item is expected to be a block expression - ($path:path, $invoke:ident) => {{ - // prevent warnings when the body is a `compile_error!` or if the command has no arguments - #[allow(unused_variables)] - let ::tauri::Invoke { message: #message, resolver: #resolver } = $invoke; - - #body - }}; - } - - // allow the macro to be resolved with the same path as the command function - #[allow(unused_imports)] - #visibility use #wrapper; - ) - .into() -} - -/// Generates an asynchronous command response from the arguments and return value of a function. -/// -/// See the [`tauri::command`] module for all the items and traits that make this possible. -/// -/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html -fn body_async(function: &ItemFn, invoke: &Invoke) -> syn::Result { - let Invoke { message, resolver } = invoke; - parse_args(function, message).map(|args| { - quote! { - #[allow(unused_imports)] - use ::tauri::command::private::*; - - #resolver.respond_async_serialized(async move { - let result = $path(#(#args?),*); - let kind = (&result).async_kind(); - kind.future(result).await - }); - } - }) -} - -/// Generates a blocking command response from the arguments and return value of a function. -/// -/// See the [`tauri::command`] module for all the items and traits that make this possible. -/// -/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html -fn body_blocking(function: &ItemFn, invoke: &Invoke) -> syn::Result { - let Invoke { message, resolver } = invoke; - let args = parse_args(function, message)?; - - // the body of a `match` to early return any argument that wasn't successful in parsing. - let match_body = quote!({ - Ok(arg) => arg, - Err(err) => return #resolver.invoke_error(err), - }); - - Ok(quote! { - #[allow(unused_imports)] - use ::tauri::command::private::*; - - let result = $path(#(match #args #match_body),*); - let kind = (&result).blocking_kind(); - kind.block(result, #resolver); - }) -} - -/// Parse all arguments for the command wrapper to use from the signature of the command function. -fn parse_args(function: &ItemFn, message: &Ident) -> syn::Result> { - function - .sig - .inputs - .iter() - .map(|arg| parse_arg(&function.sig.ident, arg, message)) - .collect() -} - -/// Transform a [`FnArg`] into a command argument. -fn parse_arg(command: &Ident, arg: &FnArg, message: &Ident) -> syn::Result { - // we have no use for self arguments - let mut arg = match arg { - FnArg::Typed(arg) => arg.pat.as_ref().clone(), - FnArg::Receiver(arg) => { - return Err(syn::Error::new( - arg.span(), - "unable to use self as a command function parameter", - )) - } - }; - - // we only support patterns that allow us to extract some sort of keyed identifier - let mut key = match &mut arg { - Pat::Ident(arg) => arg.ident.to_string(), - Pat::Wild(_) => "".into(), // we always convert to camelCase, so "_" will end up empty anyways - Pat::Struct(s) => super::path_to_command(&mut s.path).ident.to_string(), - Pat::TupleStruct(s) => super::path_to_command(&mut s.path).ident.to_string(), - err => { - return Err(syn::Error::new( - err.span(), - "only named, wildcard, struct, and tuple struct arguments allowed", - )) - } - }; - - // also catch self arguments that use FnArg::Typed syntax - if key == "self" { - return Err(syn::Error::new( - key.span(), - "unable to use self as a command function parameter", - )); - } - - // snake_case -> camelCase - if key.as_str().contains('_') { - key = snake_case_to_camel_case(key.as_str()); - } - - Ok(quote!(::tauri::command::CommandArg::from_command( - ::tauri::command::CommandItem { - name: stringify!(#command), - key: #key, - message: &#message, - } - ))) -} - -/// Convert a snake_case string into camelCase, no underscores will be left. -fn snake_case_to_camel_case(key: &str) -> String { - let mut camel = String::with_capacity(key.len()); - let mut to_upper = false; - - for c in key.chars() { - match c { - '_' => to_upper = true, - c if std::mem::take(&mut to_upper) => camel.push(c.to_ascii_uppercase()), - c => camel.push(c), - } - } - - camel -} diff --git a/core/tauri-macros/src/command_module.rs b/core/tauri-macros/src/command_module.rs deleted file mode 100644 index b28887058e6f..000000000000 --- a/core/tauri-macros/src/command_module.rs +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use heck::ToSnakeCase; -use proc_macro::TokenStream; -use proc_macro2::{Span, TokenStream as TokenStream2, TokenTree}; - -use quote::{format_ident, quote, quote_spanned}; -use syn::{ - parse::{Parse, ParseStream}, - spanned::Spanned, - Data, DeriveInput, Error, Fields, FnArg, Ident, ItemFn, LitStr, Pat, Token, -}; - -pub fn generate_run_fn(input: DeriveInput) -> TokenStream { - let name = &input.ident; - let data = &input.data; - - let mut is_async = false; - let attrs = input.attrs; - for attr in attrs { - if attr.path.is_ident("cmd") { - let _ = attr.parse_args_with(|input: ParseStream| { - while let Some(token) = input.parse()? { - if let TokenTree::Ident(ident) = token { - is_async |= ident == "async"; - } - } - Ok(()) - }); - } - } - let maybe_await = if is_async { quote!(.await) } else { quote!() }; - let maybe_async = if is_async { quote!(async) } else { quote!() }; - - let mut matcher; - - match data { - Data::Enum(data_enum) => { - matcher = TokenStream2::new(); - - for variant in &data_enum.variants { - let variant_name = &variant.ident; - - let (fields_in_variant, variables) = match &variant.fields { - Fields::Unit => (quote_spanned! { variant.span() => }, quote!()), - Fields::Unnamed(fields) => { - let mut variables = TokenStream2::new(); - for i in 0..fields.unnamed.len() { - let variable_name = format_ident!("value{}", i); - variables.extend(quote!(#variable_name,)); - } - (quote_spanned! { variant.span() => (#variables) }, variables) - } - Fields::Named(fields) => { - let mut variables = TokenStream2::new(); - for field in &fields.named { - let ident = field.ident.as_ref().unwrap(); - variables.extend(quote!(#ident,)); - } - ( - quote_spanned! { variant.span() => { #variables } }, - variables, - ) - } - }; - - let mut variant_execute_function_name = format_ident!( - "{}", - variant_name.to_string().to_snake_case().to_lowercase() - ); - variant_execute_function_name.set_span(variant_name.span()); - - matcher.extend(quote_spanned! { - variant.span() => #name::#variant_name #fields_in_variant => #name::#variant_execute_function_name(context, #variables)#maybe_await.map(Into::into), - }); - } - } - _ => { - return Error::new( - Span::call_site(), - "CommandModule is only implemented for enums", - ) - .to_compile_error() - .into() - } - }; - - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); - - let expanded = quote! { - impl #impl_generics #name #ty_generics #where_clause { - pub #maybe_async fn run(self, context: crate::endpoints::InvokeContext) -> super::Result { - match self { - #matcher - } - } - } - }; - - TokenStream::from(expanded) -} - -/// Attributes for the module enum variant handler. -pub struct HandlerAttributes { - allowlist: Ident, - error_message: String, -} - -impl Parse for HandlerAttributes { - fn parse(input: ParseStream) -> syn::Result { - let allowlist = input.parse()?; - input.parse::()?; - let raw: LitStr = input.parse()?; - let error_message = raw.value(); - Ok(Self { - allowlist, - error_message, - }) - } -} - -pub struct HandlerTestAttributes { - allowlist: Ident, - error_message: String, - is_async: bool, -} - -impl Parse for HandlerTestAttributes { - fn parse(input: ParseStream) -> syn::Result { - let allowlist = input.parse()?; - input.parse::()?; - let error_message_raw: LitStr = input.parse()?; - let error_message = error_message_raw.value(); - let _ = input.parse::(); - let is_async = input - .parse::() - .map(|i| i == "async") - .unwrap_or_default(); - - Ok(Self { - allowlist, - error_message, - is_async, - }) - } -} - -pub fn command_handler(attributes: HandlerAttributes, function: ItemFn) -> TokenStream2 { - let allowlist = attributes.allowlist; - let error_message = attributes.error_message.as_str(); - let signature = function.sig.clone(); - - quote!( - #[cfg(#allowlist)] - #function - - #[cfg(not(#allowlist))] - #[allow(unused_variables)] - #[allow(unused_mut)] - #signature { - Err(anyhow::anyhow!(crate::Error::ApiNotAllowlisted(#error_message.to_string()).to_string())) - } - ) -} - -pub fn command_test(attributes: HandlerTestAttributes, function: ItemFn) -> TokenStream2 { - let allowlist = attributes.allowlist; - let is_async = attributes.is_async; - let error_message = attributes.error_message.as_str(); - let signature = function.sig.clone(); - let test_name = function.sig.ident.clone(); - let mut args = quote!(); - for arg in &function.sig.inputs { - if let FnArg::Typed(t) = arg { - if let Pat::Ident(i) = &*t.pat { - let ident = &i.ident; - args.extend(quote!(#ident,)) - } - } - } - - let response = if is_async { - quote!(crate::async_runtime::block_on( - super::Cmd::#test_name(crate::test::mock_invoke_context(), #args) - )) - } else { - quote!(super::Cmd::#test_name(crate::test::mock_invoke_context(), #args)) - }; - - quote!( - #[cfg(#allowlist)] - #function - - #[cfg(not(#allowlist))] - #[quickcheck_macros::quickcheck] - #signature { - if let Err(e) = #response { - assert!(e.to_string().contains(#error_message)); - } else { - panic!("unexpected response"); - } - } - ) -} diff --git a/core/tauri-macros/src/context.rs b/core/tauri-macros/src/context.rs deleted file mode 100644 index 337fe3a6098e..000000000000 --- a/core/tauri-macros/src/context.rs +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use proc_macro2::{Ident, Span, TokenStream}; -use quote::{quote, ToTokens}; -use std::{env::VarError, path::PathBuf}; -use syn::{ - parse::{Parse, ParseBuffer}, - punctuated::Punctuated, - LitStr, PathArguments, PathSegment, Token, -}; -use tauri_codegen::{context_codegen, get_config, ContextData}; -use tauri_utils::config::parse::does_supported_extension_exist; - -pub(crate) struct ContextItems { - config_file: PathBuf, - root: syn::Path, -} - -impl Parse for ContextItems { - fn parse(input: &ParseBuffer<'_>) -> syn::parse::Result { - let config_file = if input.is_empty() { - std::env::var("CARGO_MANIFEST_DIR").map(|m| PathBuf::from(m).join("tauri.conf.json")) - } else { - let raw: LitStr = input.parse()?; - let path = PathBuf::from(raw.value()); - if path.is_relative() { - std::env::var("CARGO_MANIFEST_DIR").map(|m| PathBuf::from(m).join(path)) - } else { - Ok(path) - } - } - .map_err(|error| match error { - VarError::NotPresent => "no CARGO_MANIFEST_DIR env var, this should be set by cargo".into(), - VarError::NotUnicode(_) => "CARGO_MANIFEST_DIR env var contained invalid utf8".into(), - }) - .and_then(|path| { - if does_supported_extension_exist(&path) { - Ok(path) - } else { - Err(format!( - "no file at path {} exists, expected tauri config file", - path.display() - )) - } - }) - .map_err(|e| input.error(e))?; - - let context_path = if input.is_empty() { - let mut segments = Punctuated::new(); - segments.push(PathSegment { - ident: Ident::new("tauri", Span::call_site()), - arguments: PathArguments::None, - }); - syn::Path { - leading_colon: Some(Token![::](Span::call_site())), - segments, - } - } else { - let _: Token![,] = input.parse()?; - input.call(syn::Path::parse_mod_style)? - }; - - Ok(Self { - config_file, - root: context_path, - }) - } -} - -pub(crate) fn generate_context(context: ContextItems) -> TokenStream { - let context = get_config(&context.config_file) - .map_err(|e| e.to_string()) - .map(|(config, config_parent)| ContextData { - dev: cfg!(not(feature = "custom-protocol")), - config, - config_parent, - root: context.root.to_token_stream(), - }) - .and_then(|data| context_codegen(data).map_err(|e| e.to_string())); - - match context { - Ok(code) => code, - Err(error) => quote!(compile_error!(#error)), - } -} diff --git a/core/tauri-macros/src/lib.rs b/core/tauri-macros/src/lib.rs deleted file mode 100644 index 1adae76ac2bc..000000000000 --- a/core/tauri-macros/src/lib.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use crate::context::ContextItems; -use proc_macro::TokenStream; -use syn::{parse_macro_input, DeriveInput, ItemFn}; - -mod command; -mod command_module; -mod runtime; - -#[macro_use] -mod context; - -/// Mark a function as a command handler. It creates a wrapper function with the necessary glue code. -/// -/// # Stability -/// The output of this macro is managed internally by Tauri, -/// and should not be accessed directly on normal applications. -/// It may have breaking changes in the future. -#[proc_macro_attribute] -pub fn command(attributes: TokenStream, item: TokenStream) -> TokenStream { - command::wrapper(attributes, item) -} - -/// Accepts a list of commands functions. Creates a handler that allows commands to be called from JS with invoke(). -/// -/// # Examples -/// ```rust,ignore -/// use tauri_macros::{command, generate_handler}; -/// #[command] -/// fn command_one() { -/// println!("command one called"); -/// } -/// #[command] -/// fn command_two() { -/// println!("command two called"); -/// } -/// fn main() { -/// let _handler = generate_handler![command_one, command_two]; -/// } -/// ``` -/// # Stability -/// The output of this macro is managed internally by Tauri, -/// and should not be accessed directly on normal applications. -/// It may have breaking changes in the future. -#[proc_macro] -pub fn generate_handler(item: TokenStream) -> TokenStream { - parse_macro_input!(item as command::Handler).into() -} - -/// Reads a Tauri config file and generates a `::tauri::Context` based on the content. -/// -/// # Stability -/// The output of this macro is managed internally by Tauri, -/// and should not be accessed directly on normal applications. -/// It may have breaking changes in the future. -#[proc_macro] -pub fn generate_context(items: TokenStream) -> TokenStream { - // this macro is exported from the context module - let path = parse_macro_input!(items as ContextItems); - context::generate_context(path).into() -} - -/// Adds the default type for the last parameter (assumed to be runtime) for a specific feature. -/// -/// e.g. To default the runtime generic to type `crate::Wry` when the `wry` feature is enabled, the -/// syntax would look like `#[default_runtime(crate::Wry, wry)`. This is **always** set for the last -/// generic, so make sure the last generic is the runtime when using this macro. -#[doc(hidden)] -#[proc_macro_attribute] -pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStream { - let attributes = parse_macro_input!(attributes as runtime::Attributes); - let input = parse_macro_input!(input as DeriveInput); - runtime::default_runtime(attributes, input).into() -} - -/// Adds a `run` method to an enum (one of the tauri endpoint modules). -/// The `run` method takes a `tauri::endpoints::InvokeContext` -/// and returns a `tauri::Result`. -/// It matches on each enum variant and call a method with name equal to the variant name, lowercased and snake_cased, -/// passing the the context and the variant's fields as arguments. -/// That function must also return the same `Result`. -#[doc(hidden)] -#[proc_macro_derive(CommandModule, attributes(cmd))] -pub fn derive_command_module(input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); - command_module::generate_run_fn(input) -} - -#[doc(hidden)] -#[proc_macro_attribute] -pub fn module_command_handler(attributes: TokenStream, input: TokenStream) -> TokenStream { - let attributes = parse_macro_input!(attributes as command_module::HandlerAttributes); - let input = parse_macro_input!(input as ItemFn); - command_module::command_handler(attributes, input).into() -} - -#[doc(hidden)] -#[proc_macro_attribute] -pub fn module_command_test(attributes: TokenStream, input: TokenStream) -> TokenStream { - let attributes = parse_macro_input!(attributes as command_module::HandlerTestAttributes); - let input = parse_macro_input!(input as ItemFn); - command_module::command_test(attributes, input).into() -} diff --git a/core/tauri-macros/src/runtime.rs b/core/tauri-macros/src/runtime.rs deleted file mode 100644 index 3fe0f0d2b005..000000000000 --- a/core/tauri-macros/src/runtime.rs +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use proc_macro2::TokenStream; -use quote::quote; -use syn::parse::{Parse, ParseStream}; -use syn::{parse_quote, DeriveInput, GenericParam, Ident, Token, Type, TypeParam}; - -/// The default runtime type to enable when the provided feature is enabled. -pub(crate) struct Attributes { - default_type: Type, - feature: Ident, -} - -impl Parse for Attributes { - fn parse(input: ParseStream<'_>) -> syn::Result { - let default_type = input.parse()?; - input.parse::()?; - Ok(Attributes { - default_type, - feature: input.parse()?, - }) - } -} - -pub(crate) fn default_runtime(attributes: Attributes, input: DeriveInput) -> TokenStream { - // create a new copy to manipulate for the wry feature flag - let mut wry = input.clone(); - let wry_runtime = wry - .generics - .params - .last_mut() - .expect("default_runtime requires the item to have at least 1 generic parameter"); - - // set the default value of the last generic parameter to the provided runtime type - match wry_runtime { - GenericParam::Type( - param @ TypeParam { - eq_token: None, - default: None, - .. - }, - ) => { - param.eq_token = Some(parse_quote!(=)); - param.default = Some(attributes.default_type); - } - _ => { - panic!("DefaultRuntime requires the last parameter to not have a default value") - } - }; - - let feature = attributes.feature.to_string(); - - quote!( - #[cfg(feature = #feature)] - #wry - - #[cfg(not(feature = #feature))] - #input - ) -} diff --git a/core/tauri-runtime-wry/.license_template b/core/tauri-runtime-wry/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/core/tauri-runtime-wry/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/core/tauri-runtime-wry/CHANGELOG.md b/core/tauri-runtime-wry/CHANGELOG.md deleted file mode 100644 index ff7d8694eaea..000000000000 --- a/core/tauri-runtime-wry/CHANGELOG.md +++ /dev/null @@ -1,260 +0,0 @@ -# Changelog - -## \[0.3.3] - -- Fixes a deadlock on the `Focused` event when the window is not visible. - - [c08cc6d5](https://www.github.com/tauri-apps/tauri/commit/c08cc6d50041ec887d3070c41bb2c793dbac5155) fix(core): deadlock on focus events with invisible window,[#3534](https://www.github.com/tauri-apps/tauri/pull/3534) ([#3622](https://www.github.com/tauri-apps/tauri/pull/3622)) on 2022-03-06 -- **Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features. - - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 -- Print a warning to stderr if the window transparency has been set to true but `macos-private-api` is not enabled. - - [080755b5](https://www.github.com/tauri-apps/tauri/commit/080755b5377a3c0a17adf1d03e63555350422f0a) feat(core): warn if private APIs are not enabled, closes [#3481](https://www.github.com/tauri-apps/tauri/pull/3481) ([#3511](https://www.github.com/tauri-apps/tauri/pull/3511)) on 2022-02-19 - -## \[0.3.2] - -- Fix requirements for `RuntimeHandle`, `ClipboardManager`, `GlobalShortcutHandle` and `TrayHandle`. - - Bumped due to a bump in tauri-runtime. - - [84895a9c](https://www.github.com/tauri-apps/tauri/commit/84895a9cd270fc743e236d0f4d4cd6210b24a30f) fix(runtime): trait requirements ([#3489](https://www.github.com/tauri-apps/tauri/pull/3489)) on 2022-02-17 - -## \[0.3.1] - -- Change default value for the `freezePrototype` configuration to `false`. - - Bumped due to a bump in tauri-utils. - - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 - -## \[0.3.0] - -- Fix `window.center` panic when window size is bigger than screen size. - - [76ce9f61](https://www.github.com/tauri-apps/tauri/commit/76ce9f61dd3c5bdd589c7557543894e1f770dd16) fix(core): fix `window.center` panic when window size > screen, closes [#2978](https://www.github.com/tauri-apps/tauri/pull/2978) ([#3002](https://www.github.com/tauri-apps/tauri/pull/3002)) on 2021-12-09 -- Enable non-session cookie persistence on Linux. - - [d7c02a30](https://www.github.com/tauri-apps/tauri/commit/d7c02a30a56de79100804969138b379e703f0e07) feat(core): persist non-session cookies on Linux ([#3052](https://www.github.com/tauri-apps/tauri/pull/3052)) on 2021-12-09 -- Fixes a deadlock when creating a window from a menu event handler. - - [9c82006b](https://www.github.com/tauri-apps/tauri/commit/9c82006b2fe166d20510183e36cee099bf96e8d9) fix(core): deadlock when creating window from menu handler, closes [#3110](https://www.github.com/tauri-apps/tauri/pull/3110) ([#3126](https://www.github.com/tauri-apps/tauri/pull/3126)) on 2021-12-28 -- Fixes `WindowEvent::Focus` and `WindowEvent::Blur` events not firing. - - [3b33d67a](https://www.github.com/tauri-apps/tauri/commit/3b33d67aa4f48dcf4e32b3b8a5f45e83808efc2d) fix: re-adding focus/blur events for linux and macos (fix [#2485](https://www.github.com/tauri-apps/tauri/pull/2485)) ([#2489](https://www.github.com/tauri-apps/tauri/pull/2489)) on 2021-08-24 -- Use webview's inner_size instead of window's value to get the correct size on macOS. - - [4c0c780e](https://www.github.com/tauri-apps/tauri/commit/4c0c780e00d8851be38cb1c22f636d9e4ed34a23) fix(core): window's inner_size usage, closes [#2187](https://www.github.com/tauri-apps/tauri/pull/2187) ([#2690](https://www.github.com/tauri-apps/tauri/pull/2690)) on 2021-09-29 -- Reimplement `remove_system_tray` on Windows to drop the `SystemTray` to run its cleanup code. - - [a03b8554](https://www.github.com/tauri-apps/tauri/commit/a03b85545a4b0b61a598a43eabe96e03565dcaf0) fix(core): tray not closing on Windows ([#3351](https://www.github.com/tauri-apps/tauri/pull/3351)) on 2022-02-07 -- Replace `WindowBuilder`'s `has_menu` with `get_menu`. - - [ac37b56e](https://www.github.com/tauri-apps/tauri/commit/ac37b56ef43c9e97039967a5fd99f0d2dccb5b5a) fix(core): menu id map not reflecting the current window menu ([#2726](https://www.github.com/tauri-apps/tauri/pull/2726)) on 2021-10-08 -- Fix empty header from CORS on Linux. - - [b48487e6](https://www.github.com/tauri-apps/tauri/commit/b48487e6a7b33f5a352e542fae21a2efd53ce295) Fix empty header from CORS on Linux, closes [#2327](https://www.github.com/tauri-apps/tauri/pull/2327) ([#2762](https://www.github.com/tauri-apps/tauri/pull/2762)) on 2021-10-18 -- The `run_return` API is now available on Linux. - - [8483fde9](https://www.github.com/tauri-apps/tauri/commit/8483fde975aac8833d2ce426e42fb40aeaeecba9) feat(core): expose `run_return` on Linux ([#3352](https://www.github.com/tauri-apps/tauri/pull/3352)) on 2022-02-07 -- Allow window, global shortcut and clipboard APIs to be called on the main thread. - - [2812c446](https://www.github.com/tauri-apps/tauri/commit/2812c4464b93a365ab955935d05b5cea8cb03aab) feat(core): window, shortcut and clipboard API calls on main thread ([#2659](https://www.github.com/tauri-apps/tauri/pull/2659)) on 2021-09-26 - - [d24fd8d1](https://www.github.com/tauri-apps/tauri/commit/d24fd8d10242da3da143a971d976b42ec4de6079) feat(tauri-runtime-wry): allow window creation and closing on the main thread ([#2668](https://www.github.com/tauri-apps/tauri/pull/2668)) on 2021-09-27 -- Change event loop callbacks definition to allow callers to move in mutable values. - - [bdbf905e](https://www.github.com/tauri-apps/tauri/commit/bdbf905e5d802b58693d2bd27582ce4269faf79c) Transformed event-loop callback to FnMut to allow mutable values ([#2667](https://www.github.com/tauri-apps/tauri/pull/2667)) on 2021-09-27 -- **Breaking change:** Add `macos-private-api` feature flag, enabled via `tauri.conf.json > tauri > macOSPrivateApi`. - - [6ac21b3c](https://www.github.com/tauri-apps/tauri/commit/6ac21b3cef7f14358df38cc69ea3d277011accaf) feat: add private api feature flag ([#7](https://www.github.com/tauri-apps/tauri/pull/7)) on 2022-01-09 -- Refactor `create_tao_window` API to return `Weak` instead of `Arc`. - - [c1494b35](https://www.github.com/tauri-apps/tauri/commit/c1494b353233c6a9552d7ace962fdf8d5b1f199a) refactor: return Weak on create_tao_window on 2021-08-31 -- Added `any_thread` constructor on the `Runtime` trait (only possible on Linux and Windows). - - [af44bf81](https://www.github.com/tauri-apps/tauri/commit/af44bf8168310cf77fbe102a53e7c433f11641a3) feat(core): allow app run on any thread on Linux & Windows, closes [#3172](https://www.github.com/tauri-apps/tauri/pull/3172) ([#3353](https://www.github.com/tauri-apps/tauri/pull/3353)) on 2022-02-07 -- Added `run_on_main_thread` API on `RuntimeHandle`. - - [53fdfe52](https://www.github.com/tauri-apps/tauri/commit/53fdfe52bb30d52653c72ca9f42506c3863dcf4a) feat(core): expose `run_on_main_thread` API ([#2711](https://www.github.com/tauri-apps/tauri/pull/2711)) on 2021-10-04 -- **Breaking change:** Renamed the `RPC` interface to `IPC`. - - [3420aa50](https://www.github.com/tauri-apps/tauri/commit/3420aa5031b3274a95c6c5fa0f8683ca13213396) refactor: IPC handler \[TRI-019] ([#9](https://www.github.com/tauri-apps/tauri/pull/9)) on 2022-01-09 -- Added `open_devtools` to the `Dispatcher` trait. - - [55aa22de](https://www.github.com/tauri-apps/tauri/commit/55aa22de80c3de873e29bcffcb5b2fe236a637a6) feat(core): add `Window#open_devtools` API, closes [#1213](https://www.github.com/tauri-apps/tauri/pull/1213) ([#3350](https://www.github.com/tauri-apps/tauri/pull/3350)) on 2022-02-07 -- The minimum Rust version is now `1.56`. - - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 -- Replace all of the `winapi` crate references with the `windows` crate, and replace `webview2` and `webview2-sys` with `webview2-com` and `webview2-com-sys` built with the `windows` crate. This goes along with updates to the TAO and WRY `next` branches. - - [bb00d5bd](https://www.github.com/tauri-apps/tauri/commit/bb00d5bd6c9dfcb6bdd0d308dadb70e6c6aafe5c) Replace winapi with windows crate and use webview2-com instead of webview2 ([#2615](https://www.github.com/tauri-apps/tauri/pull/2615)) on 2021-09-24 -- Update the `windows` crate to 0.25.0, which comes with pre-built libraries. WRY and Tao can both reference the same types directly from the `windows` crate instead of sharing bindings in `webview2-com-sys`. - - [34be6cf3](https://www.github.com/tauri-apps/tauri/commit/34be6cf37a98ee7cbd66623ebddae08e5a6520fd) Update webview2-com and windows crates ([#2875](https://www.github.com/tauri-apps/tauri/pull/2875)) on 2021-11-11 -- This is a temporary fix of null pointer crash on `get_content` of web resource request. - We will switch it back once upstream is updated. - - [84f6e3e8](https://www.github.com/tauri-apps/tauri/commit/84f6e3e84a34b01b7fa04f5c4719acb921ef4263) Switch to next branch of wry ([#2574](https://www.github.com/tauri-apps/tauri/pull/2574)) on 2021-09-10 -- Update wry to 0.13. - - [343ea3e2](https://www.github.com/tauri-apps/tauri/commit/343ea3e2e8d51bac63ab651289295c26fcc841d8) Update wry to 0.13 ([#3336](https://www.github.com/tauri-apps/tauri/pull/3336)) on 2022-02-06 - -## \[0.2.1] - -- Migrate to latest custom protocol allowing `Partial content` streaming and Header parsing. - - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 - -## \[0.2.0] - -- Fix blur/focus events being incorrect on Windows. - - [d832d575](https://www.github.com/tauri-apps/tauri/commit/d832d575d9b03a0ff78accabe4631cc638c08c3b) fix(windows): use webview events on windows ([#2277](https://www.github.com/tauri-apps/tauri/pull/2277)) on 2021-07-23 - -- Add `ExitRequested` event that allows preventing the app from exiting when all windows are closed, and an `AppHandle.exit()` function to exit the app manually. - - [892c63a0](https://www.github.com/tauri-apps/tauri/commit/892c63a0538f8d62680dce5848657128ad6b7af3) feat([#2287](https://www.github.com/tauri-apps/tauri/pull/2287)): Add `ExitRequested` event to let users prevent app from exiting ([#2293](https://www.github.com/tauri-apps/tauri/pull/2293)) on 2021-08-09 - -- Update gtk and its related libraries to v0.14. This also remove requirements of `clang` as build dependency. - - [63ad3039](https://www.github.com/tauri-apps/tauri/commit/63ad303903bbee7c9a7382413b342e2a05d3ea75) chore(linux): bump gtk to v0.14 ([#2361](https://www.github.com/tauri-apps/tauri/pull/2361)) on 2021-08-07 - -- Implement `Debug` on public API structs and enums. - - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 - -- Fix the error "cannot find type MenuHash in this scope" - - [226414d1](https://www.github.com/tauri-apps/tauri/commit/226414d1a588c8bc2b540a71fcd84c318319d6af) "cannot find type `MenuHash` in this scope" ([#2240](https://www.github.com/tauri-apps/tauri/pull/2240)) on 2021-07-20 - -- Panic when a dispatcher getter method (`Window`, `GlobalShortcutHandle`, `ClipboardManager` and `MenuHandle` APIs) is called on the main thread. - - [50ffdc06](https://www.github.com/tauri-apps/tauri/commit/50ffdc06fbde56aba32b4291fd130104935d1408) feat(core): panic when a dispatcher getter is used on the main thread ([#2455](https://www.github.com/tauri-apps/tauri/pull/2455)) on 2021-08-16 - -- Remove menu feature flag since there's no package dependency need to be installed on any platform anymore. - - [f81ebddf](https://www.github.com/tauri-apps/tauri/commit/f81ebddfcc1aea0d4989706aef43538e8ea98bea) feat: remove menu feature flag ([#2415](https://www.github.com/tauri-apps/tauri/pull/2415)) on 2021-08-13 - -- Adds `Resumed` and `MainEventsCleared` variants to the `RunEvent` enum. - - [6be3f433](https://www.github.com/tauri-apps/tauri/commit/6be3f4339168651fe4e003b09f7d181fd12cd5a8) feat(core): add `Resumed` and `MainEventsCleared` events, closes [#2127](https://www.github.com/tauri-apps/tauri/pull/2127) ([#2439](https://www.github.com/tauri-apps/tauri/pull/2439)) on 2021-08-15 - -- Adds `set_activation_policy` API to the `Runtime` trait (macOS only). - - [4a031add](https://www.github.com/tauri-apps/tauri/commit/4a031add69014a1f3823f4ea19b172a2557f6794) feat(core): expose `set_activation_policy`, closes [#2258](https://www.github.com/tauri-apps/tauri/pull/2258) ([#2420](https://www.github.com/tauri-apps/tauri/pull/2420)) on 2021-08-13 - -- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. - - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 - - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 - -- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. - -- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. - -- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 - -- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. - - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 - -- Add webdriver support to Tauri. - - [be76fb1d](https://www.github.com/tauri-apps/tauri/commit/be76fb1dfe73a1605cc2ad246418579f4c2e1999) WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972)) on 2021-06-23 - - [b4426eda](https://www.github.com/tauri-apps/tauri/commit/b4426eda9e64fcdd25a2d72e548b8b0fbfa09619) Revert "WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972))" on 2021-06-23 - - [4b2aa356](https://www.github.com/tauri-apps/tauri/commit/4b2aa35684632ed2afd7dec4ad848df5704868e4) Add back WebDriver support ([#2324](https://www.github.com/tauri-apps/tauri/pull/2324)) on 2021-08-01 - -## \[0.1.4] - -- Allow preventing window close when the user requests it. - - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 -- Fixes SVG loading on custom protocol. - - [e663bdd5](https://www.github.com/tauri-apps/tauri/commit/e663bdd5938830ab4eba961e69c3985191b499dd) fix(core): svg mime type ([#2129](https://www.github.com/tauri-apps/tauri/pull/2129)) on 2021-06-30 -- Fixes `center` and `focus` not being allowed in `tauri.conf.json > tauri > windows` and ignored in `WindowBuilderWrapper`. - - [bc2c331d](https://www.github.com/tauri-apps/tauri/commit/bc2c331dec3dec44c79e659b082b5fb6b65cc5ea) fix: center and focus not being allowed in config ([#2199](https://www.github.com/tauri-apps/tauri/pull/2199)) on 2021-07-12 -- Expose `gtk_window` getter. - - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 -- Remove a few locks requirement in tauri-runtime-wry - - [6569c2bf](https://www.github.com/tauri-apps/tauri/commit/6569c2bf5caf24b009cad1e2cffba25418d6bb68) refactor(wry): remove a few locks requirements ([#2137](https://www.github.com/tauri-apps/tauri/pull/2137)) on 2021-07-02 -- Fix macOS high CPU usage. - - [a280ee90](https://www.github.com/tauri-apps/tauri/commit/a280ee90af0749ce18d6d0b00939b06473717bc9) Fix high cpu usage on mac, fix [#2074](https://www.github.com/tauri-apps/tauri/pull/2074) ([#2125](https://www.github.com/tauri-apps/tauri/pull/2125)) on 2021-06-30 -- Bump `wry` 0.11 and fix focus integration to make it compatible with tao 0.4. - - [f0a8db62](https://www.github.com/tauri-apps/tauri/commit/f0a8db62e445dbbc5770e7addf0390ce3844c1ea) core(deps): bump `wry` to `0.11` ([#2210](https://www.github.com/tauri-apps/tauri/pull/2210)) on 2021-07-15 -- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those - associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If - you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the - explicit type and let the compiler infer it instead. - -`tauri`: - -- See `Params` note -- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a - simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition - of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type - to these functions. -- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all - methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already - required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change - affects you. - -`tauri-macros`: - -- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when - the specified feature is enabled. - -`tauri-runtime`: - -- See `Params` note -- Removed `Params`, `MenuId`, `Tag`, `TagRef`. -- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. - - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. -- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the - `Runtime` type directly -- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. -- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. - -`tauri-runtime-wry`: - -- See `Params` note -- update menu and runtime related types to the ones changed in `tauri-runtime`. - -`tauri-utils`: - -- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object - safe. -- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 - -## \[0.1.3] - -- `Window` is now `Send + Sync` on Windows. - - [fe32afcc](https://www.github.com/tauri-apps/tauri/commit/fe32afcc933920d6282ae1d63b041b182278a031) fix(core): `Window` must be `Send + Sync` on Windows, closes [#2078](https://www.github.com/tauri-apps/tauri/pull/2078) ([#2093](https://www.github.com/tauri-apps/tauri/pull/2093)) on 2021-06-27 - -## \[0.1.2] - -- Adds `clipboard` APIs (write and read text). - - [285bf64b](https://www.github.com/tauri-apps/tauri/commit/285bf64bf9569efb2df904c69c6df405ff0d62e2) feat(core): add clipboard writeText and readText APIs ([#2035](https://www.github.com/tauri-apps/tauri/pull/2035)) on 2021-06-21 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Fixes window event being emitted to all windows listeners. - - [fca97640](https://www.github.com/tauri-apps/tauri/commit/fca976404e6bec373a81332572458c4c44f7bb3a) fix(wry): window event listeners being emitted to all windows ([#2056](https://www.github.com/tauri-apps/tauri/pull/2056)) on 2021-06-23 -- Panic on window getters usage on the main thread when the event loop is not running and document it. - - [ab3eb44b](https://www.github.com/tauri-apps/tauri/commit/ab3eb44bac7a3bf73a4985df38ccc2b87a913be7) fix(core): deadlock on window getters, fixes [#1893](https://www.github.com/tauri-apps/tauri/pull/1893) ([#1998](https://www.github.com/tauri-apps/tauri/pull/1998)) on 2021-06-16 -- Adds `focus` API to the WindowBuilder. - - [5f351622](https://www.github.com/tauri-apps/tauri/commit/5f351622c7812ad1bb56ddb37364ccaa4124c24b) feat(core): add focus API to the WindowBuilder and WindowOptions, [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds support to PNG icons. - - [40b717ed](https://www.github.com/tauri-apps/tauri/commit/40b717edc57288a1393fad0529390e101ab903c1) feat(core): set window icon on Linux, closes [#1922](https://www.github.com/tauri-apps/tauri/pull/1922) ([#1937](https://www.github.com/tauri-apps/tauri/pull/1937)) on 2021-06-01 -- Adds `is_decorated` getter on Window. - - [f58a2114](https://www.github.com/tauri-apps/tauri/commit/f58a2114fbfd5307c349f05c88f2e08fd8baa8aa) feat(core): add `is_decorated` Window getter on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `is_resizable` getter on Window. - - [1e8af280](https://www.github.com/tauri-apps/tauri/commit/1e8af280c27f381828d6209722b10e889082fa00) feat(core): add `is_resizable` Window getter on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `is_visible` getter on Window. - - [36506c96](https://www.github.com/tauri-apps/tauri/commit/36506c967de82bc7ff453d11e6104ecf66d7a588) feat(core): add `is_visible` API on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Removes `image` dependency. For now only `.ico` icons on Windows are supported, and we'll implement other types on demand to optimize bundle size. - - [1be37a3f](https://www.github.com/tauri-apps/tauri/commit/1be37a3f30ff789d9396ec9009f9c0dd0bb928a7) refactor(core): remove `image` dependency ([#1859](https://www.github.com/tauri-apps/tauri/pull/1859)) on 2021-05-18 -- The `run_on_main_thread` API now uses WRY's UserEvent, so it wakes the event loop. - - [9bf82f0d](https://www.github.com/tauri-apps/tauri/commit/9bf82f0d9261808f58bdb5b5dbd6a255e5dcd333) fix(core): `run_on_main_thread` now wakes the event loop ([#1949](https://www.github.com/tauri-apps/tauri/pull/1949)) on 2021-06-04 -- Adds global shortcut interfaces. - - [3280c4aa](https://www.github.com/tauri-apps/tauri/commit/3280c4aa91e50a8ccdd561a8b48a12a4a13ea8d5) refactor(core): global shortcut is now provided by `tao` ([#2031](https://www.github.com/tauri-apps/tauri/pull/2031)) on 2021-06-21 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `request_user_attention` API to the `Dispatcher` trait. - - [7dcca6e9](https://www.github.com/tauri-apps/tauri/commit/7dcca6e9281182b11ad3d4a79871f09b30b9b419) feat(core): add `request_user_attention` API, closes [#2023](https://www.github.com/tauri-apps/tauri/pull/2023) ([#2026](https://www.github.com/tauri-apps/tauri/pull/2026)) on 2021-06-20 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `fn run_iteration` (macOS and Windows only) to the Runtime trait. - - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 -- Adds `show_menu`, `hide_menu` and `is_menu_visible` APIs to the `Dispatcher` trait. - - [954460c5](https://www.github.com/tauri-apps/tauri/commit/954460c5205d57444ef4b1412051fbedf3e38676) feat(core): MenuHandle `show`, `hide`, `is_visible` and `toggle` APIs ([#1958](https://www.github.com/tauri-apps/tauri/pull/1958)) on 2021-06-15 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `set_focus` API on Window. - - [bb6992f8](https://www.github.com/tauri-apps/tauri/commit/bb6992f888196ca7c87bb2fe74ad2bd8bf393e05) feat(core): add `set_focus` window API, fixes [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `set_skip_taskbar` API on Window. - - [e06aa277](https://www.github.com/tauri-apps/tauri/commit/e06aa277384450cfef617c0e57b0d5d403bb1e7f) feat(core): add `set_skip_taskbar` API on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Update `wry` to v0.10.0 and replace the removed `dispatch_script` and `evaluate_script` methods with the new `evaluate_script` method in `handle_event_loop`. - - [cca8115d](https://www.github.com/tauri-apps/tauri/commit/cca8115d9c813d13efb30a38445d5bda009a7f97) refactor: update wry, simplify script eval ([#1965](https://www.github.com/tauri-apps/tauri/pull/1965)) on 2021-06-16 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `skip_taskbar` API to the WindowBuilder. - - [5525b03a](https://www.github.com/tauri-apps/tauri/commit/5525b03a78a2232c650043fbd9894ce1553cad41) feat(core): add `skip_taskbar` API to the WindowBuilder/WindowOptions on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `Window#center` and `WindowBuilder#center` APIs. - - [5cba6eb4](https://www.github.com/tauri-apps/tauri/commit/5cba6eb4d28d53f06855d60d4d0eae6b95233ccf) feat(core): add window `center` API, closes [#1822](https://www.github.com/tauri-apps/tauri/pull/1822) ([#1954](https://www.github.com/tauri-apps/tauri/pull/1954)) on 2021-06-05 -- Adds `parent_window` and `owner_window` setters to the `WindowBuilder` (Windows only). - - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 -- Adds window native handle getter (HWND on Windows). - - [abf78c58](https://www.github.com/tauri-apps/tauri/commit/abf78c5860cdc52fbfd2bc5dbca29a864e2da8f9) fix(core): set parent window handle on dialogs, closes [#1876](https://www.github.com/tauri-apps/tauri/pull/1876) ([#1889](https://www.github.com/tauri-apps/tauri/pull/1889)) on 2021-05-21 - -## \[0.1.1] - -- Fixes `system-tray` feature usage. - - [1ab8dd9](https://www.github.com/tauri-apps/tauri/commit/1ab8dd93e670d2a2d070c7a6ec48308a0ab32f1a) fix(core): `system-tray` cargo feature usage, fixes [#1798](https://www.github.com/tauri-apps/tauri/pull/1798) ([#1801](https://www.github.com/tauri-apps/tauri/pull/1801)) on 2021-05-12 -- Fixes webview transparency. - - [f5a480f](https://www.github.com/tauri-apps/tauri/commit/f5a480fea34ab3a75751f1ca760a38b3e53da2cc) fix(core): window transparency ([#1800](https://www.github.com/tauri-apps/tauri/pull/1800)) on 2021-05-12 - -## \[0.1.0] - -- **Breaking:** `Context` fields are now private, and is expected to be created through `Context::new(...)`. - All fields previously available through `Context` are now public methods. - - [5542359](https://www.github.com/tauri-apps/tauri/commit/55423590ddbf560684dab6a0214acf95aadfa8d2) refactor(core): Context fields now private, Icon used on all platforms ([#1774](https://www.github.com/tauri-apps/tauri/pull/1774)) on 2021-05-11 -- `tauri-runtime-wry` initial release. - - [45a7a11](https://www.github.com/tauri-apps/tauri/commit/45a7a111e0cf9d9956d713cc9a99fa7a5313eec7) feat(core): add `tauri-wry` crate ([#1756](https://www.github.com/tauri-apps/tauri/pull/1756)) on 2021-05-09 diff --git a/core/tauri-runtime-wry/Cargo.toml b/core/tauri-runtime-wry/Cargo.toml deleted file mode 100644 index bee76031bf2d..000000000000 --- a/core/tauri-runtime-wry/Cargo.toml +++ /dev/null @@ -1,41 +0,0 @@ -[package] -name = "tauri-runtime-wry" -version = "0.3.3" -authors = [ "Tauri Programme within The Commons Conservancy" ] -categories = [ "gui", "web-programming" ] -license = "Apache-2.0 OR MIT" -homepage = "https://tauri.studio" -repository = "https://github.com/tauri-apps/tauri" -description = "Wry bindings to the Tauri runtime" -edition = "2021" -rust-version = "1.57" -exclude = [ ".license_template", "CHANGELOG.md", "/target" ] -readme = "README.md" - -[dependencies] -wry = { version = "0.13.3", default-features = false, features = [ "file-drop", "protocol" ] } -tauri-runtime = { version = "0.3.3", path = "../tauri-runtime" } -tauri-utils = { version = "1.0.0-rc.3", path = "../tauri-utils" } -uuid = { version = "0.8.2", features = [ "v4" ] } -rand = "0.8" - -[target."cfg(windows)".dependencies] -webview2-com = "0.13.0" - - [target."cfg(windows)".dependencies.windows] - version = "0.30.0" - features = [ "Win32_Foundation" ] - -[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] -gtk = { version = "0.15", features = [ "v3_20" ] } - -[features] -dox = [ "wry/dox" ] -devtools = [ "wry/devtool", "tauri-runtime/devtools" ] -system-tray = [ "wry/tray", "tauri-runtime/system-tray" ] -macos-private-api = [ - "wry/fullscreen", - "wry/transparent", - "tauri-runtime/macos-private-api" -] -objc-exception = [ "wry/objc-exception" ] diff --git a/core/tauri-runtime-wry/README.md b/core/tauri-runtime-wry/README.md deleted file mode 100644 index ef86b1794b5d..000000000000 --- a/core/tauri-runtime-wry/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# tauri-runtime-wry - - - -[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri) -[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) -[![devto](https://img.shields.io/badge/blog-dev.to-black.svg)](https://dev.to/tauri) - -![](https://img.shields.io/github/workflow/status/tauri-apps/tauri/test%20library?label=test%20library -) -[![devto](https://img.shields.io/badge/documentation-site-purple.svg)](https://tauri.studio) - -[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) -[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri) - -| Component | Version | -| --------- | ------------------------------------------- | -| tauri-runtime-wry | [![](https://img.shields.io/crates/v/tauri-runtime-wry?style=flat-square)](https://crates.io/crates/tauri-runtime-wry) | - -## About Tauri -Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. - -Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. - -## This module -This crate opens up direct systems-level interactions specifically for WRY, such as printing, monitor detection, and other windowing related tasks. `tauri-runtime` implementation for WRY. - -To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. - -## Semver -**tauri** is following [Semantic Versioning 2.0](https://semver.org/). -## Licenses -Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. - -MIT or MIT/Apache 2.0 where applicable. - -Logo: CC-BY-NC-ND -- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs deleted file mode 100644 index 9c58b4a84088..000000000000 --- a/core/tauri-runtime-wry/src/lib.rs +++ /dev/null @@ -1,2829 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! The [`wry`] Tauri [`Runtime`]. - -use tauri_runtime::{ - http::{ - Request as HttpRequest, RequestParts as HttpRequestParts, Response as HttpResponse, - ResponseParts as HttpResponseParts, - }, - menu::{CustomMenuItem, Menu, MenuEntry, MenuHash, MenuId, MenuItem, MenuUpdate}, - monitor::Monitor, - webview::{WebviewIpcHandler, WindowBuilder, WindowBuilderBase}, - window::{ - dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, - DetachedWindow, FileDropEvent, JsEventListenerKey, PendingWindow, WindowEvent, - }, - ClipboardManager, Dispatch, Error, EventLoopProxy, ExitRequestedEventAction, - GlobalShortcutManager, Result, RunEvent, RunIteration, Runtime, RuntimeHandle, UserAttentionType, - UserEvent, WindowIcon, -}; - -use tauri_runtime::window::MenuEvent; -#[cfg(feature = "system-tray")] -use tauri_runtime::{SystemTray, SystemTrayEvent}; -#[cfg(windows)] -use webview2_com::FocusChangedEventHandler; -#[cfg(windows)] -use windows::Win32::{Foundation::HWND, System::WinRT::EventRegistrationToken}; -#[cfg(all(feature = "system-tray", target_os = "macos"))] -use wry::application::platform::macos::{SystemTrayBuilderExtMacOS, SystemTrayExtMacOS}; -#[cfg(target_os = "linux")] -use wry::application::platform::unix::{WindowBuilderExtUnix, WindowExtUnix}; -#[cfg(windows)] -use wry::application::platform::windows::{WindowBuilderExtWindows, WindowExtWindows}; - -#[cfg(feature = "system-tray")] -use wry::application::system_tray::{SystemTray as WrySystemTray, SystemTrayBuilder}; - -use tauri_utils::config::WindowConfig; -use uuid::Uuid; -use wry::{ - application::{ - accelerator::{Accelerator, AcceleratorId}, - clipboard::Clipboard, - dpi::{ - LogicalPosition as WryLogicalPosition, LogicalSize as WryLogicalSize, - PhysicalPosition as WryPhysicalPosition, PhysicalSize as WryPhysicalSize, - Position as WryPosition, Size as WrySize, - }, - event::{Event, StartCause, WindowEvent as WryWindowEvent}, - event_loop::{ - ControlFlow, EventLoop, EventLoopProxy as WryEventLoopProxy, EventLoopWindowTarget, - }, - global_shortcut::{GlobalShortcut, ShortcutManager as WryShortcutManager}, - menu::{ - CustomMenuItem as WryCustomMenuItem, MenuBar, MenuId as WryMenuId, MenuItem as WryMenuItem, - MenuItemAttributes as WryMenuItemAttributes, MenuType, - }, - monitor::MonitorHandle, - window::{Fullscreen, Icon as WryWindowIcon, UserAttentionType as WryUserAttentionType}, - }, - http::{ - Request as WryHttpRequest, RequestParts as WryRequestParts, Response as WryHttpResponse, - ResponseParts as WryResponseParts, - }, - webview::{FileDropEvent as WryFileDropEvent, WebContext, WebView, WebViewBuilder}, -}; - -pub use wry::application::window::{Window, WindowBuilder as WryWindowBuilder, WindowId}; - -#[cfg(windows)] -use wry::webview::WebviewExtWindows; - -#[cfg(target_os = "macos")] -use tauri_runtime::{menu::NativeImage, ActivationPolicy}; -#[cfg(target_os = "macos")] -pub use wry::application::platform::macos::{ - ActivationPolicy as WryActivationPolicy, CustomMenuItemExtMacOS, EventLoopExtMacOS, - NativeImage as WryNativeImage, WindowExtMacOS, -}; - -use std::{ - collections::{ - hash_map::Entry::{Occupied, Vacant}, - HashMap, HashSet, - }, - fmt, - ops::Deref, - path::PathBuf, - sync::{ - mpsc::{channel, Sender}, - Arc, Mutex, MutexGuard, Weak, - }, - thread::{current as current_thread, ThreadId}, -}; - -type WebviewId = u64; - -#[cfg(feature = "system-tray")] -mod system_tray; -#[cfg(feature = "system-tray")] -use system_tray::*; - -type WebContextStore = Arc, WebContext>>>; -// window -type WindowEventHandler = Box; -type WindowEventListenersMap = Arc>>; -type WindowEventListeners = Arc>>; -// global shortcut -type GlobalShortcutListeners = Arc>>>; -// menu -pub type MenuEventHandler = Box; -pub type MenuEventListeners = Arc>>; -pub type WindowMenuEventListeners = Arc>>; - -#[derive(Debug, Clone, Default)] -struct WebviewIdStore(Arc>>); - -impl WebviewIdStore { - fn insert(&self, w: WindowId, id: WebviewId) { - self.0.lock().unwrap().insert(w, id); - } - - fn get(&self, w: &WindowId) -> WebviewId { - *self.0.lock().unwrap().get(w).unwrap() - } -} - -macro_rules! getter { - ($self: ident, $rx: expr, $message: expr) => {{ - send_user_message(&$self.context, $message)?; - $rx.recv().map_err(|_| Error::FailedToReceiveMessage) - }}; -} - -macro_rules! window_getter { - ($self: ident, $message: expr) => {{ - let (tx, rx) = channel(); - getter!($self, rx, Message::Window($self.window_id, $message(tx))) - }}; -} - -fn send_user_message(context: &Context, message: Message) -> Result<()> { - if current_thread().id() == context.main_thread_id { - handle_user_message( - &context.main_thread.window_target, - message, - UserMessageContext { - window_event_listeners: &context.window_event_listeners, - global_shortcut_manager: context.main_thread.global_shortcut_manager.clone(), - clipboard_manager: context.main_thread.clipboard_manager.clone(), - menu_event_listeners: &context.menu_event_listeners, - windows: context.main_thread.windows.clone(), - #[cfg(feature = "system-tray")] - tray_context: &context.main_thread.tray_context, - }, - &context.main_thread.web_context, - ); - Ok(()) - } else { - context - .proxy - .send_event(message) - .map_err(|_| Error::FailedToSendMessage) - } -} - -#[derive(Clone)] -struct Context { - webview_id_map: WebviewIdStore, - main_thread_id: ThreadId, - proxy: WryEventLoopProxy>, - window_event_listeners: WindowEventListeners, - menu_event_listeners: MenuEventListeners, - main_thread: DispatcherMainThreadContext, -} - -impl Context { - fn prepare_window(&self, window_id: WebviewId) { - self - .window_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowEventListenersMap::default()); - - self - .menu_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowMenuEventListeners::default()); - } - - fn create_webview(&self, pending: PendingWindow>) -> Result>> { - let label = pending.label.clone(); - let menu_ids = pending.menu_ids.clone(); - let js_event_listeners = pending.js_event_listeners.clone(); - let context = self.clone(); - let window_id = rand::random(); - - self.prepare_window(window_id); - - self - .proxy - .send_event(Message::CreateWebview( - window_id, - Box::new(move |event_loop, web_context| { - create_webview(window_id, event_loop, web_context, context, pending) - }), - )) - .map_err(|_| Error::FailedToSendMessage)?; - - let dispatcher = WryDispatcher { - window_id, - context: self.clone(), - }; - Ok(DetachedWindow { - label, - dispatcher, - menu_ids, - js_event_listeners, - }) - } -} - -#[derive(Debug, Clone)] -struct DispatcherMainThreadContext { - window_target: EventLoopWindowTarget>, - web_context: WebContextStore, - global_shortcut_manager: Arc>, - clipboard_manager: Arc>, - windows: Arc>>, - #[cfg(feature = "system-tray")] - tray_context: TrayContext, -} - -// SAFETY: we ensure this type is only used on the main thread. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for DispatcherMainThreadContext {} - -impl fmt::Debug for Context { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Context") - .field("main_thread_id", &self.main_thread_id) - .field("proxy", &self.proxy) - .field("main_thread", &self.main_thread) - .finish() - } -} - -struct HttpRequestPartsWrapper(HttpRequestParts); - -impl From for HttpRequestParts { - fn from(parts: HttpRequestPartsWrapper) -> Self { - Self { - method: parts.0.method, - uri: parts.0.uri, - headers: parts.0.headers, - } - } -} - -impl From for HttpRequestPartsWrapper { - fn from(request: HttpRequestParts) -> Self { - Self(HttpRequestParts { - method: request.method, - uri: request.uri, - headers: request.headers, - }) - } -} - -impl From for HttpRequestPartsWrapper { - fn from(request: WryRequestParts) -> Self { - Self(HttpRequestParts { - method: request.method, - uri: request.uri, - headers: request.headers, - }) - } -} - -struct HttpRequestWrapper(HttpRequest); - -impl From<&WryHttpRequest> for HttpRequestWrapper { - fn from(req: &WryHttpRequest) -> Self { - Self(HttpRequest::new_internal( - HttpRequestPartsWrapper::from(req.head.clone()).0, - req.body.clone(), - )) - } -} - -// response -struct HttpResponsePartsWrapper(WryResponseParts); -impl From for HttpResponsePartsWrapper { - fn from(response: HttpResponseParts) -> Self { - Self(WryResponseParts { - mimetype: response.mimetype, - status: response.status, - version: response.version, - headers: response.headers, - }) - } -} - -struct HttpResponseWrapper(WryHttpResponse); -impl From for HttpResponseWrapper { - fn from(response: HttpResponse) -> Self { - let (parts, body) = response.into_parts(); - Self(WryHttpResponse { - body, - head: HttpResponsePartsWrapper::from(parts).0, - }) - } -} - -pub struct MenuItemAttributesWrapper<'a>(pub WryMenuItemAttributes<'a>); - -impl<'a> From<&'a CustomMenuItem> for MenuItemAttributesWrapper<'a> { - fn from(item: &'a CustomMenuItem) -> Self { - let mut attributes = WryMenuItemAttributes::new(&item.title) - .with_enabled(item.enabled) - .with_selected(item.selected) - .with_id(WryMenuId(item.id)); - if let Some(accelerator) = item.keyboard_accelerator.as_ref() { - attributes = attributes.with_accelerators(&accelerator.parse().expect("invalid accelerator")); - } - Self(attributes) - } -} - -pub struct MenuItemWrapper(pub WryMenuItem); - -impl From for MenuItemWrapper { - fn from(item: MenuItem) -> Self { - match item { - MenuItem::About(v) => Self(WryMenuItem::About(v)), - MenuItem::Hide => Self(WryMenuItem::Hide), - MenuItem::Services => Self(WryMenuItem::Services), - MenuItem::HideOthers => Self(WryMenuItem::HideOthers), - MenuItem::ShowAll => Self(WryMenuItem::ShowAll), - MenuItem::CloseWindow => Self(WryMenuItem::CloseWindow), - MenuItem::Quit => Self(WryMenuItem::Quit), - MenuItem::Copy => Self(WryMenuItem::Copy), - MenuItem::Cut => Self(WryMenuItem::Cut), - MenuItem::Undo => Self(WryMenuItem::Undo), - MenuItem::Redo => Self(WryMenuItem::Redo), - MenuItem::SelectAll => Self(WryMenuItem::SelectAll), - MenuItem::Paste => Self(WryMenuItem::Paste), - MenuItem::EnterFullScreen => Self(WryMenuItem::EnterFullScreen), - MenuItem::Minimize => Self(WryMenuItem::Minimize), - MenuItem::Zoom => Self(WryMenuItem::Zoom), - MenuItem::Separator => Self(WryMenuItem::Separator), - _ => unimplemented!(), - } - } -} - -#[cfg(target_os = "macos")] -pub struct NativeImageWrapper(pub WryNativeImage); - -#[cfg(target_os = "macos")] -impl std::fmt::Debug for NativeImageWrapper { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("NativeImageWrapper").finish() - } -} - -#[cfg(target_os = "macos")] -impl From for NativeImageWrapper { - fn from(image: NativeImage) -> NativeImageWrapper { - let wry_image = match image { - NativeImage::Add => WryNativeImage::Add, - NativeImage::Advanced => WryNativeImage::Advanced, - NativeImage::Bluetooth => WryNativeImage::Bluetooth, - NativeImage::Bookmarks => WryNativeImage::Bookmarks, - NativeImage::Caution => WryNativeImage::Caution, - NativeImage::ColorPanel => WryNativeImage::ColorPanel, - NativeImage::ColumnView => WryNativeImage::ColumnView, - NativeImage::Computer => WryNativeImage::Computer, - NativeImage::EnterFullScreen => WryNativeImage::EnterFullScreen, - NativeImage::Everyone => WryNativeImage::Everyone, - NativeImage::ExitFullScreen => WryNativeImage::ExitFullScreen, - NativeImage::FlowView => WryNativeImage::FlowView, - NativeImage::Folder => WryNativeImage::Folder, - NativeImage::FolderBurnable => WryNativeImage::FolderBurnable, - NativeImage::FolderSmart => WryNativeImage::FolderSmart, - NativeImage::FollowLinkFreestanding => WryNativeImage::FollowLinkFreestanding, - NativeImage::FontPanel => WryNativeImage::FontPanel, - NativeImage::GoLeft => WryNativeImage::GoLeft, - NativeImage::GoRight => WryNativeImage::GoRight, - NativeImage::Home => WryNativeImage::Home, - NativeImage::IChatTheater => WryNativeImage::IChatTheater, - NativeImage::IconView => WryNativeImage::IconView, - NativeImage::Info => WryNativeImage::Info, - NativeImage::InvalidDataFreestanding => WryNativeImage::InvalidDataFreestanding, - NativeImage::LeftFacingTriangle => WryNativeImage::LeftFacingTriangle, - NativeImage::ListView => WryNativeImage::ListView, - NativeImage::LockLocked => WryNativeImage::LockLocked, - NativeImage::LockUnlocked => WryNativeImage::LockUnlocked, - NativeImage::MenuMixedState => WryNativeImage::MenuMixedState, - NativeImage::MenuOnState => WryNativeImage::MenuOnState, - NativeImage::MobileMe => WryNativeImage::MobileMe, - NativeImage::MultipleDocuments => WryNativeImage::MultipleDocuments, - NativeImage::Network => WryNativeImage::Network, - NativeImage::Path => WryNativeImage::Path, - NativeImage::PreferencesGeneral => WryNativeImage::PreferencesGeneral, - NativeImage::QuickLook => WryNativeImage::QuickLook, - NativeImage::RefreshFreestanding => WryNativeImage::RefreshFreestanding, - NativeImage::Refresh => WryNativeImage::Refresh, - NativeImage::Remove => WryNativeImage::Remove, - NativeImage::RevealFreestanding => WryNativeImage::RevealFreestanding, - NativeImage::RightFacingTriangle => WryNativeImage::RightFacingTriangle, - NativeImage::Share => WryNativeImage::Share, - NativeImage::Slideshow => WryNativeImage::Slideshow, - NativeImage::SmartBadge => WryNativeImage::SmartBadge, - NativeImage::StatusAvailable => WryNativeImage::StatusAvailable, - NativeImage::StatusNone => WryNativeImage::StatusNone, - NativeImage::StatusPartiallyAvailable => WryNativeImage::StatusPartiallyAvailable, - NativeImage::StatusUnavailable => WryNativeImage::StatusUnavailable, - NativeImage::StopProgressFreestanding => WryNativeImage::StopProgressFreestanding, - NativeImage::StopProgress => WryNativeImage::StopProgress, - - NativeImage::TrashEmpty => WryNativeImage::TrashEmpty, - NativeImage::TrashFull => WryNativeImage::TrashFull, - NativeImage::User => WryNativeImage::User, - NativeImage::UserAccounts => WryNativeImage::UserAccounts, - NativeImage::UserGroup => WryNativeImage::UserGroup, - NativeImage::UserGuest => WryNativeImage::UserGuest, - }; - Self(wry_image) - } -} - -#[derive(Debug, Clone)] -pub struct GlobalShortcutWrapper(GlobalShortcut); - -// SAFETY: usage outside of main thread is guarded, we use the event loop on such cases. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for GlobalShortcutWrapper {} - -/// Wrapper around [`WryShortcutManager`]. -#[derive(Clone)] -pub struct GlobalShortcutManagerHandle { - context: Context, - shortcuts: Arc>>, - listeners: GlobalShortcutListeners, -} - -// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Sync for GlobalShortcutManagerHandle {} - -impl fmt::Debug for GlobalShortcutManagerHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("GlobalShortcutManagerHandle") - .field("context", &self.context) - .field("shortcuts", &self.shortcuts) - .finish() - } -} - -impl GlobalShortcutManager for GlobalShortcutManagerHandle { - fn is_registered(&self, accelerator: &str) -> Result { - let (tx, rx) = channel(); - getter!( - self, - rx, - Message::GlobalShortcut(GlobalShortcutMessage::IsRegistered( - accelerator.parse().expect("invalid accelerator"), - tx - )) - ) - } - - fn register(&mut self, accelerator: &str, handler: F) -> Result<()> { - let wry_accelerator: Accelerator = accelerator.parse().expect("invalid accelerator"); - let id = wry_accelerator.clone().id(); - let (tx, rx) = channel(); - let shortcut = getter!( - self, - rx, - Message::GlobalShortcut(GlobalShortcutMessage::Register(wry_accelerator, tx)) - )??; - - self.listeners.lock().unwrap().insert(id, Box::new(handler)); - self - .shortcuts - .lock() - .unwrap() - .insert(accelerator.into(), (id, shortcut)); - - Ok(()) - } - - fn unregister_all(&mut self) -> Result<()> { - let (tx, rx) = channel(); - getter!( - self, - rx, - Message::GlobalShortcut(GlobalShortcutMessage::UnregisterAll(tx)) - )??; - self.listeners.lock().unwrap().clear(); - self.shortcuts.lock().unwrap().clear(); - Ok(()) - } - - fn unregister(&mut self, accelerator: &str) -> Result<()> { - if let Some((accelerator_id, shortcut)) = self.shortcuts.lock().unwrap().remove(accelerator) { - let (tx, rx) = channel(); - getter!( - self, - rx, - Message::GlobalShortcut(GlobalShortcutMessage::Unregister(shortcut, tx)) - )??; - self.listeners.lock().unwrap().remove(&accelerator_id); - } - Ok(()) - } -} - -#[derive(Debug, Clone)] -pub struct ClipboardManagerWrapper { - context: Context, -} - -// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Sync for ClipboardManagerWrapper {} - -impl ClipboardManager for ClipboardManagerWrapper { - fn read_text(&self) -> Result> { - let (tx, rx) = channel(); - getter!(self, rx, Message::Clipboard(ClipboardMessage::ReadText(tx))) - } - - fn write_text>(&mut self, text: V) -> Result<()> { - let (tx, rx) = channel(); - getter!( - self, - rx, - Message::Clipboard(ClipboardMessage::WriteText(text.into(), tx)) - )?; - Ok(()) - } -} - -/// Wrapper around a [`wry::application::window::Icon`] that can be created from an [`WindowIcon`]. -pub struct WryIcon(WryWindowIcon); - -fn icon_err(e: E) -> Error { - Error::InvalidIcon(Box::new(e)) -} - -impl TryFrom for WryIcon { - type Error = Error; - fn try_from(icon: WindowIcon) -> std::result::Result { - WryWindowIcon::from_rgba(icon.rgba, icon.width, icon.height) - .map(Self) - .map_err(icon_err) - } -} - -struct WindowEventWrapper(Option); - -impl WindowEventWrapper { - fn parse(webview: &WindowHandle, event: &WryWindowEvent<'_>) -> Self { - match event { - // resized event from tao doesn't include a reliable size on macOS - // because wry replaces the NSView - WryWindowEvent::Resized(_) => Self(Some(WindowEvent::Resized( - PhysicalSizeWrapper(webview.inner_size()).into(), - ))), - e => e.into(), - } - } -} - -impl<'a> From<&WryWindowEvent<'a>> for WindowEventWrapper { - fn from(event: &WryWindowEvent<'a>) -> Self { - let event = match event { - WryWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()), - WryWindowEvent::Moved(position) => { - WindowEvent::Moved(PhysicalPositionWrapper(*position).into()) - } - WryWindowEvent::Destroyed => WindowEvent::Destroyed, - WryWindowEvent::ScaleFactorChanged { - scale_factor, - new_inner_size, - } => WindowEvent::ScaleFactorChanged { - scale_factor: *scale_factor, - new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(), - }, - #[cfg(any(target_os = "linux", target_os = "macos"))] - WryWindowEvent::Focused(focused) => WindowEvent::Focused(*focused), - _ => return Self(None), - }; - Self(Some(event)) - } -} - -impl From<&WebviewEvent> for WindowEventWrapper { - fn from(event: &WebviewEvent) -> Self { - let event = match event { - WebviewEvent::Focused(focused) => WindowEvent::Focused(*focused), - }; - Self(Some(event)) - } -} - -pub struct MonitorHandleWrapper(MonitorHandle); - -impl From for Monitor { - fn from(monitor: MonitorHandleWrapper) -> Monitor { - Self { - name: monitor.0.name(), - position: PhysicalPositionWrapper(monitor.0.position()).into(), - size: PhysicalSizeWrapper(monitor.0.size()).into(), - scale_factor: monitor.0.scale_factor(), - } - } -} - -struct PhysicalPositionWrapper(WryPhysicalPosition); - -impl From> for PhysicalPosition { - fn from(position: PhysicalPositionWrapper) -> Self { - Self { - x: position.0.x, - y: position.0.y, - } - } -} - -impl From> for PhysicalPositionWrapper { - fn from(position: PhysicalPosition) -> Self { - Self(WryPhysicalPosition { - x: position.x, - y: position.y, - }) - } -} - -struct LogicalPositionWrapper(WryLogicalPosition); - -impl From> for LogicalPositionWrapper { - fn from(position: LogicalPosition) -> Self { - Self(WryLogicalPosition { - x: position.x, - y: position.y, - }) - } -} - -struct PhysicalSizeWrapper(WryPhysicalSize); - -impl From> for PhysicalSize { - fn from(size: PhysicalSizeWrapper) -> Self { - Self { - width: size.0.width, - height: size.0.height, - } - } -} - -impl From> for PhysicalSizeWrapper { - fn from(size: PhysicalSize) -> Self { - Self(WryPhysicalSize { - width: size.width, - height: size.height, - }) - } -} - -struct LogicalSizeWrapper(WryLogicalSize); - -impl From> for LogicalSizeWrapper { - fn from(size: LogicalSize) -> Self { - Self(WryLogicalSize { - width: size.width, - height: size.height, - }) - } -} - -struct SizeWrapper(WrySize); - -impl From for SizeWrapper { - fn from(size: Size) -> Self { - match size { - Size::Logical(s) => Self(WrySize::Logical(LogicalSizeWrapper::from(s).0)), - Size::Physical(s) => Self(WrySize::Physical(PhysicalSizeWrapper::from(s).0)), - } - } -} - -struct PositionWrapper(WryPosition); - -impl From for PositionWrapper { - fn from(position: Position) -> Self { - match position { - Position::Logical(s) => Self(WryPosition::Logical(LogicalPositionWrapper::from(s).0)), - Position::Physical(s) => Self(WryPosition::Physical(PhysicalPositionWrapper::from(s).0)), - } - } -} - -#[derive(Debug, Clone)] -pub struct UserAttentionTypeWrapper(WryUserAttentionType); - -impl From for UserAttentionTypeWrapper { - fn from(request_type: UserAttentionType) -> UserAttentionTypeWrapper { - let o = match request_type { - UserAttentionType::Critical => WryUserAttentionType::Critical, - UserAttentionType::Informational => WryUserAttentionType::Informational, - }; - Self(o) - } -} - -#[derive(Debug, Clone, Default)] -pub struct WindowBuilderWrapper { - inner: WryWindowBuilder, - center: bool, - menu: Option
, -} - -// SAFETY: this type is `Send` since `menu_items` are read only here -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for WindowBuilderWrapper {} - -impl WindowBuilderBase for WindowBuilderWrapper {} -impl WindowBuilder for WindowBuilderWrapper { - fn new() -> Self { - Default::default() - } - - fn with_config(config: WindowConfig) -> Self { - let mut window = WindowBuilderWrapper::new() - .title(config.title.to_string()) - .inner_size(config.width, config.height) - .visible(config.visible) - .resizable(config.resizable) - .fullscreen(config.fullscreen) - .decorations(config.decorations) - .maximized(config.maximized) - .always_on_top(config.always_on_top) - .skip_taskbar(config.skip_taskbar); - - #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] - { - window = window.transparent(config.transparent); - } - #[cfg(all( - target_os = "macos", - not(feature = "macos-private-api"), - debug_assertions - ))] - if config.transparent { - eprintln!( - "The window is set to be transparent but the `macos-private-api` is not enabled. - This can be enabled via the `tauri.macOSPrivateApi` configuration property - "); - } - - if let (Some(min_width), Some(min_height)) = (config.min_width, config.min_height) { - window = window.min_inner_size(min_width, min_height); - } - if let (Some(max_width), Some(max_height)) = (config.max_width, config.max_height) { - window = window.max_inner_size(max_width, max_height); - } - if let (Some(x), Some(y)) = (config.x, config.y) { - window = window.position(x, y); - } - - if config.center { - window = window.center(); - } - - window - } - - fn menu(mut self, menu: Menu) -> Self { - self.menu.replace(menu); - self - } - - fn center(mut self) -> Self { - self.center = true; - self - } - - fn position(mut self, x: f64, y: f64) -> Self { - self.inner = self.inner.with_position(WryLogicalPosition::new(x, y)); - self - } - - fn inner_size(mut self, width: f64, height: f64) -> Self { - self.inner = self - .inner - .with_inner_size(WryLogicalSize::new(width, height)); - self - } - - fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { - self.inner = self - .inner - .with_min_inner_size(WryLogicalSize::new(min_width, min_height)); - self - } - - fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { - self.inner = self - .inner - .with_max_inner_size(WryLogicalSize::new(max_width, max_height)); - self - } - - fn resizable(mut self, resizable: bool) -> Self { - self.inner = self.inner.with_resizable(resizable); - self - } - - fn title>(mut self, title: S) -> Self { - self.inner = self.inner.with_title(title.into()); - self - } - - fn fullscreen(mut self, fullscreen: bool) -> Self { - self.inner = if fullscreen { - self - .inner - .with_fullscreen(Some(Fullscreen::Borderless(None))) - } else { - self.inner.with_fullscreen(None) - }; - self - } - - /// Deprecated since 0.1.4 (noop) - /// Windows is automatically focused when created. - fn focus(self) -> Self { - self - } - - fn maximized(mut self, maximized: bool) -> Self { - self.inner = self.inner.with_maximized(maximized); - self - } - - fn visible(mut self, visible: bool) -> Self { - self.inner = self.inner.with_visible(visible); - self - } - - #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] - fn transparent(mut self, transparent: bool) -> Self { - self.inner = self.inner.with_transparent(transparent); - self - } - - fn decorations(mut self, decorations: bool) -> Self { - self.inner = self.inner.with_decorations(decorations); - self - } - - fn always_on_top(mut self, always_on_top: bool) -> Self { - self.inner = self.inner.with_always_on_top(always_on_top); - self - } - - #[cfg(windows)] - fn parent_window(mut self, parent: HWND) -> Self { - self.inner = self.inner.with_parent_window(parent); - self - } - - #[cfg(windows)] - fn owner_window(mut self, owner: HWND) -> Self { - self.inner = self.inner.with_owner_window(owner); - self - } - - fn icon(mut self, icon: WindowIcon) -> Result { - self.inner = self - .inner - .with_window_icon(Some(WryIcon::try_from(icon)?.0)); - Ok(self) - } - - #[cfg(any(windows, target_os = "linux"))] - fn skip_taskbar(mut self, skip: bool) -> Self { - self.inner = self.inner.with_skip_taskbar(skip); - self - } - - #[cfg(target_os = "macos")] - fn skip_taskbar(self, _skip: bool) -> Self { - self - } - - fn has_icon(&self) -> bool { - self.inner.window.window_icon.is_some() - } - - fn get_menu(&self) -> Option<&Menu> { - self.menu.as_ref() - } -} - -pub struct FileDropEventWrapper(WryFileDropEvent); - -impl From for FileDropEvent { - fn from(event: FileDropEventWrapper) -> Self { - match event.0 { - WryFileDropEvent::Hovered(paths) => FileDropEvent::Hovered(paths), - WryFileDropEvent::Dropped(paths) => FileDropEvent::Dropped(paths), - // default to cancelled - // FIXME(maybe): Add `FileDropEvent::Unknown` event? - _ => FileDropEvent::Cancelled, - } - } -} - -#[cfg(target_os = "macos")] -pub struct NSWindow(*mut std::ffi::c_void); -#[cfg(target_os = "macos")] -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for NSWindow {} - -#[cfg(windows)] -pub struct Hwnd(HWND); -#[cfg(windows)] -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for Hwnd {} - -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -pub struct GtkWindow(gtk::ApplicationWindow); -#[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" -))] -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Send for GtkWindow {} - -#[derive(Debug, Clone)] -pub enum WindowMessage { - #[cfg(any(debug_assertions, feature = "devtools"))] - OpenDevTools, - // Getters - ScaleFactor(Sender), - InnerPosition(Sender>>), - OuterPosition(Sender>>), - InnerSize(Sender>), - OuterSize(Sender>), - IsFullscreen(Sender), - IsMaximized(Sender), - IsDecorated(Sender), - IsResizable(Sender), - IsVisible(Sender), - IsMenuVisible(Sender), - CurrentMonitor(Sender>), - PrimaryMonitor(Sender>), - AvailableMonitors(Sender>), - #[cfg(target_os = "macos")] - NSWindow(Sender), - #[cfg(windows)] - Hwnd(Sender), - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - GtkWindow(Sender), - // Setters - Center(Sender>), - RequestUserAttention(Option), - SetResizable(bool), - SetTitle(String), - Maximize, - Unmaximize, - Minimize, - Unminimize, - ShowMenu, - HideMenu, - Show, - Hide, - Close, - SetDecorations(bool), - SetAlwaysOnTop(bool), - SetSize(Size), - SetMinSize(Option), - SetMaxSize(Option), - SetPosition(Position), - SetFullscreen(bool), - SetFocus, - SetIcon(WryWindowIcon), - SetSkipTaskbar(bool), - DragWindow, - UpdateMenuItem(u16, MenuUpdate), - RequestRedraw, -} - -#[derive(Debug, Clone)] -pub enum WebviewMessage { - EvaluateScript(String), - #[allow(dead_code)] - WebviewEvent(WebviewEvent), - Print, -} - -#[allow(dead_code)] -#[derive(Debug, Clone)] -pub enum WebviewEvent { - Focused(bool), -} - -#[cfg(feature = "system-tray")] -#[derive(Debug, Clone)] -pub enum TrayMessage { - UpdateItem(u16, MenuUpdate), - UpdateMenu(SystemTrayMenu), - UpdateIcon(TrayIcon), - #[cfg(target_os = "macos")] - UpdateIconAsTemplate(bool), - Close, -} - -#[derive(Debug, Clone)] -pub enum GlobalShortcutMessage { - IsRegistered(Accelerator, Sender), - Register(Accelerator, Sender>), - Unregister(GlobalShortcutWrapper, Sender>), - UnregisterAll(Sender>), -} - -#[derive(Debug, Clone)] -pub enum ClipboardMessage { - WriteText(String, Sender<()>), - ReadText(Sender>), -} - -pub type CreateWebviewClosure = Box< - dyn FnOnce(&EventLoopWindowTarget>, &WebContextStore) -> Result + Send, ->; - -pub enum Message { - Task(Box), - Window(WebviewId, WindowMessage), - Webview(WebviewId, WebviewMessage), - #[cfg(feature = "system-tray")] - Tray(TrayMessage), - CreateWebview(WebviewId, CreateWebviewClosure), - CreateWindow( - WebviewId, - Box (String, WryWindowBuilder) + Send>, - Sender>>, - ), - GlobalShortcut(GlobalShortcutMessage), - Clipboard(ClipboardMessage), - UserEvent(T), -} - -impl Clone for Message { - fn clone(&self) -> Self { - match self { - Self::Window(i, m) => Self::Window(*i, m.clone()), - Self::Webview(i, m) => Self::Webview(*i, m.clone()), - #[cfg(feature = "system-tray")] - Self::Tray(m) => Self::Tray(m.clone()), - Self::GlobalShortcut(m) => Self::GlobalShortcut(m.clone()), - Self::Clipboard(m) => Self::Clipboard(m.clone()), - Self::UserEvent(t) => Self::UserEvent(t.clone()), - _ => unimplemented!(), - } - } -} - -/// The Tauri [`Dispatch`] for [`Wry`]. -#[derive(Debug, Clone)] -pub struct WryDispatcher { - window_id: WebviewId, - context: Context, -} - -// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Sync for WryDispatcher {} - -impl Dispatch for WryDispatcher { - type Runtime = Wry; - type WindowBuilder = WindowBuilderWrapper; - - fn run_on_main_thread(&self, f: F) -> Result<()> { - send_user_message(&self.context, Message::Task(Box::new(f))) - } - - fn on_window_event(&self, f: F) -> Uuid { - let id = Uuid::new_v4(); - self - .context - .window_event_listeners - .lock() - .unwrap() - .get(&self.window_id) - .unwrap() - .lock() - .unwrap() - .insert(id, Box::new(f)); - id - } - - fn on_menu_event(&self, f: F) -> Uuid { - let id = Uuid::new_v4(); - self - .context - .menu_event_listeners - .lock() - .unwrap() - .get(&self.window_id) - .unwrap() - .lock() - .unwrap() - .insert(id, Box::new(f)); - id - } - - #[cfg(any(debug_assertions, feature = "devtools"))] - fn open_devtools(&self) { - let _ = send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::OpenDevTools), - ); - } - - // Getters - - fn scale_factor(&self) -> Result { - window_getter!(self, WindowMessage::ScaleFactor) - } - - fn inner_position(&self) -> Result> { - window_getter!(self, WindowMessage::InnerPosition)? - } - - fn outer_position(&self) -> Result> { - window_getter!(self, WindowMessage::OuterPosition)? - } - - fn inner_size(&self) -> Result> { - window_getter!(self, WindowMessage::InnerSize) - } - - fn outer_size(&self) -> Result> { - window_getter!(self, WindowMessage::OuterSize) - } - - fn is_fullscreen(&self) -> Result { - window_getter!(self, WindowMessage::IsFullscreen) - } - - fn is_maximized(&self) -> Result { - window_getter!(self, WindowMessage::IsMaximized) - } - - /// Gets the window’s current decoration state. - fn is_decorated(&self) -> Result { - window_getter!(self, WindowMessage::IsDecorated) - } - - /// Gets the window’s current resizable state. - fn is_resizable(&self) -> Result { - window_getter!(self, WindowMessage::IsResizable) - } - - fn is_visible(&self) -> Result { - window_getter!(self, WindowMessage::IsVisible) - } - - fn is_menu_visible(&self) -> Result { - window_getter!(self, WindowMessage::IsMenuVisible) - } - - fn current_monitor(&self) -> Result> { - Ok(window_getter!(self, WindowMessage::CurrentMonitor)?.map(|m| MonitorHandleWrapper(m).into())) - } - - fn primary_monitor(&self) -> Result> { - Ok(window_getter!(self, WindowMessage::PrimaryMonitor)?.map(|m| MonitorHandleWrapper(m).into())) - } - - fn available_monitors(&self) -> Result> { - Ok( - window_getter!(self, WindowMessage::AvailableMonitors)? - .into_iter() - .map(|m| MonitorHandleWrapper(m).into()) - .collect(), - ) - } - - #[cfg(target_os = "macos")] - fn ns_window(&self) -> Result<*mut std::ffi::c_void> { - window_getter!(self, WindowMessage::NSWindow).map(|w| w.0) - } - - #[cfg(windows)] - fn hwnd(&self) -> Result { - window_getter!(self, WindowMessage::Hwnd).map(|w| w.0) - } - - /// Returns the `ApplicatonWindow` from gtk crate that is used by this window. - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - fn gtk_window(&self) -> Result { - window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0) - } - - // Setters - - fn center(&self) -> Result<()> { - window_getter!(self, WindowMessage::Center)? - } - - fn print(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Webview(self.window_id, WebviewMessage::Print), - ) - } - - fn request_user_attention(&self, request_type: Option) -> Result<()> { - send_user_message( - &self.context, - Message::Window( - self.window_id, - WindowMessage::RequestUserAttention(request_type.map(Into::into)), - ), - ) - } - - // Creates a window by dispatching a message to the event loop. - // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. - fn create_window( - &mut self, - pending: PendingWindow, - ) -> Result> { - self.context.create_webview(pending) - } - - fn set_resizable(&self, resizable: bool) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetResizable(resizable)), - ) - } - - fn set_title>(&self, title: S) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetTitle(title.into())), - ) - } - - fn maximize(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Maximize), - ) - } - - fn unmaximize(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Unmaximize), - ) - } - - fn minimize(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Minimize), - ) - } - - fn unminimize(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Unminimize), - ) - } - - fn show_menu(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::ShowMenu), - ) - } - - fn hide_menu(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::HideMenu), - ) - } - - fn show(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Show), - ) - } - - fn hide(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::Hide), - ) - } - - fn close(&self) -> Result<()> { - // NOTE: close cannot use the `send_user_message` function because it accesses the event loop callback - self - .context - .proxy - .send_event(Message::Window(self.window_id, WindowMessage::Close)) - .map_err(|_| Error::FailedToSendMessage) - } - - fn set_decorations(&self, decorations: bool) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetDecorations(decorations)), - ) - } - - fn set_always_on_top(&self, always_on_top: bool) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetAlwaysOnTop(always_on_top)), - ) - } - - fn set_size(&self, size: Size) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetSize(size)), - ) - } - - fn set_min_size(&self, size: Option) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetMinSize(size)), - ) - } - - fn set_max_size(&self, size: Option) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetMaxSize(size)), - ) - } - - fn set_position(&self, position: Position) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetPosition(position)), - ) - } - - fn set_fullscreen(&self, fullscreen: bool) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetFullscreen(fullscreen)), - ) - } - - fn set_focus(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetFocus), - ) - } - - fn set_icon(&self, icon: WindowIcon) -> Result<()> { - send_user_message( - &self.context, - Message::Window( - self.window_id, - WindowMessage::SetIcon(WryIcon::try_from(icon)?.0), - ), - ) - } - - fn set_skip_taskbar(&self, skip: bool) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::SetSkipTaskbar(skip)), - ) - } - - fn start_dragging(&self) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::DragWindow), - ) - } - - fn eval_script>(&self, script: S) -> Result<()> { - send_user_message( - &self.context, - Message::Webview( - self.window_id, - WebviewMessage::EvaluateScript(script.into()), - ), - ) - } - - fn update_menu_item(&self, id: u16, update: MenuUpdate) -> Result<()> { - send_user_message( - &self.context, - Message::Window(self.window_id, WindowMessage::UpdateMenuItem(id, update)), - ) - } -} - -#[cfg(feature = "system-tray")] -#[derive(Clone, Default)] -struct TrayContext { - tray: Arc>>>>, - listeners: SystemTrayEventListeners, - items: SystemTrayItems, -} - -#[cfg(feature = "system-tray")] -impl fmt::Debug for TrayContext { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("TrayContext") - .field("items", &self.items) - .finish() - } -} - -enum WindowHandle { - Webview(WebView), - Window(Arc), -} - -impl fmt::Debug for WindowHandle { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -impl WindowHandle { - fn window(&self) -> &Window { - match self { - Self::Webview(w) => w.window(), - Self::Window(w) => w, - } - } - - fn inner_size(&self) -> WryPhysicalSize { - match self { - WindowHandle::Window(w) => w.inner_size(), - WindowHandle::Webview(w) => w.inner_size(), - } - } -} - -#[derive(Debug)] -pub struct WindowWrapper { - label: String, - inner: WindowHandle, - menu_items: Option>, -} - -#[derive(Debug, Clone)] -pub struct EventProxy(WryEventLoopProxy>); - -impl EventLoopProxy for EventProxy { - fn send_event(&self, event: T) -> Result<()> { - self - .0 - .send_event(Message::UserEvent(event)) - .map_err(|_| Error::EventLoopClosed) - } -} - -/// A Tauri [`Runtime`] wrapper around wry. -pub struct Wry { - main_thread_id: ThreadId, - global_shortcut_manager: Arc>, - global_shortcut_manager_handle: GlobalShortcutManagerHandle, - clipboard_manager: Arc>, - clipboard_manager_handle: ClipboardManagerWrapper, - event_loop: EventLoop>, - windows: Arc>>, - webview_id_map: WebviewIdStore, - web_context: WebContextStore, - window_event_listeners: WindowEventListeners, - menu_event_listeners: MenuEventListeners, - #[cfg(feature = "system-tray")] - tray_context: TrayContext, -} - -impl fmt::Debug for Wry { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut d = f.debug_struct("Wry"); - d.field("main_thread_id", &self.main_thread_id) - .field("global_shortcut_manager", &self.global_shortcut_manager) - .field( - "global_shortcut_manager_handle", - &self.global_shortcut_manager_handle, - ) - .field("clipboard_manager", &self.clipboard_manager) - .field("clipboard_manager_handle", &self.clipboard_manager_handle) - .field("event_loop", &self.event_loop) - .field("windows", &self.windows) - .field("web_context", &self.web_context); - #[cfg(feature = "system-tray")] - d.field("tray_context", &self.tray_context); - d.finish() - } -} - -/// A handle to the Wry runtime. -#[derive(Debug, Clone)] -pub struct WryHandle { - context: Context, -} - -// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. -#[allow(clippy::non_send_fields_in_send_ty)] -unsafe impl Sync for WryHandle {} - -impl WryHandle { - /// Creates a new tao window using a callback, and returns its window id. - pub fn create_tao_window (String, WryWindowBuilder) + Send + 'static>( - &self, - f: F, - ) -> Result> { - let (tx, rx) = channel(); - send_user_message( - &self.context, - Message::CreateWindow(rand::random(), Box::new(f), tx), - )?; - rx.recv().unwrap() - } - - /// Gets the [`WebviewId'] associated with the given [`WindowId`]. - pub fn window_id(&self, window_id: WindowId) -> WebviewId { - *self - .context - .webview_id_map - .0 - .lock() - .unwrap() - .get(&window_id) - .unwrap() - } - - /// Send a message to the event loop. - pub fn send_event(&self, message: Message) -> Result<()> { - self - .context - .proxy - .send_event(message) - .map_err(|_| Error::FailedToSendMessage)?; - Ok(()) - } -} - -impl RuntimeHandle for WryHandle { - type Runtime = Wry; - - fn create_proxy(&self) -> EventProxy { - EventProxy(self.context.proxy.clone()) - } - - // Creates a window by dispatching a message to the event loop. - // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. - fn create_window( - &self, - pending: PendingWindow, - ) -> Result> { - self.context.create_webview(pending) - } - - fn run_on_main_thread(&self, f: F) -> Result<()> { - send_user_message(&self.context, Message::Task(Box::new(f))) - } - - #[cfg(all(windows, feature = "system-tray"))] - /// Deprecated. (not needed anymore) - fn remove_system_tray(&self) -> Result<()> { - send_user_message(&self.context, Message::Tray(TrayMessage::Close)) - } -} - -impl Wry { - fn init(event_loop: EventLoop>) -> Result { - let proxy = event_loop.create_proxy(); - let main_thread_id = current_thread().id(); - let web_context = WebContextStore::default(); - let global_shortcut_manager = Arc::new(Mutex::new(WryShortcutManager::new(&event_loop))); - let clipboard_manager = Arc::new(Mutex::new(Clipboard::new())); - let windows = Arc::new(Mutex::new(HashMap::default())); - let webview_id_map = WebviewIdStore::default(); - let window_event_listeners = WindowEventListeners::default(); - let menu_event_listeners = MenuEventListeners::default(); - - #[cfg(feature = "system-tray")] - let tray_context = TrayContext::default(); - - let event_loop_context = Context { - webview_id_map: webview_id_map.clone(), - main_thread_id, - proxy, - window_event_listeners: window_event_listeners.clone(), - menu_event_listeners: menu_event_listeners.clone(), - main_thread: DispatcherMainThreadContext { - window_target: event_loop.deref().clone(), - web_context: web_context.clone(), - global_shortcut_manager: global_shortcut_manager.clone(), - clipboard_manager: clipboard_manager.clone(), - windows: windows.clone(), - #[cfg(feature = "system-tray")] - tray_context: tray_context.clone(), - }, - }; - - let global_shortcut_listeners = GlobalShortcutListeners::default(); - let clipboard_manager_handle = ClipboardManagerWrapper { - context: event_loop_context.clone(), - }; - - Ok(Self { - main_thread_id, - global_shortcut_manager, - global_shortcut_manager_handle: GlobalShortcutManagerHandle { - context: event_loop_context, - shortcuts: Default::default(), - listeners: global_shortcut_listeners, - }, - clipboard_manager, - clipboard_manager_handle, - event_loop, - windows, - webview_id_map, - web_context, - window_event_listeners, - menu_event_listeners, - #[cfg(feature = "system-tray")] - tray_context, - }) - } -} - -impl Runtime for Wry { - type Dispatcher = WryDispatcher; - type Handle = WryHandle; - type GlobalShortcutManager = GlobalShortcutManagerHandle; - type ClipboardManager = ClipboardManagerWrapper; - #[cfg(feature = "system-tray")] - type TrayHandler = SystemTrayHandle; - type EventLoopProxy = EventProxy; - - fn new() -> Result { - let event_loop = EventLoop::>::with_user_event(); - Self::init(event_loop) - } - - #[cfg(any(windows, target_os = "linux"))] - fn new_any_thread() -> Result { - #[cfg(target_os = "linux")] - use wry::application::platform::unix::EventLoopExtUnix; - #[cfg(windows)] - use wry::application::platform::windows::EventLoopExtWindows; - let event_loop = EventLoop::>::new_any_thread(); - Self::init(event_loop) - } - - fn create_proxy(&self) -> EventProxy { - EventProxy(self.event_loop.create_proxy()) - } - - fn handle(&self) -> Self::Handle { - WryHandle { - context: Context { - webview_id_map: self.webview_id_map.clone(), - main_thread_id: self.main_thread_id, - proxy: self.event_loop.create_proxy(), - window_event_listeners: self.window_event_listeners.clone(), - menu_event_listeners: self.menu_event_listeners.clone(), - main_thread: DispatcherMainThreadContext { - window_target: self.event_loop.deref().clone(), - web_context: self.web_context.clone(), - global_shortcut_manager: self.global_shortcut_manager.clone(), - clipboard_manager: self.clipboard_manager.clone(), - windows: self.windows.clone(), - #[cfg(feature = "system-tray")] - tray_context: self.tray_context.clone(), - }, - }, - } - } - - fn global_shortcut_manager(&self) -> Self::GlobalShortcutManager { - self.global_shortcut_manager_handle.clone() - } - - fn clipboard_manager(&self) -> Self::ClipboardManager { - self.clipboard_manager_handle.clone() - } - - fn create_window(&self, pending: PendingWindow) -> Result> { - let label = pending.label.clone(); - let menu_ids = pending.menu_ids.clone(); - let js_event_listeners = pending.js_event_listeners.clone(); - let proxy = self.event_loop.create_proxy(); - let window_id = rand::random(); - - let context = Context { - webview_id_map: self.webview_id_map.clone(), - main_thread_id: self.main_thread_id, - proxy, - window_event_listeners: self.window_event_listeners.clone(), - menu_event_listeners: self.menu_event_listeners.clone(), - main_thread: DispatcherMainThreadContext { - window_target: self.event_loop.deref().clone(), - web_context: self.web_context.clone(), - global_shortcut_manager: self.global_shortcut_manager.clone(), - clipboard_manager: self.clipboard_manager.clone(), - windows: self.windows.clone(), - #[cfg(feature = "system-tray")] - tray_context: self.tray_context.clone(), - }, - }; - - context.prepare_window(window_id); - - let webview = create_webview( - window_id, - &self.event_loop, - &self.web_context, - context.clone(), - pending, - )?; - - let dispatcher = WryDispatcher { window_id, context }; - - self.windows.lock().unwrap().insert(window_id, webview); - - Ok(DetachedWindow { - label, - dispatcher, - menu_ids, - js_event_listeners, - }) - } - - #[cfg(feature = "system-tray")] - fn system_tray(&self, system_tray: SystemTray) -> Result { - let icon = system_tray - .icon - .expect("tray icon not set") - .into_platform_icon(); - - let mut items = HashMap::new(); - - #[cfg(target_os = "macos")] - let tray = SystemTrayBuilder::new( - icon, - system_tray - .menu - .map(|menu| to_wry_context_menu(&mut items, menu)), - ) - .with_icon_as_template(system_tray.icon_as_template) - .build(&self.event_loop) - .map_err(|e| Error::SystemTray(Box::new(e)))?; - - #[cfg(not(target_os = "macos"))] - let tray = SystemTrayBuilder::new( - icon, - system_tray - .menu - .map(|menu| to_wry_context_menu(&mut items, menu)), - ) - .build(&self.event_loop) - .map_err(|e| Error::SystemTray(Box::new(e)))?; - - *self.tray_context.items.lock().unwrap() = items; - *self.tray_context.tray.lock().unwrap() = Some(Arc::new(Mutex::new(tray))); - - Ok(SystemTrayHandle { - proxy: self.event_loop.create_proxy(), - }) - } - - #[cfg(feature = "system-tray")] - fn on_system_tray_event(&mut self, f: F) -> Uuid { - let id = Uuid::new_v4(); - self - .tray_context - .listeners - .lock() - .unwrap() - .insert(id, Box::new(f)); - id - } - - #[cfg(target_os = "macos")] - fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) { - self - .event_loop - .set_activation_policy(match activation_policy { - ActivationPolicy::Regular => WryActivationPolicy::Regular, - ActivationPolicy::Accessory => WryActivationPolicy::Accessory, - ActivationPolicy::Prohibited => WryActivationPolicy::Prohibited, - _ => unimplemented!(), - }); - } - - fn run_iteration) + 'static>(&mut self, mut callback: F) -> RunIteration { - use wry::application::platform::run_return::EventLoopExtRunReturn; - let windows = self.windows.clone(); - let webview_id_map = self.webview_id_map.clone(); - let web_context = &self.web_context; - let window_event_listeners = self.window_event_listeners.clone(); - let menu_event_listeners = self.menu_event_listeners.clone(); - #[cfg(feature = "system-tray")] - let tray_context = self.tray_context.clone(); - let global_shortcut_manager = self.global_shortcut_manager.clone(); - let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone(); - let clipboard_manager = self.clipboard_manager.clone(); - let mut iteration = RunIteration::default(); - - self - .event_loop - .run_return(|event, event_loop, control_flow| { - *control_flow = ControlFlow::Wait; - if let Event::MainEventsCleared = &event { - *control_flow = ControlFlow::Exit; - } - - iteration = handle_event_loop( - event, - event_loop, - control_flow, - EventLoopIterationContext { - callback: &mut callback, - windows: windows.clone(), - webview_id_map: webview_id_map.clone(), - window_event_listeners: &window_event_listeners, - global_shortcut_manager: global_shortcut_manager.clone(), - global_shortcut_manager_handle: &global_shortcut_manager_handle, - clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, - #[cfg(feature = "system-tray")] - tray_context: &tray_context, - }, - web_context, - ); - }); - - iteration - } - - fn run) + 'static>(self, mut callback: F) { - let windows = self.windows.clone(); - let webview_id_map = self.webview_id_map.clone(); - let web_context = self.web_context; - let window_event_listeners = self.window_event_listeners.clone(); - let menu_event_listeners = self.menu_event_listeners.clone(); - #[cfg(feature = "system-tray")] - let tray_context = self.tray_context; - let global_shortcut_manager = self.global_shortcut_manager.clone(); - let global_shortcut_manager_handle = self.global_shortcut_manager_handle.clone(); - let clipboard_manager = self.clipboard_manager.clone(); - - self.event_loop.run(move |event, event_loop, control_flow| { - handle_event_loop( - event, - event_loop, - control_flow, - EventLoopIterationContext { - callback: &mut callback, - webview_id_map: webview_id_map.clone(), - windows: windows.clone(), - window_event_listeners: &window_event_listeners, - global_shortcut_manager: global_shortcut_manager.clone(), - global_shortcut_manager_handle: &global_shortcut_manager_handle, - clipboard_manager: clipboard_manager.clone(), - menu_event_listeners: &menu_event_listeners, - #[cfg(feature = "system-tray")] - tray_context: &tray_context, - }, - &web_context, - ); - }) - } -} - -pub struct EventLoopIterationContext<'a, T: UserEvent> { - callback: &'a mut (dyn FnMut(RunEvent) + 'static), - webview_id_map: WebviewIdStore, - windows: Arc>>, - window_event_listeners: &'a WindowEventListeners, - global_shortcut_manager: Arc>, - global_shortcut_manager_handle: &'a GlobalShortcutManagerHandle, - clipboard_manager: Arc>, - menu_event_listeners: &'a MenuEventListeners, - #[cfg(feature = "system-tray")] - tray_context: &'a TrayContext, -} - -struct UserMessageContext<'a> { - window_event_listeners: &'a WindowEventListeners, - global_shortcut_manager: Arc>, - clipboard_manager: Arc>, - menu_event_listeners: &'a MenuEventListeners, - windows: Arc>>, - #[cfg(feature = "system-tray")] - tray_context: &'a TrayContext, -} - -fn handle_user_message( - event_loop: &EventLoopWindowTarget>, - message: Message, - context: UserMessageContext<'_>, - web_context: &WebContextStore, -) -> RunIteration { - let UserMessageContext { - window_event_listeners, - menu_event_listeners, - global_shortcut_manager, - clipboard_manager, - windows, - #[cfg(feature = "system-tray")] - tray_context, - } = context; - match message { - Message::Task(task) => task(), - Message::Window(id, window_message) => { - if let Some(webview) = windows - .lock() - .expect("poisoned webview collection") - .get_mut(&id) - { - let window = webview.inner.window(); - match window_message { - #[cfg(any(debug_assertions, feature = "devtools"))] - WindowMessage::OpenDevTools => { - if let WindowHandle::Webview(w) = &webview.inner { - w.devtool(); - } - } - // Getters - WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(), - WindowMessage::InnerPosition(tx) => tx - .send( - window - .inner_position() - .map(|p| PhysicalPositionWrapper(p).into()) - .map_err(|_| Error::FailedToSendMessage), - ) - .unwrap(), - WindowMessage::OuterPosition(tx) => tx - .send( - window - .outer_position() - .map(|p| PhysicalPositionWrapper(p).into()) - .map_err(|_| Error::FailedToSendMessage), - ) - .unwrap(), - WindowMessage::InnerSize(tx) => tx - .send(PhysicalSizeWrapper(webview.inner.inner_size()).into()) - .unwrap(), - WindowMessage::OuterSize(tx) => tx - .send(PhysicalSizeWrapper(window.outer_size()).into()) - .unwrap(), - WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(), - WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(), - WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(), - WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(), - WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(), - WindowMessage::IsMenuVisible(tx) => tx.send(window.is_menu_visible()).unwrap(), - WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(), - WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(), - WindowMessage::AvailableMonitors(tx) => { - tx.send(window.available_monitors().collect()).unwrap() - } - #[cfg(target_os = "macos")] - WindowMessage::NSWindow(tx) => tx.send(NSWindow(window.ns_window())).unwrap(), - #[cfg(windows)] - WindowMessage::Hwnd(tx) => tx.send(Hwnd(HWND(window.hwnd() as _))).unwrap(), - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(), - // Setters - WindowMessage::Center(tx) => { - tx.send(center_window(window, webview.inner.inner_size())) - .unwrap(); - } - WindowMessage::RequestUserAttention(request_type) => { - window.request_user_attention(request_type.map(|r| r.0)); - } - WindowMessage::SetResizable(resizable) => window.set_resizable(resizable), - WindowMessage::SetTitle(title) => window.set_title(&title), - WindowMessage::Maximize => window.set_maximized(true), - WindowMessage::Unmaximize => window.set_maximized(false), - WindowMessage::Minimize => window.set_minimized(true), - WindowMessage::Unminimize => window.set_minimized(false), - WindowMessage::ShowMenu => window.show_menu(), - WindowMessage::HideMenu => window.hide_menu(), - WindowMessage::Show => window.set_visible(true), - WindowMessage::Hide => window.set_visible(false), - WindowMessage::Close => panic!("cannot handle `WindowMessage::Close` on the main thread"), - WindowMessage::SetDecorations(decorations) => window.set_decorations(decorations), - WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top), - WindowMessage::SetSize(size) => { - window.set_inner_size(SizeWrapper::from(size).0); - } - WindowMessage::SetMinSize(size) => { - window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0)); - } - WindowMessage::SetMaxSize(size) => { - window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0)); - } - WindowMessage::SetPosition(position) => { - window.set_outer_position(PositionWrapper::from(position).0) - } - WindowMessage::SetFullscreen(fullscreen) => { - if fullscreen { - window.set_fullscreen(Some(Fullscreen::Borderless(None))) - } else { - window.set_fullscreen(None) - } - } - WindowMessage::SetFocus => { - window.set_focus(); - } - WindowMessage::SetIcon(icon) => { - window.set_window_icon(Some(icon)); - } - WindowMessage::SetSkipTaskbar(_skip) => { - #[cfg(any(windows, target_os = "linux"))] - window.set_skip_taskbar(_skip); - } - WindowMessage::DragWindow => { - let _ = window.drag_window(); - } - WindowMessage::UpdateMenuItem(id, update) => { - if let Some(menu_items) = webview.menu_items.as_mut() { - let item = menu_items.get_mut(&id).expect("menu item not found"); - match update { - MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled), - MenuUpdate::SetTitle(title) => item.set_title(&title), - MenuUpdate::SetSelected(selected) => item.set_selected(selected), - #[cfg(target_os = "macos")] - MenuUpdate::SetNativeImage(image) => { - item.set_native_image(NativeImageWrapper::from(image).0) - } - } - } - } - WindowMessage::RequestRedraw => { - window.request_redraw(); - } - } - } - } - Message::Webview(id, webview_message) => match webview_message { - WebviewMessage::EvaluateScript(script) => { - if let Some(WindowHandle::Webview(webview)) = windows - .lock() - .expect("poisoned webview collection") - .get(&id) - .map(|w| &w.inner) - { - if let Err(e) = webview.evaluate_script(&script) { - #[cfg(debug_assertions)] - eprintln!("{}", e); - } - } - } - WebviewMessage::Print => { - if let Some(WindowHandle::Webview(webview)) = windows - .lock() - .expect("poisoned webview collection") - .get(&id) - .map(|w| &w.inner) - { - let _ = webview.print(); - } - } - WebviewMessage::WebviewEvent(event) => { - if let Some(event) = WindowEventWrapper::from(&event).0 { - for handler in window_event_listeners - .lock() - .unwrap() - .get(&id) - .unwrap() - .lock() - .unwrap() - .values() - { - handler(&event); - } - } - } - }, - Message::CreateWebview(window_id, handler) => match handler(event_loop, web_context) { - Ok(webview) => { - windows - .lock() - .expect("poisoned webview collection") - .insert(window_id, webview); - } - Err(e) => { - #[cfg(debug_assertions)] - eprintln!("{}", e); - } - }, - Message::CreateWindow(window_id, handler, sender) => { - let (label, builder) = handler(); - if let Ok(window) = builder.build(event_loop) { - window_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowEventListenersMap::default()); - - menu_event_listeners - .lock() - .unwrap() - .insert(window_id, WindowMenuEventListeners::default()); - - let w = Arc::new(window); - - windows.lock().expect("poisoned webview collection").insert( - window_id, - WindowWrapper { - label, - inner: WindowHandle::Window(w.clone()), - menu_items: Default::default(), - }, - ); - sender.send(Ok(Arc::downgrade(&w))).unwrap(); - } else { - sender.send(Err(Error::CreateWindow)).unwrap(); - } - } - - #[cfg(feature = "system-tray")] - Message::Tray(tray_message) => match tray_message { - TrayMessage::UpdateItem(menu_id, update) => { - let mut tray = tray_context.items.as_ref().lock().unwrap(); - let item = tray.get_mut(&menu_id).expect("menu item not found"); - match update { - MenuUpdate::SetEnabled(enabled) => item.set_enabled(enabled), - MenuUpdate::SetTitle(title) => item.set_title(&title), - MenuUpdate::SetSelected(selected) => item.set_selected(selected), - #[cfg(target_os = "macos")] - MenuUpdate::SetNativeImage(image) => { - item.set_native_image(NativeImageWrapper::from(image).0) - } - } - } - TrayMessage::UpdateMenu(menu) => { - if let Some(tray) = &*tray_context.tray.lock().unwrap() { - let mut items = HashMap::new(); - tray - .lock() - .unwrap() - .set_menu(&to_wry_context_menu(&mut items, menu)); - *tray_context.items.lock().unwrap() = items; - } - } - TrayMessage::UpdateIcon(icon) => { - if let Some(tray) = &*tray_context.tray.lock().unwrap() { - tray.lock().unwrap().set_icon(icon.into_platform_icon()); - } - } - #[cfg(target_os = "macos")] - TrayMessage::UpdateIconAsTemplate(is_template) => { - if let Some(tray) = &*tray_context.tray.lock().unwrap() { - tray.lock().unwrap().set_icon_as_template(is_template); - } - } - TrayMessage::Close => { - *tray_context.tray.lock().unwrap() = None; - tray_context.listeners.lock().unwrap().clear(); - tray_context.items.lock().unwrap().clear(); - } - }, - Message::GlobalShortcut(message) => match message { - GlobalShortcutMessage::IsRegistered(accelerator, tx) => tx - .send( - global_shortcut_manager - .lock() - .unwrap() - .is_registered(&accelerator), - ) - .unwrap(), - GlobalShortcutMessage::Register(accelerator, tx) => tx - .send( - global_shortcut_manager - .lock() - .unwrap() - .register(accelerator) - .map(GlobalShortcutWrapper) - .map_err(|e| Error::GlobalShortcut(Box::new(e))), - ) - .unwrap(), - GlobalShortcutMessage::Unregister(shortcut, tx) => tx - .send( - global_shortcut_manager - .lock() - .unwrap() - .unregister(shortcut.0) - .map_err(|e| Error::GlobalShortcut(Box::new(e))), - ) - .unwrap(), - GlobalShortcutMessage::UnregisterAll(tx) => tx - .send( - global_shortcut_manager - .lock() - .unwrap() - .unregister_all() - .map_err(|e| Error::GlobalShortcut(Box::new(e))), - ) - .unwrap(), - }, - Message::Clipboard(message) => match message { - ClipboardMessage::WriteText(text, tx) => { - clipboard_manager.lock().unwrap().write_text(text); - tx.send(()).unwrap(); - } - ClipboardMessage::ReadText(tx) => tx - .send(clipboard_manager.lock().unwrap().read_text()) - .unwrap(), - }, - Message::UserEvent(_) => (), - } - - let it = RunIteration { - window_count: windows.lock().expect("poisoned webview collection").len(), - }; - it -} - -fn handle_event_loop( - event: Event<'_, Message>, - event_loop: &EventLoopWindowTarget>, - control_flow: &mut ControlFlow, - context: EventLoopIterationContext<'_, T>, - web_context: &WebContextStore, -) -> RunIteration { - let EventLoopIterationContext { - callback, - webview_id_map, - windows, - window_event_listeners, - global_shortcut_manager, - global_shortcut_manager_handle, - clipboard_manager, - menu_event_listeners, - #[cfg(feature = "system-tray")] - tray_context, - } = context; - if *control_flow == ControlFlow::Exit { - return RunIteration { - window_count: windows.lock().expect("poisoned webview collection").len(), - }; - } - - *control_flow = ControlFlow::Wait; - - match event { - Event::NewEvents(StartCause::Init) => { - callback(RunEvent::Ready); - } - - Event::NewEvents(StartCause::Poll) => { - callback(RunEvent::Resumed); - } - - Event::MainEventsCleared => { - callback(RunEvent::MainEventsCleared); - } - - Event::GlobalShortcutEvent(accelerator_id) => { - for (id, handler) in &*global_shortcut_manager_handle.listeners.lock().unwrap() { - if accelerator_id == *id { - handler(); - } - } - } - Event::MenuEvent { - window_id, - menu_id, - origin: MenuType::MenuBar, - .. - } => { - let window_id = window_id.unwrap(); // always Some on MenuBar event - let event = MenuEvent { - menu_item_id: menu_id.0, - }; - let window_menu_event_listeners = { - let window_id = webview_id_map.get(&window_id); - let listeners = menu_event_listeners.lock().unwrap(); - listeners.get(&window_id).cloned().unwrap_or_default() - }; - for handler in window_menu_event_listeners.lock().unwrap().values() { - handler(&event); - } - } - #[cfg(feature = "system-tray")] - Event::MenuEvent { - window_id: _, - menu_id, - origin: MenuType::ContextMenu, - .. - } => { - let event = SystemTrayEvent::MenuItemClick(menu_id.0); - for handler in tray_context.listeners.lock().unwrap().values() { - handler(&event); - } - } - #[cfg(feature = "system-tray")] - Event::TrayEvent { - bounds, - event, - position: _cursor_position, - .. - } => { - let (position, size) = ( - PhysicalPositionWrapper(bounds.position).into(), - PhysicalSizeWrapper(bounds.size).into(), - ); - let event = match event { - TrayEvent::RightClick => SystemTrayEvent::RightClick { position, size }, - TrayEvent::DoubleClick => SystemTrayEvent::DoubleClick { position, size }, - // default to left click - _ => SystemTrayEvent::LeftClick { position, size }, - }; - for handler in tray_context.listeners.lock().unwrap().values() { - handler(&event); - } - } - Event::WindowEvent { - event, window_id, .. - } => { - let window_id = webview_id_map.get(&window_id); - // NOTE(amrbashir): we handle this event here instead of `match` statement below because - // we want to focus the webview as soon as possible, especially on windows. - if event == WryWindowEvent::Focused(true) { - if let Some(WindowHandle::Webview(webview)) = windows - .lock() - .expect("poisoned webview collection") - .get(&window_id) - .map(|w| &w.inner) - { - // only focus the webview if the window is visible - // somehow tao is sending a Focused(true) event even when the window is invisible, - // which causes a deadlock: https://github.com/tauri-apps/tauri/issues/3534 - if webview.window().is_visible() { - webview.focus(); - } - } - } - - { - let windows_lock = windows.lock().expect("poisoned webview collection"); - if let Some(window_handle) = windows_lock.get(&window_id).map(|w| &w.inner) { - if let Some(event) = WindowEventWrapper::parse(window_handle, &event).0 { - drop(windows_lock); - for handler in window_event_listeners - .lock() - .unwrap() - .get(&window_id) - .unwrap() - .lock() - .unwrap() - .values() - { - handler(&event); - } - } - } - } - - match event { - WryWindowEvent::CloseRequested => { - on_close_requested( - callback, - window_id, - windows.clone(), - control_flow, - window_event_listeners, - menu_event_listeners.clone(), - ); - } - WryWindowEvent::Resized(_) => { - if let Some(WindowHandle::Webview(webview)) = windows - .lock() - .expect("poisoned webview collection") - .get(&window_id) - .map(|w| &w.inner) - { - if let Err(e) = webview.resize() { - #[cfg(debug_assertions)] - eprintln!("{}", e); - } - } - } - _ => {} - } - } - Event::UserEvent(message) => match message { - Message::Window(id, WindowMessage::Close) => { - on_window_close( - callback, - id, - windows.lock().expect("poisoned webview collection"), - control_flow, - #[cfg(target_os = "linux")] - window_event_listeners, - menu_event_listeners.clone(), - ); - } - Message::UserEvent(t) => callback(RunEvent::UserEvent(t)), - message => { - return handle_user_message( - event_loop, - message, - UserMessageContext { - window_event_listeners, - global_shortcut_manager, - clipboard_manager, - menu_event_listeners, - windows, - #[cfg(feature = "system-tray")] - tray_context, - }, - web_context, - ); - } - }, - _ => (), - } - - let it = RunIteration { - window_count: windows.lock().expect("poisoned webview collection").len(), - }; - it -} - -fn on_close_requested<'a, T: UserEvent>( - callback: &'a mut (dyn FnMut(RunEvent) + 'static), - window_id: WebviewId, - windows: Arc>>, - control_flow: &mut ControlFlow, - window_event_listeners: &WindowEventListeners, - menu_event_listeners: MenuEventListeners, -) -> Option { - let (tx, rx) = channel(); - let windows_guard = windows.lock().expect("poisoned webview collection"); - if let Some(w) = windows_guard.get(&window_id) { - let label = w.label.clone(); - drop(windows_guard); - for handler in window_event_listeners - .lock() - .unwrap() - .get(&window_id) - .unwrap() - .lock() - .unwrap() - .values() - { - handler(&WindowEvent::CloseRequested { - label: label.clone(), - signal_tx: tx.clone(), - }); - } - callback(RunEvent::CloseRequested { - label, - signal_tx: tx, - }); - if let Ok(true) = rx.try_recv() { - None - } else { - on_window_close( - callback, - window_id, - windows.lock().expect("poisoned webview collection"), - control_flow, - #[cfg(target_os = "linux")] - window_event_listeners, - menu_event_listeners, - ) - } - } else { - None - } -} - -fn on_window_close<'a, T: UserEvent>( - callback: &'a mut (dyn FnMut(RunEvent) + 'static), - window_id: WebviewId, - mut windows: MutexGuard<'a, HashMap>, - control_flow: &mut ControlFlow, - #[cfg(target_os = "linux")] window_event_listeners: &WindowEventListeners, - menu_event_listeners: MenuEventListeners, -) -> Option { - #[allow(unused_mut)] - let w = if let Some(mut webview) = windows.remove(&window_id) { - let is_empty = windows.is_empty(); - drop(windows); - menu_event_listeners.lock().unwrap().remove(&window_id); - callback(RunEvent::WindowClose(webview.label.clone())); - - if is_empty { - let (tx, rx) = channel(); - callback(RunEvent::ExitRequested { - window_label: webview.label.clone(), - tx, - }); - - let recv = rx.try_recv(); - let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent)); - - if !should_prevent { - *control_flow = ControlFlow::Exit; - callback(RunEvent::Exit); - } - } - Some(webview) - } else { - None - }; - // TODO: tao does not fire the destroyed event properly - #[cfg(target_os = "linux")] - { - for handler in window_event_listeners - .lock() - .unwrap() - .get(&window_id) - .unwrap() - .lock() - .unwrap() - .values() - { - handler(&WindowEvent::Destroyed); - } - } - w -} - -fn center_window(window: &Window, window_size: WryPhysicalSize) -> Result<()> { - if let Some(monitor) = window.current_monitor() { - let screen_size = monitor.size(); - let x = (screen_size.width as i32 - window_size.width as i32) / 2; - let y = (screen_size.height as i32 - window_size.height as i32) / 2; - window.set_outer_position(WryPhysicalPosition::new(x, y)); - Ok(()) - } else { - Err(Error::FailedToGetMonitor) - } -} - -fn to_wry_menu( - custom_menu_items: &mut HashMap, - menu: Menu, -) -> MenuBar { - let mut wry_menu = MenuBar::new(); - for item in menu.items { - match item { - MenuEntry::CustomItem(c) => { - let mut attributes = MenuItemAttributesWrapper::from(&c).0; - attributes = attributes.with_id(WryMenuId(c.id)); - #[allow(unused_mut)] - let mut item = wry_menu.add_item(attributes); - #[cfg(target_os = "macos")] - if let Some(native_image) = c.native_image { - item.set_native_image(NativeImageWrapper::from(native_image).0); - } - custom_menu_items.insert(c.id, item); - } - MenuEntry::NativeItem(i) => { - wry_menu.add_native_item(MenuItemWrapper::from(i).0); - } - MenuEntry::Submenu(submenu) => { - wry_menu.add_submenu( - &submenu.title, - submenu.enabled, - to_wry_menu(custom_menu_items, submenu.inner), - ); - } - } - } - wry_menu -} - -fn create_webview( - window_id: WebviewId, - event_loop: &EventLoopWindowTarget>, - web_context: &WebContextStore, - context: Context, - pending: PendingWindow>, -) -> Result { - #[allow(unused_mut)] - let PendingWindow { - webview_attributes, - uri_scheme_protocols, - mut window_builder, - ipc_handler, - label, - url, - menu_ids, - js_event_listeners, - .. - } = pending; - let webview_id_map = context.webview_id_map.clone(); - #[cfg(windows)] - let proxy = context.proxy.clone(); - - let is_window_transparent = window_builder.inner.window.transparent; - let menu_items = if let Some(menu) = window_builder.menu { - let mut menu_items = HashMap::new(); - let menu = to_wry_menu(&mut menu_items, menu); - window_builder.inner = window_builder.inner.with_menu(menu); - Some(menu_items) - } else { - None - }; - let window = window_builder.inner.build(event_loop).unwrap(); - - if window_builder.center { - let _ = center_window(&window, window.inner_size()); - } - let mut webview_builder = WebViewBuilder::new(window) - .map_err(|e| Error::CreateWebview(Box::new(e)))? - .with_url(&url) - .unwrap() // safe to unwrap because we validate the URL beforehand - .with_transparent(is_window_transparent); - if webview_attributes.file_drop_handler_enabled { - webview_builder = webview_builder.with_file_drop_handler(create_file_drop_handler(&context)); - } - if let Some(handler) = ipc_handler { - webview_builder = webview_builder.with_ipc_handler(create_ipc_handler( - context, - label.clone(), - menu_ids, - js_event_listeners, - handler, - )); - } - for (scheme, protocol) in uri_scheme_protocols { - webview_builder = webview_builder.with_custom_protocol(scheme, move |wry_request| { - protocol(&HttpRequestWrapper::from(wry_request).0) - .map(|tauri_response| HttpResponseWrapper::from(tauri_response).0) - .map_err(|_| wry::Error::InitScriptError) - }); - } - - for script in webview_attributes.initialization_scripts { - webview_builder = webview_builder.with_initialization_script(&script); - } - - let mut web_context = web_context.lock().expect("poisoned WebContext store"); - let is_first_context = web_context.is_empty(); - let automation_enabled = std::env::var("TAURI_AUTOMATION").as_deref() == Ok("true"); - let web_context = match web_context.entry( - // force a unique WebContext when automation is false; - // the context must be stored on the HashMap because it must outlive the WebView on macOS - if automation_enabled { - webview_attributes.data_directory.clone() - } else { - // random unique key - Some(Uuid::new_v4().to_hyphenated().to_string().into()) - }, - ) { - Occupied(occupied) => occupied.into_mut(), - Vacant(vacant) => { - let mut web_context = WebContext::new(webview_attributes.data_directory); - web_context.set_allows_automation(if automation_enabled { - is_first_context - } else { - false - }); - vacant.insert(web_context) - } - }; - - if webview_attributes.clipboard { - webview_builder.webview.clipboard = true; - } - - #[cfg(any(debug_assertions, feature = "devtools"))] - { - webview_builder = webview_builder.with_dev_tool(true); - } - - let webview = webview_builder - .with_web_context(web_context) - .build() - .map_err(|e| Error::CreateWebview(Box::new(e)))?; - - webview_id_map.insert(webview.window().id(), window_id); - - #[cfg(windows)] - { - if let Some(controller) = webview.controller() { - let proxy_ = proxy.clone(); - let mut token = EventRegistrationToken::default(); - unsafe { - controller.GotFocus( - FocusChangedEventHandler::create(Box::new(move |_, _| { - let _ = proxy_.send_event(Message::Webview( - window_id, - WebviewMessage::WebviewEvent(WebviewEvent::Focused(true)), - )); - Ok(()) - })), - &mut token, - ) - } - .unwrap(); - unsafe { - controller.LostFocus( - FocusChangedEventHandler::create(Box::new(move |_, _| { - let _ = proxy.send_event(Message::Webview( - window_id, - WebviewMessage::WebviewEvent(WebviewEvent::Focused(false)), - )); - Ok(()) - })), - &mut token, - ) - } - .unwrap(); - } - } - - Ok(WindowWrapper { - label, - inner: WindowHandle::Webview(webview), - menu_items, - }) -} - -/// Create a wry ipc handler from a tauri ipc handler. -fn create_ipc_handler( - context: Context, - label: String, - menu_ids: Arc>>, - js_event_listeners: Arc>>>, - handler: WebviewIpcHandler>, -) -> Box { - Box::new(move |window, request| { - handler( - DetachedWindow { - dispatcher: WryDispatcher { - window_id: *context - .webview_id_map - .0 - .lock() - .unwrap() - .get(&window.id()) - .unwrap(), - context: context.clone(), - }, - label: label.clone(), - menu_ids: menu_ids.clone(), - js_event_listeners: js_event_listeners.clone(), - }, - request, - ); - }) -} - -/// Create a wry file drop handler. -fn create_file_drop_handler( - context: &Context, -) -> Box bool + 'static> { - let window_event_listeners = context.window_event_listeners.clone(); - let webview_id_map = context.webview_id_map.clone(); - Box::new(move |window, event| { - let event: FileDropEvent = FileDropEventWrapper(event).into(); - let window_event = WindowEvent::FileDrop(event); - let listeners = window_event_listeners.lock().unwrap(); - if let Some(window_listeners) = listeners.get(&webview_id_map.get(&window.id())) { - let listeners_map = window_listeners.lock().unwrap(); - let has_listener = !listeners_map.is_empty(); - for listener in listeners_map.values() { - listener(&window_event); - } - // block the default OS action on file drop if we had a listener - has_listener - } else { - false - } - }) -} diff --git a/core/tauri-runtime-wry/src/system_tray.rs b/core/tauri-runtime-wry/src/system_tray.rs deleted file mode 100644 index 568c08433a40..000000000000 --- a/core/tauri-runtime-wry/src/system_tray.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -pub use tauri_runtime::{ - menu::{ - Menu, MenuEntry, MenuItem, MenuUpdate, Submenu, SystemTrayMenu, SystemTrayMenuEntry, - SystemTrayMenuItem, TrayHandle, - }, - SystemTrayEvent, TrayIcon, -}; -pub use wry::application::{ - event::TrayEvent, - event_loop::EventLoopProxy, - menu::{ - ContextMenu as WryContextMenu, CustomMenuItem as WryCustomMenuItem, MenuItem as WryMenuItem, - }, -}; - -#[cfg(target_os = "macos")] -pub use wry::application::platform::macos::CustomMenuItemExtMacOS; - -use crate::{Error, Message, Result, TrayMessage}; - -use tauri_runtime::{menu::MenuHash, UserEvent}; - -use uuid::Uuid; - -use std::{ - collections::HashMap, - sync::{Arc, Mutex}, -}; - -pub type SystemTrayEventHandler = Box; -pub type SystemTrayEventListeners = Arc>>; -pub type SystemTrayItems = Arc>>; - -#[derive(Debug, Clone)] -pub struct SystemTrayHandle { - pub(crate) proxy: EventLoopProxy>, -} - -impl TrayHandle for SystemTrayHandle { - fn set_icon(&self, icon: TrayIcon) -> Result<()> { - self - .proxy - .send_event(Message::Tray(TrayMessage::UpdateIcon(icon))) - .map_err(|_| Error::FailedToSendMessage) - } - fn set_menu(&self, menu: SystemTrayMenu) -> Result<()> { - self - .proxy - .send_event(Message::Tray(TrayMessage::UpdateMenu(menu))) - .map_err(|_| Error::FailedToSendMessage) - } - fn update_item(&self, id: u16, update: MenuUpdate) -> Result<()> { - self - .proxy - .send_event(Message::Tray(TrayMessage::UpdateItem(id, update))) - .map_err(|_| Error::FailedToSendMessage) - } - #[cfg(target_os = "macos")] - fn set_icon_as_template(&self, is_template: bool) -> tauri_runtime::Result<()> { - self - .proxy - .send_event(Message::Tray(TrayMessage::UpdateIconAsTemplate( - is_template, - ))) - .map_err(|_| Error::FailedToSendMessage) - } -} - -impl From for crate::MenuItemWrapper { - fn from(item: SystemTrayMenuItem) -> Self { - match item { - SystemTrayMenuItem::Separator => Self(WryMenuItem::Separator), - _ => unimplemented!(), - } - } -} - -pub fn to_wry_context_menu( - custom_menu_items: &mut HashMap, - menu: SystemTrayMenu, -) -> WryContextMenu { - let mut tray_menu = WryContextMenu::new(); - for item in menu.items { - match item { - SystemTrayMenuEntry::CustomItem(c) => { - #[allow(unused_mut)] - let mut item = tray_menu.add_item(crate::MenuItemAttributesWrapper::from(&c).0); - #[cfg(target_os = "macos")] - if let Some(native_image) = c.native_image { - item.set_native_image(crate::NativeImageWrapper::from(native_image).0); - } - custom_menu_items.insert(c.id, item); - } - SystemTrayMenuEntry::NativeItem(i) => { - tray_menu.add_native_item(crate::MenuItemWrapper::from(i).0); - } - SystemTrayMenuEntry::Submenu(submenu) => { - tray_menu.add_submenu( - &submenu.title, - submenu.enabled, - to_wry_context_menu(custom_menu_items, submenu.inner), - ); - } - } - } - tray_menu -} diff --git a/core/tauri-runtime/.license_template b/core/tauri-runtime/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/core/tauri-runtime/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/core/tauri-runtime/CHANGELOG.md b/core/tauri-runtime/CHANGELOG.md deleted file mode 100644 index bfab163e3225..000000000000 --- a/core/tauri-runtime/CHANGELOG.md +++ /dev/null @@ -1,212 +0,0 @@ -# Changelog - -## \[0.3.3] - -- **Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features. - - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 -- The `PendingWindow::new` and `PendingWindow::with_config` functions now return `Result` validating the window label. - - [64e00542](https://www.github.com/tauri-apps/tauri/commit/64e0054299c95f10ef5a1a9d3f914bbaeff3d73f) refactor(core): do not panic on invalid window labels,[#3544](https://www.github.com/tauri-apps/tauri/pull/3544) ([#3596](https://www.github.com/tauri-apps/tauri/pull/3596)) on 2022-03-03 - -## \[0.3.2] - -- Fix requirements for `RuntimeHandle`, `ClipboardManager`, `GlobalShortcutHandle` and `TrayHandle`. - - [84895a9c](https://www.github.com/tauri-apps/tauri/commit/84895a9cd270fc743e236d0f4d4cd6210b24a30f) fix(runtime): trait requirements ([#3489](https://www.github.com/tauri-apps/tauri/pull/3489)) on 2022-02-17 - -## \[0.3.1] - -- Change default value for the `freezePrototype` configuration to `false`. - - Bumped due to a bump in tauri-utils. - - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 - -## \[0.3.0] - -- Replace `WindowBuilder`'s `has_menu` with `get_menu`. - - [ac37b56e](https://www.github.com/tauri-apps/tauri/commit/ac37b56ef43c9e97039967a5fd99f0d2dccb5b5a) fix(core): menu id map not reflecting the current window menu ([#2726](https://www.github.com/tauri-apps/tauri/pull/2726)) on 2021-10-08 -- The `run_return` API is now available on Linux. - - [8483fde9](https://www.github.com/tauri-apps/tauri/commit/8483fde975aac8833d2ce426e42fb40aeaeecba9) feat(core): expose `run_return` on Linux ([#3352](https://www.github.com/tauri-apps/tauri/pull/3352)) on 2022-02-07 -- Add `Menu::with_items` constructor, taking an iterator of `MenuEntry`. - - [7cc95e10](https://www.github.com/tauri-apps/tauri/commit/7cc95e10ec66d8b155e9bb7f89cf73df56d1f107) feat(core): add `Menu::with_items`, closes [#2807](https://www.github.com/tauri-apps/tauri/pull/2807) ([#2966](https://www.github.com/tauri-apps/tauri/pull/2966)) on 2021-12-27 -- Change event loop callbacks definition to allow callers to move in mutable values. - - [bdbf905e](https://www.github.com/tauri-apps/tauri/commit/bdbf905e5d802b58693d2bd27582ce4269faf79c) Transformed event-loop callback to FnMut to allow mutable values ([#2667](https://www.github.com/tauri-apps/tauri/pull/2667)) on 2021-09-27 -- Added `any_thread` constructor on the `Runtime` trait (only possible on Linux and Windows). - - [af44bf81](https://www.github.com/tauri-apps/tauri/commit/af44bf8168310cf77fbe102a53e7c433f11641a3) feat(core): allow app run on any thread on Linux & Windows, closes [#3172](https://www.github.com/tauri-apps/tauri/pull/3172) ([#3353](https://www.github.com/tauri-apps/tauri/pull/3353)) on 2022-02-07 -- Added `run_on_main_thread` API on `RuntimeHandle`. - - [53fdfe52](https://www.github.com/tauri-apps/tauri/commit/53fdfe52bb30d52653c72ca9f42506c3863dcf4a) feat(core): expose `run_on_main_thread` API ([#2711](https://www.github.com/tauri-apps/tauri/pull/2711)) on 2021-10-04 -- **Breaking change:** Renamed the `RPC` interface to `IPC`. - - [3420aa50](https://www.github.com/tauri-apps/tauri/commit/3420aa5031b3274a95c6c5fa0f8683ca13213396) refactor: IPC handler \[TRI-019] ([#9](https://www.github.com/tauri-apps/tauri/pull/9)) on 2022-01-09 -- Added `open_devtools` to the `Dispatcher` trait. - - [55aa22de](https://www.github.com/tauri-apps/tauri/commit/55aa22de80c3de873e29bcffcb5b2fe236a637a6) feat(core): add `Window#open_devtools` API, closes [#1213](https://www.github.com/tauri-apps/tauri/pull/1213) ([#3350](https://www.github.com/tauri-apps/tauri/pull/3350)) on 2022-02-07 -- The minimum Rust version is now `1.56`. - - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 -- The window label is now validated and must be alphanumeric, resulting in a panic if it isn't. - - [680554de](https://www.github.com/tauri-apps/tauri/commit/680554de3ef6b7fccf87c441ad355cfef7aab6fe) feat: validate window label \[TRI-021] ([#13](https://www.github.com/tauri-apps/tauri/pull/13)) on 2021-10-23 -- Added `clipboard` field on the `WebviewAttributes` struct, which must be set to `true` to enable clipboard access on the webview. - - [d42ccfb3](https://www.github.com/tauri-apps/tauri/commit/d42ccfb34f71851dfeb22fe74c83a8bdbddb5550) feat: add `clipboard` flag to `WebviewAttributes` \[TRI-032] ([#12](https://www.github.com/tauri-apps/tauri/pull/12)) on 2021-10-23 -- Replace all of the `winapi` crate references with the `windows` crate, and replace `webview2` and `webview2-sys` with `webview2-com` and `webview2-com-sys` built with the `windows` crate. This goes along with updates to the TAO and WRY `next` branches. - - [bb00d5bd](https://www.github.com/tauri-apps/tauri/commit/bb00d5bd6c9dfcb6bdd0d308dadb70e6c6aafe5c) Replace winapi with windows crate and use webview2-com instead of webview2 ([#2615](https://www.github.com/tauri-apps/tauri/pull/2615)) on 2021-09-24 -- Update the `windows` crate to 0.25.0, which comes with pre-built libraries. WRY and Tao can both reference the same types directly from the `windows` crate instead of sharing bindings in `webview2-com-sys`. - - [34be6cf3](https://www.github.com/tauri-apps/tauri/commit/34be6cf37a98ee7cbd66623ebddae08e5a6520fd) Update webview2-com and windows crates ([#2875](https://www.github.com/tauri-apps/tauri/pull/2875)) on 2021-11-11 - -## \[0.2.1] - -- **Breaking change:** Removed `register_uri_scheme_protocol` from the `WebviewAttibutes` struct and renamed `register_global_uri_scheme_protocol` to `register_uri_scheme_protocol` on the `Builder` struct, which now takes a `Fn(&AppHandle, &http::Request) -> http::Response` closure. - - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 -- Migrate to latest custom protocol allowing `Partial content` streaming and Header parsing. - - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 - -## \[0.2.0] - -- Fix blur/focus events being incorrect on Windows. - - [d832d575](https://www.github.com/tauri-apps/tauri/commit/d832d575d9b03a0ff78accabe4631cc638c08c3b) fix(windows): use webview events on windows ([#2277](https://www.github.com/tauri-apps/tauri/pull/2277)) on 2021-07-23 - -- Add `ExitRequested` event that allows preventing the app from exiting when all windows are closed, and an `AppHandle.exit()` function to exit the app manually. - - [892c63a0](https://www.github.com/tauri-apps/tauri/commit/892c63a0538f8d62680dce5848657128ad6b7af3) feat([#2287](https://www.github.com/tauri-apps/tauri/pull/2287)): Add `ExitRequested` event to let users prevent app from exiting ([#2293](https://www.github.com/tauri-apps/tauri/pull/2293)) on 2021-08-09 - -- Fixes minimum window height being used as maximum height. - - [e3f99165](https://www.github.com/tauri-apps/tauri/commit/e3f9916526b226866137cb663e5cafab2b6a0e01) fix(core) minHeight being used as maxHeight ([#2247](https://www.github.com/tauri-apps/tauri/pull/2247)) on 2021-07-19 - -- Update gtk and its related libraries to v0.14. This also remove requirements of `clang` as build dependency. - - [63ad3039](https://www.github.com/tauri-apps/tauri/commit/63ad303903bbee7c9a7382413b342e2a05d3ea75) chore(linux): bump gtk to v0.14 ([#2361](https://www.github.com/tauri-apps/tauri/pull/2361)) on 2021-08-07 - -- Implement `Debug` on public API structs and enums. - - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 - -- Panic when a dispatcher getter method (`Window`, `GlobalShortcutHandle`, `ClipboardManager` and `MenuHandle` APIs) is called on the main thread. - - [50ffdc06](https://www.github.com/tauri-apps/tauri/commit/50ffdc06fbde56aba32b4291fd130104935d1408) feat(core): panic when a dispatcher getter is used on the main thread ([#2455](https://www.github.com/tauri-apps/tauri/pull/2455)) on 2021-08-16 - -- Remove menu feature flag since there's no package dependency need to be installed on any platform anymore. - - [f81ebddf](https://www.github.com/tauri-apps/tauri/commit/f81ebddfcc1aea0d4989706aef43538e8ea98bea) feat: remove menu feature flag ([#2415](https://www.github.com/tauri-apps/tauri/pull/2415)) on 2021-08-13 - -- Adds `Resumed` and `MainEventsCleared` variants to the `RunEvent` enum. - - [6be3f433](https://www.github.com/tauri-apps/tauri/commit/6be3f4339168651fe4e003b09f7d181fd12cd5a8) feat(core): add `Resumed` and `MainEventsCleared` events, closes [#2127](https://www.github.com/tauri-apps/tauri/pull/2127) ([#2439](https://www.github.com/tauri-apps/tauri/pull/2439)) on 2021-08-15 - -- Adds `set_activation_policy` API to the `Runtime` trait (macOS only). - - [4a031add](https://www.github.com/tauri-apps/tauri/commit/4a031add69014a1f3823f4ea19b172a2557f6794) feat(core): expose `set_activation_policy`, closes [#2258](https://www.github.com/tauri-apps/tauri/pull/2258) ([#2420](https://www.github.com/tauri-apps/tauri/pull/2420)) on 2021-08-13 - -- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. - - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 - - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 - -- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. - -- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. - -- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 - -- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. - - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 - -## \[0.1.4] - -- Allow preventing window close when the user requests it. - - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 -- Expose `gtk_window` getter. - - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 -- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those - associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If - you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the - explicit type and let the compiler infer it instead. - -`tauri`: - -- See `Params` note -- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a - simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition - of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type - to these functions. -- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all - methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already - required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change - affects you. - -`tauri-macros`: - -- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when - the specified feature is enabled. - -`tauri-runtime`: - -- See `Params` note -- Removed `Params`, `MenuId`, `Tag`, `TagRef`. -- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. - - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. -- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the - `Runtime` type directly -- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. -- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. - -`tauri-runtime-wry`: - -- See `Params` note -- update menu and runtime related types to the ones changed in `tauri-runtime`. - -`tauri-utils`: - -- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object - safe. -- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 - -## \[0.1.3] - -- `Window` is now `Send + Sync` on Windows. - - [fe32afcc](https://www.github.com/tauri-apps/tauri/commit/fe32afcc933920d6282ae1d63b041b182278a031) fix(core): `Window` must be `Send + Sync` on Windows, closes [#2078](https://www.github.com/tauri-apps/tauri/pull/2078) ([#2093](https://www.github.com/tauri-apps/tauri/pull/2093)) on 2021-06-27 - -## \[0.1.2] - -- Adds `clipboard` APIs (write and read text). - - [285bf64b](https://www.github.com/tauri-apps/tauri/commit/285bf64bf9569efb2df904c69c6df405ff0d62e2) feat(core): add clipboard writeText and readText APIs ([#2035](https://www.github.com/tauri-apps/tauri/pull/2035)) on 2021-06-21 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `focus` API to the WindowBuilder. - - [5f351622](https://www.github.com/tauri-apps/tauri/commit/5f351622c7812ad1bb56ddb37364ccaa4124c24b) feat(core): add focus API to the WindowBuilder and WindowOptions, [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `is_decorated` getter on Window. - - [f58a2114](https://www.github.com/tauri-apps/tauri/commit/f58a2114fbfd5307c349f05c88f2e08fd8baa8aa) feat(core): add `is_decorated` Window getter on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `is_resizable` getter on Window. - - [1e8af280](https://www.github.com/tauri-apps/tauri/commit/1e8af280c27f381828d6209722b10e889082fa00) feat(core): add `is_resizable` Window getter on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `is_visible` getter on Window. - - [36506c96](https://www.github.com/tauri-apps/tauri/commit/36506c967de82bc7ff453d11e6104ecf66d7a588) feat(core): add `is_visible` API on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `accelerator` method to the `CustomMenuItem` struct to define a keyboard shortcut for the menu item. - - [034c2601](https://www.github.com/tauri-apps/tauri/commit/034c26013bce0c7bbe6db067ea7fd24a53a5c998) feat(core): add `accelerator` method to `CustomMenuItem` ([#2043](https://www.github.com/tauri-apps/tauri/pull/2043)) on 2021-06-22 -- Adds global shortcut interfaces. - - [3280c4aa](https://www.github.com/tauri-apps/tauri/commit/3280c4aa91e50a8ccdd561a8b48a12a4a13ea8d5) refactor(core): global shortcut is now provided by `tao` ([#2031](https://www.github.com/tauri-apps/tauri/pull/2031)) on 2021-06-21 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `request_user_attention` API to the `Dispatcher` trait. - - [7dcca6e9](https://www.github.com/tauri-apps/tauri/commit/7dcca6e9281182b11ad3d4a79871f09b30b9b419) feat(core): add `request_user_attention` API, closes [#2023](https://www.github.com/tauri-apps/tauri/pull/2023) ([#2026](https://www.github.com/tauri-apps/tauri/pull/2026)) on 2021-06-20 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `fn run_iteration` (macOS and Windows only) to the Runtime trait. - - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 -- Adds `show_menu`, `hide_menu` and `is_menu_visible` APIs to the `Dispatcher` trait. - - [954460c5](https://www.github.com/tauri-apps/tauri/commit/954460c5205d57444ef4b1412051fbedf3e38676) feat(core): MenuHandle `show`, `hide`, `is_visible` and `toggle` APIs ([#1958](https://www.github.com/tauri-apps/tauri/pull/1958)) on 2021-06-15 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `set_focus` API on Window. - - [bb6992f8](https://www.github.com/tauri-apps/tauri/commit/bb6992f888196ca7c87bb2fe74ad2bd8bf393e05) feat(core): add `set_focus` window API, fixes [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `set_skip_taskbar` API on Window. - - [e06aa277](https://www.github.com/tauri-apps/tauri/commit/e06aa277384450cfef617c0e57b0d5d403bb1e7f) feat(core): add `set_skip_taskbar` API on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `skip_taskbar` API to the WindowBuilder. - - [5525b03a](https://www.github.com/tauri-apps/tauri/commit/5525b03a78a2232c650043fbd9894ce1553cad41) feat(core): add `skip_taskbar` API to the WindowBuilder/WindowOptions on 2021-05-30 - - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 -- Adds `Window#center` and `WindowBuilder#center` APIs. - - [5cba6eb4](https://www.github.com/tauri-apps/tauri/commit/5cba6eb4d28d53f06855d60d4d0eae6b95233ccf) feat(core): add window `center` API, closes [#1822](https://www.github.com/tauri-apps/tauri/pull/1822) ([#1954](https://www.github.com/tauri-apps/tauri/pull/1954)) on 2021-06-05 -- Adds `parent_window` and `owner_window` setters to the `WindowBuilder` (Windows only). - - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 -- Adds window native handle getter (HWND on Windows). - - [abf78c58](https://www.github.com/tauri-apps/tauri/commit/abf78c5860cdc52fbfd2bc5dbca29a864e2da8f9) fix(core): set parent window handle on dialogs, closes [#1876](https://www.github.com/tauri-apps/tauri/pull/1876) ([#1889](https://www.github.com/tauri-apps/tauri/pull/1889)) on 2021-05-21 - -## \[0.1.1] - -- Fixes `system-tray` feature usage. - - [1ab8dd9](https://www.github.com/tauri-apps/tauri/commit/1ab8dd93e670d2a2d070c7a6ec48308a0ab32f1a) fix(core): `system-tray` cargo feature usage, fixes [#1798](https://www.github.com/tauri-apps/tauri/pull/1798) ([#1801](https://www.github.com/tauri-apps/tauri/pull/1801)) on 2021-05-12 - -## \[0.1.0] - -- **Breaking:** `Context` fields are now private, and is expected to be created through `Context::new(...)`. - All fields previously available through `Context` are now public methods. - - [5542359](https://www.github.com/tauri-apps/tauri/commit/55423590ddbf560684dab6a0214acf95aadfa8d2) refactor(core): Context fields now private, Icon used on all platforms ([#1774](https://www.github.com/tauri-apps/tauri/pull/1774)) on 2021-05-11 -- `tauri-runtime` crate initial release. - - [665ec1d](https://www.github.com/tauri-apps/tauri/commit/665ec1d4a199ad06e369221da187dc838da71cbf) refactor: move runtime to `tauri-runtime` crate ([#1751](https://www.github.com/tauri-apps/tauri/pull/1751)) on 2021-05-09 - - [45a7a11](https://www.github.com/tauri-apps/tauri/commit/45a7a111e0cf9d9956d713cc9a99fa7a5313eec7) feat(core): add `tauri-wry` crate ([#1756](https://www.github.com/tauri-apps/tauri/pull/1756)) on 2021-05-09 diff --git a/core/tauri-runtime/Cargo.toml b/core/tauri-runtime/Cargo.toml deleted file mode 100644 index a54d481d7cd0..000000000000 --- a/core/tauri-runtime/Cargo.toml +++ /dev/null @@ -1,48 +0,0 @@ -[package] -name = "tauri-runtime" -version = "0.3.3" -authors = [ "Tauri Programme within The Commons Conservancy" ] -categories = [ "gui", "web-programming" ] -license = "Apache-2.0 OR MIT" -homepage = "https://tauri.studio" -repository = "https://github.com/tauri-apps/tauri" -description = "Runtime for Tauri applications" -edition = "2021" -rust-version = "1.57" -exclude = [ ".license_template", "CHANGELOG.md", "/target" ] -readme = "README.md" - -[package.metadata.docs.rs] -all-features = true -rustdoc-args = [ "--cfg", "doc_cfg" ] -default-target = "x86_64-unknown-linux-gnu" -targets = [ - "x86_64-pc-windows-msvc", - "x86_64-unknown-linux-gnu", - "x86_64-apple-darwin" -] - -[dependencies] -serde = { version = "1.0", features = [ "derive" ] } -serde_json = "1.0" -thiserror = "1.0" -tauri-utils = { version = "1.0.0-rc.3", path = "../tauri-utils" } -uuid = { version = "0.8.2", features = [ "v4" ] } -http = "0.2.4" -http-range = "0.1.4" -infer = "0.4" - -[target."cfg(windows)".dependencies] -webview2-com = "0.13.0" - - [target."cfg(windows)".dependencies.windows] - version = "0.30.0" - features = [ "Win32_Foundation" ] - -[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] -gtk = { version = "0.15", features = [ "v3_20" ] } - -[features] -devtools = [ ] -system-tray = [ ] -macos-private-api = [ ] diff --git a/core/tauri-runtime/README.md b/core/tauri-runtime/README.md deleted file mode 100644 index 0c415da3afef..000000000000 --- a/core/tauri-runtime/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# tauri-runtime - - - -[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri) -[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) -[![devto](https://img.shields.io/badge/blog-dev.to-black.svg)](https://dev.to/tauri) - -![](https://img.shields.io/github/workflow/status/tauri-apps/tauri/test%20library?label=test%20library -) -[![devto](https://img.shields.io/badge/documentation-site-purple.svg)](https://tauri.studio) - -[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) -[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri) - -| Component | Version | -| --------- | ------------------------------------------- | -| tauri-runtime | [![](https://img.shields.io/crates/v/tauri-runtime?style=flat-square)](https://crates.io/crates/tauri-runtime) | - -## About Tauri -Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. - -Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. - -## This module -This is the glue layer between tauri itself and lower level webview libraries. - -To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. - -## Semver -**tauri** is following [Semantic Versioning 2.0](https://semver.org/). -## Licenses -Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. - -MIT or MIT/Apache 2.0 where applicable. - -Logo: CC-BY-NC-ND -- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/core/tauri-runtime/src/http/mime_type.rs b/core/tauri-runtime/src/http/mime_type.rs deleted file mode 100644 index d22a8d3fa6e7..000000000000 --- a/core/tauri-runtime/src/http/mime_type.rs +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use std::fmt; - -const MIMETYPE_PLAIN: &str = "text/plain"; - -/// [Web Compatible MimeTypes](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#important_mime_types_for_web_developers) -pub enum MimeType { - Css, - Csv, - Html, - Ico, - Js, - Json, - Jsonld, - OctetStream, - Rtf, - Svg, - Mp4, -} - -impl std::fmt::Display for MimeType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mime = match self { - MimeType::Css => "text/css", - MimeType::Csv => "text/csv", - MimeType::Html => "text/html", - MimeType::Ico => "image/vnd.microsoft.icon", - MimeType::Js => "text/javascript", - MimeType::Json => "application/json", - MimeType::Jsonld => "application/ld+json", - MimeType::OctetStream => "application/octet-stream", - MimeType::Rtf => "application/rtf", - MimeType::Svg => "image/svg+xml", - MimeType::Mp4 => "video/mp4", - }; - write!(f, "{}", mime) - } -} - -impl MimeType { - /// parse a URI suffix to convert text/plain mimeType to their actual web compatible mimeType. - pub fn parse_from_uri(uri: &str) -> MimeType { - let suffix = uri.split('.').last(); - match suffix { - Some("bin") => Self::OctetStream, - Some("css") => Self::Css, - Some("csv") => Self::Csv, - Some("html") => Self::Html, - Some("ico") => Self::Ico, - Some("js") => Self::Js, - Some("json") => Self::Json, - Some("jsonld") => Self::Jsonld, - Some("rtf") => Self::Rtf, - Some("svg") => Self::Svg, - Some("mp4") => Self::Mp4, - // Assume HTML when a TLD is found for eg. `wry:://tauri.studio` | `wry://hello.com` - Some(_) => Self::Html, - // https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types - // using octet stream according to this: - None => Self::OctetStream, - } - } - - /// infer mimetype from content (or) URI if needed. - pub fn parse(content: &[u8], uri: &str) -> String { - let mime = if uri.ends_with(".svg") { - // when reading svg, we can't use `infer` - None - } else { - infer::get(content).map(|info| info.mime_type()) - }; - - match mime { - Some(mime) if mime == MIMETYPE_PLAIN => Self::parse_from_uri(uri).to_string(), - None => Self::parse_from_uri(uri).to_string(), - Some(mime) => mime.to_string(), - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn should_parse_mimetype_from_uri() { - let css = MimeType::parse_from_uri( - "https://unpkg.com/browse/bootstrap@4.1.0/dist/css/bootstrap-grid.css", - ) - .to_string(); - assert_eq!(css, "text/css".to_string()); - - let csv: String = MimeType::parse_from_uri("https://example.com/random.csv").to_string(); - assert_eq!(csv, "text/csv".to_string()); - - let ico: String = - MimeType::parse_from_uri("https://icons.duckduckgo.com/ip3/microsoft.com.ico").to_string(); - assert_eq!(ico, String::from("image/vnd.microsoft.icon")); - - let html: String = MimeType::parse_from_uri("https://tauri.studio/index.html").to_string(); - assert_eq!(html, String::from("text/html")); - - let js: String = - MimeType::parse_from_uri("https://unpkg.com/react@17.0.1/umd/react.production.min.js") - .to_string(); - assert_eq!(js, "text/javascript".to_string()); - - let json: String = - MimeType::parse_from_uri("https://unpkg.com/browse/react@17.0.1/build-info.json").to_string(); - assert_eq!(json, String::from("application/json")); - - let jsonld: String = MimeType::parse_from_uri("https:/example.com/hello.jsonld").to_string(); - assert_eq!(jsonld, String::from("application/ld+json")); - - let rtf: String = MimeType::parse_from_uri("https://example.com/document.rtf").to_string(); - assert_eq!(rtf, String::from("application/rtf")); - - let svg: String = MimeType::parse_from_uri("https://example.com/picture.svg").to_string(); - assert_eq!(svg, String::from("image/svg+xml")); - - let mp4: String = MimeType::parse_from_uri("https://example.com/video.mp4").to_string(); - assert_eq!(mp4, String::from("video/mp4")); - - let custom_scheme = MimeType::parse_from_uri("wry://tauri.studio").to_string(); - assert_eq!(custom_scheme, String::from("text/html")); - } -} diff --git a/core/tauri-runtime/src/http/mod.rs b/core/tauri-runtime/src/http/mod.rs deleted file mode 100644 index 35a694d0281e..000000000000 --- a/core/tauri-runtime/src/http/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -// custom wry types -mod mime_type; -mod request; -mod response; - -pub use self::{ - mime_type::MimeType, - request::{Request, RequestParts}, - response::{Builder as ResponseBuilder, Response, ResponseParts}, -}; - -// re-expose default http types -pub use http::{header, method, status, uri::InvalidUri, version, Uri}; - -// re-export httprange helper as it can be useful and we need it locally -pub use http_range::HttpRange; diff --git a/core/tauri-runtime/src/http/request.rs b/core/tauri-runtime/src/http/request.rs deleted file mode 100644 index 594e7c10b466..000000000000 --- a/core/tauri-runtime/src/http/request.rs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use std::fmt; - -use super::{ - header::{HeaderMap, HeaderValue}, - method::Method, -}; - -/// Represents an HTTP request from the WebView. -/// -/// An HTTP request consists of a head and a potentially optional body. -/// -/// ## Platform-specific -/// -/// - **Linux:** Headers are not exposed. -pub struct Request { - head: RequestParts, - body: Vec, -} - -/// Component parts of an HTTP `Request` -/// -/// The HTTP request head consists of a method, uri, and a set of -/// header fields. -#[derive(Clone)] -pub struct RequestParts { - /// The request's method - pub method: Method, - - /// The request's URI - pub uri: String, - - /// The request's headers - pub headers: HeaderMap, -} - -impl Request { - /// Creates a new blank `Request` with the body - #[inline] - pub fn new(body: Vec) -> Request { - Request { - head: RequestParts::new(), - body, - } - } - - /// Creates a new `Request` with the given head and body. - /// - /// # Stability - /// - /// This API is used internally. It may have breaking changes in the future. - #[inline] - #[doc(hidden)] - pub fn new_internal(head: RequestParts, body: Vec) -> Request { - Request { head, body } - } - - /// Returns a reference to the associated HTTP method. - #[inline] - pub fn method(&self) -> &Method { - &self.head.method - } - - /// Returns a reference to the associated URI. - #[inline] - pub fn uri(&self) -> &str { - &self.head.uri - } - - /// Returns a reference to the associated header field map. - #[inline] - pub fn headers(&self) -> &HeaderMap { - &self.head.headers - } - - /// Returns a reference to the associated HTTP body. - #[inline] - pub fn body(&self) -> &Vec { - &self.body - } - - /// Consumes the request returning the head and body RequestParts. - /// - /// # Stability - /// - /// This API is used internally. It may have breaking changes in the future. - #[inline] - pub fn into_parts(self) -> (RequestParts, Vec) { - (self.head, self.body) - } -} - -impl Default for Request { - fn default() -> Request { - Request::new(Vec::new()) - } -} - -impl fmt::Debug for Request { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Request") - .field("method", self.method()) - .field("uri", &self.uri()) - .field("headers", self.headers()) - .field("body", self.body()) - .finish() - } -} - -impl RequestParts { - /// Creates a new default instance of `RequestParts` - fn new() -> RequestParts { - RequestParts { - method: Method::default(), - uri: "".into(), - headers: HeaderMap::default(), - } - } -} - -impl fmt::Debug for RequestParts { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Parts") - .field("method", &self.method) - .field("uri", &self.uri) - .field("headers", &self.headers) - .finish() - } -} diff --git a/core/tauri-runtime/src/http/response.rs b/core/tauri-runtime/src/http/response.rs deleted file mode 100644 index 0f18bc83306f..000000000000 --- a/core/tauri-runtime/src/http/response.rs +++ /dev/null @@ -1,306 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use super::{ - header::{HeaderMap, HeaderName, HeaderValue}, - status::StatusCode, - version::Version, -}; -use std::fmt; - -type Result = core::result::Result>; - -/// Represents an HTTP response -/// -/// An HTTP response consists of a head and a potentially body. -/// -/// ## Platform-specific -/// -/// - **Linux:** Headers and status code cannot be changed. -/// -/// # Examples -/// -/// ``` -/// # use tauri_runtime::http::*; -/// -/// let response = ResponseBuilder::new() -/// .status(202) -/// .mimetype("text/html") -/// .body("hello!".as_bytes().to_vec()) -/// .unwrap(); -/// ``` -/// -pub struct Response { - head: ResponseParts, - body: Vec, -} - -/// Component parts of an HTTP `Response` -/// -/// The HTTP response head consists of a status, version, and a set of -/// header fields. -#[derive(Clone)] -pub struct ResponseParts { - /// The response's status. - pub status: StatusCode, - - /// The response's version. - pub version: Version, - - /// The response's headers. - pub headers: HeaderMap, - - /// The response's mimetype type. - pub mimetype: Option, -} - -/// An HTTP response builder -/// -/// This type can be used to construct an instance of `Response` through a -/// builder-like pattern. -#[derive(Debug)] -pub struct Builder { - inner: Result, -} - -impl Response { - /// Creates a new blank `Response` with the body - #[inline] - pub fn new(body: Vec) -> Response { - Response { - head: ResponseParts::new(), - body, - } - } - - /// Consumes the response returning the head and body ResponseParts. - /// - /// # Stability - /// - /// This API is used internally. It may have breaking changes in the future. - #[inline] - #[doc(hidden)] - pub fn into_parts(self) -> (ResponseParts, Vec) { - (self.head, self.body) - } - - /// Sets the status code. - #[inline] - pub fn set_status(&mut self, status: StatusCode) { - self.head.status = status; - } - - /// Returns the [`StatusCode`]. - #[inline] - pub fn status(&self) -> StatusCode { - self.head.status - } - - /// Sets the mimetype. - #[inline] - pub fn set_mimetype(&mut self, mimetype: Option) { - self.head.mimetype = mimetype; - } - - /// Returns a reference to the mime type. - #[inline] - pub fn mimetype(&self) -> Option<&String> { - self.head.mimetype.as_ref() - } - - /// Returns a reference to the associated version. - #[inline] - pub fn version(&self) -> Version { - self.head.version - } - - /// Returns a mutable reference to the associated header field map. - #[inline] - pub fn headers_mut(&mut self) -> &mut HeaderMap { - &mut self.head.headers - } - - /// Returns a reference to the associated header field map. - #[inline] - pub fn headers(&self) -> &HeaderMap { - &self.head.headers - } - - /// Returns a mutable reference to the associated HTTP body. - #[inline] - pub fn body_mut(&mut self) -> &mut Vec { - &mut self.body - } - - /// Returns a reference to the associated HTTP body. - #[inline] - pub fn body(&self) -> &Vec { - &self.body - } -} - -impl Default for Response { - #[inline] - fn default() -> Response { - Response::new(Vec::new()) - } -} - -impl fmt::Debug for Response { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Response") - .field("status", &self.status()) - .field("version", &self.version()) - .field("headers", self.headers()) - .field("body", self.body()) - .finish() - } -} - -impl ResponseParts { - /// Creates a new default instance of `ResponseParts` - fn new() -> ResponseParts { - ResponseParts { - status: StatusCode::default(), - version: Version::default(), - headers: HeaderMap::default(), - mimetype: None, - } - } -} - -impl fmt::Debug for ResponseParts { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Parts") - .field("status", &self.status) - .field("version", &self.version) - .field("headers", &self.headers) - .finish() - } -} - -impl Builder { - /// Creates a new default instance of `Builder` to construct either a - /// `Head` or a `Response`. - /// - /// # Examples - /// - /// ``` - /// # use tauri_runtime::http::*; - /// - /// let response = ResponseBuilder::new() - /// .status(200) - /// .mimetype("text/html") - /// .body(Vec::new()) - /// .unwrap(); - /// ``` - #[inline] - pub fn new() -> Builder { - Builder { - inner: Ok(ResponseParts::new()), - } - } - - /// Set the HTTP mimetype for this response. - #[must_use] - pub fn mimetype(self, mimetype: &str) -> Self { - self.and_then(move |mut head| { - head.mimetype = Some(mimetype.to_string()); - Ok(head) - }) - } - - /// Set the HTTP status for this response. - #[must_use] - pub fn status(self, status: T) -> Self - where - StatusCode: TryFrom, - >::Error: Into, - { - self.and_then(move |mut head| { - head.status = TryFrom::try_from(status).map_err(Into::into)?; - Ok(head) - }) - } - - /// Set the HTTP version for this response. - /// - /// This function will configure the HTTP version of the `Response` that - /// will be returned from `Builder::build`. - /// - /// By default this is HTTP/1.1 - #[must_use] - pub fn version(self, version: Version) -> Self { - self.and_then(move |mut head| { - head.version = version; - Ok(head) - }) - } - - /// Appends a header to this response builder. - /// - /// This function will append the provided key/value as a header to the - /// internal `HeaderMap` being constructed. Essentially this is equivalent - /// to calling `HeaderMap::append`. - #[must_use] - pub fn header(self, key: K, value: V) -> Self - where - HeaderName: TryFrom, - >::Error: Into, - HeaderValue: TryFrom, - >::Error: Into, - { - self.and_then(move |mut head| { - let name = >::try_from(key).map_err(Into::into)?; - let value = >::try_from(value).map_err(Into::into)?; - head.headers.append(name, value); - Ok(head) - }) - } - - /// "Consumes" this builder, using the provided `body` to return a - /// constructed `Response`. - /// - /// # Errors - /// - /// This function may return an error if any previously configured argument - /// failed to parse or get converted to the internal representation. For - /// example if an invalid `head` was specified via `header("Foo", - /// "Bar\r\n")` the error will be returned when this function is called - /// rather than when `header` was called. - /// - /// # Examples - /// - /// ``` - /// # use tauri_runtime::http::*; - /// - /// let response = ResponseBuilder::new() - /// .mimetype("text/html") - /// .body(Vec::new()) - /// .unwrap(); - /// ``` - pub fn body(self, body: Vec) -> Result { - self.inner.map(move |head| Response { head, body }) - } - - // private - - fn and_then(self, func: F) -> Self - where - F: FnOnce(ResponseParts) -> Result, - { - Builder { - inner: self.inner.and_then(func), - } - } -} - -impl Default for Builder { - #[inline] - fn default() -> Builder { - Builder { - inner: Ok(ResponseParts::new()), - } - } -} diff --git a/core/tauri-runtime/src/lib.rs b/core/tauri-runtime/src/lib.rs deleted file mode 100644 index ba91331e5e23..000000000000 --- a/core/tauri-runtime/src/lib.rs +++ /dev/null @@ -1,574 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Internal runtime between Tauri and the underlying webview runtime. - -#![cfg_attr(doc_cfg, feature(doc_cfg))] - -use serde::Deserialize; -use std::{fmt::Debug, path::PathBuf, sync::mpsc::Sender}; -use uuid::Uuid; - -#[cfg(windows)] -use windows::Win32::Foundation::HWND; - -pub mod http; -/// Create window and system tray menus. -pub mod menu; -/// Types useful for interacting with a user's monitors. -pub mod monitor; -pub mod webview; -pub mod window; - -use monitor::Monitor; -use webview::WindowBuilder; -use window::{ - dpi::{PhysicalPosition, PhysicalSize, Position, Size}, - DetachedWindow, PendingWindow, WindowEvent, -}; - -use crate::http::{ - header::{InvalidHeaderName, InvalidHeaderValue}, - method::InvalidMethod, - status::InvalidStatusCode, - InvalidUri, -}; - -#[cfg(feature = "system-tray")] -#[non_exhaustive] -#[derive(Debug, Default)] -pub struct SystemTray { - pub icon: Option, - pub menu: Option, - #[cfg(target_os = "macos")] - pub icon_as_template: bool, -} - -#[cfg(feature = "system-tray")] -impl SystemTray { - /// Creates a new system tray that only renders an icon. - pub fn new() -> Self { - Default::default() - } - - pub fn menu(&self) -> Option<&menu::SystemTrayMenu> { - self.menu.as_ref() - } - - /// Sets the tray icon. Must be a [`TrayIcon::File`] on Linux and a [`TrayIcon::Raw`] on Windows and macOS. - #[must_use] - pub fn with_icon(mut self, icon: TrayIcon) -> Self { - self.icon.replace(icon); - self - } - - /// Sets the tray icon as template. - #[cfg(target_os = "macos")] - #[must_use] - pub fn with_icon_as_template(mut self, is_template: bool) -> Self { - self.icon_as_template = is_template; - self - } - - /// Sets the menu to show when the system tray is right clicked. - #[must_use] - pub fn with_menu(mut self, menu: menu::SystemTrayMenu) -> Self { - self.menu.replace(menu); - self - } -} - -/// Type of user attention requested on a window. -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] -#[serde(tag = "type")] -pub enum UserAttentionType { - /// ## Platform-specific - /// - **macOS:** Bounces the dock icon until the application is in focus. - /// - **Windows:** Flashes both the window and the taskbar button until the application is in focus. - Critical, - /// ## Platform-specific - /// - **macOS:** Bounces the dock icon once. - /// - **Windows:** Flashes the taskbar button until the application is in focus. - Informational, -} - -#[derive(Debug, thiserror::Error)] -#[non_exhaustive] -pub enum Error { - /// Failed to create webview. - #[error("failed to create webview: {0}")] - CreateWebview(Box), - /// Failed to create window. - #[error("failed to create window")] - CreateWindow, - /// The given window label is invalid. - #[error("Window labels must only include alphanumeric characters, `-`, `/`, `:` and `_`.")] - InvalidWindowLabel, - /// Failed to send message to webview. - #[error("failed to send message to the webview")] - FailedToSendMessage, - /// Failed to receive message from webview. - #[error("failed to receive message from webview")] - FailedToReceiveMessage, - /// Failed to serialize/deserialize. - #[error("JSON error: {0}")] - Json(#[from] serde_json::Error), - /// Encountered an error creating the app system tray. - #[cfg(feature = "system-tray")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] - #[error("error encountered during tray setup: {0}")] - SystemTray(Box), - /// Failed to load window icon. - #[error("invalid icon: {0}")] - InvalidIcon(Box), - /// Failed to get monitor on window operation. - #[error("failed to get monitor")] - FailedToGetMonitor, - /// Global shortcut error. - #[error(transparent)] - GlobalShortcut(Box), - #[error("Invalid header name: {0}")] - InvalidHeaderName(#[from] InvalidHeaderName), - #[error("Invalid header value: {0}")] - InvalidHeaderValue(#[from] InvalidHeaderValue), - #[error("Invalid uri: {0}")] - InvalidUri(#[from] InvalidUri), - #[error("Invalid status code: {0}")] - InvalidStatusCode(#[from] InvalidStatusCode), - #[error("Invalid method: {0}")] - InvalidMethod(#[from] InvalidMethod), - #[error("Infallible error, something went really wrong: {0}")] - Infallible(#[from] std::convert::Infallible), - #[error("the event loop has been closed")] - EventLoopClosed, -} - -/// Result type. -pub type Result = std::result::Result; - -/// Window icon. -#[derive(Debug, Clone)] -pub struct WindowIcon { - /// RGBA bytes of the icon. - pub rgba: Vec, - /// Icon width. - pub width: u32, - /// Icon height. - pub height: u32, -} - -/// A icon definition. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum TrayIcon { - /// Icon from file path. - File(PathBuf), - /// Icon from raw file bytes. - Raw(Vec), -} - -impl TrayIcon { - /// Converts the icon to a the expected system tray format. - /// We expect the code that passes the Icon enum to have already checked the platform. - #[cfg(target_os = "linux")] - pub fn into_platform_icon(self) -> PathBuf { - match self { - Self::File(path) => path, - Self::Raw(_) => { - panic!("linux requires the system menu icon to be a file path, not raw bytes.") - } - } - } - - /// Converts the icon to a the expected system tray format. - /// We expect the code that passes the Icon enum to have already checked the platform. - #[cfg(not(target_os = "linux"))] - pub fn into_platform_icon(self) -> Vec { - match self { - Self::Raw(r) => r, - Self::File(_) => { - panic!("non-linux system menu icons must be raw bytes, not a file path.") - } - } - } -} - -/// A type that can be used as an user event. -pub trait UserEvent: Debug + Clone + Send + 'static {} - -impl UserEvent for T {} - -/// Event triggered on the event loop run. -#[non_exhaustive] -pub enum RunEvent { - /// Event loop is exiting. - Exit, - /// Event loop is about to exit - ExitRequested { - /// Label of the last window managed by the runtime. - window_label: String, - tx: Sender, - }, - /// Window close was requested by the user. - CloseRequested { - /// The window label. - label: String, - /// A signal sender. If a `true` value is emitted, the window won't be closed. - signal_tx: Sender, - }, - /// Window closed. - WindowClose(String), - /// Application ready. - Ready, - /// Sent if the event loop is being resumed. - Resumed, - /// Emitted when all of the event loop’s input events have been processed and redraw processing is about to begin. - /// - /// This event is useful as a place to put your code that should be run after all state-changing events have been handled and you want to do stuff (updating state, performing calculations, etc) that happens as the “main body” of your event loop. - MainEventsCleared, - /// A custom event defined by the user. - UserEvent(T), -} - -/// Action to take when the event loop is about to exit -#[derive(Debug)] -pub enum ExitRequestedEventAction { - /// Prevent the event loop from exiting - Prevent, -} - -/// A system tray event. -#[derive(Debug)] -pub enum SystemTrayEvent { - MenuItemClick(u16), - LeftClick { - position: PhysicalPosition, - size: PhysicalSize, - }, - RightClick { - position: PhysicalPosition, - size: PhysicalSize, - }, - DoubleClick { - position: PhysicalPosition, - size: PhysicalSize, - }, -} - -/// Metadata for a runtime event loop iteration on `run_iteration`. -#[derive(Debug, Clone, Default)] -pub struct RunIteration { - pub window_count: usize, -} - -/// Application's activation policy. Corresponds to NSApplicationActivationPolicy. -#[cfg(target_os = "macos")] -#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] -#[non_exhaustive] -pub enum ActivationPolicy { - /// Corresponds to NSApplicationActivationPolicyRegular. - Regular, - /// Corresponds to NSApplicationActivationPolicyAccessory. - Accessory, - /// Corresponds to NSApplicationActivationPolicyProhibited. - Prohibited, -} - -/// A [`Send`] handle to the runtime. -pub trait RuntimeHandle: Debug + Clone + Send + Sync + Sized + 'static { - type Runtime: Runtime; - - /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop. - fn create_proxy(&self) -> >::EventLoopProxy; - - /// Create a new webview window. - fn create_window( - &self, - pending: PendingWindow, - ) -> crate::Result>; - - /// Run a task on the main thread. - fn run_on_main_thread(&self, f: F) -> crate::Result<()>; - - #[cfg(all(windows, feature = "system-tray"))] - #[cfg_attr(doc_cfg, doc(cfg(all(windows, feature = "system-tray"))))] - fn remove_system_tray(&self) -> crate::Result<()>; -} - -/// A global shortcut manager. -pub trait GlobalShortcutManager: Debug + Clone + Send + Sync { - /// Whether the application has registered the given `accelerator`. - fn is_registered(&self, accelerator: &str) -> crate::Result; - - /// Register a global shortcut of `accelerator`. - fn register( - &mut self, - accelerator: &str, - handler: F, - ) -> crate::Result<()>; - - /// Unregister all accelerators registered by the manager instance. - fn unregister_all(&mut self) -> crate::Result<()>; - - /// Unregister the provided `accelerator`. - fn unregister(&mut self, accelerator: &str) -> crate::Result<()>; -} - -/// Clipboard manager. -pub trait ClipboardManager: Debug + Clone + Send + Sync { - /// Writes the text into the clipboard as plain text. - fn write_text>(&mut self, text: T) -> Result<()>; - /// Read the content in the clipboard as plain text. - fn read_text(&self) -> Result>; -} - -pub trait EventLoopProxy: Debug + Clone + Send + Sync { - fn send_event(&self, event: T) -> Result<()>; -} - -/// The webview runtime interface. -pub trait Runtime: Debug + Sized + 'static { - /// The message dispatcher. - type Dispatcher: Dispatch; - /// The runtime handle type. - type Handle: RuntimeHandle; - /// The global shortcut manager type. - type GlobalShortcutManager: GlobalShortcutManager; - /// The clipboard manager type. - type ClipboardManager: ClipboardManager; - /// The tray handler type. - #[cfg(feature = "system-tray")] - type TrayHandler: menu::TrayHandle; - /// The proxy type. - type EventLoopProxy: EventLoopProxy; - - /// Creates a new webview runtime. Must be used on the main thread. - fn new() -> crate::Result; - - /// Creates a new webview runtime on any thread. - #[cfg(any(windows, target_os = "linux"))] - #[cfg_attr(doc_cfg, doc(cfg(any(windows, target_os = "linux"))))] - fn new_any_thread() -> crate::Result; - - /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop. - fn create_proxy(&self) -> Self::EventLoopProxy; - - /// Gets a runtime handle. - fn handle(&self) -> Self::Handle; - - /// Gets the global shortcut manager. - fn global_shortcut_manager(&self) -> Self::GlobalShortcutManager; - - /// Gets the clipboard manager. - fn clipboard_manager(&self) -> Self::ClipboardManager; - - /// Create a new webview window. - fn create_window( - &self, - pending: PendingWindow, - ) -> crate::Result>; - - /// Adds the icon to the system tray with the specified menu items. - #[cfg(feature = "system-tray")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] - fn system_tray(&self, system_tray: SystemTray) -> crate::Result; - - /// Registers a system tray event handler. - #[cfg(feature = "system-tray")] - #[cfg_attr(doc_cfg, doc(cfg(feature = "system-tray")))] - fn on_system_tray_event(&mut self, f: F) -> Uuid; - - /// Sets the activation policy for the application. It is set to `NSApplicationActivationPolicyRegular` by default. - #[cfg(target_os = "macos")] - #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] - fn set_activation_policy(&mut self, activation_policy: ActivationPolicy); - - /// Runs the one step of the webview runtime event loop and returns control flow to the caller. - fn run_iteration) + 'static>(&mut self, callback: F) -> RunIteration; - - /// Run the webview runtime. - fn run) + 'static>(self, callback: F); -} - -/// Webview dispatcher. A thread-safe handle to the webview API. -pub trait Dispatch: Debug + Clone + Send + Sync + Sized + 'static { - /// The runtime this [`Dispatch`] runs under. - type Runtime: Runtime; - - /// The winoow builder type. - type WindowBuilder: WindowBuilder; - - /// Run a task on the main thread. - fn run_on_main_thread(&self, f: F) -> crate::Result<()>; - - /// Registers a window event handler. - fn on_window_event(&self, f: F) -> Uuid; - - /// Registers a window event handler. - fn on_menu_event(&self, f: F) -> Uuid; - - #[cfg(any(debug_assertions, feature = "devtools"))] - fn open_devtools(&self); - - // GETTERS - - /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa. - fn scale_factor(&self) -> crate::Result; - - /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop. - fn inner_position(&self) -> crate::Result>; - - /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop. - fn outer_position(&self) -> crate::Result>; - - /// Returns the physical size of the window's client area. - /// - /// The client area is the content of the window, excluding the title bar and borders. - fn inner_size(&self) -> crate::Result>; - - /// Returns the physical size of the entire window. - /// - /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead. - fn outer_size(&self) -> crate::Result>; - - /// Gets the window's current fullscreen state. - fn is_fullscreen(&self) -> crate::Result; - - /// Gets the window's current maximized state. - fn is_maximized(&self) -> crate::Result; - - /// Gets the window’s current decoration state. - fn is_decorated(&self) -> crate::Result; - - /// Gets the window’s current resizable state. - fn is_resizable(&self) -> crate::Result; - - /// Gets the window's current vibility state. - fn is_visible(&self) -> crate::Result; - - /// Gets the window menu current visibility state. - fn is_menu_visible(&self) -> crate::Result; - - /// Returns the monitor on which the window currently resides. - /// - /// Returns None if current monitor can't be detected. - fn current_monitor(&self) -> crate::Result>; - - /// Returns the primary monitor of the system. - /// - /// Returns None if it can't identify any monitor as a primary one. - fn primary_monitor(&self) -> crate::Result>; - - /// Returns the list of all the monitors available on the system. - fn available_monitors(&self) -> crate::Result>; - - /// Returns the native handle that is used by this window. - #[cfg(windows)] - fn hwnd(&self) -> crate::Result; - - /// Returns the native handle that is used by this window. - #[cfg(target_os = "macos")] - fn ns_window(&self) -> crate::Result<*mut std::ffi::c_void>; - - /// Returns the `ApplicatonWindow` from gtk crate that is used by this window. - #[cfg(any( - target_os = "linux", - target_os = "dragonfly", - target_os = "freebsd", - target_os = "netbsd", - target_os = "openbsd" - ))] - fn gtk_window(&self) -> crate::Result; - - // SETTERS - - /// Centers the window. - fn center(&self) -> crate::Result<()>; - - /// Opens the dialog to prints the contents of the webview. - fn print(&self) -> crate::Result<()>; - - /// Requests user attention to the window. - /// - /// Providing `None` will unset the request for user attention. - fn request_user_attention(&self, request_type: Option) -> crate::Result<()>; - - /// Create a new webview window. - fn create_window( - &mut self, - pending: PendingWindow, - ) -> crate::Result>; - - /// Updates the window resizable flag. - fn set_resizable(&self, resizable: bool) -> crate::Result<()>; - - /// Updates the window title. - fn set_title>(&self, title: S) -> crate::Result<()>; - - /// Maximizes the window. - fn maximize(&self) -> crate::Result<()>; - - /// Unmaximizes the window. - fn unmaximize(&self) -> crate::Result<()>; - - /// Minimizes the window. - fn minimize(&self) -> crate::Result<()>; - - /// Unminimizes the window. - fn unminimize(&self) -> crate::Result<()>; - - /// Shows the window menu. - fn show_menu(&self) -> crate::Result<()>; - - /// Hides the window menu. - fn hide_menu(&self) -> crate::Result<()>; - - /// Shows the window. - fn show(&self) -> crate::Result<()>; - - /// Hides the window. - fn hide(&self) -> crate::Result<()>; - - /// Closes the window. - fn close(&self) -> crate::Result<()>; - - /// Updates the hasDecorations flag. - fn set_decorations(&self, decorations: bool) -> crate::Result<()>; - - /// Updates the window alwaysOnTop flag. - fn set_always_on_top(&self, always_on_top: bool) -> crate::Result<()>; - - /// Resizes the window. - fn set_size(&self, size: Size) -> crate::Result<()>; - - /// Updates the window min size. - fn set_min_size(&self, size: Option) -> crate::Result<()>; - - /// Updates the window max size. - fn set_max_size(&self, size: Option) -> crate::Result<()>; - - /// Updates the window position. - fn set_position(&self, position: Position) -> crate::Result<()>; - - /// Updates the window fullscreen state. - fn set_fullscreen(&self, fullscreen: bool) -> crate::Result<()>; - - /// Bring the window to front and focus. - fn set_focus(&self) -> crate::Result<()>; - - /// Updates the window icon. - fn set_icon(&self, icon: WindowIcon) -> crate::Result<()>; - - /// Whether to show the window icon in the task bar or not. - fn set_skip_taskbar(&self, skip: bool) -> crate::Result<()>; - - /// Starts dragging the window. - fn start_dragging(&self) -> crate::Result<()>; - - /// Executes javascript on the window this [`Dispatch`] represents. - fn eval_script>(&self, script: S) -> crate::Result<()>; - - /// Applies the specified `update` to the menu item associated with the given `id`. - fn update_menu_item(&self, id: u16, update: menu::MenuUpdate) -> crate::Result<()>; -} diff --git a/core/tauri-runtime/src/menu.rs b/core/tauri-runtime/src/menu.rs deleted file mode 100644 index 74b38101a12d..000000000000 --- a/core/tauri-runtime/src/menu.rs +++ /dev/null @@ -1,542 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use std::{ - collections::hash_map::DefaultHasher, - fmt, - hash::{Hash, Hasher}, -}; - -pub type MenuHash = u16; -pub type MenuId = String; -pub type MenuIdRef<'a> = &'a str; - -/// Named images defined by the system. -#[cfg(target_os = "macos")] -#[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] -#[derive(Debug, Clone)] -pub enum NativeImage { - /// An add item template image. - Add, - /// Advanced preferences toolbar icon for the preferences window. - Advanced, - /// A Bluetooth template image. - Bluetooth, - /// Bookmarks image suitable for a template. - Bookmarks, - /// A caution image. - Caution, - /// A color panel toolbar icon. - ColorPanel, - /// A column view mode template image. - ColumnView, - /// A computer icon. - Computer, - /// An enter full-screen mode template image. - EnterFullScreen, - /// Permissions for all users. - Everyone, - /// An exit full-screen mode template image. - ExitFullScreen, - /// A cover flow view mode template image. - FlowView, - /// A folder image. - Folder, - /// A burnable folder icon. - FolderBurnable, - /// A smart folder icon. - FolderSmart, - /// A link template image. - FollowLinkFreestanding, - /// A font panel toolbar icon. - FontPanel, - /// A `go back` template image. - GoLeft, - /// A `go forward` template image. - GoRight, - /// Home image suitable for a template. - Home, - /// An iChat Theater template image. - IChatTheater, - /// An icon view mode template image. - IconView, - /// An information toolbar icon. - Info, - /// A template image used to denote invalid data. - InvalidDataFreestanding, - /// A generic left-facing triangle template image. - LeftFacingTriangle, - /// A list view mode template image. - ListView, - /// A locked padlock template image. - LockLocked, - /// An unlocked padlock template image. - LockUnlocked, - /// A horizontal dash, for use in menus. - MenuMixedState, - /// A check mark template image, for use in menus. - MenuOnState, - /// A MobileMe icon. - MobileMe, - /// A drag image for multiple items. - MultipleDocuments, - /// A network icon. - Network, - /// A path button template image. - Path, - /// General preferences toolbar icon for the preferences window. - PreferencesGeneral, - /// A Quick Look template image. - QuickLook, - /// A refresh template image. - RefreshFreestanding, - /// A refresh template image. - Refresh, - /// A remove item template image. - Remove, - /// A reveal contents template image. - RevealFreestanding, - /// A generic right-facing triangle template image. - RightFacingTriangle, - /// A share view template image. - Share, - /// A slideshow template image. - Slideshow, - /// A badge for a `smart` item. - SmartBadge, - /// Small green indicator, similar to iChat’s available image. - StatusAvailable, - /// Small clear indicator. - StatusNone, - /// Small yellow indicator, similar to iChat’s idle image. - StatusPartiallyAvailable, - /// Small red indicator, similar to iChat’s unavailable image. - StatusUnavailable, - /// A stop progress template image. - StopProgressFreestanding, - /// A stop progress button template image. - StopProgress, - - /// An image of the empty trash can. - TrashEmpty, - /// An image of the full trash can. - TrashFull, - /// Permissions for a single user. - User, - /// User account toolbar icon for the preferences window. - UserAccounts, - /// Permissions for a group of users. - UserGroup, - /// Permissions for guests. - UserGuest, -} - -#[derive(Debug, Clone)] -pub enum MenuUpdate { - /// Modifies the enabled state of the menu item. - SetEnabled(bool), - /// Modifies the title (label) of the menu item. - SetTitle(String), - /// Modifies the selected state of the menu item. - SetSelected(bool), - /// Update native image. - #[cfg(target_os = "macos")] - #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] - SetNativeImage(NativeImage), -} - -pub trait TrayHandle: fmt::Debug + Clone + Send + Sync { - fn set_icon(&self, icon: crate::TrayIcon) -> crate::Result<()>; - fn set_menu(&self, menu: crate::menu::SystemTrayMenu) -> crate::Result<()>; - fn update_item(&self, id: u16, update: MenuUpdate) -> crate::Result<()>; - #[cfg(target_os = "macos")] - fn set_icon_as_template(&self, is_template: bool) -> crate::Result<()>; -} - -/// A window menu. -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct Menu { - pub items: Vec, -} - -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct Submenu { - pub title: String, - pub enabled: bool, - pub inner: Menu, -} - -impl Submenu { - /// Creates a new submenu with the given title and menu items. - pub fn new>(title: S, menu: Menu) -> Self { - Self { - title: title.into(), - enabled: true, - inner: menu, - } - } -} - -impl Menu { - /// Creates a new window menu. - pub fn new() -> Self { - Default::default() - } - - /// Creates a new window menu with the given items. - /// - /// # Examples - /// ``` - /// # use tauri_runtime::menu::{Menu, MenuItem, CustomMenuItem, Submenu}; - /// Menu::with_items([ - /// MenuItem::SelectAll.into(), - /// #[cfg(target_os = "macos")] - /// MenuItem::Redo.into(), - /// CustomMenuItem::new("toggle", "Toggle visibility").into(), - /// Submenu::new("View", Menu::new()).into(), - /// ]); - /// ``` - pub fn with_items>(items: I) -> Self { - Self { - items: items.into_iter().collect(), - } - } - - /// Adds the custom menu item to the menu. - #[must_use] - pub fn add_item(mut self, item: CustomMenuItem) -> Self { - self.items.push(MenuEntry::CustomItem(item)); - self - } - - /// Adds a native item to the menu. - #[must_use] - pub fn add_native_item(mut self, item: MenuItem) -> Self { - self.items.push(MenuEntry::NativeItem(item)); - self - } - - /// Adds an entry with submenu. - #[must_use] - pub fn add_submenu(mut self, submenu: Submenu) -> Self { - self.items.push(MenuEntry::Submenu(submenu)); - self - } -} - -/// A custom menu item. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct CustomMenuItem { - pub id: MenuHash, - pub id_str: MenuId, - pub title: String, - pub keyboard_accelerator: Option, - pub enabled: bool, - pub selected: bool, - #[cfg(target_os = "macos")] - pub native_image: Option, -} - -impl CustomMenuItem { - /// Create new custom menu item. - pub fn new, T: Into>(id: I, title: T) -> Self { - let id_str = id.into(); - Self { - id: Self::hash(&id_str), - id_str, - title: title.into(), - keyboard_accelerator: None, - enabled: true, - selected: false, - #[cfg(target_os = "macos")] - native_image: None, - } - } - - /// Assign a keyboard shortcut to the menu action. - #[must_use] - pub fn accelerator>(mut self, accelerator: T) -> Self { - self.keyboard_accelerator.replace(accelerator.into()); - self - } - - #[cfg(target_os = "macos")] - #[cfg_attr(doc_cfg, doc(cfg(target_os = "macos")))] - #[must_use] - /// A native image do render on the menu item. - pub fn native_image(mut self, image: NativeImage) -> Self { - self.native_image.replace(image); - self - } - - /// Mark the item as disabled. - #[must_use] - pub fn disabled(mut self) -> Self { - self.enabled = false; - self - } - - /// Mark the item as selected. - #[must_use] - pub fn selected(mut self) -> Self { - self.selected = true; - self - } - - fn hash(id: &str) -> MenuHash { - let mut hasher = DefaultHasher::new(); - id.hash(&mut hasher); - hasher.finish() as MenuHash - } -} - -/// A system tray menu. -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct SystemTrayMenu { - pub items: Vec, -} - -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct SystemTraySubmenu { - pub title: String, - pub enabled: bool, - pub inner: SystemTrayMenu, -} - -impl SystemTraySubmenu { - /// Creates a new submenu with the given title and menu items. - pub fn new>(title: S, menu: SystemTrayMenu) -> Self { - Self { - title: title.into(), - enabled: true, - inner: menu, - } - } -} - -impl SystemTrayMenu { - /// Creates a new system tray menu. - pub fn new() -> Self { - Default::default() - } - - /// Adds the custom menu item to the system tray menu. - #[must_use] - pub fn add_item(mut self, item: CustomMenuItem) -> Self { - self.items.push(SystemTrayMenuEntry::CustomItem(item)); - self - } - - /// Adds a native item to the system tray menu. - #[must_use] - pub fn add_native_item(mut self, item: SystemTrayMenuItem) -> Self { - self.items.push(SystemTrayMenuEntry::NativeItem(item)); - self - } - - /// Adds an entry with submenu. - #[must_use] - pub fn add_submenu(mut self, submenu: SystemTraySubmenu) -> Self { - self.items.push(SystemTrayMenuEntry::Submenu(submenu)); - self - } -} - -/// An entry on the system tray menu. -#[derive(Debug, Clone)] -pub enum SystemTrayMenuEntry { - /// A custom item. - CustomItem(CustomMenuItem), - /// A native item. - NativeItem(SystemTrayMenuItem), - /// An entry with submenu. - Submenu(SystemTraySubmenu), -} - -/// System tray menu item. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum SystemTrayMenuItem { - /// A separator. - Separator, -} - -/// An entry on the system tray menu. -#[derive(Debug, Clone)] -pub enum MenuEntry { - /// A custom item. - CustomItem(CustomMenuItem), - /// A native item. - NativeItem(MenuItem), - /// An entry with submenu. - Submenu(Submenu), -} - -impl From for MenuEntry { - fn from(item: CustomMenuItem) -> Self { - Self::CustomItem(item) - } -} - -impl From for MenuEntry { - fn from(item: MenuItem) -> Self { - Self::NativeItem(item) - } -} - -impl From for MenuEntry { - fn from(submenu: Submenu) -> Self { - Self::Submenu(submenu) - } -} - -/// A menu item, bound to a pre-defined action or `Custom` emit an event. Note that status bar only -/// supports `Custom` menu item variants. And on the menu bar, some platforms might not support some -/// of the variants. Unsupported variant will be no-op on such platform. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum MenuItem { - /// Shows a standard "About" item - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - About(String), - - /// A standard "hide the app" menu item. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Hide, - - /// A standard "Services" menu item. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - Services, - - /// A "hide all other windows" menu item. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - HideOthers, - - /// A menu item to show all the windows for this app. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - ShowAll, - - /// Close the current window. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - CloseWindow, - - /// A "quit this app" menu icon. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Quit, - - /// A menu item for enabling copying (often text) from responders. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Copy, - - /// A menu item for enabling cutting (often text) from responders. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Cut, - - /// An "undo" menu item; particularly useful for supporting the cut/copy/paste/undo lifecycle - /// of events. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - Undo, - - /// An "redo" menu item; particularly useful for supporting the cut/copy/paste/undo lifecycle - /// of events. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - Redo, - - /// A menu item for selecting all (often text) from responders. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - SelectAll, - - /// A menu item for pasting (often text) into responders. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Paste, - - /// A standard "enter full screen" item. - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - EnterFullScreen, - - /// An item for minimizing the window with the standard system controls. - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Minimize, - - /// An item for instructing the app to zoom - /// - /// ## Platform-specific - /// - /// - **Windows / Linux / Android / iOS:** Unsupported - /// - Zoom, - - /// Represents a Separator - /// - /// ## Platform-specific - /// - /// - **Windows / Android / iOS:** Unsupported - /// - Separator, -} diff --git a/core/tauri-runtime/src/webview.rs b/core/tauri-runtime/src/webview.rs deleted file mode 100644 index 6409b4b5875a..000000000000 --- a/core/tauri-runtime/src/webview.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! Items specific to the [`Runtime`](crate::Runtime)'s webview. - -use crate::{menu::Menu, window::DetachedWindow, WindowIcon}; - -use tauri_utils::config::{WindowConfig, WindowUrl}; - -#[cfg(windows)] -use windows::Win32::Foundation::HWND; - -use std::{fmt, path::PathBuf}; - -/// The attributes used to create an webview. -#[derive(Debug, Clone)] -pub struct WebviewAttributes { - pub url: WindowUrl, - pub initialization_scripts: Vec, - pub data_directory: Option, - pub file_drop_handler_enabled: bool, - pub clipboard: bool, -} - -impl WebviewAttributes { - /// Initializes the default attributes for a webview. - pub fn new(url: WindowUrl) -> Self { - Self { - url, - initialization_scripts: Vec::new(), - data_directory: None, - file_drop_handler_enabled: true, - clipboard: false, - } - } - - /// Sets the init script. - #[must_use] - pub fn initialization_script(mut self, script: &str) -> Self { - self.initialization_scripts.push(script.to_string()); - self - } - - /// Data directory for the webview. - #[must_use] - pub fn data_directory(mut self, data_directory: PathBuf) -> Self { - self.data_directory.replace(data_directory); - self - } - - /// Disables the file drop handler. This is required to use drag and drop APIs on the front end on Windows. - #[must_use] - pub fn disable_file_drop_handler(mut self) -> Self { - self.file_drop_handler_enabled = false; - self - } - - /// Enables clipboard access for the page rendered on **Linux** and **Windows**. - /// - /// **macOS** doesn't provide such method and is always enabled by default, - /// but you still need to add menu item accelerators to use shortcuts. - #[must_use] - pub fn enable_clipboard_access(mut self) -> Self { - self.clipboard = true; - self - } -} - -/// Do **NOT** implement this trait except for use in a custom [`Runtime`](crate::Runtime). -/// -/// This trait is separate from [`WindowBuilder`] to prevent "accidental" implementation. -pub trait WindowBuilderBase: fmt::Debug + Clone + Sized {} - -/// A builder for all attributes related to a single webview. -/// -/// This trait is only meant to be implemented by a custom [`Runtime`](crate::Runtime) -/// and not by applications. -pub trait WindowBuilder: WindowBuilderBase { - /// Initializes a new window attributes builder. - fn new() -> Self; - - /// Initializes a new webview builder from a [`WindowConfig`] - fn with_config(config: WindowConfig) -> Self; - - /// Sets the menu for the window. - #[must_use] - fn menu(self, menu: Menu) -> Self; - - /// Show window in the center of the screen. - #[must_use] - fn center(self) -> Self; - - /// The initial position of the window's. - #[must_use] - fn position(self, x: f64, y: f64) -> Self; - - /// Window size. - #[must_use] - fn inner_size(self, width: f64, height: f64) -> Self; - - /// Window min inner size. - #[must_use] - fn min_inner_size(self, min_width: f64, min_height: f64) -> Self; - - /// Window max inner size. - #[must_use] - fn max_inner_size(self, max_width: f64, max_height: f64) -> Self; - - /// Whether the window is resizable or not. - #[must_use] - fn resizable(self, resizable: bool) -> Self; - - /// The title of the window in the title bar. - #[must_use] - fn title>(self, title: S) -> Self; - - /// Whether to start the window in fullscreen or not. - #[must_use] - fn fullscreen(self, fullscreen: bool) -> Self; - - /// Whether the window will be initially hidden or focused. - #[must_use] - fn focus(self) -> Self; - - /// Whether the window should be maximized upon creation. - #[must_use] - fn maximized(self, maximized: bool) -> Self; - - /// Whether the window should be immediately visible upon creation. - #[must_use] - fn visible(self, visible: bool) -> Self; - - /// Whether the the window should be transparent. If this is true, writing colors - /// with alpha values different than `1.0` will produce a transparent window. - #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] - #[cfg_attr( - doc_cfg, - doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api"))) - )] - #[must_use] - fn transparent(self, transparent: bool) -> Self; - - /// Whether the window should have borders and bars. - #[must_use] - fn decorations(self, decorations: bool) -> Self; - - /// Whether the window should always be on top of other windows. - #[must_use] - fn always_on_top(self, always_on_top: bool) -> Self; - - /// Sets the window icon. - fn icon(self, icon: WindowIcon) -> crate::Result; - - /// Sets whether or not the window icon should be added to the taskbar. - #[must_use] - fn skip_taskbar(self, skip: bool) -> Self; - - /// Sets a parent to the window to be created. - /// - /// A child window has the WS_CHILD style and is confined to the client area of its parent window. - /// - /// For more information, see - #[cfg(windows)] - #[must_use] - fn parent_window(self, parent: HWND) -> Self; - - /// Set an owner to the window to be created. - /// - /// From MSDN: - /// - An owned window is always above its owner in the z-order. - /// - The system automatically destroys an owned window when its owner is destroyed. - /// - An owned window is hidden when its owner is minimized. - /// - /// For more information, see - #[cfg(windows)] - #[must_use] - fn owner_window(self, owner: HWND) -> Self; - - /// Whether the icon was set or not. - fn has_icon(&self) -> bool; - - /// Gets the window menu. - fn get_menu(&self) -> Option<&Menu>; -} - -/// IPC handler. -pub type WebviewIpcHandler = Box, String) + Send>; diff --git a/core/tauri-runtime/src/window.rs b/core/tauri-runtime/src/window.rs deleted file mode 100644 index dbcf5576a2ee..000000000000 --- a/core/tauri-runtime/src/window.rs +++ /dev/null @@ -1,267 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -//! A layer between raw [`Runtime`] webview windows and Tauri. - -use crate::{ - http::{Request as HttpRequest, Response as HttpResponse}, - menu::{Menu, MenuEntry, MenuHash, MenuId}, - webview::{WebviewAttributes, WebviewIpcHandler}, - Dispatch, Runtime, UserEvent, WindowBuilder, -}; -use serde::Serialize; -use tauri_utils::config::WindowConfig; - -use std::{ - collections::{HashMap, HashSet}, - hash::{Hash, Hasher}, - path::PathBuf, - sync::{mpsc::Sender, Arc, Mutex}, -}; - -type UriSchemeProtocol = - dyn Fn(&HttpRequest) -> Result> + Send + Sync + 'static; - -/// UI scaling utilities. -pub mod dpi; - -/// An event from a window. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum WindowEvent { - /// The size of the window has changed. Contains the client area's new dimensions. - Resized(dpi::PhysicalSize), - /// The position of the window has changed. Contains the window's new position. - Moved(dpi::PhysicalPosition), - /// The window has been requested to close. - CloseRequested { - /// The window label. - label: String, - /// A signal sender. If a `true` value is emitted, the window won't be closed. - signal_tx: Sender, - }, - /// The window has been destroyed. - Destroyed, - /// The window gained or lost focus. - /// - /// The parameter is true if the window has gained focus, and false if it has lost focus. - Focused(bool), - /// The window's scale factor has changed. - /// - /// The following user actions can cause DPI changes: - /// - /// - Changing the display's resolution. - /// - Changing the display's scale factor (e.g. in Control Panel on Windows). - /// - Moving the window to a display with a different scale factor. - ScaleFactorChanged { - /// The new scale factor. - scale_factor: f64, - /// The window inner size. - new_inner_size: dpi::PhysicalSize, - }, - /// An event associated with the file drop action. - FileDrop(FileDropEvent), -} - -/// The file drop event payload. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub enum FileDropEvent { - /// The file(s) have been dragged onto the window, but have not been dropped yet. - Hovered(Vec), - /// The file(s) have been dropped onto the window. - Dropped(Vec), - /// The file drop was aborted. - Cancelled, -} - -/// A menu event. -#[derive(Debug, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct MenuEvent { - pub menu_item_id: u16, -} - -fn get_menu_ids(map: &mut HashMap, menu: &Menu) { - for item in &menu.items { - match item { - MenuEntry::CustomItem(c) => { - map.insert(c.id, c.id_str.clone()); - } - MenuEntry::Submenu(s) => get_menu_ids(map, &s.inner), - _ => {} - } - } -} - -/// A webview window that has yet to be built. -pub struct PendingWindow> { - /// The label that the window will be named. - pub label: String, - - /// The [`WindowBuilder`] that the window will be created with. - pub window_builder: >::WindowBuilder, - - /// The [`WebviewAttributes`] that the webview will be created with. - pub webview_attributes: WebviewAttributes, - - pub uri_scheme_protocols: HashMap>, - - /// How to handle IPC calls on the webview window. - pub ipc_handler: Option>, - - /// The resolved URL to load on the webview. - pub url: String, - - /// Maps runtime id to a string menu id. - pub menu_ids: Arc>>, - - /// A HashMap mapping JS event names with associated listener ids. - pub js_event_listeners: Arc>>>, -} - -pub fn is_label_valid(label: &str) -> bool { - label - .chars() - .all(|c| char::is_alphanumeric(c) || c == '-' || c == '/' || c == ':' || c == '_') -} - -pub fn assert_label_is_valid(label: &str) { - assert!( - is_label_valid(label), - "Window label must include only alphanumeric characters, `-`, `/`, `:` and `_`." - ); -} - -impl> PendingWindow { - /// Create a new [`PendingWindow`] with a label and starting url. - pub fn new( - window_builder: >::WindowBuilder, - webview_attributes: WebviewAttributes, - label: impl Into, - ) -> crate::Result { - let mut menu_ids = HashMap::new(); - if let Some(menu) = window_builder.get_menu() { - get_menu_ids(&mut menu_ids, menu); - } - let label = label.into(); - if !is_label_valid(&label) { - Err(crate::Error::InvalidWindowLabel) - } else { - Ok(Self { - window_builder, - webview_attributes, - uri_scheme_protocols: Default::default(), - label, - ipc_handler: None, - url: "tauri://localhost".to_string(), - menu_ids: Arc::new(Mutex::new(menu_ids)), - js_event_listeners: Default::default(), - }) - } - } - - /// Create a new [`PendingWindow`] from a [`WindowConfig`] with a label and starting url. - pub fn with_config( - window_config: WindowConfig, - webview_attributes: WebviewAttributes, - label: impl Into, - ) -> crate::Result { - let window_builder = - <>::WindowBuilder>::with_config(window_config); - let mut menu_ids = HashMap::new(); - if let Some(menu) = window_builder.get_menu() { - get_menu_ids(&mut menu_ids, menu); - } - let label = label.into(); - if !is_label_valid(&label) { - Err(crate::Error::InvalidWindowLabel) - } else { - Ok(Self { - window_builder, - webview_attributes, - uri_scheme_protocols: Default::default(), - label, - ipc_handler: None, - url: "tauri://localhost".to_string(), - menu_ids: Arc::new(Mutex::new(menu_ids)), - js_event_listeners: Default::default(), - }) - } - } - - #[must_use] - pub fn set_menu(mut self, menu: Menu) -> Self { - let mut menu_ids = HashMap::new(); - get_menu_ids(&mut menu_ids, &menu); - *self.menu_ids.lock().unwrap() = menu_ids; - self.window_builder = self.window_builder.menu(menu); - self - } - - pub fn register_uri_scheme_protocol< - N: Into, - H: Fn(&HttpRequest) -> Result> + Send + Sync + 'static, - >( - &mut self, - uri_scheme: N, - protocol: H, - ) { - let uri_scheme = uri_scheme.into(); - self - .uri_scheme_protocols - .insert(uri_scheme, Box::new(move |data| (protocol)(data))); - } -} - -/// Key for a JS event listener. -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct JsEventListenerKey { - /// The associated window label. - pub window_label: Option, - /// The event name. - pub event: String, -} - -/// A webview window that is not yet managed by Tauri. -#[derive(Debug)] -pub struct DetachedWindow> { - /// Name of the window - pub label: String, - - /// The [`Dispatch`](crate::Dispatch) associated with the window. - pub dispatcher: R::Dispatcher, - - /// Maps runtime id to a string menu id. - pub menu_ids: Arc>>, - - /// A HashMap mapping JS event names with associated listener ids. - pub js_event_listeners: Arc>>>, -} - -impl> Clone for DetachedWindow { - fn clone(&self) -> Self { - Self { - label: self.label.clone(), - dispatcher: self.dispatcher.clone(), - menu_ids: self.menu_ids.clone(), - js_event_listeners: self.js_event_listeners.clone(), - } - } -} - -impl> Hash for DetachedWindow { - /// Only use the [`DetachedWindow`]'s label to represent its hash. - fn hash(&self, state: &mut H) { - self.label.hash(state) - } -} - -impl> Eq for DetachedWindow {} -impl> PartialEq for DetachedWindow { - /// Only use the [`DetachedWindow`]'s label to compare equality. - fn eq(&self, other: &Self) -> bool { - self.label.eq(&other.label) - } -} diff --git a/core/tauri-runtime/src/window/dpi.rs b/core/tauri-runtime/src/window/dpi.rs deleted file mode 100644 index 5a91205108b2..000000000000 --- a/core/tauri-runtime/src/window/dpi.rs +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use serde::{Deserialize, Serialize}; - -fn validate_scale_factor(scale_factor: f64) -> bool { - scale_factor.is_sign_positive() && scale_factor.is_normal() -} - -/// A pixel definition. Must be created from a `f64` value. -pub trait Pixel: Copy + Into { - /// Creates the pixel from the `f64` value. - fn from_f64(f: f64) -> Self; - /// Casts a pixel. - fn cast(self) -> P { - P::from_f64(self.into()) - } -} - -impl Pixel for u8 { - fn from_f64(f: f64) -> Self { - f.round() as u8 - } -} - -impl Pixel for u16 { - fn from_f64(f: f64) -> Self { - f.round() as u16 - } -} - -impl Pixel for u32 { - fn from_f64(f: f64) -> Self { - f.round() as u32 - } -} - -impl Pixel for i8 { - fn from_f64(f: f64) -> Self { - f.round() as i8 - } -} - -impl Pixel for i16 { - fn from_f64(f: f64) -> Self { - f.round() as i16 - } -} - -impl Pixel for i32 { - fn from_f64(f: f64) -> Self { - f.round() as i32 - } -} - -impl Pixel for f32 { - fn from_f64(f: f64) -> Self { - f as f32 - } -} - -impl Pixel for f64 { - #[allow(clippy::wrong_self_convention)] - fn from_f64(f: f64) -> Self { - f - } -} - -/// A position represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] -pub struct PhysicalPosition

{ - /// Vertical axis value. - pub x: P, - /// Horizontal axis value. - pub y: P, -} - -impl PhysicalPosition

{ - /// Converts the physical position to a logical one, using the scale factor. - #[inline] - pub fn to_logical(self, scale_factor: f64) -> LogicalPosition { - assert!(validate_scale_factor(scale_factor)); - let x = self.x.into() / scale_factor; - let y = self.y.into() / scale_factor; - LogicalPosition { x, y }.cast() - } -} - -/// A position represented in logical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] -pub struct LogicalPosition

{ - /// Vertical axis value. - pub x: P, - /// Horizontal axis value. - pub y: P, -} - -impl LogicalPosition { - /// Casts the logical size to another pixel type. - #[inline] - pub fn cast(&self) -> LogicalPosition { - LogicalPosition { - x: self.x.cast(), - y: self.y.cast(), - } - } -} - -/// A position that's either physical or logical. -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] -#[serde(tag = "type", content = "data")] -pub enum Position { - /// Physical position. - Physical(PhysicalPosition), - /// Logical position. - Logical(LogicalPosition), -} - -/// A size represented in physical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] -pub struct PhysicalSize { - /// Width. - pub width: T, - /// Height. - pub height: T, -} - -impl PhysicalSize { - /// Converts the physical size to a logical one, applying the scale factor. - #[inline] - pub fn to_logical(self, scale_factor: f64) -> LogicalSize { - assert!(validate_scale_factor(scale_factor)); - let width = self.width.into() / scale_factor; - let height = self.height.into() / scale_factor; - LogicalSize { width, height }.cast() - } -} - -/// A size represented in logical pixels. -#[derive(Debug, Copy, Clone, Eq, PartialEq, Default, Hash, Serialize, Deserialize)] -pub struct LogicalSize { - /// Width. - pub width: T, - /// Height. - pub height: T, -} - -impl LogicalSize { - /// Casts the logical size to another pixel type. - #[inline] - pub fn cast(&self) -> LogicalSize { - LogicalSize { - width: self.width.cast(), - height: self.height.cast(), - } - } -} - -/// A size that's either physical or logical. -#[derive(Debug, Copy, Clone, PartialEq, Serialize, Deserialize)] -#[serde(tag = "type", content = "data")] -pub enum Size { - /// Physical size. - Physical(PhysicalSize), - /// Logical size. - Logical(LogicalSize), -} diff --git a/core/tauri-utils/.license_template b/core/tauri-utils/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/core/tauri-utils/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/core/tauri-utils/CHANGELOG.md b/core/tauri-utils/CHANGELOG.md deleted file mode 100644 index 540977346bb0..000000000000 --- a/core/tauri-utils/CHANGELOG.md +++ /dev/null @@ -1,172 +0,0 @@ -# Changelog - -## \[1.0.0-rc.3] - -- Use `is_symlink` API compatible with Rust v1.57 instead of std/fs/struct.Metadata.html#method.is_symlink. - - [73388119](https://www.github.com/tauri-apps/tauri/commit/73388119e653e7902b19beef2ab6d7c5f8a7b83a) use older symlink check function ([#3579](https://www.github.com/tauri-apps/tauri/pull/3579)) on 2022-03-01 - -## \[1.0.0-rc.2] - -- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. - - [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17 - -## \[1.0.0-rc.1] - -- Change default value for the `freezePrototype` configuration to `false`. - - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 - -## \[1.0.0-rc.0] - -- The `allowlist` configuration now includes a `clipboard` object, controlling the exposure of the `writeText` and `readText` APIs. - - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 -- The dialog allowlist now includes flags for the `message`, `ask` and `confirm` APIs. - - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 -- The `allowlist` configuration now includes a `process` object, controlling the exposure of the `relaunch` and `exit` APIs. - - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 -- The `window` allowlist now includes options to enable all window modification APIs: `center`, `close`, `create`, `hide`, `maximize`, `minimize`, `print`, `requestUserAttention`, `setAlwaysOnTop`, `setDecorations`, `setFocus`, `setFullscreen`, `setIcon`, `setMaxSize`, `setMinSize`, `setPosition`, `setResizable`, `setSize`, `setSkipTaskbar`, `setTitle`, `show`, `startDragging`, `unmaximize` and `unminimize`. - - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 -- Added `asset` allowlist configuration, which enables the `asset` protocol and defines it access scope. - - [7920ff14](https://www.github.com/tauri-apps/tauri/commit/7920ff14e6424079c48ea5645d9aa13e7a272b87) feat: scope the `fs` API and the `asset` protocol \[TRI-026] \[TRI-010] \[TRI-011] ([#10](https://www.github.com/tauri-apps/tauri/pull/10)) on 2022-01-09 -- Change `CliArg` numeric types from `u64` to `usize`. - - [1f988535](https://www.github.com/tauri-apps/tauri/commit/1f98853573a837dd0cfc2161b206a5033ec2da5e) chore(deps) Update Tauri Core ([#2480](https://www.github.com/tauri-apps/tauri/pull/2480)) on 2021-08-24 -- Apply `nonce` to `script` and `style` tags and set them on the `CSP` (`script-src` and `style-src` fetch directives). - - [cf54dcf9](https://www.github.com/tauri-apps/tauri/commit/cf54dcf9c81730e42c9171daa9c8aa474c95b522) feat: improve `CSP` security with nonces and hashes, add `devCsp` \[TRI-004] ([#8](https://www.github.com/tauri-apps/tauri/pull/8)) on 2022-01-09 -- The path returned from `tauri::api::process::current_binary` is now cached when loading the binary. - - [7c3db7a3](https://www.github.com/tauri-apps/tauri/commit/7c3db7a3811fd4de3e71c78cfd00894fa51ab786) cache current binary path much sooner ([#45](https://www.github.com/tauri-apps/tauri/pull/45)) on 2022-02-01 -- Added `dev_csp` to the `security` configuration object. - - [cf54dcf9](https://www.github.com/tauri-apps/tauri/commit/cf54dcf9c81730e42c9171daa9c8aa474c95b522) feat: improve `CSP` security with nonces and hashes, add `devCsp` \[TRI-004] ([#8](https://www.github.com/tauri-apps/tauri/pull/8)) on 2022-01-09 -- Fixes resource directory resolution on Linux. - - [1a28904b](https://www.github.com/tauri-apps/tauri/commit/1a28904b8ebea92e143d5dc21ebd209e9edec531) fix(core): resource path resolution on Linux, closes [#2493](https://www.github.com/tauri-apps/tauri/pull/2493) on 2021-08-22 -- Allow using a fixed version for the Webview2 runtime via the `tauri > bundle > windows > webviewFixedRuntimePath` config option. - - [85df94f2](https://www.github.com/tauri-apps/tauri/commit/85df94f2b0d40255812b42c5e32a70c4b45392df) feat(core): config for fixed webview2 runtime version path ([#27](https://www.github.com/tauri-apps/tauri/pull/27)) on 2021-11-02 -- The updater `pubkey` is now a required field for security reasons. Sign your updates with the `tauri signer` command. - - [d95cc831](https://www.github.com/tauri-apps/tauri/commit/d95cc83105dda52df7514e30e54f3676cdb374ee) feat: enforce updater public key \[TRI-015] ([#42](https://www.github.com/tauri-apps/tauri/pull/42)) on 2022-01-09 -- Added the `isolation` pattern. - - [d5d6d2ab](https://www.github.com/tauri-apps/tauri/commit/d5d6d2abc17cd89c3a079d2ce01581193469dbc0) Isolation Pattern ([#43](https://www.github.com/tauri-apps/tauri/pull/43)) Co-authored-by: Ngo Iok Ui (Wu Yu Wei) Co-authored-by: Lucas Fernandes Nogueira on 2022-01-17 -- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. - -Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: - -1. Check if `tauri.conf.json` exists - a. Parse it with `serde_json` - b. Parse it with `json5` if `serde_json` fails - c. Return original `serde_json` error if all above steps failed -2. Check if `tauri.conf.json5` exists - a. Parse it with `json5` - b. Return error if all above steps failed -3. Return error if all above steps failed - -- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 -- Move the copying of resources and sidecars from `cli.rs` to `tauri-build` so using the Cargo CLI directly processes the files for the application execution in development. - - [5eb72c24](https://www.github.com/tauri-apps/tauri/commit/5eb72c24deddf5a01093bea96b90c0d8806afc3f) refactor: copy resources and sidecars on the Cargo build script ([#3357](https://www.github.com/tauri-apps/tauri/pull/3357)) on 2022-02-08 -- **Breaking change**\* Remove default webview window when `tauri.conf.json > tauri > windows` is not set. - - [c119060e](https://www.github.com/tauri-apps/tauri/commit/c119060e3d9a5a824639fb6b3c45a87e7a62e4e2) refactor(core): empty default value for config > tauri > windows ([#3380](https://www.github.com/tauri-apps/tauri/pull/3380)) on 2022-02-10 -- The minimum Rust version is now `1.56`. - - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 -- Adds `scope` glob array config under `tauri > allowlist > fs`. - Adds `assetScope` glob array config under `tauri > allowlist > protocol`. - Adds `scope` URL array config under `tauri > allowlist > http`. - - [7920ff14](https://www.github.com/tauri-apps/tauri/commit/7920ff14e6424079c48ea5645d9aa13e7a272b87) feat: scope the `fs` API and the `asset` protocol \[TRI-026] \[TRI-010] \[TRI-011] ([#10](https://www.github.com/tauri-apps/tauri/pull/10)) on 2022-01-09 - - [0ad1c651](https://www.github.com/tauri-apps/tauri/commit/0ad1c6515f696fadefddbf133a9561836b3d5934) feat(core): add `http` allowlist scope \[TRI-008] ([#24](https://www.github.com/tauri-apps/tauri/pull/24)) on 2021-10-29 -- The `shell` allowlist now includes a `sidecar` flag, which enables the use of the `shell` API to execute sidecars. - - [eed01728](https://www.github.com/tauri-apps/tauri/commit/eed017287fed2ade689af4268e8b63b9c9f2e585) feat(core): add `shell > sidecar` allowlist and `process` feature flag \[TRI-037] ([#18](https://www.github.com/tauri-apps/tauri/pull/18)) on 2021-10-24 -- Force updater endpoint URL to use `https` on release builds. - - [c077f449](https://www.github.com/tauri-apps/tauri/commit/c077f449270cffbf7956b1af81e1fb237ebf564a) feat: force endpoint URL to use https on release \[TRI-015] ([#41](https://www.github.com/tauri-apps/tauri/pull/41)) on 2022-01-09 - -## \[1.0.0-beta.3] - -- Fixes minimum window height being used as maximum height. - - [e3f99165](https://www.github.com/tauri-apps/tauri/commit/e3f9916526b226866137cb663e5cafab2b6a0e01) fix(core) minHeight being used as maxHeight ([#2247](https://www.github.com/tauri-apps/tauri/pull/2247)) on 2021-07-19 -- Implement `Debug` on public API structs and enums. - - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 -- Keep original value on `config > package > productName` on Linux (previously converted to kebab-case). - - [3f039cb8](https://www.github.com/tauri-apps/tauri/commit/3f039cb8a308b0f18deaa37d7cfb1cc50d308d0e) fix: keep original `productName` for .desktop `Name` field, closes [#2295](https://www.github.com/tauri-apps/tauri/pull/2295) ([#2384](https://www.github.com/tauri-apps/tauri/pull/2384)) on 2021-08-10 -- Inject the invoke key on regular `` tags. - - [d0142e87](https://www.github.com/tauri-apps/tauri/commit/d0142e87ddf5231fd46e2cbe4769bb16f3fe01e9) fix(core): invoke key injection on regular JS scripts, closes [#2342](https://www.github.com/tauri-apps/tauri/pull/2342) ([#2344](https://www.github.com/tauri-apps/tauri/pull/2344)) on 2021-08-03 - -## \[1.0.0-beta.2] - -- Inject invoke key on `script` tags with `type="module"`. - - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on `` tags. - - [d0142e87](https://www.github.com/tauri-apps/tauri/commit/d0142e87ddf5231fd46e2cbe4769bb16f3fe01e9) fix(core): invoke key injection on regular JS scripts, closes [#2342](https://www.github.com/tauri-apps/tauri/pull/2342) ([#2344](https://www.github.com/tauri-apps/tauri/pull/2344)) on 2021-08-03 - -- Remove salt-related APIs (no longer needed after the `__TAURI_INVOKE_KEY__` implementation). - - [e2a0704c](https://www.github.com/tauri-apps/tauri/commit/e2a0704c6c7a447b628a95f8920f9bbe9feef229) refactor(core): remove salt APIs ([#2426](https://www.github.com/tauri-apps/tauri/pull/2426)) on 2021-08-14 - -- Update minimum Rust version to 1.54.0. - - [a5394716](https://www.github.com/tauri-apps/tauri/commit/a53947160985a4f5b0ad1fbb4aa6865d6f852c66) chore: update rust to 1.54.0 ([#2434](https://www.github.com/tauri-apps/tauri/pull/2434)) on 2021-08-15 - -- Run the setup callback after preparing the system tray. - - [1792c455](https://www.github.com/tauri-apps/tauri/commit/1792c45592cd4999af063fa89017f52a985553c1) fix(core): run setup after preparing system tray ([#2312](https://www.github.com/tauri-apps/tauri/pull/2312)) on 2021-07-28 - -- Fixes a consistency issue on the order of `tauri::process::Command` emitted events. - - [737da872](https://www.github.com/tauri-apps/tauri/commit/737da87244cbdeb1158c93944bcb5e10bb383b31) fix(core): random shell command output order, closes [#2184](https://www.github.com/tauri-apps/tauri/pull/2184) ([#2376](https://www.github.com/tauri-apps/tauri/pull/2376)) on 2021-08-09 - -- Force data directory even on non-local window. - - [70a19414](https://www.github.com/tauri-apps/tauri/commit/70a1941468f55f0dc09ac2e13802945891d766f4) fix(core): Force data_directory on Windows ([#2288](https://www.github.com/tauri-apps/tauri/pull/2288)) on 2021-07-23 - -- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. - - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 - - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 - -- Make `ClipboardManager` and `GlobalShortcutManager` public as they are exposed in the `AppHandle`. - - [6e0dbf63](https://www.github.com/tauri-apps/tauri/commit/6e0dbf639ac2c79e00fee9270a2ca8e613dc1f98) fix(core): Expose `ClipboardManager` and `GlobalShortcutManager` ([#2263](https://www.github.com/tauri-apps/tauri/pull/2263)) on 2021-08-03 - -- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. - -- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. - -- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 - -- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. - - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 - -- - Do not run the updater with UAC task if server don't tell us. (Allow toggling server-side) - -- The updater expect a field named `with_elevated_task` with a `boolean` and will not run if the task is not installed first. (windows only) - -- [c5761190](https://www.github.com/tauri-apps/tauri/commit/c576119013297f3731d76924a887c5c2a62c13ba) fix(updater): Run elevated task only if server tell us ([#2357](https://www.github.com/tauri-apps/tauri/pull/2357)) on 2021-08-08 - -- Add `try_state` API to the `Manager` trait. - - [84a0e04c](https://www.github.com/tauri-apps/tauri/commit/84a0e04cbe242b2b7abb388da2d878fce10bc27d) feat(core): `try_state` API on the `Manager` trait ([#2341](https://www.github.com/tauri-apps/tauri/pull/2341)) on 2021-08-02 - -## \[1.0.0-beta.5] - -- Allow preventing window close when the user requests it. - - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 -- Add `App#run` method with callback argument (event loop event handler). - - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 -- Fixes `data-tauri-drag-region` not firing its events. - - [578610a2](https://www.github.com/tauri-apps/tauri/commit/578610a29d5cefb8df070606b7587318b14c397a) fix(core): fix drag-region not sending its events correctly ([#2196](https://www.github.com/tauri-apps/tauri/pull/2196)) on 2021-07-12 -- Fix macOS `EXC_BAD_ACCESS` panic when app is code-signed. - - [456a94f6](https://www.github.com/tauri-apps/tauri/commit/456a94f6637746800b9b85fc3922e82871603402) fix(macOS): updater `EXC_BAD_ACCESS` ([#2181](https://www.github.com/tauri-apps/tauri/pull/2181)) on 2021-07-12 -- Fixes SVG loading on custom protocol. - - [e663bdd5](https://www.github.com/tauri-apps/tauri/commit/e663bdd5938830ab4eba961e69c3985191b499dd) fix(core): svg mime type ([#2129](https://www.github.com/tauri-apps/tauri/pull/2129)) on 2021-06-30 -- Expose `gtk_window` getter. - - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 -- Inject invoke key on `script` tags with `type="module"`. - - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on ` + + +"#; + + let expected = r#" + + + + + +"#; + + let mut new_plugins = Vec::new(); + let mut npm_packages_to_remove = Vec::new(); + + let migrated = migrate_imports( + Path::new("file.vue"), + input, + &mut new_plugins, + &mut npm_packages_to_remove, + ) + .unwrap(); + + assert_eq!(migrated, expected); + + assert_eq!( + new_plugins, + vec![ + "dialog", + "cli", + "dialog", + "global-shortcut", + "clipboard-manager", + "fs" + ] + ); + assert_eq!(npm_packages_to_remove, Vec::::new()); + } + + #[test] + fn migrates_svelte() { + let input = r#" +

+
+ + +"#; + + let expected = r#" +
+
+ + +"#; + + let mut new_plugins = Vec::new(); + let mut npm_packages_to_remove = Vec::new(); + + let migrated = migrate_imports( + Path::new("file.svelte"), + input, + &mut new_plugins, + &mut npm_packages_to_remove, + ) + .unwrap(); + + assert_eq!(migrated, expected); + + assert_eq!( + new_plugins, + vec![ + "dialog", + "cli", + "dialog", + "global-shortcut", + "clipboard-manager", + "fs" + ] + ); + assert_eq!(npm_packages_to_remove, Vec::::new()); + } + + #[test] + fn migrates_js() { + let input = r#" +import { useState } from "react"; +import reactLogo from "./assets/react.svg"; +import { invoke, dialog, cli as superCli } from "@tauri-apps/api"; +import { appWindow } from "@tauri-apps/api/window"; +import { convertFileSrc } from "@tauri-apps/api/tauri"; +import { open } from "@tauri-apps/api/dialog"; +import { register } from "@tauri-apps/api/globalShortcut"; +import clipboard from "@tauri-apps/api/clipboard"; +import * as fs from "@tauri-apps/api/fs"; +import { Store } from "tauri-plugin-store-api"; +import Database from "tauri-plugin-sql-api"; +import "./App.css"; + +function App() { + const [greetMsg, setGreetMsg] = useState(""); + const [name, setName] = useState(""); + + async function greet() { + // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands + setGreetMsg(await invoke("greet", { name })); + await open(); + await dialog.save(); + await convertFileSrc(""); + const a = appWindow.label; + superCli.getMatches(); + clipboard.readText(); + fs.exists(""); + } + + return ( +
+

Welcome to Tauri!

+ +
+ +

Click on the Tauri, Vite, and React logos to learn more.

+ +
{ + e.preventDefault(); + greet(); + }} + > + setName(e.currentTarget.value)} + placeholder="Enter a name..." + /> + +
+ +

{greetMsg}

+
+ ); +} + +export default App; +"#; + + let expected = r#" +import { useState } from "react"; +import reactLogo from "./assets/react.svg"; +import { invoke, } from "@tauri-apps/api"; +import { getCurrentWebviewWindow } from "@tauri-apps/api/webviewWindow"; +import { convertFileSrc } from "@tauri-apps/api/core"; +import { open } from "@tauri-apps/plugin-dialog"; +import { register } from "@tauri-apps/plugin-global-shortcut"; +import clipboard from "@tauri-apps/plugin-clipboard-manager"; +import * as fs from "@tauri-apps/plugin-fs"; +import { Store } from "@tauri-apps/plugin-store"; +import Database from "@tauri-apps/plugin-sql"; +import "./App.css"; +import * as dialog from "@tauri-apps/plugin-dialog" +import * as cli as superCli from "@tauri-apps/plugin-cli" +const appWindow = getCurrentWebviewWindow() + +function App() { + const [greetMsg, setGreetMsg] = useState(""); + const [name, setName] = useState(""); + + async function greet() { + // Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands + setGreetMsg(await invoke("greet", { name })); + await open(); + await dialog.save(); + await convertFileSrc(""); + const a = appWindow.label; + superCli.getMatches(); + clipboard.readText(); + fs.exists(""); + } + + return ( +
+

Welcome to Tauri!

+ + + +

Click on the Tauri, Vite, and React logos to learn more.

+ +
{ + e.preventDefault(); + greet(); + }} + > + setName(e.currentTarget.value)} + placeholder="Enter a name..." + /> + +
+ +

{greetMsg}

+
+ ); +} + +export default App; +"#; + + let mut new_plugins = Vec::new(); + let mut npm_packages_to_remove = Vec::new(); + + let migrated = migrate_imports( + Path::new("file.js"), + input, + &mut new_plugins, + &mut npm_packages_to_remove, + ) + .unwrap(); + + assert_eq!(migrated, expected); + + assert_eq!( + new_plugins, + vec![ + "dialog", + "cli", + "dialog", + "global-shortcut", + "clipboard-manager", + "fs", + "store", + "sql" + ] + ); + assert_eq!( + npm_packages_to_remove, + vec!["tauri-plugin-store-api", "tauri-plugin-sql-api"] + ); + } +} diff --git a/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/mod.rs b/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/mod.rs new file mode 100644 index 000000000000..bb95b33c0094 --- /dev/null +++ b/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/mod.rs @@ -0,0 +1,69 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/oxc-project/oxc/blob/main/crates/oxc_linter/src/partial_loader/mod.rs + +mod svelte; +mod vue; + +use oxc_span::SourceType; + +pub use self::{svelte::SveltePartialLoader, vue::VuePartialLoader}; + +const SCRIPT_START: &str = " { + pub source_text: &'a str, + pub source_type: SourceType, + /// The javascript source could be embedded in some file, + /// use `start` to record start offset of js block in the original file. + pub start: usize, +} + +impl<'a> JavaScriptSource<'a> { + pub fn new(source_text: &'a str, source_type: SourceType, start: usize) -> Self { + Self { + source_text, + source_type, + start, + } + } +} + +pub struct PartialLoader; + +impl PartialLoader { + /// Extract js section of specifial files. + /// Returns `None` if the specifial file does not have a js section. + pub fn parse<'a>(ext: &str, source_text: &'a str) -> Option>> { + match ext { + "vue" => Some(VuePartialLoader::new(source_text).parse()), + "svelte" => Some(SveltePartialLoader::new(source_text).parse()), + _ => None, + } + } +} + +/// Find closing angle for situations where there is another `>` in between. +/// e.g. `" + let offset = script_end_finder.find(self.source_text[pointer..].as_bytes())?; + let js_end = pointer + offset; + + let source_text = &self.source_text[js_start..js_end]; + let source_type = SourceType::default() + .with_module(true) + .with_typescript(is_ts); + Some(JavaScriptSource::new(source_text, source_type, js_start)) + } +} + +#[cfg(test)] +mod test { + use super::{JavaScriptSource, SveltePartialLoader}; + + fn parse_svelte(source_text: &str) -> JavaScriptSource<'_> { + let sources = SveltePartialLoader::new(source_text).parse(); + *sources.first().unwrap() + } + + #[test] + fn test_parse_svelte() { + let source_text = r#" + +

Hello World

+ "#; + + let result = parse_svelte(source_text); + assert_eq!(result.source_text.trim(), r#"console.log("hi");"#); + } + + #[test] + fn test_parse_svelte_ts_with_generic() { + let source_text = r#" + +

Hello World

+ "#; + + let result = parse_svelte(source_text); + assert_eq!(result.source_text.trim(), r#"console.log("hi");"#); + } +} diff --git a/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/vue.rs b/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/vue.rs new file mode 100644 index 000000000000..6d5a8ee2836c --- /dev/null +++ b/crates/tauri-cli/src/migrate/migrations/v1/frontend/partial_loader/vue.rs @@ -0,0 +1,246 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// taken from https://github.com/oxc-project/oxc/blob/main/crates/oxc_linter/src/partial_loader/vue.rs + +use memchr::memmem::Finder; +use oxc_span::SourceType; + +use super::{find_script_closing_angle, JavaScriptSource, SCRIPT_END, SCRIPT_START}; + +pub struct VuePartialLoader<'a> { + source_text: &'a str, +} + +impl<'a> VuePartialLoader<'a> { + pub fn new(source_text: &'a str) -> Self { + Self { source_text } + } + + pub fn parse(self) -> Vec> { + self.parse_scripts() + } + + /// Each *.vue file can contain at most + /// * one `" + let offset = script_end_finder.find(self.source_text[*pointer..].as_bytes())?; + let js_end = *pointer + offset; + *pointer += offset + SCRIPT_END.len(); + + let source_text = &self.source_text[js_start..js_end]; + let source_type = SourceType::default() + .with_module(true) + .with_typescript(is_ts) + .with_jsx(is_jsx); + Some(JavaScriptSource::new(source_text, source_type, js_start)) + } +} + +#[cfg(test)] +mod test { + use super::{JavaScriptSource, VuePartialLoader}; + + fn parse_vue(source_text: &str) -> JavaScriptSource<'_> { + let sources = VuePartialLoader::new(source_text).parse(); + *sources.first().unwrap() + } + + #[test] + fn test_parse_vue_one_line() { + let source_text = r#" + + + "#; + + let result = parse_vue(source_text); + assert_eq!(result.source_text, r#" console.log("hi") "#); + } + + #[test] + fn test_build_vue_with_ts_flag_1() { + let source_text = r#" + + "#; + + let result = parse_vue(source_text); + assert!(result.source_type.is_typescript()); + assert_eq!(result.source_text.trim(), "1/1"); + } + + #[test] + fn test_build_vue_with_ts_flag_2() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert!(result.source_type.is_typescript()); + assert_eq!(result.source_text.trim(), "1/1"); + } + + #[test] + fn test_build_vue_with_ts_flag_3() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert!(result.source_type.is_typescript()); + assert_eq!(result.source_text.trim(), "1/1"); + } + + #[test] + fn test_build_vue_with_tsx_flag() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert!(result.source_type.is_jsx()); + assert!(result.source_type.is_typescript()); + assert_eq!(result.source_text.trim(), "1/1"); + } + + #[test] + fn test_build_vue_with_escape_string() { + let source_text = r" + + + "; + + let result = parse_vue(source_text); + assert!(!result.source_type.is_typescript()); + assert_eq!(result.source_text.trim(), r"a.replace(/'/g, '\''))"); + } + + #[test] + fn test_multi_level_template_literal() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert_eq!(result.source_text.trim(), r"`a${b( `c \`${d}\``)}`"); + } + + #[test] + fn test_brace_with_regex_in_template_literal() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert_eq!(result.source_text.trim(), r"`${/{/}`"); + } + + #[test] + fn test_no_script() { + let source_text = r" + + "; + + let sources = VuePartialLoader::new(source_text).parse(); + assert!(sources.is_empty()); + } + + #[test] + fn test_syntax_error() { + let source_text = r" + + + "; + let sources = VuePartialLoader::new(source_text).parse(); + assert_eq!(sources.len(), 2); + assert_eq!(sources[0].source_text, "a"); + assert_eq!(sources[1].source_text, "b"); + } + + #[test] + fn test_unicode() { + let source_text = r" + + "; + + let result = parse_vue(source_text); + assert_eq!( + result.source_text.trim(), + "let 日历 = '2000年'; + const t = useTranslate({ + 'zh-CN': { + calendar: '日历', + tiledDisplay: '平铺展示', + }, + });" + .trim() + ); + } +} diff --git a/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs b/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs new file mode 100644 index 000000000000..9ff9276425b2 --- /dev/null +++ b/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs @@ -0,0 +1,412 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + interface::rust::manifest::{read_manifest, serialize_manifest}, + Result, +}; + +use anyhow::Context; +use tauri_utils_v1::config::Allowlist; +use toml_edit::{DocumentMut, Entry, Item, TableLike, Value}; + +use std::path::Path; + +const CRATE_TYPES: [&str; 3] = ["lib", "staticlib", "cdylib"]; + +pub fn migrate(tauri_dir: &Path) -> Result<()> { + let manifest_path = tauri_dir.join("Cargo.toml"); + let (mut manifest, _) = read_manifest(&manifest_path)?; + migrate_manifest(&mut manifest)?; + + std::fs::write(&manifest_path, serialize_manifest(&manifest)) + .context("failed to rewrite Cargo manifest")?; + + Ok(()) +} + +fn migrate_manifest(manifest: &mut DocumentMut) -> Result<()> { + let version = dependency_version(); + + let remove_features = features_to_remove(); + let rename_features = features_to_rename(); + let rename_message = rename_features + .iter() + .map(|(from, to)| format!("{from} to {to}")) + .collect::>() + .join(", "); + + for (dependency, table) in [ + // normal deps + ("tauri", "dependencies"), + ("tauri-utils", "dependencies"), + ("tauri-runtime", "dependencies"), + ("tauri-codegen", "dependencies"), + ("tauri-macros", "dependencies"), + ("tauri-runtime-wry", "dependencies"), + // normal deps - plugins + ("tauri-plugin-authenticator", "dependencies"), + ("tauri-plugin-autostart", "dependencies"), + ("tauri-plugin-fs-extra", "dependencies"), + ("tauri-plugin-fs-watch", "dependencies"), + ("tauri-plugin-localhost", "dependencies"), + ("tauri-plugin-log", "dependencies"), + ("tauri-plugin-persisted-scope", "dependencies"), + ("tauri-plugin-positioner", "dependencies"), + ("tauri-plugin-single-instance", "dependencies"), + ("tauri-plugin-sql", "dependencies"), + ("tauri-plugin-store", "dependencies"), + ("tauri-plugin-stronghold", "dependencies"), + ("tauri-plugin-upload", "dependencies"), + ("tauri-plugin-websocket", "dependencies"), + ("tauri-plugin-window-state", "dependencies"), + // dev + ("tauri", "dev-dependencies"), + ("tauri-utils", "dev-dependencies"), + ("tauri-runtime", "dev-dependencies"), + ("tauri-codegen", "dev-dependencies"), + ("tauri-macros", "dev-dependencies"), + ("tauri-runtime-wry", "dev-dependencies"), + // build + ("tauri-build", "build-dependencies"), + ] { + let items = find_dependency(manifest, dependency, table); + + for item in items { + // do not rewrite if dependency uses workspace inheritance + if item + .get("workspace") + .and_then(|v| v.as_bool()) + .unwrap_or_default() + { + log::warn!("`{dependency}` dependency has workspace inheritance enabled. This migration must be manually migrated to v2 by changing its version to {version}, removing any of the {remove_features:?} and renaming [{}] Cargo features.", rename_message); + } else { + migrate_dependency(item, &version, &remove_features, &rename_features); + } + } + } + + if let Some(lib) = manifest + .as_table_mut() + .get_mut("lib") + .and_then(|l| l.as_table_mut()) + { + match lib.entry("crate-type") { + Entry::Occupied(mut e) => { + if let Item::Value(Value::Array(types)) = e.get_mut() { + let mut crate_types_to_add = CRATE_TYPES.to_vec(); + for t in types.iter() { + // type is already in the manifest, skip adding it + if let Some(i) = crate_types_to_add + .iter() + .position(|ty| Some(ty) == t.as_str().as_ref()) + { + crate_types_to_add.remove(i); + } + } + for t in crate_types_to_add { + types.push(t); + } + } + } + Entry::Vacant(e) => { + let mut arr = toml_edit::Array::new(); + arr.extend(CRATE_TYPES.to_vec()); + e.insert(Item::Value(arr.into())); + } + } + } + + Ok(()) +} + +fn find_dependency<'a>( + manifest: &'a mut DocumentMut, + name: &'a str, + table: &'a str, +) -> Vec<&'a mut Item> { + let m = manifest.as_table_mut(); + for (k, v) in m.iter_mut() { + if let Some(t) = v.as_table_mut() { + if k == table { + if let Some(item) = t.get_mut(name) { + return vec![item]; + } + } else if k == "target" { + let mut matching_deps = Vec::new(); + for (_, target_value) in t.iter_mut() { + if let Some(target_table) = target_value.as_table_mut() { + if let Some(deps) = target_table.get_mut(table) { + if let Some(item) = deps.as_table_mut().and_then(|t| t.get_mut(name)) { + matching_deps.push(item); + } + } + } + } + return matching_deps; + } + } + } + + Vec::new() +} + +fn features_to_rename() -> Vec<(&'static str, &'static str)> { + vec![ + ("window-data-url", "webview-data-url"), + ("reqwest-native-tls-vendored", "native-tls-vendored"), + ("system-tray", "tray-icon"), + ("icon-ico", "image-ico"), + ("icon-png", "image-png"), + ] +} + +fn features_to_remove() -> Vec<&'static str> { + let mut features_to_remove = tauri_utils_v1::config::AllowlistConfig::all_features(); + features_to_remove.extend(&[ + "reqwest-client", + "http-multipart", + "process-command-api", + "shell-open-api", + "os-api", + "global-shortcut", + "clipboard", + "dialog", + "notification", + "fs-extract-api", + "windows7-compat", + "updater", + "cli", + "linux-protocol-headers", + "dox", + ]); + + // this allowlist feature was not removed + let index = features_to_remove + .iter() + .position(|x| x == &"protocol-asset") + .unwrap(); + features_to_remove.remove(index); + + features_to_remove +} + +fn dependency_version() -> String { + let pre = env!("CARGO_PKG_VERSION_PRE"); + if pre.is_empty() { + env!("CARGO_PKG_VERSION_MAJOR").to_string() + } else { + format!( + "{}.0.0-{}", + env!("CARGO_PKG_VERSION_MAJOR"), + pre.split('.').next().unwrap() + ) + } +} + +fn migrate_dependency(item: &mut Item, version: &str, remove: &[&str], rename: &[(&str, &str)]) { + if let Some(dep) = item.as_table_mut() { + migrate_dependency_table(dep, version, remove, rename); + } else if let Some(Value::InlineTable(table)) = item.as_value_mut() { + migrate_dependency_table(table, version, remove, rename); + } else if item.as_str().is_some() { + *item = Item::Value(version.into()); + } +} + +fn migrate_dependency_table( + dep: &mut D, + version: &str, + remove: &[&str], + rename: &[(&str, &str)], +) { + dep.remove("rev"); + dep.remove("git"); + dep.remove("branch"); + dep.remove("tag"); + *dep.entry("version").or_insert(Item::None) = Item::Value(version.into()); + let manifest_features = dep.entry("features").or_insert(Item::None); + if let Some(features_array) = manifest_features.as_array_mut() { + // remove features that shouldn't be in the manifest anymore + let mut i = features_array.len(); + let mut add_features = Vec::new(); + while i != 0 { + let index = i - 1; + if let Some(f) = features_array.get(index).and_then(|f| f.as_str()) { + if remove.contains(&f) { + features_array.remove(index); + } else if let Some((_from, rename_to)) = rename.iter().find(|(from, _to)| *from == f) { + features_array.remove(index); + add_features.push(rename_to); + } + } + i -= 1; + } + + for f in add_features { + features_array.push(f.to_string()); + } + } +} + +#[cfg(test)] +mod tests { + use itertools::Itertools; + + fn migrate_deps String>(get_toml: F) { + let keep_features = vec!["isolation", "protocol-asset"]; + let mut features = super::features_to_remove(); + features.extend(keep_features.clone()); + let toml = get_toml(&features); + + let mut manifest = toml + .parse::() + .expect("invalid toml"); + super::migrate_manifest(&mut manifest).expect("failed to migrate manifest"); + + let dependencies = manifest + .as_table() + .get("dependencies") + .expect("missing manifest dependencies") + .as_table() + .expect("manifest dependencies isn't a table"); + + let tauri = dependencies + .get("tauri") + .expect("missing tauri dependency in manifest"); + + let tauri_table = if let Some(table) = tauri.as_table() { + table.clone() + } else if let Some(toml_edit::Value::InlineTable(table)) = tauri.as_value() { + table.clone().into_table() + } else if let Some(version) = tauri.as_str() { + // convert the value to a table for the assert logic below + let mut table = toml_edit::Table::new(); + table.insert( + "version", + toml_edit::Item::Value(version.to_string().into()), + ); + table.insert( + "features", + toml_edit::Item::Value(toml_edit::Value::Array(Default::default())), + ); + table + } else { + panic!("unexpected tauri dependency format"); + }; + + // assert version matches + let version = tauri_table + .get("version") + .expect("missing version") + .as_str() + .expect("version must be a string"); + assert_eq!(version, super::dependency_version()); + + // assert features matches + let features = tauri_table + .get("features") + .expect("missing features") + .as_array() + .expect("features must be an array") + .clone(); + + if toml.contains("reqwest-native-tls-vendored") { + assert!( + features + .iter() + .any(|f| f.as_str().expect("feature must be a string") == "native-tls-vendored"), + "reqwest-native-tls-vendored was not replaced with native-tls-vendored" + ); + } + + if toml.contains("system-tray") { + assert!( + features + .iter() + .any(|f| f.as_str().expect("feature must be a string") == "tray-icon"), + "system-tray was not replaced with tray-icon" + ); + } + + for feature in features.iter() { + let feature = feature.as_str().expect("feature must be a string"); + assert!( + keep_features.contains(&feature) + || feature == "native-tls-vendored" + || feature == "tray-icon", + "feature {feature} should have been removed" + ); + } + } + + #[test] + fn migrate_table() { + migrate_deps(|features| { + format!( + r#" + [dependencies] + tauri = {{ version = "1.0.0", features = [{}] }} +"#, + features.iter().map(|f| format!("{:?}", f)).join(", ") + ) + }); + } + + #[test] + fn migrate_inline_table() { + migrate_deps(|features| { + format!( + r#" + [dependencies.tauri] + version = "1.0.0" + features = [{}] +"#, + features.iter().map(|f| format!("{:?}", f)).join(", ") + ) + }); + } + + #[test] + fn migrate_str() { + migrate_deps(|_features| { + r#" + [dependencies] + tauri = "1.0.0" +"# + .into() + }) + } + + #[test] + fn migrate_add_crate_types() { + let toml = r#" + [lib] + crate-type = ["something"]"#; + + let mut manifest = toml + .parse::() + .expect("invalid toml"); + super::migrate_manifest(&mut manifest).expect("failed to migrate manifest"); + + if let Some(crate_types) = manifest + .as_table() + .get("lib") + .and_then(|l| l.get("crate-type")) + .and_then(|c| c.as_array()) + { + let mut not_added_crate_types = super::CRATE_TYPES.to_vec(); + for t in crate_types { + let t = t.as_str().expect("crate-type must be a string"); + if let Some(i) = not_added_crate_types.iter().position(|ty| ty == &t) { + not_added_crate_types.remove(i); + } + } + assert!( + not_added_crate_types.is_empty(), + "missing crate-type: {not_added_crate_types:?}" + ); + } + } +} diff --git a/crates/tauri-cli/src/migrate/migrations/v1/mod.rs b/crates/tauri-cli/src/migrate/migrations/v1/mod.rs new file mode 100644 index 000000000000..8be16e3e2b37 --- /dev/null +++ b/crates/tauri-cli/src/migrate/migrations/v1/mod.rs @@ -0,0 +1,39 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::app_paths::{frontend_dir, tauri_dir}, + Result, +}; + +use anyhow::Context; + +mod config; +mod frontend; +mod manifest; + +pub fn run() -> Result<()> { + let tauri_dir = tauri_dir(); + let frontend_dir = frontend_dir(); + + let mut migrated = config::migrate(tauri_dir).context("Could not migrate config")?; + manifest::migrate(tauri_dir).context("Could not migrate manifest")?; + let plugins = frontend::migrate(frontend_dir)?; + + migrated.plugins.extend(plugins); + + // Add plugins + for plugin in migrated.plugins { + crate::add::run(crate::add::Options { + plugin: plugin.clone(), + branch: None, + tag: None, + rev: None, + no_fmt: false, + }) + .with_context(|| format!("Could not migrate plugin '{plugin}'"))?; + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/migrate/migrations/v2_rc.rs b/crates/tauri-cli/src/migrate/migrations/v2_rc.rs new file mode 100644 index 000000000000..844c7de048be --- /dev/null +++ b/crates/tauri-cli/src/migrate/migrations/v2_rc.rs @@ -0,0 +1,193 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::{ + app_paths::{frontend_dir, tauri_dir}, + npm::PackageManager, + }, + interface::rust::manifest::{read_manifest, serialize_manifest}, + Result, +}; + +use std::{fs::read_to_string, path::Path}; + +use anyhow::Context; +use toml_edit::{DocumentMut, Item, Table, TableLike, Value}; + +pub fn run() -> Result<()> { + let frontend_dir = frontend_dir(); + let tauri_dir = tauri_dir(); + + let manifest_path = tauri_dir.join("Cargo.toml"); + let (mut manifest, _) = read_manifest(&manifest_path)?; + migrate_manifest(&mut manifest)?; + + migrate_permissions(tauri_dir)?; + + migrate_npm_dependencies(frontend_dir)?; + + std::fs::write(&manifest_path, serialize_manifest(&manifest)) + .context("failed to rewrite Cargo manifest")?; + + Ok(()) +} + +fn migrate_npm_dependencies(frontend_dir: &Path) -> Result<()> { + let pm = PackageManager::from_project(frontend_dir); + + let mut install_deps = Vec::new(); + for pkg in [ + "@tauri-apps/cli", + "@tauri-apps/api", + "@tauri-apps/plugin-authenticator", + "@tauri-apps/plugin-autostart", + "@tauri-apps/plugin-barcode-scanner", + "@tauri-apps/plugin-biometric", + "@tauri-apps/plugin-cli", + "@tauri-apps/plugin-clipboard-manager", + "@tauri-apps/plugin-deep-link", + "@tauri-apps/plugin-dialog", + "@tauri-apps/plugin-fs", + "@tauri-apps/plugin-global-shortcut", + "@tauri-apps/plugin-http", + "@tauri-apps/plugin-log", + "@tauri-apps/plugin-nfc", + "@tauri-apps/plugin-notification", + "@tauri-apps/plugin-os", + "@tauri-apps/plugin-positioner", + "@tauri-apps/plugin-process", + "@tauri-apps/plugin-shell", + "@tauri-apps/plugin-sql", + "@tauri-apps/plugin-store", + "@tauri-apps/plugin-stronghold", + "@tauri-apps/plugin-updater", + "@tauri-apps/plugin-upload", + "@tauri-apps/plugin-websocket", + "@tauri-apps/plugin-window-state", + ] { + let version = pm + .current_package_version(pkg, frontend_dir) + .unwrap_or_default() + .unwrap_or_default(); + if version.starts_with('1') { + install_deps.push(format!("{pkg}@^2.0.0-rc.0")); + } + } + + if !install_deps.is_empty() { + pm.install(&install_deps, frontend_dir)?; + } + + Ok(()) +} + +fn migrate_permissions(tauri_dir: &Path) -> Result<()> { + let core_plugins = [ + "app", + "event", + "image", + "menu", + "path", + "resources", + "tray", + "webview", + "window", + ]; + + for entry in walkdir::WalkDir::new(tauri_dir.join("capabilities")) { + let entry = entry?; + let path = entry.path(); + if path.extension().map_or(false, |ext| ext == "json") { + let mut capability = read_to_string(path).context("failed to read capability")?; + for plugin in core_plugins { + capability = capability.replace(&format!("\"{plugin}:"), &format!("\"core:{plugin}:")); + } + std::fs::write(path, capability).context("failed to rewrite capability")?; + } + } + Ok(()) +} + +fn migrate_manifest(manifest: &mut DocumentMut) -> Result<()> { + let version = "2.0.0-rc.0"; + + let dependencies = manifest + .as_table_mut() + .entry("dependencies") + .or_insert(Item::Table(Table::new())) + .as_table_mut() + .context("manifest dependencies isn't a table")?; + + for dep in [ + "tauri", + "tauri-plugin-authenticator", + "tauri-plugin-autostart", + "tauri-plugin-barcode-scanner", + "tauri-plugin-biometric", + "tauri-plugin-cli", + "tauri-plugin-clipboard-manager", + "tauri-plugin-deep-link", + "tauri-plugin-dialog", + "tauri-plugin-fs", + "tauri-plugin-global-shortcut", + "tauri-plugin-http", + "tauri-plugin-localhost", + "tauri-plugin-log", + "tauri-plugin-nfc", + "tauri-plugin-notification", + "tauri-plugin-os", + "tauri-plugin-persisted-scope", + "tauri-plugin-positioner", + "tauri-plugin-process", + "tauri-plugin-shell", + "tauri-plugin-single-instance", + "tauri-plugin-sql", + "tauri-plugin-store", + "tauri-plugin-stronghold", + "tauri-plugin-updater", + "tauri-plugin-upload", + "tauri-plugin-websocket", + "tauri-plugin-window-state", + ] { + migrate_dependency(dependencies, dep, version); + } + + let build_dependencies = manifest + .as_table_mut() + .entry("build-dependencies") + .or_insert(Item::Table(Table::new())) + .as_table_mut() + .context("manifest build-dependencies isn't a table")?; + + migrate_dependency(build_dependencies, "tauri-build", version); + + Ok(()) +} + +fn migrate_dependency(dependencies: &mut Table, name: &str, version: &str) { + let item = dependencies.entry(name).or_insert(Item::None); + + // do not rewrite if dependency uses workspace inheritance + if item + .get("workspace") + .and_then(|v| v.as_bool()) + .unwrap_or_default() + { + log::info!("`{name}` dependency has workspace inheritance enabled. The features array won't be automatically rewritten."); + return; + } + + if let Some(dep) = item.as_table_mut() { + migrate_dependency_table(dep, version); + } else if let Some(Value::InlineTable(table)) = item.as_value_mut() { + migrate_dependency_table(table, version); + } else if item.as_str().is_some() { + *item = Item::Value(version.into()); + } +} + +fn migrate_dependency_table(dep: &mut D, version: &str) { + *dep.entry("version").or_insert(Item::None) = Item::Value(version.into()); +} diff --git a/crates/tauri-cli/src/migrate/mod.rs b/crates/tauri-cli/src/migrate/mod.rs new file mode 100644 index 000000000000..b5e4ef0ec4d2 --- /dev/null +++ b/crates/tauri-cli/src/migrate/mod.rs @@ -0,0 +1,57 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::{ + app_paths::tauri_dir, + cargo_manifest::{crate_version, CargoLock, CargoManifest}, + }, + interface::rust::get_workspace_dir, + Result, +}; + +use std::{fs::read_to_string, str::FromStr}; + +use anyhow::Context; + +mod migrations; + +pub fn command() -> Result<()> { + crate::helpers::app_paths::resolve(); + + let tauri_dir = tauri_dir(); + + let manifest_contents = + read_to_string(tauri_dir.join("Cargo.toml")).context("failed to read Cargo manifest")?; + let manifest = toml::from_str::(&manifest_contents) + .context("failed to parse Cargo manifest")?; + + let workspace_dir = get_workspace_dir()?; + let lock_path = workspace_dir.join("Cargo.lock"); + let lock = if lock_path.exists() { + let lockfile_contents = read_to_string(lock_path).context("failed to read Cargo lockfile")?; + let lock = + toml::from_str::(&lockfile_contents).context("failed to parse Cargo lockfile")?; + Some(lock) + } else { + None + }; + + let tauri_version = crate_version(tauri_dir, Some(&manifest), lock.as_ref(), "tauri") + .version + .context("failed to get tauri version")?; + let tauri_version = semver::Version::from_str(&tauri_version)?; + + if tauri_version.major == 1 { + migrations::v1::run().context("failed to migrate from v1")?; + } else if tauri_version.major == 2 { + if let Some((pre, _number)) = tauri_version.pre.as_str().split_once('.') { + if pre == "beta" { + migrations::v2_rc::run().context("failed to migrate from v2 beta to rc")?; + } + } + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/mobile/android/android_studio_script.rs b/crates/tauri-cli/src/mobile/android/android_studio_script.rs new file mode 100644 index 000000000000..32f936130004 --- /dev/null +++ b/crates/tauri-cli/src/mobile/android/android_studio_script.rs @@ -0,0 +1,283 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_options, MobileTarget}; +use crate::{ + helpers::config::get as get_tauri_config, + interface::{AppInterface, Interface}, + mobile::CliOptions, + Result, +}; +use clap::{ArgAction, Parser}; + +use anyhow::Context; +use cargo_mobile2::{ + android::{adb, target::Target}, + opts::Profile, + target::{call_for_targets_with_fallback, TargetTrait}, +}; + +use std::path::Path; + +#[derive(Debug, Parser)] +pub struct Options { + /// Targets to build. + #[clap( + short, + long = "target", + action = ArgAction::Append, + num_args(0..), + default_value = Target::DEFAULT_KEY, + value_parser(clap::builder::PossibleValuesParser::new(Target::name_list())) + )] + targets: Option>, + /// Builds with the release flag + #[clap(short, long)] + release: bool, +} + +pub fn command(options: Options) -> Result<()> { + crate::helpers::app_paths::resolve(); + + let profile = if options.release { + Profile::Release + } else { + Profile::Debug + }; + + let tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, None)?; + + let (config, metadata, cli_options) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + let cli_options = read_options(&tauri_config_.identifier); + let (config, metadata) = get_config( + &get_app( + MobileTarget::Android, + tauri_config_, + &AppInterface::new(tauri_config_, None)?, + ), + tauri_config_, + None, + &cli_options, + ); + (config, metadata, cli_options) + }; + + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Android, + )?; + + if let Some(config) = &cli_options.config { + crate::helpers::config::merge_with(&config.0)?; + } + + let env = env()?; + + if cli_options.dev { + let dev_url = tauri_config + .lock() + .unwrap() + .as_ref() + .unwrap() + .build + .dev_url + .clone(); + + if let Some(url) = dev_url { + let localhost = match url.host() { + Some(url::Host::Domain(d)) => d == "localhost", + Some(url::Host::Ipv4(i)) => i == std::net::Ipv4Addr::LOCALHOST, + _ => false, + }; + + if localhost { + if let Some(port) = url.port_or_known_default() { + adb_forward_port(port, &env, &cli_options)?; + } + } + } + } + + let mut validated_lib = false; + + call_for_targets_with_fallback( + options.targets.unwrap_or_default().iter(), + &detect_target_ok, + &env, + |target: &Target| { + target.build( + &config, + &metadata, + &env, + cli_options.noise_level, + true, + profile, + )?; + + if !validated_lib { + validated_lib = true; + + let lib_path = config + .app() + .target_dir(target.triple, profile) + .join(config.so_name()); + + validate_lib(&lib_path)?; + } + + Ok(()) + }, + ) + .map_err(|e| anyhow::anyhow!(e.to_string()))? +} + +fn validate_lib(path: &Path) -> Result<()> { + let so_bytes = std::fs::read(path)?; + let elf = elf::ElfBytes::::minimal_parse(&so_bytes) + .context("failed to parse ELF")?; + let (symbol_table, string_table) = elf + .dynamic_symbol_table() + .context("failed to read dynsym section")? + .context("missing dynsym tables")?; + + let mut symbols = Vec::new(); + for s in symbol_table.iter() { + if let Ok(symbol) = string_table.get(s.st_name as usize) { + symbols.push(symbol); + } + } + + if !symbols.contains(&"Java_app_tauri_plugin_PluginManager_handlePluginResponse") { + anyhow::bail!( + "Library from {} does not include required runtime symbols. This means you are likely missing the tauri::mobile_entry_point macro usage, see the documentation for more information: https://v2.tauri.app/start/migrate/from-tauri-1", + path.display() + ); + } + + Ok(()) +} + +fn adb_forward_port( + port: u16, + env: &cargo_mobile2::android::env::Env, + cli_options: &CliOptions, +) -> Result<()> { + let forward = format!("tcp:{port}"); + log::info!("Forwarding port {port} with adb"); + + let mut devices = adb::device_list(env).unwrap_or_default(); + // if we could not detect any running device, let's wait a few seconds, it might be booting up + if devices.is_empty() { + log::warn!( + "ADB device list is empty, waiting a few seconds to see if there's any booting device..." + ); + + let max = 5; + let mut count = 0; + loop { + std::thread::sleep(std::time::Duration::from_secs(1)); + + devices = adb::device_list(env).unwrap_or_default(); + if !devices.is_empty() { + break; + } + + count += 1; + if count == max { + break; + } + } + } + + let target_device = if let Some(target_device) = &cli_options.target_device { + Some((target_device.id.clone(), target_device.name.clone())) + } else if devices.len() == 1 { + let device = devices.first().unwrap(); + Some((device.serial_no().to_string(), device.name().to_string())) + } else if devices.len() > 1 { + anyhow::bail!("Multiple Android devices are connected ({}), please disconnect devices you do not intend to use so Tauri can determine which to use", + devices.iter().map(|d| d.name()).collect::>().join(", ")); + } else { + // when building the app without running to a device, we might have an empty devices list + None + }; + + if let Some((target_device_serial_no, target_device_name)) = target_device { + let mut already_forwarded = false; + + // clear port forwarding for all devices + for device in &devices { + let reverse_list_output = adb_reverse_list(env, device.serial_no())?; + + // check if the device has the port forwarded + if String::from_utf8_lossy(&reverse_list_output.stdout).contains(&forward) { + // device matches our target, we can skip forwarding + if device.serial_no() == target_device_serial_no { + log::debug!( + "device {} already has the forward for {}", + device.name(), + forward + ); + already_forwarded = true; + } + break; + } + } + + // if there's a known target, we should forward the port to it + if already_forwarded { + log::info!("{forward} already forwarded to {target_device_name}"); + } else { + loop { + run_adb_reverse(env, &target_device_serial_no, &forward, &forward).with_context(|| { + format!("failed to forward port with adb, is the {target_device_name} device connected?",) + })?; + + let reverse_list_output = adb_reverse_list(env, &target_device_serial_no)?; + // wait and retry until the port has actually been forwarded + if String::from_utf8_lossy(&reverse_list_output.stdout).contains(&forward) { + break; + } else { + log::warn!( + "waiting for the port to be forwarded to {}...", + target_device_name + ); + std::thread::sleep(std::time::Duration::from_secs(1)); + } + } + } + } else { + log::warn!("no running devices detected with ADB; skipping port forwarding"); + } + + Ok(()) +} + +fn run_adb_reverse( + env: &cargo_mobile2::android::env::Env, + device_serial_no: &str, + remote: &str, + local: &str, +) -> std::io::Result { + adb::adb(env, ["-s", device_serial_no, "reverse", remote, local]) + .stdin_file(os_pipe::dup_stdin().unwrap()) + .stdout_file(os_pipe::dup_stdout().unwrap()) + .stderr_file(os_pipe::dup_stdout().unwrap()) + .run() +} + +fn adb_reverse_list( + env: &cargo_mobile2::android::env::Env, + device_serial_no: &str, +) -> std::io::Result { + adb::adb(env, ["-s", device_serial_no, "reverse", "--list"]) + .stdin_file(os_pipe::dup_stdin().unwrap()) + .stdout_capture() + .stderr_capture() + .run() +} diff --git a/crates/tauri-cli/src/mobile/android/build.rs b/crates/tauri-cli/src/mobile/android/build.rs new file mode 100644 index 000000000000..f6ccf7eaf3a6 --- /dev/null +++ b/crates/tauri-cli/src/mobile/android/build.rs @@ -0,0 +1,269 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{ + configure_cargo, delete_codegen_vars, ensure_init, env, get_app, get_config, inject_resources, + log_finished, open_and_wait, MobileTarget, OptionsHandle, +}; +use crate::{ + build::Options as BuildOptions, + helpers::{ + app_paths::tauri_dir, + config::{get as get_tauri_config, ConfigHandle}, + flock, + }, + interface::{AppInterface, Interface, Options as InterfaceOptions}, + mobile::{write_options, CliOptions}, + ConfigValue, Result, +}; +use clap::{ArgAction, Parser}; + +use anyhow::Context; +use cargo_mobile2::{ + android::{aab, apk, config::Config as AndroidConfig, env::Env, target::Target}, + opts::{NoiseLevel, Profile}, + target::TargetTrait, +}; + +use std::env::set_current_dir; + +#[derive(Debug, Clone, Parser)] +#[clap( + about = "Build your app in release mode for Android and generate APKs and AABs", + long_about = "Build your app in release mode for Android and generate APKs and AABs. It makes use of the `build.frontendDist` property from your `tauri.conf.json` file. It also runs your `build.beforeBuildCommand` which usually builds your frontend into `build.frontendDist`." +)] +pub struct Options { + /// Builds with the debug flag + #[clap(short, long)] + pub debug: bool, + /// Which targets to build (all by default). + #[clap( + short, + long = "target", + action = ArgAction::Append, + num_args(0..), + value_parser(clap::builder::PossibleValuesParser::new(Target::name_list())) + )] + pub targets: Option>, + /// List of cargo features to activate + #[clap(short, long, action = ArgAction::Append, num_args(0..))] + pub features: Option>, + /// JSON string or path to JSON file to merge with tauri.conf.json + #[clap(short, long)] + pub config: Option, + /// Whether to split the APKs and AABs per ABIs. + #[clap(long)] + pub split_per_abi: bool, + /// Build APKs. + #[clap(long)] + pub apk: bool, + /// Build AABs. + #[clap(long)] + pub aab: bool, + /// Open Android Studio + #[clap(short, long)] + pub open: bool, + /// Skip prompting for values + #[clap(long, env = "CI")] + pub ci: bool, +} + +impl From for BuildOptions { + fn from(options: Options) -> Self { + Self { + runner: None, + debug: options.debug, + target: None, + features: options.features, + bundles: None, + no_bundle: false, + config: options.config, + args: Vec::new(), + ci: options.ci, + } + } +} + +pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { + crate::helpers::app_paths::resolve(); + + delete_codegen_vars(); + + let mut build_options: BuildOptions = options.clone().into(); + + let first_target = Target::all() + .get( + options + .targets + .as_ref() + .and_then(|l| l.first().map(|t| t.as_str())) + .unwrap_or(Target::DEFAULT_KEY), + ) + .unwrap(); + build_options.target = Some(first_target.triple.into()); + + let tauri_config = get_tauri_config( + tauri_utils::platform::Target::Android, + options.config.as_ref().map(|c| &c.0), + )?; + let (interface, config, metadata) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let interface = AppInterface::new(tauri_config_, build_options.target.clone())?; + interface.build_options(&mut Vec::new(), &mut build_options.features, true); + + let app = get_app(MobileTarget::Android, tauri_config_, &interface); + let (config, metadata) = get_config( + &app, + tauri_config_, + build_options.features.as_ref(), + &Default::default(), + ); + (interface, config, metadata) + }; + + let profile = if options.debug { + Profile::Debug + } else { + Profile::Release + }; + + let tauri_path = tauri_dir(); + set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?; + + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Android, + )?; + + let mut env = env()?; + configure_cargo(&mut env, &config)?; + + crate::build::setup(&interface, &mut build_options, tauri_config.clone(), true)?; + + // run an initial build to initialize plugins + first_target.build(&config, &metadata, &env, noise_level, true, profile)?; + + let open = options.open; + let _handle = run_build( + interface, + options, + build_options, + tauri_config, + profile, + &config, + &mut env, + noise_level, + )?; + + if open { + open_and_wait(&config, &env); + } + + Ok(()) +} + +#[allow(clippy::too_many_arguments)] +fn run_build( + interface: AppInterface, + mut options: Options, + build_options: BuildOptions, + tauri_config: ConfigHandle, + profile: Profile, + config: &AndroidConfig, + env: &mut Env, + noise_level: NoiseLevel, +) -> Result { + if !(options.apk || options.aab) { + // if the user didn't specify the format to build, we'll do both + options.apk = true; + options.aab = true; + } + + let interface_options = InterfaceOptions { + debug: build_options.debug, + target: build_options.target.clone(), + ..Default::default() + }; + + let app_settings = interface.app_settings(); + let out_dir = app_settings.out_dir(&interface_options)?; + let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; + + let cli_options = CliOptions { + dev: false, + features: build_options.features.clone(), + args: build_options.args.clone(), + noise_level, + vars: Default::default(), + config: build_options.config.clone(), + target_device: None, + }; + let handle = write_options( + &tauri_config.lock().unwrap().as_ref().unwrap().identifier, + cli_options, + )?; + + inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?; + + let apk_outputs = if options.apk { + apk::build( + config, + env, + noise_level, + profile, + get_targets_or_all(options.targets.clone().unwrap_or_default())?, + options.split_per_abi, + )? + } else { + Vec::new() + }; + + let aab_outputs = if options.aab { + aab::build( + config, + env, + noise_level, + profile, + get_targets_or_all(options.targets.unwrap_or_default())?, + options.split_per_abi, + )? + } else { + Vec::new() + }; + + log_finished(apk_outputs, "APK"); + log_finished(aab_outputs, "AAB"); + + Ok(handle) +} + +fn get_targets_or_all<'a>(targets: Vec) -> Result>> { + if targets.is_empty() { + Ok(Target::all().iter().map(|t| t.1).collect()) + } else { + let mut outs = Vec::new(); + + let possible_targets = Target::all() + .keys() + .map(|key| key.to_string()) + .collect::>() + .join(","); + + for t in targets { + let target = Target::for_name(&t).ok_or_else(|| { + anyhow::anyhow!( + "Target {} is invalid; the possible targets are {}", + t, + possible_targets + ) + })?; + outs.push(target); + } + Ok(outs) + } +} diff --git a/crates/tauri-cli/src/mobile/android/dev.rs b/crates/tauri-cli/src/mobile/android/dev.rs new file mode 100644 index 000000000000..6899b21a174e --- /dev/null +++ b/crates/tauri-cli/src/mobile/android/dev.rs @@ -0,0 +1,325 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{ + configure_cargo, delete_codegen_vars, device_prompt, ensure_init, env, get_app, get_config, + inject_resources, open_and_wait, MobileTarget, +}; +use crate::{ + dev::Options as DevOptions, + helpers::{ + app_paths::tauri_dir, + config::{get as get_tauri_config, ConfigHandle}, + flock, + }, + interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, + mobile::{ + use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, + TargetDevice, + }, + ConfigValue, Result, +}; +use clap::{ArgAction, Parser}; + +use anyhow::Context; +use cargo_mobile2::{ + android::{ + config::{Config as AndroidConfig, Metadata as AndroidMetadata}, + device::Device, + env::Env, + target::Target, + }, + opts::{FilterLevel, NoiseLevel, Profile}, + target::TargetTrait, +}; + +use std::env::set_current_dir; + +#[derive(Debug, Clone, Parser)] +#[clap( + about = "Run your app in development mode on Android", + long_about = "Run your app in development mode on Android with hot-reloading for the Rust code. It makes use of the `build.devUrl` property from your `tauri.conf.json` file. It also runs your `build.beforeDevCommand` which usually starts your frontend devServer." +)] +pub struct Options { + /// List of cargo features to activate + #[clap(short, long, action = ArgAction::Append, num_args(0..))] + pub features: Option>, + /// Exit on panic + #[clap(short, long)] + exit_on_panic: bool, + /// JSON string or path to JSON file to merge with tauri.conf.json + #[clap(short, long)] + pub config: Option, + /// Run the code in release mode + #[clap(long = "release")] + pub release_mode: bool, + /// Skip waiting for the frontend dev server to start before building the tauri application. + #[clap(long, env = "TAURI_CLI_NO_DEV_SERVER_WAIT")] + pub no_dev_server_wait: bool, + /// Disable the file watcher + #[clap(long)] + pub no_watch: bool, + /// Open Android Studio instead of trying to run on a connected device + #[clap(short, long)] + pub open: bool, + /// Runs on the given device name + pub device: Option, + /// Force prompting for an IP to use to connect to the dev server on mobile. + #[clap(long)] + pub force_ip_prompt: bool, + /// Use the public network address for the development server. + /// If an actual address it provided, it is used instead of prompting to pick one. + /// + /// On Windows we use the public network address by default. + /// + /// This option is particularly useful along the `--open` flag when you intend on running on a physical device. + /// + /// This replaces the devUrl configuration value to match the public network address host, + /// it is your responsibility to set up your development server to listen on this address + /// by using 0.0.0.0 as host for instance. + /// + /// When this is set or when running on an iOS device the CLI sets the `TAURI_DEV_HOST` + /// environment variable so you can check this on your framework's configuration to expose the development server + /// on the public network address. + #[clap(long, default_value_t, default_missing_value(""), num_args(0..=1))] + pub host: DevHost, + /// Disable the built-in dev server for static files. + #[clap(long)] + pub no_dev_server: bool, + /// Specify port for the built-in dev server for static files. Defaults to 1430. + #[clap(long, env = "TAURI_CLI_PORT")] + pub port: Option, +} + +impl From for DevOptions { + fn from(options: Options) -> Self { + Self { + runner: None, + target: None, + features: options.features, + exit_on_panic: options.exit_on_panic, + config: options.config, + args: Vec::new(), + no_watch: options.no_watch, + no_dev_server_wait: options.no_dev_server_wait, + no_dev_server: options.no_dev_server, + port: options.port, + release_mode: options.release_mode, + host: options.host.0.unwrap_or_default(), + } + } +} + +pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { + crate::helpers::app_paths::resolve(); + + let result = run_command(options, noise_level); + if result.is_err() { + crate::dev::kill_before_dev_process(); + } + result +} + +fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { + delete_codegen_vars(); + + let tauri_config = get_tauri_config( + tauri_utils::platform::Target::Android, + options.config.as_ref().map(|c| &c.0), + )?; + + let env = env()?; + let device = if options.open { + None + } else { + match device_prompt(&env, options.device.as_deref()) { + Ok(d) => Some(d), + Err(e) => { + log::error!("{e}"); + None + } + } + }; + + let mut dev_options: DevOptions = options.clone().into(); + let target_triple = device + .as_ref() + .map(|d| d.target().triple.to_string()) + .unwrap_or_else(|| Target::all().values().next().unwrap().triple.into()); + dev_options.target = Some(target_triple.clone()); + + let (interface, config, metadata) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let interface = AppInterface::new(tauri_config_, dev_options.target.clone())?; + + let app = get_app(MobileTarget::Android, tauri_config_, &interface); + let (config, metadata) = get_config( + &app, + tauri_config_, + dev_options.features.as_ref(), + &Default::default(), + ); + (interface, config, metadata) + }; + + let tauri_path = tauri_dir(); + set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?; + + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Android, + )?; + run_dev( + interface, + options, + dev_options, + tauri_config, + device, + env, + &config, + &metadata, + noise_level, + ) +} + +#[allow(clippy::too_many_arguments)] +fn run_dev( + mut interface: AppInterface, + options: Options, + mut dev_options: DevOptions, + tauri_config: ConfigHandle, + device: Option, + mut env: Env, + config: &AndroidConfig, + metadata: &AndroidMetadata, + noise_level: NoiseLevel, +) -> Result<()> { + // when running on an actual device we must use the network IP + if options.host.0.is_some() + || device + .as_ref() + .map(|device| !device.serial_no().starts_with("emulator")) + .unwrap_or(false) + { + use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?; + } + + crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; + + let interface_options = InterfaceOptions { + debug: !dev_options.release_mode, + target: dev_options.target.clone(), + ..Default::default() + }; + + let app_settings = interface.app_settings(); + let out_dir = app_settings.out_dir(&interface_options)?; + let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; + + configure_cargo(&mut env, config)?; + + // run an initial build to initialize plugins + let target_triple = dev_options.target.as_ref().unwrap(); + let target = Target::all() + .values() + .find(|t| t.triple == target_triple) + .unwrap_or_else(|| Target::all().values().next().unwrap()); + target.build( + config, + metadata, + &env, + noise_level, + true, + if options.release_mode { + Profile::Release + } else { + Profile::Debug + }, + )?; + + let open = options.open; + interface.mobile_dev( + MobileOptions { + debug: !options.release_mode, + features: options.features, + args: Vec::new(), + config: dev_options.config.clone(), + no_watch: options.no_watch, + }, + |options| { + let cli_options = CliOptions { + dev: true, + features: options.features.clone(), + args: options.args.clone(), + noise_level, + vars: Default::default(), + config: dev_options.config.clone(), + target_device: device.as_ref().map(|d| TargetDevice { + id: d.serial_no().to_string(), + name: d.name().to_string(), + }), + }; + + let _handle = write_options( + &tauri_config.lock().unwrap().as_ref().unwrap().identifier, + cli_options, + )?; + + inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?; + + if open { + open_and_wait(config, &env) + } else if let Some(device) = &device { + match run(device, options, config, &env, metadata, noise_level) { + Ok(c) => Ok(Box::new(c) as Box), + Err(e) => { + crate::dev::kill_before_dev_process(); + Err(e) + } + } + } else { + open_and_wait(config, &env) + } + }, + ) +} + +fn run( + device: &Device<'_>, + options: MobileOptions, + config: &AndroidConfig, + env: &Env, + metadata: &AndroidMetadata, + noise_level: NoiseLevel, +) -> crate::Result { + let profile = if options.debug { + Profile::Debug + } else { + Profile::Release + }; + + let build_app_bundle = metadata.asset_packs().is_some(); + + device + .run( + config, + env, + noise_level, + profile, + Some(match noise_level { + NoiseLevel::Polite => FilterLevel::Info, + NoiseLevel::LoudAndProud => FilterLevel::Debug, + NoiseLevel::FranklyQuitePedantic => FilterLevel::Verbose, + }), + build_app_bundle, + false, + ".MainActivity".into(), + ) + .map(DevChild::new) + .map_err(Into::into) +} diff --git a/crates/tauri-cli/src/mobile/android/mod.rs b/crates/tauri-cli/src/mobile/android/mod.rs new file mode 100644 index 000000000000..7521e87a9d4e --- /dev/null +++ b/crates/tauri-cli/src/mobile/android/mod.rs @@ -0,0 +1,348 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use cargo_mobile2::{ + android::{ + adb, + config::{Config as AndroidConfig, Metadata as AndroidMetadata, Raw as RawAndroidConfig}, + device::Device, + emulator, + env::Env, + target::Target, + }, + config::app::{App, DEFAULT_ASSET_DIR}, + opts::{FilterLevel, NoiseLevel}, + os, + target::TargetTrait, + util::prompt, +}; +use clap::{Parser, Subcommand}; +use std::{ + env::set_var, + fs::{create_dir, create_dir_all, write}, + process::exit, + thread::sleep, + time::Duration, +}; +use sublime_fuzzy::best_match; +use tauri_utils::resources::ResourcePaths; + +use super::{ + ensure_init, get_app, init::command as init_command, log_finished, read_options, CliOptions, + OptionsHandle, Target as MobileTarget, MIN_DEVICE_MATCH_SCORE, +}; +use crate::{ + helpers::config::{BundleResources, Config as TauriConfig}, + Result, +}; + +mod android_studio_script; +mod build; +mod dev; +pub(crate) mod project; + +#[derive(Parser)] +#[clap( + author, + version, + about = "Android commands", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Debug, Parser)] +#[clap(about = "Initialize Android target in the project")] +pub struct InitOptions { + /// Skip prompting for values + #[clap(long, env = "CI")] + ci: bool, + /// Skips installing rust toolchains via rustup + #[clap(long)] + skip_targets_install: bool, +} + +#[derive(Subcommand)] +enum Commands { + Init(InitOptions), + Dev(dev::Options), + Build(build::Options), + #[clap(hide(true))] + AndroidStudioScript(android_studio_script::Options), +} + +pub fn command(cli: Cli, verbosity: u8) -> Result<()> { + let noise_level = NoiseLevel::from_occurrences(verbosity as u64); + match cli.command { + Commands::Init(options) => { + crate::helpers::app_paths::resolve(); + init_command( + MobileTarget::Android, + options.ci, + false, + options.skip_targets_install, + )? + } + Commands::Dev(options) => dev::command(options, noise_level)?, + Commands::Build(options) => build::command(options, noise_level)?, + Commands::AndroidStudioScript(options) => android_studio_script::command(options)?, + } + + Ok(()) +} + +pub fn get_config( + app: &App, + config: &TauriConfig, + features: Option<&Vec>, + cli_options: &CliOptions, +) -> (AndroidConfig, AndroidMetadata) { + let mut android_options = cli_options.clone(); + if let Some(features) = features { + android_options + .features + .get_or_insert(Vec::new()) + .extend_from_slice(features); + } + + let raw = RawAndroidConfig { + features: android_options.features.clone(), + logcat_filter_specs: vec![ + "RustStdoutStderr".into(), + format!( + "*:{}", + match cli_options.noise_level { + NoiseLevel::Polite => FilterLevel::Info, + NoiseLevel::LoudAndProud => FilterLevel::Debug, + NoiseLevel::FranklyQuitePedantic => FilterLevel::Verbose, + } + .logcat() + ), + ], + min_sdk_version: Some(config.bundle.android.min_sdk_version), + ..Default::default() + }; + let config = AndroidConfig::from_raw(app.clone(), Some(raw)).unwrap(); + + let metadata = AndroidMetadata { + supported: true, + cargo_args: Some(android_options.args), + features: android_options.features, + ..Default::default() + }; + + set_var( + "WRY_ANDROID_PACKAGE", + app.android_identifier_escape_kotlin_keyword(), + ); + set_var("TAURI_ANDROID_PACKAGE_UNESCAPED", app.identifier()); + set_var("WRY_ANDROID_LIBRARY", app.lib_name()); + set_var("TAURI_ANDROID_PROJECT_PATH", config.project_dir()); + + let src_main_dir = config + .project_dir() + .join("app/src/main") + .join(format!("java/{}", app.identifier().replace('.', "/"),)); + if config.project_dir().exists() { + if src_main_dir.exists() { + let _ = create_dir(src_main_dir.join("generated")); + } else { + log::error!( + "Project directory {} does not exist. Did you update the package name in `Cargo.toml` or the bundle identifier in `tauri.conf.json > identifier`? Save your changes, delete the `gen/android` folder and run `tauri android init` to recreate the Android project.", + src_main_dir.display() + ); + exit(1); + } + } + set_var( + "WRY_ANDROID_KOTLIN_FILES_OUT_DIR", + src_main_dir.join("generated"), + ); + + (config, metadata) +} + +fn env() -> Result { + let env = super::env()?; + cargo_mobile2::android::env::Env::from_env(env).map_err(Into::into) +} + +fn delete_codegen_vars() { + for (k, _) in std::env::vars() { + if k.starts_with("WRY_") && (k.ends_with("CLASS_EXTENSION") || k.ends_with("CLASS_INIT")) { + std::env::remove_var(k); + } + } +} + +fn adb_device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result> { + let device_list = adb::device_list(env) + .map_err(|cause| anyhow::anyhow!("Failed to detect connected Android devices: {cause}"))?; + if !device_list.is_empty() { + let device = if let Some(t) = target { + let (device, score) = device_list + .into_iter() + .rev() + .map(|d| { + let score = best_match(t, d.name()).map_or(0, |m| m.score()); + (d, score) + }) + .max_by_key(|(_, score)| *score) + // we already checked the list is not empty + .unwrap(); + if score > MIN_DEVICE_MATCH_SCORE { + device + } else { + anyhow::bail!("Could not find an Android device matching {t}") + } + } else if device_list.len() > 1 { + let index = prompt::list( + concat!("Detected ", "Android", " devices"), + device_list.iter(), + "device", + None, + "Device", + ) + .map_err(|cause| anyhow::anyhow!("Failed to prompt for Android device: {cause}"))?; + device_list.into_iter().nth(index).unwrap() + } else { + device_list.into_iter().next().unwrap() + }; + + log::info!( + "Detected connected device: {} with target {:?}", + device, + device.target().triple, + ); + Ok(device) + } else { + Err(anyhow::anyhow!("No connected Android devices detected")) + } +} + +fn emulator_prompt(env: &'_ Env, target: Option<&str>) -> Result { + let emulator_list = emulator::avd_list(env).unwrap_or_default(); + if !emulator_list.is_empty() { + let emulator = if let Some(t) = target { + let (device, score) = emulator_list + .into_iter() + .rev() + .map(|d| { + let score = best_match(t, d.name()).map_or(0, |m| m.score()); + (d, score) + }) + .max_by_key(|(_, score)| *score) + // we already checked the list is not empty + .unwrap(); + if score > MIN_DEVICE_MATCH_SCORE { + device + } else { + anyhow::bail!("Could not find an Android Emulator matching {t}") + } + } else if emulator_list.len() > 1 { + let index = prompt::list( + concat!("Detected ", "Android", " emulators"), + emulator_list.iter(), + "emulator", + None, + "Emulator", + ) + .map_err(|cause| anyhow::anyhow!("Failed to prompt for Android Emulator device: {cause}"))?; + emulator_list.into_iter().nth(index).unwrap() + } else { + emulator_list.into_iter().next().unwrap() + }; + + Ok(emulator) + } else { + Err(anyhow::anyhow!("No available Android Emulator detected")) + } +} + +fn device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result> { + if let Ok(device) = adb_device_prompt(env, target) { + Ok(device) + } else { + let emulator = emulator_prompt(env, target)?; + log::info!("Starting emulator {}", emulator.name()); + emulator.start_detached(env)?; + let mut tries = 0; + loop { + sleep(Duration::from_secs(2)); + if let Ok(device) = adb_device_prompt(env, Some(emulator.name())) { + return Ok(device); + } + if tries >= 3 { + log::info!("Waiting for emulator to start... (maybe the emulator is unauthorized or offline, run `adb devices` to check)"); + } else { + log::info!("Waiting for emulator to start..."); + } + tries += 1; + } + } +} + +fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> { + device_prompt(env, None).map(|device| device.target()).ok() +} + +fn open_and_wait(config: &AndroidConfig, env: &Env) -> ! { + log::info!("Opening Android Studio"); + if let Err(e) = os::open_file_with("Android Studio", config.project_dir(), &env.base) { + log::error!("{}", e); + } + loop { + sleep(Duration::from_secs(24 * 60 * 60)); + } +} + +fn inject_resources(config: &AndroidConfig, tauri_config: &TauriConfig) -> Result<()> { + let asset_dir = config + .project_dir() + .join("app/src/main") + .join(DEFAULT_ASSET_DIR); + create_dir_all(&asset_dir)?; + + write( + asset_dir.join("tauri.conf.json"), + serde_json::to_string(&tauri_config)?, + )?; + + let resources = match &tauri_config.bundle.resources { + Some(BundleResources::List(paths)) => Some(ResourcePaths::new(paths.as_slice(), true)), + Some(BundleResources::Map(map)) => Some(ResourcePaths::from_map(map, true)), + None => None, + }; + if let Some(resources) = resources { + for resource in resources.iter() { + let resource = resource?; + let dest = asset_dir.join(resource.target()); + crate::helpers::fs::copy_file(resource.path(), dest)?; + } + } + + Ok(()) +} + +fn configure_cargo(env: &mut Env, config: &AndroidConfig) -> Result<()> { + for target in Target::all().values() { + let config = target.generate_cargo_config(config, env)?; + let target_var_name = target.triple.replace('-', "_").to_uppercase(); + if let Some(linker) = config.linker { + env.base.insert_env_var( + format!("CARGO_TARGET_{target_var_name}_LINKER"), + linker.into(), + ); + } + env.base.insert_env_var( + format!("CARGO_TARGET_{target_var_name}_RUSTFLAGS"), + config.rustflags.join(" ").into(), + ); + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/mobile/android/project.rs b/crates/tauri-cli/src/mobile/android/project.rs new file mode 100644 index 000000000000..d24fdd49d43d --- /dev/null +++ b/crates/tauri-cli/src/mobile/android/project.rs @@ -0,0 +1,221 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{helpers::template, Result}; +use anyhow::Context; +use cargo_mobile2::{ + android::{ + config::{Config, Metadata}, + target::Target, + }, + config::app::DEFAULT_ASSET_DIR, + os, + target::TargetTrait as _, + util::{ + self, + cli::{Report, TextWrapper}, + prefix_path, + }, +}; +use handlebars::Handlebars; +use include_dir::{include_dir, Dir}; + +use std::{ + ffi::OsStr, + fs, + path::{Path, PathBuf}, +}; + +const TEMPLATE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/mobile/android"); + +pub fn gen( + config: &Config, + metadata: &Metadata, + (handlebars, mut map): (Handlebars, template::JsonMap), + wrapper: &TextWrapper, + skip_targets_install: bool, +) -> Result<()> { + if !skip_targets_install { + let installed_targets = + crate::interface::rust::installation::installed_targets().unwrap_or_default(); + let missing_targets = Target::all() + .values() + .filter(|t| !installed_targets.contains(&t.triple().into())) + .collect::>(); + + if !missing_targets.is_empty() { + println!("Installing Android Rust toolchains..."); + for target in missing_targets { + target + .install() + .context("failed to install target with rustup")?; + } + } + } + println!("Generating Android Studio project..."); + let dest = config.project_dir(); + let asset_packs = metadata.asset_packs().unwrap_or_default(); + + map.insert( + "root-dir-rel", + Path::new(&os::replace_path_separator( + util::relativize_path( + config.app().root_dir(), + config.project_dir().join(config.app().name_snake()), + ) + .into_os_string(), + )), + ); + map.insert("root-dir", config.app().root_dir()); + map.insert( + "abi-list", + Target::all() + .values() + .map(|target| target.abi) + .collect::>(), + ); + map.insert("target-list", Target::all().keys().collect::>()); + map.insert( + "arch-list", + Target::all() + .values() + .map(|target| target.arch) + .collect::>(), + ); + map.insert("android-app-plugins", metadata.app_plugins()); + map.insert( + "android-project-dependencies", + metadata.project_dependencies(), + ); + map.insert("android-app-dependencies", metadata.app_dependencies()); + map.insert( + "android-app-dependencies-platform", + metadata.app_dependencies_platform(), + ); + map.insert( + "has-code", + metadata.project_dependencies().is_some() + || metadata.app_dependencies().is_some() + || metadata.app_dependencies_platform().is_some(), + ); + map.insert("has-asset-packs", !asset_packs.is_empty()); + map.insert( + "asset-packs", + asset_packs + .iter() + .map(|p| p.name.as_str()) + .collect::>(), + ); + map.insert("windows", cfg!(windows)); + + let identifier = config.app().identifier().replace('.', "/"); + let package_path = format!("java/{}", identifier); + + map.insert("package-path", &package_path); + + let mut created_dirs = Vec::new(); + template::render_with_generator( + &handlebars, + map.inner(), + &TEMPLATE_DIR, + &dest, + &mut |path| generate_out_file(&path, &dest, &package_path, &mut created_dirs), + ) + .with_context(|| "failed to process template")?; + + if !asset_packs.is_empty() { + Report::action_request( + "When running from Android Studio, you must first set your deployment option to \"APK from app bundle\".", + "Android Studio will not be able to find your asset packs otherwise. The option can be found under \"Run > Edit Configurations > Deploy\"." + ).print(wrapper); + } + + let source_dest = dest.join("app"); + for source in metadata.app_sources() { + let source_src = config.app().root_dir().join(source); + let source_file = source_src + .file_name() + .ok_or_else(|| anyhow::anyhow!("asset source {} is invalid", source_src.display()))?; + fs::copy(&source_src, source_dest.join(source_file)).map_err(|cause| { + anyhow::anyhow!( + "failed to copy {} to {}: {}", + source_src.display(), + source_dest.display(), + cause + ) + })?; + } + + let dest = prefix_path(dest, "app/src/main/"); + fs::create_dir_all(&dest).map_err(|cause| { + anyhow::anyhow!( + "failed to create directory at {}: {}", + dest.display(), + cause + ) + })?; + + let asset_dir = dest.join(DEFAULT_ASSET_DIR); + if !asset_dir.is_dir() { + fs::create_dir_all(&asset_dir).map_err(|cause| { + anyhow::anyhow!( + "failed to create asset dir {path}: {cause}", + path = asset_dir.display() + ) + })?; + } + + Ok(()) +} + +fn generate_out_file( + path: &Path, + dest: &Path, + package_path: &str, + created_dirs: &mut Vec, +) -> std::io::Result> { + let mut iter = path.iter(); + let root = iter.next().unwrap().to_str().unwrap(); + let path_without_root: std::path::PathBuf = iter.collect(); + let path = match ( + root, + path.extension().and_then(|o| o.to_str()), + path_without_root.strip_prefix("src/main"), + ) { + ("app" | "buildSrc", Some("kt"), Ok(path)) => { + let parent = path.parent().unwrap(); + let file_name = path.file_name().unwrap(); + let out_dir = dest + .join(root) + .join("src/main") + .join(package_path) + .join(parent); + out_dir.join(file_name) + } + _ => dest.join(path), + }; + + let parent = path.parent().unwrap().to_path_buf(); + if !created_dirs.contains(&parent) { + fs::create_dir_all(&parent)?; + created_dirs.push(parent); + } + + let mut options = fs::OpenOptions::new(); + options.write(true); + + #[cfg(unix)] + if path.file_name().unwrap() == OsStr::new("gradlew") { + use std::os::unix::fs::OpenOptionsExt; + options.mode(0o755); + } + + if path.file_name().unwrap() == OsStr::new("BuildTask.kt") { + options.truncate(true).create(true).open(path).map(Some) + } else if !path.exists() { + options.create(true).open(path).map(Some) + } else { + Ok(None) + } +} diff --git a/crates/tauri-cli/src/mobile/init.rs b/crates/tauri-cli/src/mobile/init.rs new file mode 100644 index 000000000000..c24ddbe84408 --- /dev/null +++ b/crates/tauri-cli/src/mobile/init.rs @@ -0,0 +1,373 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{get_app, Target}; +use crate::{ + helpers::{config::get as get_tauri_config, template::JsonMap}, + interface::{AppInterface, Interface}, + Result, +}; +use cargo_mobile2::{ + android::env::Env as AndroidEnv, + config::app::App, + reserved_names::KOTLIN_ONLY_KEYWORDS, + util::{ + self, + cli::{Report, TextWrapper}, + }, +}; +use handlebars::{ + Context, Handlebars, Helper, HelperResult, Output, RenderContext, RenderError, RenderErrorReason, +}; + +use std::{env::var_os, path::PathBuf}; + +pub fn command( + target: Target, + ci: bool, + reinstall_deps: bool, + skip_targets_install: bool, +) -> Result<()> { + let wrapper = TextWrapper::default(); + + exec(target, &wrapper, ci, reinstall_deps, skip_targets_install) + .map_err(|e| anyhow::anyhow!("{:#}", e))?; + Ok(()) +} + +pub fn exec( + target: Target, + wrapper: &TextWrapper, + #[allow(unused_variables)] non_interactive: bool, + #[allow(unused_variables)] reinstall_deps: bool, + skip_targets_install: bool, +) -> Result { + let tauri_config = get_tauri_config(target.platform_target(), None)?; + + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let app = get_app( + target, + tauri_config_, + &AppInterface::new(tauri_config_, None)?, + ); + + let (handlebars, mut map) = handlebars(&app); + + let mut args = std::env::args_os(); + + let (binary, mut build_args) = args + .next() + .map(|bin| { + let bin_path = PathBuf::from(&bin); + let mut build_args = vec!["tauri"]; + + if let Some(bin_stem) = bin_path.file_stem() { + let r = regex::Regex::new("(nodejs|node)\\-?([1-9]*)*$").unwrap(); + if r.is_match(&bin_stem.to_string_lossy()) { + if var_os("PNPM_PACKAGE_NAME").is_some() { + return ("pnpm".into(), build_args); + } else if let Some(npm_execpath) = var_os("npm_execpath") { + let manager_stem = PathBuf::from(&npm_execpath) + .file_stem() + .unwrap() + .to_os_string(); + let is_npm = manager_stem == "npm-cli"; + let binary = if is_npm { + "npm".into() + } else if manager_stem == "npx-cli" { + "npx".into() + } else { + manager_stem + }; + + if is_npm { + build_args.insert(0, "run"); + build_args.insert(1, "--"); + } + + return (binary, build_args); + } + } else if bin_stem == "deno" { + build_args.insert(0, "task"); + return (std::ffi::OsString::from("deno"), build_args); + } else if !cfg!(debug_assertions) && bin_stem == "cargo-tauri" { + return (std::ffi::OsString::from("cargo"), build_args); + } + } + + (bin, build_args) + }) + .unwrap_or_else(|| (std::ffi::OsString::from("cargo"), vec!["tauri"])); + + build_args.push(target.command_name()); + build_args.push(target.ide_build_script_name()); + + map.insert("tauri-binary", binary.to_string_lossy()); + map.insert("tauri-binary-args", &build_args); + map.insert("tauri-binary-args-str", build_args.join(" ")); + + let app = match target { + // Generate Android Studio project + Target::Android => match AndroidEnv::new() { + Ok(_env) => { + let (config, metadata) = + super::android::get_config(&app, tauri_config_, None, &Default::default()); + map.insert("android", &config); + super::android::project::gen( + &config, + &metadata, + (handlebars, map), + wrapper, + skip_targets_install, + )?; + app + } + Err(err) => { + if err.sdk_or_ndk_issue() { + Report::action_request( + " to initialize Android environment; Android support won't be usable until you fix the issue below and re-run `tauri android init`!", + err, + ) + .print(wrapper); + app + } else { + return Err(err.into()); + } + } + }, + #[cfg(target_os = "macos")] + // Generate Xcode project + Target::Ios => { + let (config, metadata) = + super::ios::get_config(&app, tauri_config_, None, &Default::default()); + map.insert("apple", &config); + super::ios::project::gen( + tauri_config_, + &config, + &metadata, + (handlebars, map), + wrapper, + non_interactive, + reinstall_deps, + skip_targets_install, + )?; + app + } + }; + + Report::victory( + "Project generated successfully!", + "Make cool apps! 🌻 🐕 🎉", + ) + .print(wrapper); + Ok(app) +} + +fn handlebars(app: &App) -> (Handlebars<'static>, JsonMap) { + let mut h = Handlebars::new(); + h.register_escape_fn(handlebars::no_escape); + + h.register_helper("html-escape", Box::new(html_escape)); + h.register_helper("join", Box::new(join)); + h.register_helper("quote-and-join", Box::new(quote_and_join)); + h.register_helper( + "quote-and-join-colon-prefix", + Box::new(quote_and_join_colon_prefix), + ); + h.register_helper("snake-case", Box::new(snake_case)); + h.register_helper("escape-kotlin-keyword", Box::new(escape_kotlin_keyword)); + // don't mix these up or very bad things will happen to all of us + h.register_helper("prefix-path", Box::new(prefix_path)); + h.register_helper("unprefix-path", Box::new(unprefix_path)); + + let mut map = JsonMap::default(); + map.insert("app", app); + + (h, map) +} + +fn get_str<'a>(helper: &'a Helper) -> &'a str { + helper + .param(0) + .and_then(|v| v.value().as_str()) + .unwrap_or("") +} + +fn get_str_array(helper: &Helper, formatter: impl Fn(&str) -> String) -> Option> { + helper.param(0).and_then(|v| { + v.value() + .as_array() + .and_then(|arr| arr.iter().map(|val| val.as_str().map(&formatter)).collect()) + }) +} + +fn html_escape( + helper: &Helper, + _: &Handlebars, + _ctx: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write(&handlebars::html_escape(get_str(helper))) + .map_err(Into::into) +} + +fn join( + helper: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write( + &get_str_array(helper, |s| s.to_string()) + .ok_or_else(|| { + RenderErrorReason::ParamTypeMismatchForName("join", "0".to_owned(), "array".to_owned()) + })? + .join(", "), + ) + .map_err(Into::into) +} + +fn quote_and_join( + helper: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write( + &get_str_array(helper, |s| format!("{s:?}")) + .ok_or_else(|| { + RenderErrorReason::ParamTypeMismatchForName( + "quote-and-join", + "0".to_owned(), + "array".to_owned(), + ) + })? + .join(", "), + ) + .map_err(Into::into) +} + +fn quote_and_join_colon_prefix( + helper: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write( + &get_str_array(helper, |s| format!("{:?}", format!(":{s}"))) + .ok_or_else(|| { + RenderErrorReason::ParamTypeMismatchForName( + "quote-and-join-colon-prefix", + "0".to_owned(), + "array".to_owned(), + ) + })? + .join(", "), + ) + .map_err(Into::into) +} + +fn snake_case( + helper: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + use heck::ToSnekCase as _; + out + .write(&get_str(helper).to_snek_case()) + .map_err(Into::into) +} + +fn escape_kotlin_keyword( + helper: &Helper, + _: &Handlebars, + _: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + let escaped_result = get_str(helper) + .split('.') + .map(|s| { + if KOTLIN_ONLY_KEYWORDS.contains(&s) { + format!("`{}`", s) + } else { + s.to_string() + } + }) + .collect::>() + .join("."); + + out.write(&escaped_result).map_err(Into::into) +} + +fn app_root(ctx: &Context) -> Result<&str, RenderError> { + let app_root = ctx + .data() + .get("app") + .ok_or_else(|| RenderErrorReason::Other("`app` missing from template data.".to_owned()))? + .get("root-dir") + .ok_or_else(|| { + RenderErrorReason::Other("`app.root-dir` missing from template data.".to_owned()) + })?; + app_root.as_str().ok_or_else(|| { + RenderErrorReason::Other("`app.root-dir` contained invalid UTF-8.".to_owned()).into() + }) +} + +fn prefix_path( + helper: &Helper, + _: &Handlebars, + ctx: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write( + util::prefix_path(app_root(ctx)?, get_str(helper)) + .to_str() + .ok_or_else(|| { + RenderErrorReason::Other( + "Either the `app.root-dir` or the specified path contained invalid UTF-8.".to_owned(), + ) + })?, + ) + .map_err(Into::into) +} + +fn unprefix_path( + helper: &Helper, + _: &Handlebars, + ctx: &Context, + _: &mut RenderContext, + out: &mut dyn Output, +) -> HelperResult { + out + .write( + util::unprefix_path(app_root(ctx)?, get_str(helper)) + .map_err(|_| { + RenderErrorReason::Other( + "Attempted to unprefix a path that wasn't in the app root dir.".to_owned(), + ) + })? + .to_str() + .ok_or_else(|| { + RenderErrorReason::Other( + "Either the `app.root-dir` or the specified path contained invalid UTF-8.".to_owned(), + ) + })?, + ) + .map_err(Into::into) +} diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs new file mode 100644 index 000000000000..759eb178bca8 --- /dev/null +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -0,0 +1,434 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{ + detect_target_ok, ensure_init, env, get_app, get_config, inject_resources, load_pbxproj, + log_finished, merge_plist, open_and_wait, project_config, synchronize_project_config, + MobileTarget, OptionsHandle, +}; +use crate::{ + build::Options as BuildOptions, + helpers::{ + app_paths::tauri_dir, + config::{get as get_tauri_config, ConfigHandle}, + flock, + }, + interface::{AppInterface, AppSettings, Interface, Options as InterfaceOptions}, + mobile::{write_options, CliOptions}, + ConfigValue, Result, +}; +use clap::{ArgAction, Parser, ValueEnum}; + +use anyhow::Context; +use cargo_mobile2::{ + apple::{ + config::Config as AppleConfig, + target::{ArchiveConfig, BuildConfig, ExportConfig, Target}, + }, + env::Env, + opts::{NoiseLevel, Profile}, + target::{call_for_targets_with_fallback, TargetInvalid, TargetTrait}, +}; +use rand::distributions::{Alphanumeric, DistString}; + +use std::{ + env::{set_current_dir, var, var_os}, + fs, + path::PathBuf, +}; + +#[derive(Debug, Clone, Parser)] +#[clap( + about = "Build your app in release mode for iOS and generate IPAs", + long_about = "Build your app in release mode for iOS and generate IPAs. It makes use of the `build.frontendDist` property from your `tauri.conf.json` file. It also runs your `build.beforeBuildCommand` which usually builds your frontend into `build.frontendDist`." +)] +pub struct Options { + /// Builds with the debug flag + #[clap(short, long)] + pub debug: bool, + /// Which targets to build. + #[clap( + short, + long = "target", + action = ArgAction::Append, + num_args(0..), + default_value = Target::DEFAULT_KEY, + value_parser(clap::builder::PossibleValuesParser::new(Target::name_list())) + )] + pub targets: Vec, + /// List of cargo features to activate + #[clap(short, long, action = ArgAction::Append, num_args(0..))] + pub features: Option>, + /// JSON string or path to JSON file to merge with tauri.conf.json + #[clap(short, long)] + pub config: Option, + /// Build number to append to the app version. + #[clap(long)] + pub build_number: Option, + /// Open Xcode + #[clap(short, long)] + pub open: bool, + /// Skip prompting for values + #[clap(long, env = "CI")] + pub ci: bool, + /// Describes how Xcode should export the archive. + /// + /// Use this to create a package ready for the App Store (app-store-connect option) or TestFlight (release-testing option). + #[clap(long, value_enum)] + pub export_method: Option, +} + +#[derive(Debug, Clone, Copy, ValueEnum)] +pub enum ExportMethod { + AppStoreConnect, + ReleaseTesting, + Debugging, +} + +impl std::fmt::Display for ExportMethod { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::AppStoreConnect => write!(f, "app-store-connect"), + Self::ReleaseTesting => write!(f, "release-testing"), + Self::Debugging => write!(f, "debugging"), + } + } +} + +impl std::str::FromStr for ExportMethod { + type Err = &'static str; + + fn from_str(s: &str) -> Result { + match s { + "app-store-connect" => Ok(Self::AppStoreConnect), + "release-testing" => Ok(Self::ReleaseTesting), + "debugging" => Ok(Self::Debugging), + _ => Err("unknown ios target"), + } + } +} + +impl From for BuildOptions { + fn from(options: Options) -> Self { + Self { + runner: None, + debug: options.debug, + target: None, + features: options.features, + bundles: None, + no_bundle: false, + config: options.config, + args: Vec::new(), + ci: options.ci, + } + } +} + +pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { + crate::helpers::app_paths::resolve(); + + let mut build_options: BuildOptions = options.clone().into(); + build_options.target = Some( + Target::all() + .get( + options + .targets + .first() + .map(|t| t.as_str()) + .unwrap_or(Target::DEFAULT_KEY), + ) + .unwrap() + .triple + .into(), + ); + + let tauri_config = get_tauri_config( + tauri_utils::platform::Target::Ios, + options.config.as_ref().map(|c| &c.0), + )?; + let (interface, mut config) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let interface = AppInterface::new(tauri_config_, build_options.target.clone())?; + interface.build_options(&mut Vec::new(), &mut build_options.features, true); + + let app = get_app(MobileTarget::Ios, tauri_config_, &interface); + let (config, _metadata) = get_config( + &app, + tauri_config_, + build_options.features.as_ref(), + &Default::default(), + ); + (interface, config) + }; + + let tauri_path = tauri_dir(); + set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?; + + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Ios, + )?; + inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?; + + let mut plist = plist::Dictionary::new(); + let version = interface.app_settings().get_package_settings().version; + plist.insert("CFBundleShortVersionString".into(), version.clone().into()); + plist.insert("CFBundleVersion".into(), version.into()); + + let info_plist_path = config + .project_dir() + .join(config.scheme()) + .join("Info.plist"); + let merged_info_plist = merge_plist(vec![ + info_plist_path.clone().into(), + tauri_path.join("Info.plist").into(), + tauri_path.join("Info.ios.plist").into(), + plist::Value::Dictionary(plist).into(), + ])?; + merged_info_plist.to_file_xml(&info_plist_path)?; + + let mut env = env()?; + + let mut export_options_plist = plist::Dictionary::new(); + if let Some(method) = options.export_method { + export_options_plist.insert("method".to_string(), method.to_string().into()); + } + + let (keychain, provisioning_profile) = super::signing_from_env()?; + let project_config = project_config(keychain.as_ref(), provisioning_profile.as_ref())?; + let mut pbxproj = load_pbxproj(&config)?; + + // synchronize pbxproj and exportoptions + synchronize_project_config( + &config, + &tauri_config, + &mut pbxproj, + &mut export_options_plist, + &project_config, + options.debug, + )?; + if pbxproj.has_changes() { + pbxproj.save()?; + } + + // merge export options and write to temp file + let _export_options_tmp = if !export_options_plist.is_empty() { + let export_options_plist_path = config.project_dir().join("ExportOptions.plist"); + let export_options = tempfile::NamedTempFile::new()?; + + let merged_plist = merge_plist(vec![ + export_options.path().to_owned().into(), + export_options_plist_path.clone().into(), + plist::Value::from(export_options_plist).into(), + ])?; + merged_plist.to_file_xml(export_options.path())?; + + config.set_export_options_plist_path(export_options.path()); + + Some(export_options) + } else { + None + }; + + let open = options.open; + let _handle = run_build( + interface, + options, + build_options, + tauri_config, + &mut config, + &mut env, + noise_level, + )?; + + if open { + open_and_wait(&config, &env); + } + + Ok(()) +} + +#[allow(clippy::too_many_arguments)] +fn run_build( + interface: AppInterface, + options: Options, + mut build_options: BuildOptions, + tauri_config: ConfigHandle, + config: &mut AppleConfig, + env: &mut Env, + noise_level: NoiseLevel, +) -> Result { + let profile = if options.debug { + Profile::Debug + } else { + Profile::Release + }; + + crate::build::setup(&interface, &mut build_options, tauri_config.clone(), true)?; + + let app_settings = interface.app_settings(); + let out_dir = app_settings.out_dir(&InterfaceOptions { + debug: build_options.debug, + target: build_options.target.clone(), + ..Default::default() + })?; + let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; + + let cli_options = CliOptions { + dev: false, + features: build_options.features.clone(), + args: build_options.args.clone(), + noise_level, + vars: Default::default(), + config: build_options.config.clone(), + target_device: None, + }; + let handle = write_options( + &tauri_config.lock().unwrap().as_ref().unwrap().identifier, + cli_options, + )?; + + let mut out_files = Vec::new(); + + call_for_targets_with_fallback( + options.targets.iter(), + &detect_target_ok, + env, + |target: &Target| -> Result<()> { + let mut app_version = config.bundle_version().clone(); + if let Some(build_number) = options.build_number { + app_version.push_extra(build_number); + } + + let credentials = auth_credentials_from_env()?; + let skip_signing = credentials.is_some(); + + let mut build_config = BuildConfig::new().allow_provisioning_updates(); + if let Some(credentials) = &credentials { + build_config = build_config + .authentication_credentials(credentials.clone()) + .skip_codesign(); + } + + target.build(config, env, noise_level, profile, build_config)?; + + let mut archive_config = ArchiveConfig::new(); + if skip_signing { + archive_config = archive_config.skip_codesign(); + } + + target.archive( + config, + env, + noise_level, + profile, + Some(app_version), + archive_config, + )?; + + let out_dir = config.export_dir().join(target.arch); + + if target.sdk == "iphonesimulator" { + fs::create_dir_all(&out_dir)?; + + let app_path = config + .archive_dir() + .join(format!("{}.xcarchive", config.scheme())) + .join("Products") + .join("Applications") + .join(config.app().stylized_name()) + .with_extension("app"); + + let path = out_dir.join(app_path.file_name().unwrap()); + fs::rename(&app_path, &path)?; + out_files.push(path); + } else { + // if we skipped code signing, we do not have the entitlements applied to our exported IPA + // we must force sign the app binary with a dummy certificate just to preserve the entitlements + // target.export() will sign it with an actual certificate for us + if skip_signing { + let password = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); + let certificate = tauri_macos_sign::certificate::generate_self_signed( + tauri_macos_sign::certificate::SelfSignedCertificateRequest { + algorithm: "rsa".to_string(), + profile: tauri_macos_sign::certificate::CertificateProfile::AppleDistribution, + team_id: "unset".to_string(), + person_name: "Tauri".to_string(), + country_name: "NL".to_string(), + validity_days: 365, + password: password.clone(), + }, + )?; + let tmp_dir = tempfile::tempdir()?; + let cert_path = tmp_dir.path().join("cert.p12"); + std::fs::write(&cert_path, certificate)?; + let self_signed_cert_keychain = + tauri_macos_sign::Keychain::with_certificate_file(&cert_path, &password.into())?; + + let app_dir = config + .export_dir() + .join(format!("{}.xcarchive", config.scheme())) + .join("Products/Applications") + .join(format!("{}.app", config.app().stylized_name())); + + self_signed_cert_keychain.sign( + &app_dir.join(config.app().stylized_name()), + Some( + &config + .project_dir() + .join(config.scheme()) + .join(format!("{}.entitlements", config.scheme())), + ), + false, + )?; + } + + let mut export_config = ExportConfig::new().allow_provisioning_updates(); + if let Some(credentials) = &credentials { + export_config = export_config.authentication_credentials(credentials.clone()); + } + + target.export(config, env, noise_level, export_config)?; + + if let Ok(ipa_path) = config.ipa_path() { + fs::create_dir_all(&out_dir)?; + let path = out_dir.join(ipa_path.file_name().unwrap()); + fs::rename(&ipa_path, &path)?; + out_files.push(path); + } + } + + Ok(()) + }, + ) + .map_err(|e: TargetInvalid| anyhow::anyhow!(e.to_string()))??; + + log_finished(out_files, "iOS Bundle"); + + Ok(handle) +} + +fn auth_credentials_from_env() -> Result> { + match ( + var("APPLE_API_KEY"), + var("APPLE_API_ISSUER"), + var_os("APPLE_API_KEY_PATH").map(PathBuf::from), + ) { + (Ok(key_id), Ok(key_issuer_id), Some(key_path)) => { + Ok(Some(cargo_mobile2::apple::AuthCredentials { + key_path, + key_id, + key_issuer_id, + })) + } + (Err(_), Err(_), None) => Ok(None), + _ => anyhow::bail!( + "APPLE_API_KEY, APPLE_API_ISSUER and APPLE_API_KEY_PATH must be provided for code signing" + ), + } +} diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs new file mode 100644 index 000000000000..892afa76e26e --- /dev/null +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -0,0 +1,326 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{ + device_prompt, ensure_init, env, get_app, get_config, inject_resources, load_pbxproj, + merge_plist, open_and_wait, synchronize_project_config, MobileTarget, ProjectConfig, +}; +use crate::{ + dev::Options as DevOptions, + helpers::{ + app_paths::tauri_dir, + config::{get as get_tauri_config, ConfigHandle}, + flock, + }, + interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, + mobile::{ + use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, + }, + ConfigValue, Result, +}; +use clap::{ArgAction, Parser}; + +use anyhow::Context; +use cargo_mobile2::{ + apple::{ + config::Config as AppleConfig, + device::{Device, DeviceKind}, + }, + env::Env, + opts::{NoiseLevel, Profile}, +}; + +use std::env::set_current_dir; + +const PHYSICAL_IPHONE_DEV_WARNING: &str = "To develop on physical phones you need the `--host` option (not required for Simulators). See the documentation for more information: https://v2.tauri.app/develop/#development-server"; + +#[derive(Debug, Clone, Parser)] +#[clap( + about = "Run your app in development mode on iOS", + long_about = "Run your app in development mode on iOS with hot-reloading for the Rust code. +It makes use of the `build.devUrl` property from your `tauri.conf.json` file. +It also runs your `build.beforeDevCommand` which usually starts your frontend devServer. + +When connected to a physical iOS device, the public network address must be used instead of `localhost` +for the devUrl property. Tauri makes that change automatically, but your dev server might need +a different configuration to listen on the public address. You can check the `TAURI_DEV_HOST` +environment variable to determine whether the public network should be used or not." +)] +pub struct Options { + /// List of cargo features to activate + #[clap(short, long, action = ArgAction::Append, num_args(0..))] + pub features: Option>, + /// Exit on panic + #[clap(short, long)] + exit_on_panic: bool, + /// JSON string or path to JSON file to merge with tauri.conf.json + #[clap(short, long)] + pub config: Option, + /// Run the code in release mode + #[clap(long = "release")] + pub release_mode: bool, + /// Skip waiting for the frontend dev server to start before building the tauri application. + #[clap(long, env = "TAURI_CLI_NO_DEV_SERVER_WAIT")] + pub no_dev_server_wait: bool, + /// Disable the file watcher + #[clap(long)] + pub no_watch: bool, + /// Open Xcode instead of trying to run on a connected device + #[clap(short, long)] + pub open: bool, + /// Runs on the given device name + pub device: Option, + /// Force prompting for an IP to use to connect to the dev server on mobile. + #[clap(long)] + pub force_ip_prompt: bool, + /// Use the public network address for the development server. + /// If an actual address it provided, it is used instead of prompting to pick one. + /// + /// This option is particularly useful along the `--open` flag when you intend on running on a physical device. + /// + /// This replaces the devUrl configuration value to match the public network address host, + /// it is your responsibility to set up your development server to listen on this address + /// by using 0.0.0.0 as host for instance. + /// + /// When this is set or when running on an iOS device the CLI sets the `TAURI_DEV_HOST` + /// environment variable so you can check this on your framework's configuration to expose the development server + /// on the public network address. + #[clap(long, default_value_t, default_missing_value(""), num_args(0..=1))] + pub host: DevHost, + /// Disable the built-in dev server for static files. + #[clap(long)] + pub no_dev_server: bool, + /// Specify port for the built-in dev server for static files. Defaults to 1430. + #[clap(long, env = "TAURI_CLI_PORT")] + pub port: Option, +} + +impl From for DevOptions { + fn from(options: Options) -> Self { + Self { + runner: None, + target: None, + features: options.features, + exit_on_panic: options.exit_on_panic, + config: options.config, + release_mode: options.release_mode, + args: Vec::new(), + no_watch: options.no_watch, + no_dev_server: options.no_dev_server, + no_dev_server_wait: options.no_dev_server_wait, + port: options.port, + host: options.host.0.unwrap_or_default(), + } + } +} + +pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { + crate::helpers::app_paths::resolve(); + + let result = run_command(options, noise_level); + if result.is_err() { + crate::dev::kill_before_dev_process(); + } + result +} + +fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { + let env = env()?; + let device = if options.open { + None + } else { + match device_prompt(&env, options.device.as_deref()) { + Ok(d) => Some(d), + Err(e) => { + log::error!("{e}"); + None + } + } + }; + + let mut dev_options: DevOptions = options.clone().into(); + let target_triple = device + .as_ref() + .map(|d| d.target().triple.to_string()) + .unwrap_or_else(|| "aarch64-apple-ios".into()); + dev_options.target = Some(target_triple.clone()); + + let tauri_config = get_tauri_config( + tauri_utils::platform::Target::Ios, + options.config.as_ref().map(|c| &c.0), + )?; + let (interface, config) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let interface = AppInterface::new(tauri_config_, Some(target_triple))?; + + let app = get_app(MobileTarget::Ios, tauri_config_, &interface); + let (config, _metadata) = get_config( + &app, + tauri_config_, + dev_options.features.as_ref(), + &Default::default(), + ); + + (interface, config) + }; + + let tauri_path = tauri_dir(); + set_current_dir(tauri_path).with_context(|| "failed to change current working directory")?; + + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Ios, + )?; + inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?; + + let info_plist_path = config + .project_dir() + .join(config.scheme()) + .join("Info.plist"); + let merged_info_plist = merge_plist(vec![ + info_plist_path.clone().into(), + tauri_path.join("Info.plist").into(), + tauri_path.join("Info.ios.plist").into(), + ])?; + merged_info_plist.to_file_xml(&info_plist_path)?; + + let mut pbxproj = load_pbxproj(&config)?; + + // synchronize pbxproj + synchronize_project_config( + &config, + &tauri_config, + &mut pbxproj, + &mut plist::Dictionary::new(), + &ProjectConfig { + code_sign_identity: None, + team_id: None, + provisioning_profile_uuid: None, + }, + !options.release_mode, + )?; + if pbxproj.has_changes() { + pbxproj.save()?; + } + + run_dev( + interface, + options, + dev_options, + tauri_config, + device, + env, + &config, + noise_level, + ) +} + +#[allow(clippy::too_many_arguments)] +fn run_dev( + mut interface: AppInterface, + options: Options, + mut dev_options: DevOptions, + tauri_config: ConfigHandle, + device: Option, + env: Env, + config: &AppleConfig, + noise_level: NoiseLevel, +) -> Result<()> { + // when running on an actual device we must use the network IP + if options.host.0.is_some() + || device + .as_ref() + .map(|device| !matches!(device.kind(), DeviceKind::Simulator)) + .unwrap_or(false) + { + use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?; + } + + crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; + + let app_settings = interface.app_settings(); + let out_dir = app_settings.out_dir(&InterfaceOptions { + debug: !dev_options.release_mode, + target: dev_options.target.clone(), + ..Default::default() + })?; + let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; + + let set_host = options.host.0.is_some(); + + let open = options.open; + interface.mobile_dev( + MobileOptions { + debug: true, + features: options.features, + args: Vec::new(), + config: dev_options.config.clone(), + no_watch: options.no_watch, + }, + |options| { + let cli_options = CliOptions { + dev: true, + features: options.features.clone(), + args: options.args.clone(), + noise_level, + vars: Default::default(), + config: dev_options.config.clone(), + target_device: None, + }; + let _handle = write_options( + &tauri_config.lock().unwrap().as_ref().unwrap().identifier, + cli_options, + )?; + + if open { + if !set_host { + log::warn!("{PHYSICAL_IPHONE_DEV_WARNING}"); + } + open_and_wait(config, &env) + } else if let Some(device) = &device { + match run(device, options, config, noise_level, &env) { + Ok(c) => Ok(Box::new(c) as Box), + Err(e) => { + crate::dev::kill_before_dev_process(); + Err(e) + } + } + } else { + if !set_host { + log::warn!("{PHYSICAL_IPHONE_DEV_WARNING}"); + } + open_and_wait(config, &env) + } + }, + ) +} + +fn run( + device: &Device<'_>, + options: MobileOptions, + config: &AppleConfig, + noise_level: NoiseLevel, + env: &Env, +) -> crate::Result { + let profile = if options.debug { + Profile::Debug + } else { + Profile::Release + }; + + device + .run( + config, + env, + noise_level, + false, // do not quit on app exit + profile, + ) + .map(DevChild::new) + .map_err(Into::into) +} diff --git a/crates/tauri-cli/src/mobile/ios/mod.rs b/crates/tauri-cli/src/mobile/ios/mod.rs new file mode 100644 index 000000000000..1e0e63a56ed4 --- /dev/null +++ b/crates/tauri-cli/src/mobile/ios/mod.rs @@ -0,0 +1,572 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use cargo_mobile2::{ + apple::{ + config::{ + Config as AppleConfig, Metadata as AppleMetadata, Platform as ApplePlatform, + Raw as RawAppleConfig, + }, + device::{self, Device}, + target::Target, + teams::find_development_teams, + }, + config::app::{App, DEFAULT_ASSET_DIR}, + env::Env, + opts::NoiseLevel, + os, + util::{prompt, relativize_path}, +}; +use clap::{Parser, Subcommand}; +use sublime_fuzzy::best_match; +use tauri_utils::resources::ResourcePaths; + +use super::{ + ensure_init, env, get_app, init::command as init_command, log_finished, read_options, CliOptions, + OptionsHandle, Target as MobileTarget, MIN_DEVICE_MATCH_SCORE, +}; +use crate::{ + helpers::{ + app_paths::tauri_dir, + config::{BundleResources, Config as TauriConfig, ConfigHandle}, + pbxproj, + }, + Result, +}; + +use std::{ + env::{set_var, var_os}, + fs::create_dir_all, + path::PathBuf, + thread::sleep, + time::Duration, +}; + +mod build; +mod dev; +pub(crate) mod project; +mod xcode_script; + +pub const APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME: &str = "APPLE_DEVELOPMENT_TEAM"; +pub const LIB_OUTPUT_FILE_NAME: &str = "libapp.a"; + +#[derive(Parser)] +#[clap( + author, + version, + about = "iOS commands", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Debug, Parser)] +#[clap(about = "Initialize iOS target in the project")] +pub struct InitOptions { + /// Skip prompting for values + #[clap(long, env = "CI")] + ci: bool, + /// Reinstall dependencies + #[clap(short, long)] + reinstall_deps: bool, + /// Skips installing rust toolchains via rustup + #[clap(long)] + skip_targets_install: bool, +} + +#[derive(Subcommand)] +enum Commands { + Init(InitOptions), + Dev(dev::Options), + Build(build::Options), + #[clap(hide(true))] + XcodeScript(xcode_script::Options), +} + +pub fn command(cli: Cli, verbosity: u8) -> Result<()> { + let noise_level = NoiseLevel::from_occurrences(verbosity as u64); + match cli.command { + Commands::Init(options) => { + crate::helpers::app_paths::resolve(); + init_command( + MobileTarget::Ios, + options.ci, + options.reinstall_deps, + options.skip_targets_install, + )? + } + Commands::Dev(options) => dev::command(options, noise_level)?, + Commands::Build(options) => build::command(options, noise_level)?, + Commands::XcodeScript(options) => xcode_script::command(options)?, + } + + Ok(()) +} + +pub fn get_config( + app: &App, + tauri_config: &TauriConfig, + features: Option<&Vec>, + cli_options: &CliOptions, +) -> (AppleConfig, AppleMetadata) { + let mut ios_options = cli_options.clone(); + if let Some(features) = features { + ios_options + .features + .get_or_insert(Vec::new()) + .extend_from_slice(features); + } + + let raw = RawAppleConfig { + development_team: std::env::var(APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME) + .ok() + .or_else(|| tauri_config.bundle.ios.development_team.clone()) + .or_else(|| { + let teams = find_development_teams().unwrap_or_default(); + match teams.len() { + 0 => { + log::warn!("No code signing certificates found. You must add one and set the certificate development team ID on the `bundle > iOS > developmentTeam` config value or the `{APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME}` environment variable. To list the available certificates, run `tauri info`."); + None + } + 1 => None, + _ => { + log::warn!("You must set the code signing certificate development team ID on the `bundle > iOS > developmentTeam` config value or the `{APPLE_DEVELOPMENT_TEAM_ENV_VAR_NAME}` environment variable. Available certificates: {}", teams.iter().map(|t| format!("{} (ID: {})", t.name, t.id)).collect::>().join(", ")); + None + } + } + }), + ios_features: ios_options.features.clone(), + bundle_version: tauri_config.version.clone(), + bundle_version_short: tauri_config.version.clone(), + ios_version: Some(tauri_config.bundle.ios.minimum_system_version.clone()), + ..Default::default() + }; + let config = AppleConfig::from_raw(app.clone(), Some(raw)).unwrap(); + + let tauri_dir = tauri_dir(); + + let mut vendor_frameworks = Vec::new(); + let mut frameworks = Vec::new(); + for framework in tauri_config + .bundle + .ios + .frameworks + .clone() + .unwrap_or_default() + { + let framework_path = PathBuf::from(&framework); + let ext = framework_path.extension().unwrap_or_default(); + if ext.is_empty() { + frameworks.push(framework); + } else if ext == "framework" { + frameworks.push( + framework_path + .file_stem() + .unwrap() + .to_string_lossy() + .to_string(), + ); + } else { + vendor_frameworks.push( + relativize_path(tauri_dir.join(framework_path), config.project_dir()) + .to_string_lossy() + .to_string(), + ); + } + } + + let metadata = AppleMetadata { + supported: true, + ios: ApplePlatform { + cargo_args: Some(ios_options.args), + features: ios_options.features, + frameworks: Some(frameworks), + vendor_frameworks: Some(vendor_frameworks), + ..Default::default() + }, + macos: Default::default(), + }; + + set_var("TAURI_IOS_PROJECT_PATH", config.project_dir()); + set_var("TAURI_IOS_APP_NAME", config.app().name()); + + (config, metadata) +} + +fn connected_device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result> { + let device_list = device::list_devices(env) + .map_err(|cause| anyhow::anyhow!("Failed to detect connected iOS devices: {cause}"))?; + if !device_list.is_empty() { + let device = if let Some(t) = target { + let (device, score) = device_list + .into_iter() + .rev() + .map(|d| { + let score = best_match(t, d.name()).map_or(0, |m| m.score()); + (d, score) + }) + .max_by_key(|(_, score)| *score) + // we already checked the list is not empty + .unwrap(); + if score > MIN_DEVICE_MATCH_SCORE { + device + } else { + anyhow::bail!("Could not find an iOS device matching {t}") + } + } else { + let index = if device_list.len() > 1 { + prompt::list( + concat!("Detected ", "iOS", " devices"), + device_list.iter(), + "device", + None, + "Device", + ) + .map_err(|cause| anyhow::anyhow!("Failed to prompt for iOS device: {cause}"))? + } else { + 0 + }; + device_list.into_iter().nth(index).unwrap() + }; + println!( + "Detected connected device: {} with target {:?}", + device, + device.target().triple, + ); + Ok(device) + } else { + Err(anyhow::anyhow!("No connected iOS devices detected")) + } +} + +fn simulator_prompt(env: &'_ Env, target: Option<&str>) -> Result { + let simulator_list = device::list_simulators(env).map_err(|cause| { + anyhow::anyhow!("Failed to detect connected iOS Simulator devices: {cause}") + })?; + if !simulator_list.is_empty() { + let device = if let Some(t) = target { + let (device, score) = simulator_list + .into_iter() + .rev() + .map(|d| { + let score = best_match(t, d.name()).map_or(0, |m| m.score()); + (d, score) + }) + .max_by_key(|(_, score)| *score) + // we already checked the list is not empty + .unwrap(); + if score > MIN_DEVICE_MATCH_SCORE { + device + } else { + anyhow::bail!("Could not find an iOS Simulator matching {t}") + } + } else if simulator_list.len() > 1 { + let index = prompt::list( + concat!("Detected ", "iOS", " simulators"), + simulator_list.iter(), + "simulator", + None, + "Simulator", + ) + .map_err(|cause| anyhow::anyhow!("Failed to prompt for iOS Simulator device: {cause}"))?; + simulator_list.into_iter().nth(index).unwrap() + } else { + simulator_list.into_iter().next().unwrap() + }; + Ok(device) + } else { + Err(anyhow::anyhow!("No available iOS Simulator detected")) + } +} + +fn device_prompt<'a>(env: &'_ Env, target: Option<&str>) -> Result> { + if let Ok(device) = connected_device_prompt(env, target) { + Ok(device) + } else { + let simulator = simulator_prompt(env, target)?; + log::info!("Starting simulator {}", simulator.name()); + simulator.start_detached(env)?; + Ok(simulator.into()) + } +} + +fn detect_target_ok<'a>(env: &Env) -> Option<&'a Target<'a>> { + device_prompt(env, None).map(|device| device.target()).ok() +} + +fn open_and_wait(config: &AppleConfig, env: &Env) -> ! { + log::info!("Opening Xcode"); + if let Err(e) = os::open_file_with("Xcode", config.project_dir(), env) { + log::error!("{}", e); + } + loop { + sleep(Duration::from_secs(24 * 60 * 60)); + } +} + +fn inject_resources(config: &AppleConfig, tauri_config: &TauriConfig) -> Result<()> { + let asset_dir = config.project_dir().join(DEFAULT_ASSET_DIR); + create_dir_all(&asset_dir)?; + + let resources = match &tauri_config.bundle.resources { + Some(BundleResources::List(paths)) => Some(ResourcePaths::new(paths.as_slice(), true)), + Some(BundleResources::Map(map)) => Some(ResourcePaths::from_map(map, true)), + None => None, + }; + if let Some(resources) = resources { + for resource in resources.iter() { + let resource = resource?; + let dest = asset_dir.join(resource.target()); + crate::helpers::fs::copy_file(resource.path(), dest)?; + } + } + + Ok(()) +} + +enum PlistKind { + Path(PathBuf), + Plist(plist::Value), +} + +impl From for PlistKind { + fn from(p: PathBuf) -> Self { + Self::Path(p) + } +} +impl From for PlistKind { + fn from(p: plist::Value) -> Self { + Self::Plist(p) + } +} + +fn merge_plist(src: Vec) -> Result { + let mut merged_plist = plist::Dictionary::new(); + + for plist_kind in src { + let plist = match plist_kind { + PlistKind::Path(p) => plist::Value::from_file(p), + PlistKind::Plist(v) => Ok(v), + }; + if let Ok(src_plist) = plist { + if let Some(dict) = src_plist.into_dictionary() { + for (key, value) in dict { + merged_plist.insert(key, value); + } + } + } + } + + Ok(plist::Value::Dictionary(merged_plist)) +} + +pub fn signing_from_env() -> Result<( + Option, + Option, +)> { + let keychain = match ( + var_os("IOS_CERTIFICATE"), + var_os("IOS_CERTIFICATE_PASSWORD"), + ) { + (Some(certificate), Some(certificate_password)) => { + log::info!("Reading iOS certificates from "); + tauri_macos_sign::Keychain::with_certificate(&certificate, &certificate_password).map(Some)? + } + (Some(_), None) => { + log::warn!("The IOS_CERTIFICATE environment variable is set but not IOS_CERTIFICATE_PASSWORD. Ignoring the certificate..."); + None + } + _ => None, + }; + + let provisioning_profile = if let Some(provisioning_profile) = var_os("IOS_MOBILE_PROVISION") { + tauri_macos_sign::ProvisioningProfile::from_base64(&provisioning_profile).map(Some)? + } else { + if keychain.is_some() { + log::warn!("You have provided an iOS certificate via environment variables but the IOS_MOBILE_PROVISION environment variable is not set. This will fail when signing unless the profile is set in your Xcode project."); + } + None + }; + + Ok((keychain, provisioning_profile)) +} + +pub struct ProjectConfig { + pub code_sign_identity: Option, + pub team_id: Option, + pub provisioning_profile_uuid: Option, +} + +pub fn project_config( + keychain: Option<&tauri_macos_sign::Keychain>, + provisioning_profile: Option<&tauri_macos_sign::ProvisioningProfile>, +) -> Result { + Ok(ProjectConfig { + code_sign_identity: keychain.map(|k| k.signing_identity()), + team_id: keychain.and_then(|k| k.team_id().map(ToString::to_string)), + provisioning_profile_uuid: provisioning_profile.and_then(|p| p.uuid().ok()), + }) +} + +pub fn load_pbxproj(config: &AppleConfig) -> Result { + pbxproj::parse( + config + .project_dir() + .join(format!("{}.xcodeproj", config.app().name())) + .join("project.pbxproj"), + ) +} + +pub fn synchronize_project_config( + config: &AppleConfig, + tauri_config: &ConfigHandle, + pbxproj: &mut pbxproj::Pbxproj, + export_options_plist: &mut plist::Dictionary, + project_config: &ProjectConfig, + debug: bool, +) -> Result<()> { + let identifier = tauri_config + .lock() + .unwrap() + .as_ref() + .unwrap() + .identifier + .clone(); + + let manual_signing = project_config.code_sign_identity.is_some() + || project_config.provisioning_profile_uuid.is_some(); + + if let Some(xc_configuration_list) = pbxproj + .xc_configuration_list + .clone() + .into_values() + .find(|l| l.comment.contains("_iOS")) + { + for build_configuration_ref in xc_configuration_list.build_configurations { + if manual_signing { + pbxproj.set_build_settings(&build_configuration_ref.id, "CODE_SIGN_STYLE", "Manual"); + } + + if let Some(team) = config.development_team() { + pbxproj.set_build_settings(&build_configuration_ref.id, "DEVELOPMENT_TEAM", team); + } + + pbxproj.set_build_settings( + &build_configuration_ref.id, + "PRODUCT_BUNDLE_IDENTIFIER", + &identifier, + ); + + if let Some(identity) = &project_config.code_sign_identity { + let identity = format!("\"{identity}\""); + pbxproj.set_build_settings(&build_configuration_ref.id, "CODE_SIGN_IDENTITY", &identity); + pbxproj.set_build_settings( + &build_configuration_ref.id, + "\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"", + &identity, + ); + } + + if let Some(id) = &project_config.team_id { + pbxproj.set_build_settings(&build_configuration_ref.id, "DEVELOPMENT_TEAM", id); + pbxproj.set_build_settings( + &build_configuration_ref.id, + "\"DEVELOPMENT_TEAM[sdk=iphoneos*]\"", + id, + ); + } + + if let Some(profile_uuid) = &project_config.provisioning_profile_uuid { + let profile_uuid = format!("\"{profile_uuid}\""); + pbxproj.set_build_settings( + &build_configuration_ref.id, + "PROVISIONING_PROFILE_SPECIFIER", + &profile_uuid, + ); + pbxproj.set_build_settings( + &build_configuration_ref.id, + "\"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]\"", + &profile_uuid, + ); + } + } + } + + let build_configuration = { + if let Some(xc_configuration_list) = pbxproj + .xc_configuration_list + .clone() + .into_values() + .find(|l| l.comment.contains("_iOS")) + { + let mut configuration = None; + let target = if debug { "debug" } else { "release" }; + for build_configuration_ref in xc_configuration_list.build_configurations { + if build_configuration_ref.comments.contains(target) { + configuration = pbxproj + .xc_build_configuration + .get(&build_configuration_ref.id); + break; + } + } + + configuration + } else { + None + } + }; + + if let Some(build_configuration) = build_configuration { + if let Some(style) = build_configuration.get_build_setting("CODE_SIGN_STYLE") { + export_options_plist.insert( + "signingStyle".to_string(), + style.value.to_lowercase().into(), + ); + } else { + export_options_plist.insert("signingStyle".to_string(), "automatic".into()); + } + + if manual_signing { + if let Some(identity) = build_configuration + .get_build_setting("\"CODE_SIGN_IDENTITY[sdk=iphoneos*]\"") + .or_else(|| build_configuration.get_build_setting("CODE_SIGN_IDENTITY")) + { + export_options_plist.insert( + "signingCertificate".to_string(), + identity.value.trim_matches('"').into(), + ); + } + + let profile_uuid = project_config + .provisioning_profile_uuid + .clone() + .or_else(|| { + build_configuration + .get_build_setting("\"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]\"") + .or_else(|| build_configuration.get_build_setting("PROVISIONING_PROFILE_SPECIFIER")) + .map(|setting| setting.value.trim_matches('"').to_string()) + }); + if let Some(profile_uuid) = profile_uuid { + let mut provisioning_profiles = plist::Dictionary::new(); + provisioning_profiles.insert(config.app().identifier().to_string(), profile_uuid.into()); + export_options_plist.insert( + "provisioningProfiles".to_string(), + provisioning_profiles.into(), + ); + } + } + + if let Some(id) = build_configuration + .get_build_setting("\"DEVELOPMENT_TEAM[sdk=iphoneos*]\"") + .or_else(|| build_configuration.get_build_setting("DEVELOPMENT_TEAM")) + { + export_options_plist.insert("teamID".to_string(), id.value.trim_matches('"').into()); + } + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/mobile/ios/project.rs b/crates/tauri-cli/src/mobile/ios/project.rs new file mode 100644 index 000000000000..f87b5ce02d42 --- /dev/null +++ b/crates/tauri-cli/src/mobile/ios/project.rs @@ -0,0 +1,229 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::{config::Config as TauriConfig, template}, + mobile::ios::LIB_OUTPUT_FILE_NAME, + Result, +}; +use anyhow::Context; +use cargo_mobile2::{ + apple::{ + config::{Config, Metadata}, + deps, rust_version_check, + target::Target, + }, + config::app::DEFAULT_ASSET_DIR, + target::TargetTrait as _, + util::{self, cli::TextWrapper}, +}; +use handlebars::Handlebars; +use include_dir::{include_dir, Dir}; +use std::{ + ffi::OsString, + fs::{create_dir_all, OpenOptions}, + path::{Component, PathBuf}, +}; + +const TEMPLATE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/mobile/ios"); + +// unprefixed app_root seems pretty dangerous!! +// TODO: figure out what cargo-mobile meant by that +#[allow(clippy::too_many_arguments)] +pub fn gen( + tauri_config: &TauriConfig, + config: &Config, + metadata: &Metadata, + (handlebars, mut map): (Handlebars, template::JsonMap), + wrapper: &TextWrapper, + non_interactive: bool, + reinstall_deps: bool, + skip_targets_install: bool, +) -> Result<()> { + if !skip_targets_install { + let installed_targets = + crate::interface::rust::installation::installed_targets().unwrap_or_default(); + let missing_targets = Target::all() + .values() + .filter(|t| !installed_targets.contains(&t.triple().into())) + .collect::>(); + + if !missing_targets.is_empty() { + println!("Installing iOS Rust toolchains..."); + for target in missing_targets { + target + .install() + .context("failed to install target with rustup")?; + } + } + } + + rust_version_check(wrapper)?; + + deps::install_all(wrapper, non_interactive, true, reinstall_deps) + .with_context(|| "failed to install Apple dependencies")?; + + let dest = config.project_dir(); + let rel_prefix = util::relativize_path(config.app().root_dir(), &dest); + let source_dirs = vec![rel_prefix.join("src")]; + + let asset_catalogs = metadata.ios().asset_catalogs().unwrap_or_default(); + let ios_pods = metadata.ios().pods().unwrap_or_default(); + let macos_pods = metadata.macos().pods().unwrap_or_default(); + + #[cfg(target_arch = "aarch64")] + let default_archs = ["arm64", "arm64-sim"]; + #[cfg(not(target_arch = "aarch64"))] + let default_archs = ["arm64", "x86_64"]; + + map.insert("lib-output-file-name", LIB_OUTPUT_FILE_NAME); + + map.insert("file-groups", &source_dirs); + map.insert("ios-frameworks", metadata.ios().frameworks()); + map.insert("ios-valid-archs", default_archs); + map.insert("ios-vendor-frameworks", metadata.ios().vendor_frameworks()); + map.insert("ios-vendor-sdks", metadata.ios().vendor_sdks()); + map.insert("macos-frameworks", metadata.macos().frameworks()); + map.insert( + "macos-vendor-frameworks", + metadata.macos().vendor_frameworks(), + ); + map.insert("macos-vendor-sdks", metadata.macos().vendor_frameworks()); + map.insert("asset-catalogs", asset_catalogs); + map.insert("ios-pods", ios_pods); + map.insert("macos-pods", macos_pods); + map.insert( + "ios-additional-targets", + metadata.ios().additional_targets(), + ); + map.insert( + "macos-additional-targets", + metadata.macos().additional_targets(), + ); + map.insert("ios-pre-build-scripts", metadata.ios().pre_build_scripts()); + map.insert( + "ios-post-compile-scripts", + metadata.ios().post_compile_scripts(), + ); + map.insert( + "ios-post-build-scripts", + metadata.ios().post_build_scripts(), + ); + map.insert( + "macos-pre-build-scripts", + metadata.macos().pre_build_scripts(), + ); + map.insert( + "macos-post-compile-scripts", + metadata.macos().post_compile_scripts(), + ); + map.insert( + "macos-post-build-scripts", + metadata.macos().post_build_scripts(), + ); + map.insert( + "ios-command-line-arguments", + metadata.ios().command_line_arguments(), + ); + map.insert( + "macos-command-line-arguments", + metadata.macos().command_line_arguments(), + ); + + let mut created_dirs = Vec::new(); + template::render_with_generator( + &handlebars, + map.inner(), + &TEMPLATE_DIR, + &dest, + &mut |path| { + let mut components: Vec<_> = path.components().collect(); + let mut new_component = None; + for component in &mut components { + if let Component::Normal(c) = component { + let c = c.to_string_lossy(); + if c.contains("{{app.name}}") { + new_component.replace(OsString::from( + &c.replace("{{app.name}}", config.app().name()), + )); + *component = Component::Normal(new_component.as_ref().unwrap()); + break; + } + } + } + let path = dest.join(components.iter().collect::()); + + let parent = path.parent().unwrap().to_path_buf(); + if !created_dirs.contains(&parent) { + create_dir_all(&parent)?; + created_dirs.push(parent); + } + + let mut options = OpenOptions::new(); + options.write(true); + + if !path.exists() { + options.create(true).open(path).map(Some) + } else { + Ok(None) + } + }, + ) + .with_context(|| "failed to process template")?; + + if let Some(template_path) = tauri_config.bundle.ios.template.as_ref() { + let template = std::fs::read_to_string(template_path) + .context("failed to read custom Xcode project template")?; + let mut output_file = std::fs::File::create(dest.join("project.yml"))?; + handlebars + .render_template_to_write(&template, map.inner(), &mut output_file) + .expect("Failed to render template"); + } + + let mut dirs_to_create = asset_catalogs.to_vec(); + dirs_to_create.push(dest.join(DEFAULT_ASSET_DIR)); + dirs_to_create.push(dest.join("Externals")); + dirs_to_create.push(dest.join(format!("{}_iOS", config.app().name()))); + + // Create all required project directories if they don't already exist + for dir in &dirs_to_create { + std::fs::create_dir_all(dir).map_err(|cause| { + anyhow::anyhow!( + "failed to create directory at {path}: {cause}", + path = dir.display() + ) + })?; + } + + // Note that Xcode doesn't always reload the project nicely; reopening is + // often necessary. + println!("Generating Xcode project..."); + duct::cmd( + "xcodegen", + [ + "generate", + "--spec", + &dest.join("project.yml").to_string_lossy(), + ], + ) + .stdout_file(os_pipe::dup_stdout().unwrap()) + .stderr_file(os_pipe::dup_stderr().unwrap()) + .run() + .with_context(|| "failed to run `xcodegen`")?; + + if !ios_pods.is_empty() || !macos_pods.is_empty() { + duct::cmd( + "pod", + [ + "install", + &format!("--project-directory={}", dest.display()), + ], + ) + .stdout_file(os_pipe::dup_stdout().unwrap()) + .stderr_file(os_pipe::dup_stderr().unwrap()) + .run() + .with_context(|| "failed to run `pod install`")?; + } + Ok(()) +} diff --git a/crates/tauri-cli/src/mobile/ios/xcode_script.rs b/crates/tauri-cli/src/mobile/ios/xcode_script.rs new file mode 100644 index 000000000000..cc34d81da9a2 --- /dev/null +++ b/crates/tauri-cli/src/mobile/ios/xcode_script.rs @@ -0,0 +1,285 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::{ensure_init, env, get_app, get_config, read_options, MobileTarget}; +use crate::{ + helpers::config::get as get_tauri_config, + interface::{AppInterface, Interface, Options as InterfaceOptions}, + mobile::ios::LIB_OUTPUT_FILE_NAME, + Result, +}; + +use anyhow::Context; +use cargo_mobile2::{apple::target::Target, opts::Profile}; +use clap::{ArgAction, Parser}; +use object::{Object, ObjectSymbol}; + +use std::{ + collections::HashMap, + env::{current_dir, set_current_dir, var, var_os}, + ffi::OsStr, + fs::read_to_string, + io::Read, + path::{Path, PathBuf}, +}; + +#[derive(Debug, Parser)] +pub struct Options { + /// Value of `PLATFORM_DISPLAY_NAME` env var + #[clap(long)] + platform: String, + /// Value of `SDKROOT` env var + #[clap(long)] + sdk_root: PathBuf, + /// Value of `FRAMEWORK_SEARCH_PATHS` env var + #[clap(long, action = ArgAction::Append, num_args(0..))] + framework_search_paths: Vec, + /// Value of `GCC_PREPROCESSOR_DEFINITIONS` env var + #[clap(long, action = ArgAction::Append, num_args(0..))] + gcc_preprocessor_definitions: Vec, + /// Value of `HEADER_SEARCH_PATHS` env var + #[clap(long, action = ArgAction::Append, num_args(0..))] + header_search_paths: Vec, + /// Value of `CONFIGURATION` env var + #[clap(long)] + configuration: String, + /// Value of `FORCE_COLOR` env var + #[clap(long)] + force_color: bool, + /// Value of `ARCHS` env var + #[clap(index = 1, required = true)] + arches: Vec, +} + +pub fn command(options: Options) -> Result<()> { + fn macos_from_platform(platform: &str) -> bool { + platform == "macOS" + } + + fn profile_from_configuration(configuration: &str) -> Profile { + if configuration == "release" { + Profile::Release + } else { + Profile::Debug + } + } + + // `xcode-script` is ran from the `gen/apple` folder when not using NPM. + // so we must change working directory to the src-tauri folder to resolve the tauri dir + if (var_os("npm_lifecycle_event").is_none() && var_os("PNPM_PACKAGE_NAME").is_none()) + || var("npm_config_user_agent").map_or(false, |agent| agent.starts_with("bun")) + { + set_current_dir(current_dir()?.parent().unwrap().parent().unwrap()).unwrap(); + } + + crate::helpers::app_paths::resolve(); + + let profile = profile_from_configuration(&options.configuration); + let macos = macos_from_platform(&options.platform); + + let tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, None)?; + + let (config, metadata, cli_options) = { + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + let cli_options = read_options(&tauri_config_.identifier); + let (config, metadata) = get_config( + &get_app( + MobileTarget::Ios, + tauri_config_, + &AppInterface::new(tauri_config_, None)?, + ), + tauri_config_, + None, + &cli_options, + ); + (config, metadata, cli_options) + }; + ensure_init( + &tauri_config, + config.app(), + config.project_dir(), + MobileTarget::Ios, + )?; + + if let Some(config) = &cli_options.config { + crate::helpers::config::merge_with(&config.0)?; + } + + let env = env()?.explicit_env_vars(cli_options.vars); + + if !options.sdk_root.is_dir() { + return Err(anyhow::anyhow!( + "SDK root provided by Xcode was invalid. {} doesn't exist or isn't a directory", + options.sdk_root.display(), + )); + } + let include_dir = options.sdk_root.join("usr/include"); + if !include_dir.is_dir() { + return Err(anyhow::anyhow!( + "Include dir was invalid. {} doesn't exist or isn't a directory", + include_dir.display() + )); + } + + // Host flags that are used by build scripts + let macos_isysroot = { + let macos_sdk_root = options + .sdk_root + .join("../../../../MacOSX.platform/Developer/SDKs/MacOSX.sdk"); + if !macos_sdk_root.is_dir() { + return Err(anyhow::anyhow!( + "Invalid SDK root {}", + macos_sdk_root.display() + )); + } + format!("-isysroot {}", macos_sdk_root.display()) + }; + + let mut host_env = HashMap::<&str, &OsStr>::new(); + + host_env.insert("RUST_BACKTRACE", "1".as_ref()); + + host_env.insert("CFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref()); + host_env.insert("CXXFLAGS_x86_64_apple_darwin", macos_isysroot.as_ref()); + + host_env.insert( + "OBJC_INCLUDE_PATH_x86_64_apple_darwin", + include_dir.as_os_str(), + ); + + let framework_search_paths = options.framework_search_paths.join(" "); + host_env.insert("FRAMEWORK_SEARCH_PATHS", framework_search_paths.as_ref()); + + let gcc_preprocessor_definitions = options.gcc_preprocessor_definitions.join(" "); + host_env.insert( + "GCC_PREPROCESSOR_DEFINITIONS", + gcc_preprocessor_definitions.as_ref(), + ); + + let header_search_paths = options.header_search_paths.join(" "); + host_env.insert("HEADER_SEARCH_PATHS", header_search_paths.as_ref()); + + let macos_target = Target::macos(); + + let isysroot = format!("-isysroot {}", options.sdk_root.display()); + + for arch in options.arches { + // Set target-specific flags + let (env_triple, rust_triple) = match arch.as_str() { + "arm64" => ("aarch64_apple_ios", "aarch64-apple-ios"), + "arm64-sim" => ("aarch64_apple_ios_sim", "aarch64-apple-ios-sim"), + "x86_64" => ("x86_64_apple_ios", "x86_64-apple-ios"), + "Simulator" => { + // when using Xcode, the arches for a simulator build will be ['Simulator', 'arm64-sim'] instead of ['arm64-sim'] + // so we ignore that on our end + continue; + } + _ => { + return Err(anyhow::anyhow!( + "Arch specified by Xcode was invalid. {} isn't a known arch", + arch + )) + } + }; + + let interface = AppInterface::new( + tauri_config.lock().unwrap().as_ref().unwrap(), + Some(rust_triple.into()), + )?; + + let cflags = format!("CFLAGS_{}", env_triple); + let cxxflags = format!("CFLAGS_{}", env_triple); + let objc_include_path = format!("OBJC_INCLUDE_PATH_{}", env_triple); + let mut target_env = host_env.clone(); + target_env.insert(cflags.as_ref(), isysroot.as_ref()); + target_env.insert(cxxflags.as_ref(), isysroot.as_ref()); + target_env.insert(objc_include_path.as_ref(), include_dir.as_ref()); + + let target = if macos { + &macos_target + } else { + Target::for_arch(&arch).ok_or_else(|| { + anyhow::anyhow!( + "Arch specified by Xcode was invalid. {} isn't a known arch", + arch + ) + })? + }; + target.compile_lib( + &config, + &metadata, + cli_options.noise_level, + true, + profile, + &env, + target_env, + )?; + + let out_dir = interface.app_settings().out_dir(&InterfaceOptions { + debug: matches!(profile, Profile::Debug), + target: Some(rust_triple.into()), + ..Default::default() + })?; + + let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name())); + if !lib_path.exists() { + return Err(anyhow::anyhow!("Library not found at {}. Make sure your Cargo.toml file has a [lib] block with `crate-type = [\"staticlib\", \"cdylib\", \"lib\"]`", lib_path.display())); + } + + validate_lib(&lib_path)?; + + let project_dir = config.project_dir(); + let externals_lib_dir = project_dir.join(format!("Externals/{arch}/{}", profile.as_str())); + std::fs::create_dir_all(&externals_lib_dir)?; + + // backwards compatible lib output file name + let uses_new_lib_output_file_name = { + let pbxproj_contents = read_to_string( + project_dir + .join(format!("{}.xcodeproj", config.app().name())) + .join("project.pbxproj"), + ) + .context("missing project.pbxproj file in the Xcode project")?; + + pbxproj_contents.contains(LIB_OUTPUT_FILE_NAME) + }; + + let lib_output_file_name = if uses_new_lib_output_file_name { + LIB_OUTPUT_FILE_NAME.to_string() + } else { + format!("lib{}.a", config.app().lib_name()) + }; + + std::fs::copy(lib_path, externals_lib_dir.join(lib_output_file_name))?; + } + Ok(()) +} + +fn validate_lib(path: &Path) -> Result<()> { + let mut archive = ar::Archive::new(std::fs::File::open(path)?); + // Iterate over all entries in the archive: + while let Some(entry) = archive.next_entry() { + let Ok(mut entry) = entry else { + continue; + }; + let mut obj_bytes = Vec::new(); + entry.read_to_end(&mut obj_bytes)?; + + let file = object::File::parse(&*obj_bytes)?; + for symbol in file.symbols() { + let Ok(name) = symbol.name() else { + continue; + }; + if name.contains("start_app") { + return Ok(()); + } + } + } + + anyhow::bail!( + "Library from {} does not include required runtime symbols. This means you are likely missing the tauri::mobile_entry_point macro usage, see the documentation for more information: https://v2.tauri.app/start/migrate/from-tauri-1", + path.display() + ) +} diff --git a/crates/tauri-cli/src/mobile/mod.rs b/crates/tauri-cli/src/mobile/mod.rs new file mode 100644 index 000000000000..d9e5a10dbc19 --- /dev/null +++ b/crates/tauri-cli/src/mobile/mod.rs @@ -0,0 +1,570 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::{ + app_paths::tauri_dir, + config::{reload as reload_config, Config as TauriConfig, ConfigHandle}, + }, + interface::{AppInterface, AppSettings, DevProcess, Interface, Options as InterfaceOptions}, + ConfigValue, +}; +#[cfg(unix)] +use anyhow::Context; +use anyhow::{bail, Result}; +use heck::ToSnekCase; +use jsonrpsee::core::client::{Client, ClientBuilder, ClientT}; +use jsonrpsee::server::{RpcModule, ServerBuilder, ServerHandle}; +use jsonrpsee_client_transport::ws::WsTransportClientBuilder; +use jsonrpsee_core::rpc_params; +use serde::{Deserialize, Serialize}; + +use cargo_mobile2::{ + config::app::{App, Raw as RawAppConfig}, + env::Error as EnvError, + opts::{NoiseLevel, Profile}, + ChildHandle, +}; +use std::{ + collections::HashMap, + env::{set_var, temp_dir}, + ffi::OsString, + fmt::{Display, Write}, + fs::{read_to_string, write}, + net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr}, + path::PathBuf, + process::{exit, ExitStatus}, + str::FromStr, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, OnceLock, + }, +}; +use tokio::runtime::Runtime; + +#[cfg(not(windows))] +use cargo_mobile2::env::Env; +#[cfg(windows)] +use cargo_mobile2::os::Env; + +pub mod android; +mod init; +#[cfg(target_os = "macos")] +pub mod ios; + +const MIN_DEVICE_MATCH_SCORE: isize = 0; + +#[derive(Clone)] +pub struct DevChild { + child: Arc, + manually_killed_process: Arc, +} + +impl DevChild { + fn new(handle: ChildHandle) -> Self { + Self { + child: Arc::new(handle), + manually_killed_process: Default::default(), + } + } +} + +impl DevProcess for DevChild { + fn kill(&self) -> std::io::Result<()> { + self.manually_killed_process.store(true, Ordering::Relaxed); + match self.child.kill() { + Ok(_) => Ok(()), + Err(e) => { + self.manually_killed_process.store(false, Ordering::Relaxed); + Err(e) + } + } + } + + fn try_wait(&self) -> std::io::Result> { + self.child.try_wait().map(|res| res.map(|o| o.status)) + } + + fn wait(&self) -> std::io::Result { + self.child.wait().map(|o| o.status) + } + + fn manually_killed_process(&self) -> bool { + self.manually_killed_process.load(Ordering::Relaxed) + } +} + +#[derive(PartialEq, Eq, Copy, Clone)] +pub enum Target { + Android, + #[cfg(target_os = "macos")] + Ios, +} + +impl Target { + fn ide_name(&self) -> &'static str { + match self { + Self::Android => "Android Studio", + #[cfg(target_os = "macos")] + Self::Ios => "Xcode", + } + } + + fn command_name(&self) -> &'static str { + match self { + Self::Android => "android", + #[cfg(target_os = "macos")] + Self::Ios => "ios", + } + } + + fn ide_build_script_name(&self) -> &'static str { + match self { + Self::Android => "android-studio-script", + #[cfg(target_os = "macos")] + Self::Ios => "xcode-script", + } + } + + fn platform_target(&self) -> tauri_utils::platform::Target { + match self { + Self::Android => tauri_utils::platform::Target::Android, + #[cfg(target_os = "macos")] + Self::Ios => tauri_utils::platform::Target::Ios, + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct TargetDevice { + id: String, + name: String, +} + +#[derive(Debug, Clone)] +pub struct DevHost(Option>); + +impl FromStr for DevHost { + type Err = AddrParseError; + fn from_str(s: &str) -> std::result::Result { + if s.is_empty() || s == "" { + Ok(Self(Some(None))) + } else if s == "" { + Ok(Self(None)) + } else { + IpAddr::from_str(s).map(|addr| Self(Some(Some(addr)))) + } + } +} + +impl Display for DevHost { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self.0 { + Some(None) => write!(f, ""), + Some(Some(addr)) => write!(f, "{addr}"), + None => write!(f, ""), + } + } +} + +impl Default for DevHost { + fn default() -> Self { + // on Windows we want to force using the public network address for the development server + // because the adb port forwarding does not work well + if cfg!(windows) { + Self(Some(None)) + } else { + Self(None) + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct CliOptions { + pub dev: bool, + pub features: Option>, + pub args: Vec, + pub noise_level: NoiseLevel, + pub vars: HashMap, + pub config: Option, + pub target_device: Option, +} + +impl Default for CliOptions { + fn default() -> Self { + Self { + dev: false, + features: None, + args: vec!["--lib".into()], + noise_level: Default::default(), + vars: Default::default(), + config: None, + target_device: None, + } + } +} + +fn local_ip_address(force: bool) -> &'static IpAddr { + static LOCAL_IP: OnceLock = OnceLock::new(); + LOCAL_IP.get_or_init(|| { + let prompt_for_ip = || { + let addresses: Vec = local_ip_address::list_afinet_netifas() + .expect("failed to list networks") + .into_iter() + .map(|(_, ipaddr)| ipaddr) + .filter(|ipaddr| match ipaddr { + IpAddr::V4(i) => i != &Ipv4Addr::LOCALHOST, + IpAddr::V6(i) => i.to_string().ends_with("::2"), + + }) + .collect(); + match addresses.len() { + 0 => panic!("No external IP detected."), + 1 => { + let ipaddr = addresses.first().unwrap(); + *ipaddr + } + _ => { + let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default()) + .with_prompt( + "Failed to detect external IP, What IP should we use to access your development server?", + ) + .items(&addresses) + .default(0) + .interact() + .expect("failed to select external IP"); + *addresses.get(selected).unwrap() + } + } + }; + + let ip = if force { + prompt_for_ip() + } else { + local_ip_address::local_ip().unwrap_or_else(|_| prompt_for_ip()) + }; + log::info!("Using {ip} to access the development server."); + ip + }) +} + +struct DevUrlConfig { + no_dev_server_wait: bool, +} + +fn use_network_address_for_dev_url( + config: &ConfigHandle, + dev_options: &mut crate::dev::Options, + force_ip_prompt: bool, +) -> crate::Result { + let mut dev_url = config + .lock() + .unwrap() + .as_ref() + .unwrap() + .build + .dev_url + .clone(); + + let ip = if let Some(url) = &mut dev_url { + let localhost = match url.host() { + Some(url::Host::Domain(d)) => d == "localhost", + Some(url::Host::Ipv4(i)) => { + i == std::net::Ipv4Addr::LOCALHOST || i == std::net::Ipv4Addr::UNSPECIFIED + } + _ => false, + }; + + if localhost { + let ip = dev_options + .host + .unwrap_or_else(|| *local_ip_address(force_ip_prompt)); + log::info!( + "Replacing devUrl host with {ip}. {}.", + "If your frontend is not listening on that address, try configuring your development server to use the `TAURI_DEV_HOST` environment variable or 0.0.0.0 as host" + ); + + *url = url::Url::parse(&format!( + "{}://{}{}", + url.scheme(), + SocketAddr::new(ip, url.port_or_known_default().unwrap()), + url.path() + ))?; + + if let Some(c) = &mut dev_options.config { + if let Some(build) = c + .0 + .as_object_mut() + .and_then(|root| root.get_mut("build")) + .and_then(|build| build.as_object_mut()) + { + build.insert("devUrl".into(), url.to_string().into()); + } + } else { + let mut build = serde_json::Map::new(); + build.insert("devUrl".into(), url.to_string().into()); + + dev_options + .config + .replace(crate::ConfigValue(serde_json::json!({ + "build": build + }))); + } + reload_config(dev_options.config.as_ref().map(|c| &c.0))?; + + Some(ip) + } else { + None + } + } else if !dev_options.no_dev_server { + let ip = dev_options + .host + .unwrap_or_else(|| *local_ip_address(force_ip_prompt)); + dev_options.host.replace(ip); + Some(ip) + } else { + None + }; + + let mut dev_url_config = DevUrlConfig { + no_dev_server_wait: false, + }; + + if let Some(ip) = ip { + std::env::set_var("TAURI_DEV_HOST", ip.to_string()); + std::env::set_var("TRUNK_SERVE_ADDRESS", ip.to_string()); + if ip.is_ipv6() { + // in this case we can't ping the server for some reason + dev_url_config.no_dev_server_wait = true; + } + } + + Ok(dev_url_config) +} + +fn env_vars() -> HashMap { + let mut vars = HashMap::new(); + vars.insert("RUST_LOG_STYLE".into(), "always".into()); + for (k, v) in std::env::vars_os() { + let k = k.to_string_lossy(); + if (k.starts_with("TAURI") + && k != "TAURI_SIGNING_PRIVATE_KEY" + && k != "TAURI_SIGNING_PRIVATE_KEY_PASSWORD") + || k.starts_with("WRY") + || k.starts_with("CARGO_") + || k == "TMPDIR" + || k == "PATH" + { + vars.insert(k.into_owned(), v); + } + } + vars +} + +fn env() -> Result { + let env = Env::new()?.explicit_env_vars(env_vars()); + Ok(env) +} + +pub struct OptionsHandle(#[allow(unused)] Runtime, #[allow(unused)] ServerHandle); + +/// Writes CLI options to be used later on the Xcode and Android Studio build commands +pub fn write_options(identifier: &str, mut options: CliOptions) -> crate::Result { + options.vars.extend(env_vars()); + + let runtime = Runtime::new().unwrap(); + let r: anyhow::Result<(ServerHandle, SocketAddr)> = runtime.block_on(async move { + let server = ServerBuilder::default().build("127.0.0.1:0").await?; + let addr = server.local_addr()?; + + let mut module = RpcModule::new(()); + module.register_method("options", move |_, _, _| Some(options.clone()))?; + + let handle = server.start(module); + + Ok((handle, addr)) + }); + let (handle, addr) = r?; + + write( + temp_dir().join(format!("{identifier}-server-addr")), + addr.to_string(), + )?; + + Ok(OptionsHandle(runtime, handle)) +} + +fn read_options(identifier: &str) -> CliOptions { + let runtime = tokio::runtime::Runtime::new().unwrap(); + let options = runtime + .block_on(async move { + let addr_path = temp_dir().join(format!("{identifier}-server-addr")); + let (tx, rx) = WsTransportClientBuilder::default() + .build( + format!( + "ws://{}", + read_to_string(&addr_path).unwrap_or_else(|e| panic!( + "failed to read missing addr file {}: {e}", + addr_path.display() + )) + ) + .parse() + .unwrap(), + ) + .await?; + let client: Client = ClientBuilder::default().build_with_tokio(tx, rx); + let options: CliOptions = client.request("options", rpc_params![]).await?; + Ok::(options) + }) + .expect("failed to read CLI options"); + + for (k, v) in &options.vars { + set_var(k, v); + } + options +} + +pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) -> App { + let identifier = match target { + Target::Android => config.identifier.replace('-', "_"), + #[cfg(target_os = "macos")] + Target::Ios => config.identifier.replace('_', "-"), + }; + + if identifier.is_empty() { + log::error!("Bundle identifier set in `tauri.conf.json > identifier` cannot be empty"); + exit(1); + } + + let app_name = interface + .app_settings() + .app_name() + .unwrap_or_else(|| "app".into()); + let lib_name = interface + .app_settings() + .lib_name() + .unwrap_or_else(|| app_name.to_snek_case()); + + let raw = RawAppConfig { + name: app_name, + lib_name: Some(lib_name), + stylized_name: config.product_name.clone(), + identifier, + asset_dir: None, + template_pack: None, + }; + + let app_settings = interface.app_settings(); + App::from_raw(tauri_dir().to_path_buf(), raw) + .unwrap() + .with_target_dir_resolver(move |target, profile| { + app_settings + .out_dir(&InterfaceOptions { + debug: matches!(profile, Profile::Debug), + target: Some(target.into()), + ..Default::default() + }) + .expect("failed to resolve target directory") + }) +} + +#[allow(unused_variables)] +fn ensure_init( + tauri_config: &ConfigHandle, + app: &App, + project_dir: PathBuf, + target: Target, +) -> Result<()> { + if !project_dir.exists() { + bail!( + "{} project directory {} doesn't exist. Please run `tauri {} init` and try again.", + target.ide_name(), + project_dir.display(), + target.command_name(), + ) + } + + let tauri_config_guard = tauri_config.lock().unwrap(); + let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + + let mut project_outdated_reasons = Vec::new(); + + match target { + Target::Android => { + let java_folder = project_dir + .join("app/src/main/java") + .join(tauri_config_.identifier.replace('.', "/").replace('-', "_")); + if java_folder.exists() { + #[cfg(unix)] + ensure_gradlew(&project_dir)?; + } else { + project_outdated_reasons + .push("you have modified your \"identifier\" in the Tauri configuration"); + } + } + #[cfg(target_os = "macos")] + Target::Ios => { + let pbxproj_contents = read_to_string( + project_dir + .join(format!("{}.xcodeproj", app.name())) + .join("project.pbxproj"), + ) + .context("missing project.yml file in the Xcode project directory")?; + + if !(pbxproj_contents.contains(ios::LIB_OUTPUT_FILE_NAME) + || pbxproj_contents.contains(&format!("lib{}.a", app.lib_name()))) + { + project_outdated_reasons + .push("you have modified your [lib.name] or [package.name] in the Cargo.toml file"); + } + } + } + + if !project_outdated_reasons.is_empty() { + let reason = project_outdated_reasons.join(" and "); + bail!( + "{} project directory is outdated because {reason}. Please run `tauri {} init` and try again.", + target.ide_name(), + target.command_name(), + ) + } + + Ok(()) +} + +#[cfg(unix)] +fn ensure_gradlew(project_dir: &std::path::Path) -> Result<()> { + use std::os::unix::fs::PermissionsExt; + + let gradlew_path = project_dir.join("gradlew"); + if let Ok(metadata) = gradlew_path.metadata() { + let mut permissions = metadata.permissions(); + let is_executable = permissions.mode() & 0o111 != 0; + if !is_executable { + permissions.set_mode(permissions.mode() | 0o111); + std::fs::set_permissions(&gradlew_path, permissions) + .context("failed to mark gradlew as executable")?; + } + std::fs::write( + &gradlew_path, + std::fs::read_to_string(&gradlew_path) + .context("failed to read gradlew")? + .replace("\r\n", "\n"), + ) + .context("failed to replace gradlew CRLF with LF")?; + } + + Ok(()) +} + +fn log_finished(outputs: Vec, kind: &str) { + if !outputs.is_empty() { + let mut printable_paths = String::new(); + for path in &outputs { + writeln!(printable_paths, " {}", path.display()).unwrap(); + } + + log::info!(action = "Finished"; "{} {}{} at:\n{}", outputs.len(), kind, if outputs.len() == 1 { "" } else { "s" }, printable_paths); + } +} diff --git a/crates/tauri-cli/src/plugin/android.rs b/crates/tauri-cli/src/plugin/android.rs new file mode 100644 index 000000000000..59451405350e --- /dev/null +++ b/crates/tauri-cli/src/plugin/android.rs @@ -0,0 +1,138 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::{prompts, template}, + Result, +}; +use clap::{Parser, Subcommand}; +use handlebars::Handlebars; + +use std::{ + collections::BTreeMap, + env::current_dir, + ffi::OsStr, + path::{Component, PathBuf}, +}; + +#[derive(Parser)] +#[clap( + author, + version, + about = "Manage the Android project for a Tauri plugin", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + Init(InitOptions), +} + +#[derive(Debug, Parser)] +#[clap(about = "Initializes the Android project for an existing Tauri plugin")] +pub struct InitOptions { + /// Name of your Tauri plugin. Must match the current plugin's name. + /// If not specified, it will be inferred from the current directory. + plugin_name: Option, + /// The output directory. + #[clap(short, long)] + #[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())] + out_dir: String, +} + +pub fn command(cli: Cli) -> Result<()> { + match cli.command { + Commands::Init(options) => { + let plugin_name = match options.plugin_name { + None => super::infer_plugin_name(std::env::current_dir()?)?, + Some(name) => name, + }; + + let out_dir = PathBuf::from(options.out_dir); + if out_dir.join("android").exists() { + return Err(anyhow::anyhow!("android folder already exists")); + } + + let plugin_id = prompts::input( + "What should be the Android Package ID for your plugin?", + Some(format!("com.plugin.{}", plugin_name)), + false, + false, + )? + .unwrap(); + + let handlebars = Handlebars::new(); + + let mut data = BTreeMap::new(); + super::init::plugin_name_data(&mut data, &plugin_name); + data.insert("android_package_id", handlebars::to_json(&plugin_id)); + + let mut created_dirs = Vec::new(); + template::render_with_generator( + &handlebars, + &data, + &super::init::TEMPLATE_DIR, + &out_dir, + &mut |path| { + let mut components = path.components(); + let root = components.next().unwrap(); + if let Component::Normal(component) = root { + if component == OsStr::new("android") { + return super::init::generate_android_out_file( + &path, + &out_dir, + &plugin_id.replace('.', "/"), + &mut created_dirs, + ); + } + } + + Ok(None) + }, + )?; + + let metadata = super::init::crates_metadata()?; + + let cargo_toml_addition = format!( + r#" +[build-dependencies] +tauri-build = "{}" +"#, + metadata.tauri_build + ); + let build_file = super::init::TEMPLATE_DIR + .get_file("build.rs") + .unwrap() + .contents_utf8() + .unwrap(); + let init_fn = format!( + r#" +pub fn init() -> TauriPlugin {{ + Builder::new("{name}") + .setup(|app, api| {{ + #[cfg(target_os = "android")] + let handle = api.register_android_plugin("{identifier}", "ExamplePlugin")?; + Ok(()) + }}) + .build() +}} +"#, + name = plugin_name, + identifier = plugin_id + ); + + log::info!("Android project added"); + println!("You must add the following to the Cargo.toml file:\n{cargo_toml_addition}",); + println!("You must add the following code to the build.rs file:\n\n{build_file}",); + println!("Your plugin's init function under src/lib.rs must initialize the Android plugin:\n{init_fn}"); + } + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/plugin/init.rs b/crates/tauri-cli/src/plugin/init.rs new file mode 100644 index 000000000000..06317be77f08 --- /dev/null +++ b/crates/tauri-cli/src/plugin/init.rs @@ -0,0 +1,319 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::PluginIosFramework; +use crate::helpers::prompts; +use crate::Result; +use crate::{ + helpers::{resolve_tauri_path, template}, + VersionMetadata, +}; +use anyhow::Context; +use clap::Parser; +use handlebars::{to_json, Handlebars}; +use heck::{ToKebabCase, ToPascalCase, ToSnakeCase}; +use include_dir::{include_dir, Dir}; +use std::ffi::{OsStr, OsString}; +use std::{ + collections::BTreeMap, + env::current_dir, + fs::{create_dir_all, remove_dir_all, File, OpenOptions}, + path::{Component, Path, PathBuf}, +}; + +pub const TEMPLATE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/templates/plugin"); + +#[derive(Debug, Parser)] +#[clap(about = "Initialize a Tauri plugin project on an existing directory")] +pub struct Options { + /// Name of your Tauri plugin. + /// If not specified, it will be inferred from the current directory. + pub(crate) plugin_name: Option, + /// Initializes a Tauri plugin without the TypeScript API + #[clap(long)] + pub(crate) no_api: bool, + /// Initialize without an example project. + #[clap(long)] + pub(crate) no_example: bool, + /// Set target directory for init + #[clap(short, long)] + #[clap(default_value_t = current_dir().expect("failed to read cwd").display().to_string())] + pub(crate) directory: String, + /// Author name + #[clap(short, long)] + pub(crate) author: Option, + /// Whether to initialize an Android project for the plugin. + #[clap(long)] + pub(crate) android: bool, + /// Whether to initialize an iOS project for the plugin. + #[clap(long)] + pub(crate) ios: bool, + /// Whether to initialize Android and iOS projects for the plugin. + #[clap(long)] + pub(crate) mobile: bool, + /// Type of framework to use for the iOS project. + #[clap(long)] + #[clap(default_value_t = PluginIosFramework::default())] + pub(crate) ios_framework: PluginIosFramework, + /// Generate github workflows + #[clap(long)] + pub(crate) github_workflows: bool, + + /// Initializes a Tauri core plugin (internal usage) + #[clap(long, hide(true))] + pub(crate) tauri: bool, + /// Path of the Tauri project to use (relative to the cwd) + #[clap(short, long)] + pub(crate) tauri_path: Option, +} + +impl Options { + fn load(&mut self) { + if self.author.is_none() { + self.author.replace(if self.tauri { + "Tauri Programme within The Commons Conservancy".into() + } else { + "You".into() + }); + } + } +} + +pub fn command(mut options: Options) -> Result<()> { + options.load(); + + let plugin_name = match options.plugin_name { + None => super::infer_plugin_name(&options.directory)?, + Some(name) => name, + }; + + let template_target_path = PathBuf::from(options.directory); + let metadata = crates_metadata()?; + if std::fs::read_dir(&template_target_path)?.count() > 0 { + log::warn!("Plugin dir ({:?}) not empty.", template_target_path); + } else { + let (tauri_dep, tauri_example_dep, tauri_build_dep, tauri_plugin_dep) = + if let Some(tauri_path) = options.tauri_path { + ( + format!( + r#"{{ path = {:?} }}"#, + resolve_tauri_path(&tauri_path, "crates/tauri") + ), + format!( + r#"{{ path = {:?} }}"#, + resolve_tauri_path(&tauri_path, "crates/tauri") + ), + format!( + "{{ path = {:?}, default-features = false }}", + resolve_tauri_path(&tauri_path, "crates/tauri-build") + ), + format!( + r#"{{ path = {:?}, features = ["build"] }}"#, + resolve_tauri_path(&tauri_path, "crates/tauri-plugin") + ), + ) + } else { + ( + format!(r#"{{ version = "{}" }}"#, metadata.tauri), + format!(r#"{{ version = "{}" }}"#, metadata.tauri), + format!( + r#"{{ version = "{}", default-features = false }}"#, + metadata.tauri_build + ), + format!( + r#"{{ version = "{}", features = ["build"] }}"#, + metadata.tauri_plugin + ), + ) + }; + + let _ = remove_dir_all(&template_target_path); + let mut handlebars = Handlebars::new(); + handlebars.register_escape_fn(handlebars::no_escape); + + let mut data = BTreeMap::new(); + plugin_name_data(&mut data, &plugin_name); + data.insert("tauri_dep", to_json(tauri_dep)); + data.insert("tauri_example_dep", to_json(tauri_example_dep)); + data.insert("tauri_build_dep", to_json(tauri_build_dep)); + data.insert("tauri_plugin_dep", to_json(tauri_plugin_dep)); + data.insert("author", to_json(options.author)); + + if options.tauri { + data.insert( + "license_header", + to_json( + "// Copyright 2019-2024 Tauri Programme within The Commons Conservancy + // SPDX-License-Identifier: Apache-2.0 + // SPDX-License-Identifier: MIT\n\n" + .replace(" ", "") + .replace(" //", "//"), + ), + ); + } + + let plugin_id = if options.android || options.mobile { + let plugin_id = prompts::input( + "What should be the Android Package ID for your plugin?", + Some(format!("com.plugin.{}", plugin_name)), + false, + false, + )? + .unwrap(); + + data.insert("android_package_id", to_json(&plugin_id)); + Some(plugin_id) + } else { + None + }; + + let ios_framework = options.ios_framework; + + let mut created_dirs = Vec::new(); + template::render_with_generator( + &handlebars, + &data, + &TEMPLATE_DIR, + &template_target_path, + &mut |mut path| { + let mut components = path.components(); + let root = components.next().unwrap(); + + if let Component::Normal(component) = root { + match component.to_str().unwrap() { + "__example-api" => { + if options.no_api || options.no_example { + return Ok(None); + } else { + path = Path::new("examples").join(components.collect::()); + } + } + "__example-basic" => { + if options.no_api && !options.no_example { + path = Path::new("examples").join(components.collect::()); + } else { + return Ok(None); + } + } + ".github" if !options.github_workflows => return Ok(None), + "android" => { + if options.android || options.mobile { + return generate_android_out_file( + &path, + &template_target_path, + &plugin_id.as_ref().unwrap().replace('.', "/"), + &mut created_dirs, + ); + } else { + return Ok(None); + } + } + "ios-spm" | "ios-xcode" if !(options.ios || options.mobile) => return Ok(None), + "ios-spm" if !matches!(ios_framework, PluginIosFramework::Spm) => return Ok(None), + "ios-xcode" if !matches!(ios_framework, PluginIosFramework::Xcode) => return Ok(None), + "ios-spm" | "ios-xcode" => { + let folder_name = components.next().unwrap().as_os_str().to_string_lossy(); + let new_folder_name = folder_name.replace("{{ plugin_name }}", &plugin_name); + let new_folder_name = OsString::from(&new_folder_name); + + path = [ + Component::Normal(OsStr::new("ios")), + Component::Normal(&new_folder_name), + ] + .into_iter() + .chain(components) + .collect::(); + } + "guest-js" | "rollup.config.js" | "tsconfig.json" | "package.json" + if options.no_api => + { + return Ok(None); + } + _ => (), + } + } + + let path = template_target_path.join(path); + let parent = path.parent().unwrap().to_path_buf(); + if !created_dirs.contains(&parent) { + create_dir_all(&parent)?; + created_dirs.push(parent); + } + File::create(path).map(Some) + }, + ) + .with_context(|| "failed to render plugin template")?; + } + + let permissions_dir = template_target_path.join("permissions"); + std::fs::create_dir(&permissions_dir) + .with_context(|| "failed to create `permissions` directory")?; + + let default_permissions = r#"[default] +description = "Default permissions for the plugin" +permissions = ["allow-ping"] +"#; + std::fs::write(permissions_dir.join("default.toml"), default_permissions) + .with_context(|| "failed to write `permissions/default.toml`")?; + + Ok(()) +} + +pub fn plugin_name_data(data: &mut BTreeMap<&'static str, serde_json::Value>, plugin_name: &str) { + data.insert("plugin_name_original", to_json(plugin_name)); + data.insert("plugin_name", to_json(plugin_name.to_kebab_case())); + data.insert( + "plugin_name_snake_case", + to_json(plugin_name.to_snake_case()), + ); + data.insert( + "plugin_name_pascal_case", + to_json(plugin_name.to_pascal_case()), + ); +} + +pub fn crates_metadata() -> Result { + serde_json::from_str::(include_str!("../../metadata-v2.json")) + .map_err(Into::into) +} + +pub fn generate_android_out_file( + path: &Path, + dest: &Path, + package_path: &str, + created_dirs: &mut Vec, +) -> std::io::Result> { + let mut iter = path.iter(); + let root = iter.next().unwrap().to_str().unwrap(); + let path = match (root, path.extension().and_then(|o| o.to_str())) { + ("src", Some("kt")) => { + let parent = path.parent().unwrap(); + let file_name = path.file_name().unwrap(); + let out_dir = dest.join(parent).join(package_path); + out_dir.join(file_name) + } + _ => dest.join(path), + }; + + let parent = path.parent().unwrap().to_path_buf(); + if !created_dirs.contains(&parent) { + create_dir_all(&parent)?; + created_dirs.push(parent); + } + + let mut options = OpenOptions::new(); + options.write(true); + + #[cfg(unix)] + if path.file_name().unwrap() == std::ffi::OsStr::new("gradlew") { + use std::os::unix::fs::OpenOptionsExt; + options.mode(0o755); + } + + if !path.exists() { + options.create(true).open(path).map(Some) + } else { + Ok(None) + } +} diff --git a/crates/tauri-cli/src/plugin/ios.rs b/crates/tauri-cli/src/plugin/ios.rs new file mode 100644 index 000000000000..f0be47f2a775 --- /dev/null +++ b/crates/tauri-cli/src/plugin/ios.rs @@ -0,0 +1,154 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::PluginIosFramework; +use crate::{helpers::template, Result}; +use clap::{Parser, Subcommand}; +use handlebars::Handlebars; + +use std::{ + collections::BTreeMap, + env::current_dir, + ffi::{OsStr, OsString}, + fs::{create_dir_all, File}, + path::{Component, PathBuf}, +}; + +#[derive(Parser)] +#[clap( + author, + version, + about = "Manage the iOS project for a Tauri plugin", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + Init(InitOptions), +} + +#[derive(Debug, Parser)] +#[clap(about = "Initializes the iOS project for an existing Tauri plugin")] +pub struct InitOptions { + /// Name of your Tauri plugin. Must match the current plugin's name. + /// If not specified, it will be inferred from the current directory. + plugin_name: Option, + /// The output directory. + #[clap(short, long)] + #[clap(default_value_t = current_dir().expect("failed to read cwd").to_string_lossy().into_owned())] + out_dir: String, + /// Type of framework to use for the iOS project. + #[clap(long)] + #[clap(default_value_t = PluginIosFramework::default())] + ios_framework: PluginIosFramework, +} + +pub fn command(cli: Cli) -> Result<()> { + match cli.command { + Commands::Init(options) => { + let plugin_name = match options.plugin_name { + None => super::infer_plugin_name(std::env::current_dir()?)?, + Some(name) => name, + }; + + let out_dir = PathBuf::from(options.out_dir); + if out_dir.join("ios").exists() { + return Err(anyhow::anyhow!("ios folder already exists")); + } + + let handlebars = Handlebars::new(); + + let mut data = BTreeMap::new(); + super::init::plugin_name_data(&mut data, &plugin_name); + + let ios_folder_name = match options.ios_framework { + PluginIosFramework::Spm => OsStr::new("ios-spm"), + PluginIosFramework::Xcode => OsStr::new("ios-xcode"), + }; + + let mut created_dirs = Vec::new(); + template::render_with_generator( + &handlebars, + &data, + &super::init::TEMPLATE_DIR, + &out_dir, + &mut |path| { + let mut components = path.components(); + let root = components.next().unwrap(); + if let Component::Normal(component) = root { + if component == ios_folder_name { + let folder_name = components.next().unwrap().as_os_str().to_string_lossy(); + let new_folder_name = folder_name.replace("{{ plugin_name }}", &plugin_name); + let new_folder_name = OsString::from(&new_folder_name); + + let path = [ + Component::Normal(OsStr::new("ios")), + Component::Normal(&new_folder_name), + ] + .into_iter() + .chain(components) + .collect::(); + + let path = out_dir.join(path); + let parent = path.parent().unwrap().to_path_buf(); + if !created_dirs.contains(&parent) { + create_dir_all(&parent)?; + created_dirs.push(parent); + } + return File::create(path).map(Some); + } + } + + Ok(None) + }, + )?; + + let metadata = super::init::crates_metadata()?; + + let cargo_toml_addition = format!( + r#" +[build-dependencies] +tauri-build = "{}" +"#, + metadata.tauri_build + ); + let build_file = super::init::TEMPLATE_DIR + .get_file("build.rs") + .unwrap() + .contents_utf8() + .unwrap(); + let init_fn = format!( + r#" +#[cfg(target_os = "ios")] +tauri::ios_plugin_binding!(init_plugin_{name}); + +pub fn init() -> TauriPlugin {{ + Builder::new("{name}") + .setup(|app| {{ + #[cfg(target_os = "ios")] + app.register_ios_plugin(init_plugin_{name})?; + Ok(()) + }}) + .build() +}} +"#, + name = plugin_name, + ); + + log::info!("iOS project added"); + println!("You must add the following to the Cargo.toml file:\n{cargo_toml_addition}",); + println!("You must add the following code to the build.rs file:\n\n{build_file}",); + println!( + "Your plugin's init function under src/lib.rs must initialize the iOS plugin:\n{init_fn}" + ); + } + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/plugin/mod.rs b/crates/tauri-cli/src/plugin/mod.rs new file mode 100644 index 000000000000..a1c5c7d9afbf --- /dev/null +++ b/crates/tauri-cli/src/plugin/mod.rs @@ -0,0 +1,91 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{fmt::Display, path::Path}; + +use clap::{Parser, Subcommand, ValueEnum}; + +use crate::Result; + +mod android; +mod init; +mod ios; +mod new; + +#[derive(Debug, Clone, ValueEnum, Default)] +pub enum PluginIosFramework { + /// Swift Package Manager project + #[default] + Spm, + /// Xcode project + Xcode, +} + +impl Display for PluginIosFramework { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Spm => write!(f, "spm"), + Self::Xcode => write!(f, "xcode"), + } + } +} + +#[derive(Parser)] +#[clap( + author, + version, + about = "Manage or create Tauri plugins", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + New(new::Options), + Init(init::Options), + Android(android::Cli), + Ios(ios::Cli), +} + +pub fn command(cli: Cli) -> Result<()> { + match cli.command { + Commands::New(options) => new::command(options)?, + Commands::Init(options) => init::command(options)?, + Commands::Android(cli) => android::command(cli)?, + Commands::Ios(cli) => ios::command(cli)?, + } + + Ok(()) +} + +fn infer_plugin_name>(directory: P) -> Result { + let dir = directory.as_ref(); + let cargo_toml_path = dir.join("Cargo.toml"); + let name = if cargo_toml_path.exists() { + let contents = std::fs::read_to_string(cargo_toml_path)?; + let cargo_toml: toml::Value = toml::from_str(&contents)?; + cargo_toml + .get("package") + .and_then(|v| v.get("name")) + .map(|v| v.as_str().unwrap_or_default()) + .unwrap_or_default() + .to_string() + } else { + dir + .file_name() + .unwrap_or_default() + .to_string_lossy() + .to_string() + }; + Ok( + name + .strip_prefix("tauri-plugin-") + .unwrap_or(&name) + .to_string(), + ) +} diff --git a/crates/tauri-cli/src/plugin/new.rs b/crates/tauri-cli/src/plugin/new.rs new file mode 100644 index 000000000000..3e000d43ad86 --- /dev/null +++ b/crates/tauri-cli/src/plugin/new.rs @@ -0,0 +1,83 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use super::PluginIosFramework; +use crate::Result; +use clap::Parser; +use std::path::PathBuf; + +#[derive(Debug, Parser)] +#[clap(about = "Initializes a new Tauri plugin project")] +pub struct Options { + /// Name of your Tauri plugin + plugin_name: String, + /// Initializes a Tauri plugin without the TypeScript API + #[clap(long)] + no_api: bool, + /// Initialize without an example project. + #[clap(long)] + no_example: bool, + /// Set target directory for init + #[clap(short, long)] + directory: Option, + /// Author name + #[clap(short, long)] + author: Option, + /// Whether to initialize an Android project for the plugin. + #[clap(long)] + android: bool, + /// Whether to initialize an iOS project for the plugin. + #[clap(long)] + ios: bool, + /// Whether to initialize Android and iOS projects for the plugin. + #[clap(long)] + mobile: bool, + /// Type of framework to use for the iOS project. + #[clap(long)] + #[clap(default_value_t = PluginIosFramework::default())] + pub(crate) ios_framework: PluginIosFramework, + /// Generate github workflows + #[clap(long)] + github_workflows: bool, + + /// Initializes a Tauri core plugin (internal usage) + #[clap(long, hide(true))] + tauri: bool, + /// Path of the Tauri project to use (relative to the cwd) + #[clap(short, long)] + tauri_path: Option, +} + +impl From for super::init::Options { + fn from(o: Options) -> Self { + Self { + plugin_name: Some(o.plugin_name), + no_api: o.no_api, + no_example: o.no_example, + directory: o.directory.unwrap(), + author: o.author, + android: o.android, + ios: o.ios, + mobile: o.mobile, + ios_framework: o.ios_framework, + github_workflows: o.github_workflows, + + tauri: o.tauri, + tauri_path: o.tauri_path, + } + } +} + +pub fn command(mut options: Options) -> Result<()> { + let cwd = std::env::current_dir()?; + if let Some(dir) = &options.directory { + std::fs::create_dir_all(cwd.join(dir))?; + } else { + let target = cwd.join(format!("tauri-plugin-{}", options.plugin_name)); + std::fs::create_dir_all(&target)?; + options.directory.replace(target.display().to_string()); + } + + super::init::command(options.into()) +} diff --git a/crates/tauri-cli/src/remove.rs b/crates/tauri-cli/src/remove.rs new file mode 100644 index 000000000000..319f60e82860 --- /dev/null +++ b/crates/tauri-cli/src/remove.rs @@ -0,0 +1,69 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use clap::Parser; + +use crate::{ + acl, + helpers::{ + app_paths::{resolve_frontend_dir, tauri_dir}, + cargo, + npm::PackageManager, + }, + Result, +}; + +#[derive(Debug, Parser)] +#[clap(about = "Remove a tauri plugin from the project")] +pub struct Options { + /// The plugin to remove. + pub plugin: String, +} + +pub fn command(options: Options) -> Result<()> { + crate::helpers::app_paths::resolve(); + run(options) +} + +pub fn run(options: Options) -> Result<()> { + let plugin = options.plugin; + + let crate_name = format!("tauri-plugin-{plugin}"); + + let mut plugins = crate::helpers::plugins::known_plugins(); + let metadata = plugins.remove(plugin.as_str()).unwrap_or_default(); + + let frontend_dir = resolve_frontend_dir(); + let tauri_dir = tauri_dir(); + + let target_str = metadata + .desktop_only + .then_some(r#"cfg(not(any(target_os = "android", target_os = "ios")))"#) + .or_else(|| { + metadata + .mobile_only + .then_some(r#"cfg(any(target_os = "android", target_os = "ios"))"#) + }); + + cargo::uninstall_one(cargo::CargoUninstallOptions { + name: &crate_name, + cwd: Some(tauri_dir), + target: target_str, + })?; + + if !metadata.rust_only { + if let Some(manager) = frontend_dir.map(PackageManager::from_project) { + let npm_name = format!("@tauri-apps/plugin-{plugin}"); + manager.remove(&[npm_name], tauri_dir)?; + } + + acl::permission::rm::command(acl::permission::rm::Options { + identifier: format!("{plugin}:*"), + })?; + } + + log::info!("Now, you must manually remove the plugin from your Rust code.",); + + Ok(()) +} diff --git a/crates/tauri-cli/src/signer/generate.rs b/crates/tauri-cli/src/signer/generate.rs new file mode 100644 index 000000000000..97f3b37088f1 --- /dev/null +++ b/crates/tauri-cli/src/signer/generate.rs @@ -0,0 +1,64 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + helpers::updater_signature::{generate_key, save_keypair}, + Result, +}; +use clap::Parser; +use std::path::PathBuf; +use tauri_utils::display_path; + +#[derive(Debug, Parser)] +#[clap(about = "Generate a new signing key to sign files")] +pub struct Options { + /// Set private key password when signing + #[clap(short, long)] + password: Option, + /// Write private key to a file + #[clap(short, long)] + write_keys: Option, + /// Overwrite private key even if it exists on the specified path + #[clap(short, long)] + force: bool, + /// Skip prompting for values + #[clap(long, env = "CI")] + ci: bool, +} + +pub fn command(mut options: Options) -> Result<()> { + if options.ci && options.password.is_none() { + log::warn!("Generating new private key without password. For security reasons, we recommend setting a password instead."); + options.password.replace("".into()); + } + let keypair = generate_key(options.password).expect("Failed to generate key"); + + if let Some(output_path) = options.write_keys { + let (secret_path, public_path) = + save_keypair(options.force, output_path, &keypair.sk, &keypair.pk) + .expect("Unable to write keypair"); + + println!( + "\nYour keypair was generated successfully\nPrivate: {} (Keep it secret!)\nPublic: {}\n---------------------------", + display_path(secret_path), + display_path(public_path) + ) + } else { + println!( + "\nYour secret key was generated successfully - Keep it secret!\n{}\n\n", + keypair.sk + ); + println!( + "Your public key was generated successfully:\n{}\n\nAdd the public key in your tauri.conf.json\n---------------------------\n", + keypair.pk + ); + } + + println!("\nEnvironment variables used to sign:"); + println!("`TAURI_SIGNING_PRIVATE_KEY` Path or String of your private key"); + println!("`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` Your private key password (optional)"); + println!("\nATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not work.\n---------------------------\n"); + + Ok(()) +} diff --git a/crates/tauri-cli/src/signer/mod.rs b/crates/tauri-cli/src/signer/mod.rs new file mode 100644 index 000000000000..1b907b24c3d5 --- /dev/null +++ b/crates/tauri-cli/src/signer/mod.rs @@ -0,0 +1,36 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::Result; +use clap::{Parser, Subcommand}; + +mod generate; +mod sign; + +#[derive(Parser)] +#[clap( + author, + version, + about = "Generate signing keys for Tauri updater or sign files", + subcommand_required(true), + arg_required_else_help(true) +)] +pub struct Cli { + #[clap(subcommand)] + command: Commands, +} + +#[derive(Subcommand)] +enum Commands { + Sign(sign::Options), + Generate(generate::Options), +} + +pub fn command(cli: Cli) -> Result<()> { + match cli.command { + Commands::Sign(options) => sign::command(options)?, + Commands::Generate(options) => generate::command(options)?, + } + Ok(()) +} diff --git a/crates/tauri-cli/src/signer/sign.rs b/crates/tauri-cli/src/signer/sign.rs new file mode 100644 index 000000000000..303cc2e37ad1 --- /dev/null +++ b/crates/tauri-cli/src/signer/sign.rs @@ -0,0 +1,71 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::path::{Path, PathBuf}; + +use crate::{ + helpers::updater_signature::{secret_key, sign_file}, + Result, +}; +use anyhow::Context; +use base64::Engine; +use clap::Parser; +use tauri_utils::display_path; + +#[derive(Debug, Parser)] +#[clap(about = "Sign a file")] +pub struct Options { + /// Load the private key from a string + #[clap( + short = 'k', + long, + conflicts_with("private_key_path"), + env = "TAURI_PRIVATE_KEY" + )] + private_key: Option, + /// Load the private key from a file + #[clap( + short = 'f', + long, + conflicts_with("private_key"), + env = "TAURI_PRIVATE_KEY_PATH" + )] + private_key_path: Option, + /// Set private key password when signing + #[clap(short, long, env = "TAURI_PRIVATE_KEY_PASSWORD")] + password: Option, + /// Sign the specified file + file: PathBuf, +} + +pub fn command(mut options: Options) -> Result<()> { + options.private_key = if let Some(private_key) = options.private_key_path { + Some(std::fs::read_to_string(Path::new(&private_key)).expect("Unable to extract private key")) + } else { + options.private_key + }; + let private_key = if let Some(pk) = options.private_key { + pk + } else { + return Err(anyhow::anyhow!( + "Key generation aborted: Unable to find the private key".to_string(), + )); + }; + + if options.password.is_none() { + println!("Signing without password."); + } + + let (manifest_dir, signature) = + sign_file(&secret_key(private_key, options.password)?, options.file) + .with_context(|| "failed to sign file")?; + + println!( + "\nYour file was signed successfully, You can find the signature here:\n{}\n\nPublic signature:\n{}\n\nMake sure to include this into the signature field of your update server.", + display_path(manifest_dir), + base64::engine::general_purpose::STANDARD.encode(signature.to_string()) + ); + + Ok(()) +} diff --git a/crates/tauri-cli/tauri-dev-watcher.gitignore b/crates/tauri-cli/tauri-dev-watcher.gitignore new file mode 100644 index 000000000000..0d6c4d181095 --- /dev/null +++ b/crates/tauri-cli/tauri-dev-watcher.gitignore @@ -0,0 +1,5 @@ +node_modules/ +target/ +gen/ +Cargo.lock +.DS_Store diff --git a/crates/tauri-cli/tauri.config.schema.json b/crates/tauri-cli/tauri.config.schema.json new file mode 100644 index 000000000000..9d28874da38b --- /dev/null +++ b/crates/tauri-cli/tauri.config.schema.json @@ -0,0 +1,2998 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Config", + "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://tauri.app/v1/api/cli#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"../dist\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", + "type": "object", + "properties": { + "$schema": { + "description": "The JSON schema for the Tauri config.", + "type": [ + "string", + "null" + ] + }, + "productName": { + "description": "App name.", + "type": [ + "string", + "null" + ], + "pattern": "^[^/\\:*?\"<>|]+$" + }, + "version": { + "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\n By default version 1.0 is used on Android.", + "type": [ + "string", + "null" + ] + }, + "identifier": { + "description": "The application identifier in reverse domain name notation (e.g. `com.tauri.example`).\n This string must be unique across applications since it is used in system configurations like\n the bundle ID and path to the webview data directory.\n This string must contain only alphanumeric characters (A–Z, a–z, and 0–9), hyphens (-),\n and periods (.).", + "default": "", + "type": "string" + }, + "app": { + "description": "The App configuration.", + "default": { + "enableGTKAppId": false, + "macOSPrivateApi": false, + "security": { + "assetProtocol": { + "enable": false, + "scope": [] + }, + "capabilities": [], + "dangerousDisableAssetCspModification": false, + "freezePrototype": false, + "pattern": { + "use": "brownfield" + } + }, + "windows": [], + "withGlobalTauri": false + }, + "allOf": [ + { + "$ref": "#/definitions/AppConfig" + } + ] + }, + "build": { + "description": "The build configuration.", + "default": {}, + "allOf": [ + { + "$ref": "#/definitions/BuildConfig" + } + ] + }, + "bundle": { + "description": "The bundler configuration.", + "default": { + "active": false, + "android": { + "minSdkVersion": 24 + }, + "createUpdaterArtifacts": false, + "iOS": { + "minimumSystemVersion": "13.0" + }, + "icon": [], + "linux": { + "appimage": { + "bundleMediaFramework": false, + "files": {} + }, + "deb": { + "files": {} + }, + "rpm": { + "epoch": 0, + "files": {}, + "release": "1" + } + }, + "macOS": { + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "files": {}, + "hardenedRuntime": true, + "minimumSystemVersion": "10.13" + }, + "targets": "all", + "windows": { + "allowDowngrades": true, + "certificateThumbprint": null, + "digestAlgorithm": null, + "nsis": null, + "signCommand": null, + "timestampUrl": null, + "tsp": false, + "webviewInstallMode": { + "silent": true, + "type": "downloadBootstrapper" + }, + "wix": null + } + }, + "allOf": [ + { + "$ref": "#/definitions/BundleConfig" + } + ] + }, + "plugins": { + "description": "The plugins config.", + "default": {}, + "allOf": [ + { + "$ref": "#/definitions/PluginConfig" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "AppConfig": { + "description": "The App configuration object.\n\n See more: ", + "type": "object", + "properties": { + "windows": { + "description": "The windows configuration.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/WindowConfig" + } + }, + "security": { + "description": "Security configuration.", + "default": { + "assetProtocol": { + "enable": false, + "scope": [] + }, + "capabilities": [], + "dangerousDisableAssetCspModification": false, + "freezePrototype": false, + "pattern": { + "use": "brownfield" + } + }, + "allOf": [ + { + "$ref": "#/definitions/SecurityConfig" + } + ] + }, + "trayIcon": { + "description": "Configuration for app tray icon.", + "anyOf": [ + { + "$ref": "#/definitions/TrayIconConfig" + }, + { + "type": "null" + } + ] + }, + "macOSPrivateApi": { + "description": "MacOS private API configuration. Enables the transparent background API and sets the `fullScreenEnabled` preference to `true`.", + "default": false, + "type": "boolean" + }, + "withGlobalTauri": { + "description": "Whether we should inject the Tauri API on `window.__TAURI__` or not.", + "default": false, + "type": "boolean" + }, + "enableGTKAppId": { + "description": "If set to true \"identifier\" will be set as GTK app ID (on systems that use GTK).", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "WindowConfig": { + "description": "The window configuration object.\n\n See more: ", + "type": "object", + "properties": { + "label": { + "description": "The window identifier. It must be alphanumeric.", + "default": "main", + "type": "string" + }, + "url": { + "description": "The window webview URL.", + "default": "index.html", + "allOf": [ + { + "$ref": "#/definitions/WebviewUrl" + } + ] + }, + "userAgent": { + "description": "The user agent for the webview", + "type": [ + "string", + "null" + ] + }, + "dragDropEnabled": { + "description": "Whether the drag and drop is enabled or not on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows.", + "default": true, + "type": "boolean" + }, + "center": { + "description": "Whether or not the window starts centered or not.", + "default": false, + "type": "boolean" + }, + "x": { + "description": "The horizontal position of the window's top left corner", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "y": { + "description": "The vertical position of the window's top left corner", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "width": { + "description": "The window width.", + "default": 800.0, + "type": "number", + "format": "double" + }, + "height": { + "description": "The window height.", + "default": 600.0, + "type": "number", + "format": "double" + }, + "minWidth": { + "description": "The min window width.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "minHeight": { + "description": "The min window height.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "maxWidth": { + "description": "The max window width.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "maxHeight": { + "description": "The max window height.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "resizable": { + "description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.", + "default": true, + "type": "boolean" + }, + "maximizable": { + "description": "Whether the window's native maximize button is enabled or not.\n If resizable is set to false, this setting is ignored.\n\n ## Platform-specific\n\n - **macOS:** Disables the \"zoom\" button in the window titlebar, which is also used to enter fullscreen mode.\n - **Linux / iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "minimizable": { + "description": "Whether the window's native minimize button is enabled or not.\n\n ## Platform-specific\n\n - **Linux / iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "closable": { + "description": "Whether the window's native close button is enabled or not.\n\n ## Platform-specific\n\n - **Linux:** \"GTK+ will do its best to convince the window manager not to show a close button.\n Depending on the system, this function may not have any effect when called on a window that is already visible\"\n - **iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "title": { + "description": "The window title.", + "default": "Tauri App", + "type": "string" + }, + "fullscreen": { + "description": "Whether the window starts as fullscreen or not.", + "default": false, + "type": "boolean" + }, + "focus": { + "description": "Whether the window will be initially focused or not.", + "default": true, + "type": "boolean" + }, + "transparent": { + "description": "Whether the window is transparent or not.\n\n Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.\n WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.", + "default": false, + "type": "boolean" + }, + "maximized": { + "description": "Whether the window is maximized or not.", + "default": false, + "type": "boolean" + }, + "visible": { + "description": "Whether the window is visible or not.", + "default": true, + "type": "boolean" + }, + "decorations": { + "description": "Whether the window should have borders and bars.", + "default": true, + "type": "boolean" + }, + "alwaysOnBottom": { + "description": "Whether the window should always be below other windows.", + "default": false, + "type": "boolean" + }, + "alwaysOnTop": { + "description": "Whether the window should always be on top of other windows.", + "default": false, + "type": "boolean" + }, + "visibleOnAllWorkspaces": { + "description": "Whether the window should be visible on all workspaces or virtual desktops.\n\n ## Platform-specific\n\n - **Windows / iOS / Android:** Unsupported.", + "default": false, + "type": "boolean" + }, + "contentProtected": { + "description": "Prevents the window contents from being captured by other apps.", + "default": false, + "type": "boolean" + }, + "skipTaskbar": { + "description": "If `true`, hides the window icon from the taskbar on Windows and Linux.", + "default": false, + "type": "boolean" + }, + "theme": { + "description": "The initial window theme. Defaults to the system theme. Only implemented on Windows and macOS 10.14+.", + "anyOf": [ + { + "$ref": "#/definitions/Theme" + }, + { + "type": "null" + } + ] + }, + "titleBarStyle": { + "description": "The style of the macOS title bar.", + "default": "Visible", + "allOf": [ + { + "$ref": "#/definitions/TitleBarStyle" + } + ] + }, + "hiddenTitle": { + "description": "If `true`, sets the window title to be hidden on macOS.", + "default": false, + "type": "boolean" + }, + "acceptFirstMouse": { + "description": "Whether clicking an inactive window also clicks through to the webview on macOS.", + "default": false, + "type": "boolean" + }, + "tabbingIdentifier": { + "description": "Defines the window [tabbing identifier] for macOS.\n\n Windows with matching tabbing identifiers will be grouped together.\n If the tabbing identifier is not set, automatic tabbing will be disabled.\n\n [tabbing identifier]: ", + "type": [ + "string", + "null" + ] + }, + "additionalBrowserArgs": { + "description": "Defines additional browser arguments on Windows. By default wry passes `--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection`\n so if you use this method, you also need to disable these components by yourself if you want.", + "type": [ + "string", + "null" + ] + }, + "shadow": { + "description": "Whether or not the window has shadow.\n\n ## Platform-specific\n\n - **Windows:**\n - `false` has no effect on decorated window, shadow are always ON.\n - `true` will make undecorated window have a 1px white border,\n and on Windows 11, it will have a rounded corners.\n - **Linux:** Unsupported.", + "default": true, + "type": "boolean" + }, + "windowEffects": { + "description": "Window effects.\n\n Requires the window to be transparent.\n\n ## Platform-specific:\n\n - **Windows**: If using decorations or shadows, you may want to try this workaround \n - **Linux**: Unsupported", + "anyOf": [ + { + "$ref": "#/definitions/WindowEffectsConfig" + }, + { + "type": "null" + } + ] + }, + "incognito": { + "description": "Whether or not the webview should be launched in incognito mode.\n\n ## Platform-specific:\n\n - **Android**: Unsupported.", + "default": false, + "type": "boolean" + }, + "parent": { + "description": "Sets the window associated with this label to be the parent of the window to be created.\n\n ## Platform-specific\n\n - **Windows**: This sets the passed parent as an owner window to the window to be created.\n From [MSDN owned windows docs](https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows):\n - An owned window is always above its owner in the z-order.\n - The system automatically destroys an owned window when its owner is destroyed.\n - An owned window is hidden when its owner is minimized.\n - **Linux**: This makes the new window transient for parent, see \n - **macOS**: This adds the window as a child of parent, see ", + "type": [ + "string", + "null" + ] + }, + "proxyUrl": { + "description": "The proxy URL for the WebView for all network requests.\n\n Must be either a `http://` or a `socks5://` URL.\n\n ## Platform-specific\n\n - **macOS**: Requires the `macos-proxy` feature flag and only compiles for macOS 14+.", + "type": [ + "string", + "null" + ], + "format": "uri" + }, + "zoomHotkeysEnabled": { + "description": "Whether page zooming by hotkeys is enabled\n\n ## Platform-specific:\n\n - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.\n - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`,\n 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission\n\n - **Android / iOS**: Unsupported.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "WebviewUrl": { + "description": "An URL to open on a Tauri webview window.", + "anyOf": [ + { + "description": "An external URL. Must use either the `http` or `https` schemes.", + "type": "string", + "format": "uri" + }, + { + "description": "The path portion of an app URL.\n For instance, to load `tauri://localhost/users/john`,\n you can simply provide `users/john` in this configuration.", + "type": "string" + }, + { + "description": "A custom protocol url, for example, `doom://index.html`", + "type": "string", + "format": "uri" + } + ] + }, + "Theme": { + "description": "System theme.", + "oneOf": [ + { + "description": "Light theme.", + "type": "string", + "enum": [ + "Light" + ] + }, + { + "description": "Dark theme.", + "type": "string", + "enum": [ + "Dark" + ] + } + ] + }, + "TitleBarStyle": { + "description": "How the window title bar should be displayed on macOS.", + "oneOf": [ + { + "description": "A normal title bar.", + "type": "string", + "enum": [ + "Visible" + ] + }, + { + "description": "Makes the title bar transparent, so the window background color is shown instead.\n\n Useful if you don't need to have actual HTML under the title bar. This lets you avoid the caveats of using `TitleBarStyle::Overlay`. Will be more useful when Tauri lets you set a custom window background color.", + "type": "string", + "enum": [ + "Transparent" + ] + }, + { + "description": "Shows the title bar as a transparent overlay over the window's content.\n\n Keep in mind:\n - The height of the title bar is different on different OS versions, which can lead to window the controls and title not being where you don't expect.\n - You need to define a custom drag region to make your window draggable, however due to a limitation you can't drag the window when it's not in focus .\n - The color of the window title depends on the system theme.", + "type": "string", + "enum": [ + "Overlay" + ] + } + ] + }, + "WindowEffectsConfig": { + "description": "The window effects configuration object", + "type": "object", + "required": [ + "effects" + ], + "properties": { + "effects": { + "description": "List of Window effects to apply to the Window.\n Conflicting effects will apply the first one and ignore the rest.", + "type": "array", + "items": { + "$ref": "#/definitions/WindowEffect" + } + }, + "state": { + "description": "Window effect state **macOS Only**", + "anyOf": [ + { + "$ref": "#/definitions/WindowEffectState" + }, + { + "type": "null" + } + ] + }, + "radius": { + "description": "Window effect corner radius **macOS Only**", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "color": { + "description": "Window effect color. Affects [`WindowEffect::Blur`] and [`WindowEffect::Acrylic`] only\n on Windows 10 v1903+. Doesn't have any effect on Windows 7 or Windows 11.", + "anyOf": [ + { + "$ref": "#/definitions/Color" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "WindowEffect": { + "description": "Platform-specific window effects", + "oneOf": [ + { + "description": "A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "appearanceBased" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "light" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "dark" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "mediumLight" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "ultraDark" + ] + }, + { + "description": "**macOS 10.10+**", + "type": "string", + "enum": [ + "titlebar" + ] + }, + { + "description": "**macOS 10.10+**", + "type": "string", + "enum": [ + "selection" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "menu" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "popover" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "sidebar" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "headerView" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "sheet" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "windowBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "hudWindow" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "fullScreenUI" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "tooltip" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "contentBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "underWindowBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "underPageBackground" + ] + }, + { + "description": "Mica effect that matches the system dark perefence **Windows 11 Only**", + "type": "string", + "enum": [ + "mica" + ] + }, + { + "description": "Mica effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**", + "type": "string", + "enum": [ + "micaDark" + ] + }, + { + "description": "Mica effect with light mode **Windows 11 Only**", + "type": "string", + "enum": [ + "micaLight" + ] + }, + { + "description": "Tabbed effect that matches the system dark perefence **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbed" + ] + }, + { + "description": "Tabbed effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbedDark" + ] + }, + { + "description": "Tabbed effect with light mode **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbedLight" + ] + }, + { + "description": "**Windows 7/10/11(22H1) Only**\n\n ## Notes\n\n This effect has bad performance when resizing/dragging the window on Windows 11 build 22621.", + "type": "string", + "enum": [ + "blur" + ] + }, + { + "description": "**Windows 10/11 Only**\n\n ## Notes\n\n This effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.", + "type": "string", + "enum": [ + "acrylic" + ] + } + ] + }, + "WindowEffectState": { + "description": "Window effect state **macOS only**\n\n ", + "oneOf": [ + { + "description": "Make window effect state follow the window's active state", + "type": "string", + "enum": [ + "followsWindowActiveState" + ] + }, + { + "description": "Make window effect state always active", + "type": "string", + "enum": [ + "active" + ] + }, + { + "description": "Make window effect state always inactive", + "type": "string", + "enum": [ + "inactive" + ] + } + ] + }, + "Color": { + "description": "a tuple struct of RGBA colors. Each value has minimum of 0 and maximum of 255.", + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + ], + "maxItems": 4, + "minItems": 4 + }, + "SecurityConfig": { + "description": "Security configuration.\n\n See more: ", + "type": "object", + "properties": { + "csp": { + "description": "The Content Security Policy that will be injected on all HTML files on the built application.\n If [`dev_csp`](#SecurityConfig.devCsp) is not specified, this value is also injected on dev.\n\n This is a really important part of the configuration since it helps you ensure your WebView is secured.\n See .", + "anyOf": [ + { + "$ref": "#/definitions/Csp" + }, + { + "type": "null" + } + ] + }, + "devCsp": { + "description": "The Content Security Policy that will be injected on all HTML files on development.\n\n This is a really important part of the configuration since it helps you ensure your WebView is secured.\n See .", + "anyOf": [ + { + "$ref": "#/definitions/Csp" + }, + { + "type": "null" + } + ] + }, + "freezePrototype": { + "description": "Freeze the `Object.prototype` when using the custom protocol.", + "default": false, + "type": "boolean" + }, + "dangerousDisableAssetCspModification": { + "description": "Disables the Tauri-injected CSP sources.\n\n At compile time, Tauri parses all the frontend assets and changes the Content-Security-Policy\n to only allow loading of your own scripts and styles by injecting nonce and hash sources.\n This stricts your CSP, which may introduce issues when using along with other flexing sources.\n\n This configuration option allows both a boolean and a list of strings as value.\n A boolean instructs Tauri to disable the injection for all CSP injections,\n and a list of strings indicates the CSP directives that Tauri cannot inject.\n\n **WARNING:** Only disable this if you know what you are doing and have properly configured the CSP.\n Your application might be vulnerable to XSS attacks without this Tauri protection.", + "default": false, + "allOf": [ + { + "$ref": "#/definitions/DisabledCspModificationKind" + } + ] + }, + "assetProtocol": { + "description": "Custom protocol config.", + "default": { + "enable": false, + "scope": [] + }, + "allOf": [ + { + "$ref": "#/definitions/AssetProtocolConfig" + } + ] + }, + "pattern": { + "description": "The pattern to use.", + "default": { + "use": "brownfield" + }, + "allOf": [ + { + "$ref": "#/definitions/PatternKind" + } + ] + }, + "capabilities": { + "description": "List of capabilities that are enabled on the application.\n\n If the list is empty, all capabilities are included.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/CapabilityEntry" + } + } + }, + "additionalProperties": false + }, + "Csp": { + "description": "A Content-Security-Policy definition.\n See .", + "anyOf": [ + { + "description": "The entire CSP policy in a single text string.", + "type": "string" + }, + { + "description": "An object mapping a directive with its sources values as a list of strings.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/CspDirectiveSources" + } + } + ] + }, + "CspDirectiveSources": { + "description": "A Content-Security-Policy directive source list.\n See .", + "anyOf": [ + { + "description": "An inline list of CSP sources. Same as [`Self::List`], but concatenated with a space separator.", + "type": "string" + }, + { + "description": "A list of CSP sources. The collection will be concatenated with a space separator for the CSP string.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "DisabledCspModificationKind": { + "description": "The possible values for the `dangerous_disable_asset_csp_modification` config option.", + "anyOf": [ + { + "description": "If `true`, disables all CSP modification.\n `false` is the default value and it configures Tauri to control the CSP.", + "type": "boolean" + }, + { + "description": "Disables the given list of CSP directives modifications.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "AssetProtocolConfig": { + "description": "Config for the asset custom protocol.\n\n See more: ", + "type": "object", + "properties": { + "scope": { + "description": "The access scope for the asset protocol.", + "default": [], + "allOf": [ + { + "$ref": "#/definitions/FsScope" + } + ] + }, + "enable": { + "description": "Enables the asset protocol.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "FsScope": { + "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,\n `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "anyOf": [ + { + "description": "A list of paths that are allowed by this scope.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A complete scope configuration.", + "type": "object", + "properties": { + "allow": { + "description": "A list of paths that are allowed by this scope.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "A list of paths that are not allowed by this scope.\n This gets precedence over the [`Self::Scope::allow`] list.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "requireLiteralLeadingDot": { + "description": "Whether or not paths that contain components that start with a `.`\n will require that `.` appears literally in the pattern; `*`, `?`, `**`,\n or `[...]` will not match. This is useful because such files are\n conventionally considered hidden on Unix systems and it might be\n desirable to skip them when listing files.\n\n Defaults to `true` on Unix systems and `false` on Windows", + "type": [ + "boolean", + "null" + ] + } + } + } + ] + }, + "PatternKind": { + "description": "The application pattern.", + "oneOf": [ + { + "description": "Brownfield pattern.", + "type": "object", + "required": [ + "use" + ], + "properties": { + "use": { + "type": "string", + "enum": [ + "brownfield" + ] + } + } + }, + { + "description": "Isolation pattern. Recommended for security purposes.", + "type": "object", + "required": [ + "options", + "use" + ], + "properties": { + "use": { + "type": "string", + "enum": [ + "isolation" + ] + }, + "options": { + "type": "object", + "required": [ + "dir" + ], + "properties": { + "dir": { + "description": "The dir containing the index.html file that contains the secure isolation application.", + "type": "string" + } + } + } + } + } + ] + }, + "CapabilityEntry": { + "description": "A capability entry which can be either an inlined capability or a reference to a capability defined on its own file.", + "anyOf": [ + { + "description": "An inlined capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "Reference to a capability identifier.", + "type": "string" + } + ] + }, + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n ## Example\n\n `main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\n It should contain a description of what the grouped permissions should allow.\n\n ## Example\n\n This capability allows the `main` window access to `filesystem` write related\n commands and `dialog` commands to enable programatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\n This setting is optional and defaults to not being set, as our\n default use case is that the content is served from our local application.\n\n :::caution\n Make sure you understand the security implications of providing remote\n sources with local system access.\n :::\n\n ## Example\n\n ```json\n {\n \"urls\": [\"https://*.mydomain.dev\"]\n }\n ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\n On multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n ## Example\n\n `[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\n This is only required when using on multiwebview contexts, by default\n all child webviews of a window that matches [`Self::windows`] are linked.\n\n ## Example\n\n `[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\n By default all platforms are targeted.\n\n ## Example\n\n `[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n ## Examples\n\n - \"https://*.mydomain.dev\": allows subdomains of mydomain.dev\n - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`]\n or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ] + }, + "Identifier": { + "type": "string" + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "TrayIconConfig": { + "description": "Configuration for application tray icon.\n\n See more: ", + "type": "object", + "required": [ + "iconPath" + ], + "properties": { + "id": { + "description": "Set an id for this tray icon so you can reference it later, defaults to `main`.", + "type": [ + "string", + "null" + ] + }, + "iconPath": { + "description": "Path to the default icon to use for the tray icon.\n\n Note: this stores the image in raw pixels to the final binary,\n so keep the icon size (width and height) small\n or else it's going to bloat your final executable", + "type": "string" + }, + "iconAsTemplate": { + "description": "A Boolean value that determines whether the image represents a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) image on macOS.", + "default": false, + "type": "boolean" + }, + "menuOnLeftClick": { + "description": "A Boolean value that determines whether the menu should appear when the tray icon receives a left click on macOS.", + "default": true, + "type": "boolean" + }, + "title": { + "description": "Title for MacOS tray", + "type": [ + "string", + "null" + ] + }, + "tooltip": { + "description": "Tray icon tooltip on Windows and macOS", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "BuildConfig": { + "description": "The Build configuration object.\n\n See more: ", + "type": "object", + "properties": { + "runner": { + "description": "The binary used to build and run the application.", + "type": [ + "string", + "null" + ] + }, + "devUrl": { + "description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [vite](https://vitejs.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.", + "type": [ + "string", + "null" + ], + "format": "uri" + }, + "frontendDist": { + "description": "The path to the application assets (usually the `dist` folder of your javascript bundler)\n or a URL that could be either a custom protocol registered in the tauri app (for example: `myprotocol://`)\n or a remote URL (for example: `https://site.com/app`).\n\n When a path relative to the configuration file is provided,\n it is read recursively and all files are embedded in the application binary.\n Tauri then looks for an `index.html` and serves it as the default entry point for your application.\n\n You can also provide a list of paths to be embedded, which allows granular control over what files are added to the binary.\n In this case, all files are added to the root and you must reference it that way in your HTML files.\n\n When a URL is provided, the application won't have bundled assets\n and the application will load that URL by default.", + "anyOf": [ + { + "$ref": "#/definitions/FrontendDist" + }, + { + "type": "null" + } + ] + }, + "beforeDevCommand": { + "description": "A shell command to run before `tauri dev` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/BeforeDevCommand" + }, + { + "type": "null" + } + ] + }, + "beforeBuildCommand": { + "description": "A shell command to run before `tauri build` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/HookCommand" + }, + { + "type": "null" + } + ] + }, + "beforeBundleCommand": { + "description": "A shell command to run before the bundling phase in `tauri build` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/HookCommand" + }, + { + "type": "null" + } + ] + }, + "features": { + "description": "Features passed to `cargo` commands.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "FrontendDist": { + "description": "Defines the URL or assets to embed in the application.", + "anyOf": [ + { + "description": "An external URL that should be used as the default application URL.", + "type": "string", + "format": "uri" + }, + { + "description": "Path to a directory containing the frontend dist assets.", + "type": "string" + }, + { + "description": "An array of files to embed on the app.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "BeforeDevCommand": { + "description": "Describes the shell command to run before `tauri dev`.", + "anyOf": [ + { + "description": "Run the given script with the default options.", + "type": "string" + }, + { + "description": "Run the given script with custom options.", + "type": "object", + "required": [ + "script" + ], + "properties": { + "script": { + "description": "The script to execute.", + "type": "string" + }, + "cwd": { + "description": "The current working directory.", + "type": [ + "string", + "null" + ] + }, + "wait": { + "description": "Whether `tauri dev` should wait for the command to finish or not. Defaults to `false`.", + "default": false, + "type": "boolean" + } + } + } + ] + }, + "HookCommand": { + "description": "Describes a shell command to be executed when a CLI hook is triggered.", + "anyOf": [ + { + "description": "Run the given script with the default options.", + "type": "string" + }, + { + "description": "Run the given script with custom options.", + "type": "object", + "required": [ + "script" + ], + "properties": { + "script": { + "description": "The script to execute.", + "type": "string" + }, + "cwd": { + "description": "The current working directory.", + "type": [ + "string", + "null" + ] + } + } + } + ] + }, + "BundleConfig": { + "description": "Configuration for tauri-bundler.\n\n See more: ", + "type": "object", + "properties": { + "active": { + "description": "Whether Tauri should bundle your application or just output the executable.", + "default": false, + "type": "boolean" + }, + "targets": { + "description": "The bundle targets, currently supports [\"deb\", \"rpm\", \"appimage\", \"nsis\", \"msi\", \"app\", \"dmg\"] or \"all\".", + "default": "all", + "allOf": [ + { + "$ref": "#/definitions/BundleTarget" + } + ] + }, + "createUpdaterArtifacts": { + "description": "Produce updaters and their signatures or not", + "default": false, + "allOf": [ + { + "$ref": "#/definitions/Updater" + } + ] + }, + "publisher": { + "description": "The application's publisher. Defaults to the second element in the identifier string.\n Currently maps to the Manufacturer property of the Windows Installer.", + "type": [ + "string", + "null" + ] + }, + "homepage": { + "description": "A url to the home page of your application. If unset, will\n fallback to `homepage` defined in `Cargo.toml`.\n\n Supported bundle targets: `deb`, `rpm`, `nsis` and `msi`.", + "type": [ + "string", + "null" + ] + }, + "icon": { + "description": "The app's icons", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "description": "App resources to bundle.\n Each resource is a path to a file or directory.\n Glob patterns are supported.", + "anyOf": [ + { + "$ref": "#/definitions/BundleResources" + }, + { + "type": "null" + } + ] + }, + "copyright": { + "description": "A copyright string associated with your application.", + "type": [ + "string", + "null" + ] + }, + "license": { + "description": "The package's license identifier to be included in the appropriate bundles.\n If not set, defaults to the license from the Cargo.toml file.", + "type": [ + "string", + "null" + ] + }, + "licenseFile": { + "description": "The path to the license file to be included in the appropriate bundles.", + "type": [ + "string", + "null" + ] + }, + "category": { + "description": "The application kind.\n\n Should be one of the following:\n Business, DeveloperTool, Education, Entertainment, Finance, Game, ActionGame, AdventureGame, ArcadeGame, BoardGame, CardGame, CasinoGame, DiceGame, EducationalGame, FamilyGame, KidsGame, MusicGame, PuzzleGame, RacingGame, RolePlayingGame, SimulationGame, SportsGame, StrategyGame, TriviaGame, WordGame, GraphicsAndDesign, HealthcareAndFitness, Lifestyle, Medical, Music, News, Photography, Productivity, Reference, SocialNetworking, Sports, Travel, Utility, Video, Weather.", + "type": [ + "string", + "null" + ] + }, + "fileAssociations": { + "description": "File associations to application.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/FileAssociation" + } + }, + "shortDescription": { + "description": "A short description of your application.", + "type": [ + "string", + "null" + ] + }, + "longDescription": { + "description": "A longer, multi-line description of the application.", + "type": [ + "string", + "null" + ] + }, + "externalBin": { + "description": "A list of—either absolute or relative—paths to binaries to embed with your application.\n\n Note that Tauri will look for system-specific binaries following the pattern \"binary-name{-target-triple}{.system-extension}\".\n\n E.g. for the external binary \"my-binary\", Tauri looks for:\n\n - \"my-binary-x86_64-pc-windows-msvc.exe\" for Windows\n - \"my-binary-x86_64-apple-darwin\" for macOS\n - \"my-binary-x86_64-unknown-linux-gnu\" for Linux\n\n so don't forget to provide binaries for all targeted platforms.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "windows": { + "description": "Configuration for the Windows bundles.", + "default": { + "allowDowngrades": true, + "certificateThumbprint": null, + "digestAlgorithm": null, + "nsis": null, + "signCommand": null, + "timestampUrl": null, + "tsp": false, + "webviewInstallMode": { + "silent": true, + "type": "downloadBootstrapper" + }, + "wix": null + }, + "allOf": [ + { + "$ref": "#/definitions/WindowsConfig" + } + ] + }, + "linux": { + "description": "Configuration for the Linux bundles.", + "default": { + "appimage": { + "bundleMediaFramework": false, + "files": {} + }, + "deb": { + "files": {} + }, + "rpm": { + "epoch": 0, + "files": {}, + "release": "1" + } + }, + "allOf": [ + { + "$ref": "#/definitions/LinuxConfig" + } + ] + }, + "macOS": { + "description": "Configuration for the macOS bundles.", + "default": { + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "files": {}, + "hardenedRuntime": true, + "minimumSystemVersion": "10.13" + }, + "allOf": [ + { + "$ref": "#/definitions/MacConfig" + } + ] + }, + "iOS": { + "description": "iOS configuration.", + "default": { + "minimumSystemVersion": "13.0" + }, + "allOf": [ + { + "$ref": "#/definitions/IosConfig" + } + ] + }, + "android": { + "description": "Android configuration.", + "default": { + "minSdkVersion": 24 + }, + "allOf": [ + { + "$ref": "#/definitions/AndroidConfig" + } + ] + } + }, + "additionalProperties": false + }, + "BundleTarget": { + "description": "Targets to bundle. Each value is case insensitive.", + "anyOf": [ + { + "description": "Bundle all targets.", + "enum": [ + "all" + ] + }, + { + "description": "A list of bundle targets.", + "type": "array", + "items": { + "$ref": "#/definitions/BundleType" + } + }, + { + "description": "A single bundle target.", + "allOf": [ + { + "$ref": "#/definitions/BundleType" + } + ] + } + ] + }, + "BundleType": { + "description": "A bundle referenced by tauri-bundler.", + "oneOf": [ + { + "description": "The debian bundle (.deb).", + "type": "string", + "enum": [ + "deb" + ] + }, + { + "description": "The RPM bundle (.rpm).", + "type": "string", + "enum": [ + "rpm" + ] + }, + { + "description": "The AppImage bundle (.appimage).", + "type": "string", + "enum": [ + "appimage" + ] + }, + { + "description": "The Microsoft Installer bundle (.msi).", + "type": "string", + "enum": [ + "msi" + ] + }, + { + "description": "The NSIS bundle (.exe).", + "type": "string", + "enum": [ + "nsis" + ] + }, + { + "description": "The macOS application bundle (.app).", + "type": "string", + "enum": [ + "app" + ] + }, + { + "description": "The Apple Disk Image bundle (.dmg).", + "type": "string", + "enum": [ + "dmg" + ] + } + ] + }, + "Updater": { + "description": "Updater type", + "anyOf": [ + { + "description": "Generates lagacy zipped v1 compatible updaters", + "allOf": [ + { + "$ref": "#/definitions/V1Compatible" + } + ] + }, + { + "description": "Produce updaters and their signatures or not", + "type": "boolean" + } + ] + }, + "V1Compatible": { + "description": "Generates lagacy zipped v1 compatible updaters", + "oneOf": [ + { + "description": "Generates lagacy zipped v1 compatible updaters", + "type": "string", + "enum": [ + "v1Compatible" + ] + } + ] + }, + "BundleResources": { + "description": "Definition for bundle resources.\n Can be either a list of paths to include or a map of source to target paths.", + "anyOf": [ + { + "description": "A list of paths to include.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A map of source to target paths.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + ] + }, + "FileAssociation": { + "description": "File association", + "type": "object", + "required": [ + "ext" + ], + "properties": { + "ext": { + "description": "File extensions to associate with this app. e.g. 'png'", + "type": "array", + "items": { + "$ref": "#/definitions/AssociationExt" + } + }, + "name": { + "description": "The name. Maps to `CFBundleTypeName` on macOS. Default to `ext[0]`", + "type": [ + "string", + "null" + ] + }, + "description": { + "description": "The association description. Windows-only. It is displayed on the `Type` column on Windows Explorer.", + "type": [ + "string", + "null" + ] + }, + "role": { + "description": "The app's role with respect to the type. Maps to `CFBundleTypeRole` on macOS.", + "default": "Editor", + "allOf": [ + { + "$ref": "#/definitions/BundleTypeRole" + } + ] + }, + "mimeType": { + "description": "The mime-type e.g. 'image/png' or 'text/plain'. Linux-only.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "AssociationExt": { + "description": "An extension for a [`FileAssociation`].\n\n A leading `.` is automatically stripped.", + "type": "string" + }, + "BundleTypeRole": { + "description": "macOS-only. Corresponds to CFBundleTypeRole", + "oneOf": [ + { + "description": "CFBundleTypeRole.Editor. Files can be read and edited.", + "type": "string", + "enum": [ + "Editor" + ] + }, + { + "description": "CFBundleTypeRole.Viewer. Files can be read.", + "type": "string", + "enum": [ + "Viewer" + ] + }, + { + "description": "CFBundleTypeRole.Shell", + "type": "string", + "enum": [ + "Shell" + ] + }, + { + "description": "CFBundleTypeRole.QLGenerator", + "type": "string", + "enum": [ + "QLGenerator" + ] + }, + { + "description": "CFBundleTypeRole.None", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, + "WindowsConfig": { + "description": "Windows bundler configuration.\n\n See more: ", + "type": "object", + "properties": { + "digestAlgorithm": { + "description": "Specifies the file digest algorithm to use for creating file signatures.\n Required for code signing. SHA-256 is recommended.", + "type": [ + "string", + "null" + ] + }, + "certificateThumbprint": { + "description": "Specifies the SHA1 hash of the signing certificate.", + "type": [ + "string", + "null" + ] + }, + "timestampUrl": { + "description": "Server to use during timestamping.", + "type": [ + "string", + "null" + ] + }, + "tsp": { + "description": "Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may\n use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.", + "default": false, + "type": "boolean" + }, + "webviewInstallMode": { + "description": "The installation mode for the Webview2 runtime.", + "default": { + "silent": true, + "type": "downloadBootstrapper" + }, + "allOf": [ + { + "$ref": "#/definitions/WebviewInstallMode" + } + ] + }, + "allowDowngrades": { + "description": "Validates a second app installation, blocking the user from installing an older version if set to `false`.\n\n For instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.\n\n The default value of this flag is `true`.", + "default": true, + "type": "boolean" + }, + "wix": { + "description": "Configuration for the MSI generated with WiX.", + "anyOf": [ + { + "$ref": "#/definitions/WixConfig" + }, + { + "type": "null" + } + ] + }, + "nsis": { + "description": "Configuration for the installer generated with NSIS.", + "anyOf": [ + { + "$ref": "#/definitions/NsisConfig" + }, + { + "type": "null" + } + ] + }, + "signCommand": { + "description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in args which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.", + "anyOf": [ + { + "$ref": "#/definitions/CustomSignCommandConfig" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "WebviewInstallMode": { + "description": "Install modes for the Webview2 runtime.\n Note that for the updater bundle [`Self::DownloadBootstrapper`] is used.\n\n For more information see .", + "oneOf": [ + { + "description": "Do not install the Webview2 as part of the Windows Installer.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "skip" + ] + } + }, + "additionalProperties": false + }, + { + "description": "Download the bootstrapper and run it.\n Requires an internet connection.\n Results in a smaller installer size, but is not recommended on Windows 7.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "downloadBootstrapper" + ] + }, + "silent": { + "description": "Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed the bootstrapper and run it.\n Requires an internet connection.\n Increases the installer size by around 1.8MB, but offers better support on Windows 7.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "embedBootstrapper" + ] + }, + "silent": { + "description": "Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed the offline installer and run it.\n Does not require an internet connection.\n Increases the installer size by around 127MB.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "offlineInstaller" + ] + }, + "silent": { + "description": "Instructs the installer to run the installer in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed a fixed webview2 version and use it at runtime.\n Increases the installer size by around 180MB.", + "type": "object", + "required": [ + "path", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "fixedRuntime" + ] + }, + "path": { + "description": "The path to the fixed runtime to use.\n\n The fixed version can be downloaded [on the official website](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section).\n The `.cab` file must be extracted to a folder and this folder path must be defined on this field.", + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "WixConfig": { + "description": "Configuration for the MSI bundle using WiX.\n\n See more: ", + "type": "object", + "properties": { + "language": { + "description": "The installer languages to build. See .", + "default": "en-US", + "allOf": [ + { + "$ref": "#/definitions/WixLanguage" + } + ] + }, + "template": { + "description": "A custom .wxs template to use.", + "type": [ + "string", + "null" + ] + }, + "fragmentPaths": { + "description": "A list of paths to .wxs files with WiX fragments to use.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "componentGroupRefs": { + "description": "The ComponentGroup element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "componentRefs": { + "description": "The Component element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "featureGroupRefs": { + "description": "The FeatureGroup element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "featureRefs": { + "description": "The Feature element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "mergeRefs": { + "description": "The Merge element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "enableElevatedUpdateTask": { + "description": "Create an elevated update task within Windows Task Scheduler.", + "default": false, + "type": "boolean" + }, + "bannerPath": { + "description": "Path to a bitmap file to use as the installation user interface banner.\n This bitmap will appear at the top of all but the first page of the installer.\n\n The required dimensions are 493px × 58px.", + "type": [ + "string", + "null" + ] + }, + "dialogImagePath": { + "description": "Path to a bitmap file to use on the installation user interface dialogs.\n It is used on the welcome and completion dialogs.\n The required dimensions are 493px × 312px.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "WixLanguage": { + "description": "The languages to build using WiX.", + "anyOf": [ + { + "description": "A single language to build, without configuration.", + "type": "string" + }, + { + "description": "A list of languages to build, without configuration.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A map of languages and its configuration.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/WixLanguageConfig" + } + } + ] + }, + "WixLanguageConfig": { + "description": "Configuration for a target language for the WiX build.\n\n See more: ", + "type": "object", + "properties": { + "localePath": { + "description": "The path to a locale (`.wxl`) file. See .", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "NsisConfig": { + "description": "Configuration for the Installer bundle using NSIS.", + "type": "object", + "properties": { + "template": { + "description": "A custom .nsi template to use.", + "type": [ + "string", + "null" + ] + }, + "headerImage": { + "description": "The path to a bitmap file to display on the header of installers pages.\n\n The recommended dimensions are 150px x 57px.", + "type": [ + "string", + "null" + ] + }, + "sidebarImage": { + "description": "The path to a bitmap file for the Welcome page and the Finish page.\n\n The recommended dimensions are 164px x 314px.", + "type": [ + "string", + "null" + ] + }, + "installerIcon": { + "description": "The path to an icon file used as the installer icon.", + "type": [ + "string", + "null" + ] + }, + "installMode": { + "description": "Whether the installation will be for all users or just the current user.", + "default": "currentUser", + "allOf": [ + { + "$ref": "#/definitions/NSISInstallerMode" + } + ] + }, + "languages": { + "description": "A list of installer languages.\n By default the OS language is used. If the OS language is not in the list of languages, the first language will be used.\n To allow the user to select the language, set `display_language_selector` to `true`.\n\n See for the complete list of languages.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "customLanguageFiles": { + "description": "A key-value pair where the key is the language and the\n value is the path to a custom `.nsh` file that holds the translated text for tauri's custom messages.\n\n See for an example `.nsh` file.\n\n **Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`] languages array,", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "displayLanguageSelector": { + "description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not.\n By default the OS language is selected, with a fallback to the first language in the `languages` array.", + "default": false, + "type": "boolean" + }, + "compression": { + "description": "Set the compression algorithm used to compress files in the installer.\n\n See ", + "default": "lzma", + "allOf": [ + { + "$ref": "#/definitions/NsisCompression" + } + ] + }, + "startMenuFolder": { + "description": "Set the folder name for the start menu shortcut.\n\n Use this option if you have multiple apps and wish to group their shortcuts under one folder\n or if you generally prefer to set your shortcut inside a folder.\n\n Examples:\n - `AwesomePublisher`, shortcut will be placed in `%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\AwesomePublisher\\.lnk`\n - If unset, shortcut will be placed in `%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\.lnk`", + "type": [ + "string", + "null" + ] + }, + "installerHooks": { + "description": "A path to a `.nsh` file that contains special NSIS macros to be hooked into the\n main installer.nsi script.\n\n Supported hooks are:\n - `NSIS_HOOK_PREINSTALL`: This hook runs before copying files, setting registry key values and creating shortcuts.\n - `NSIS_HOOK_POSTINSTALL`: This hook runs after the installer has finished copying all files, setting the registry keys and created shortcuts.\n - `NSIS_HOOK_PREUNINSTALL`: This hook runs before removing any files, registry keys and shortcuts.\n - `NSIS_HOOK_POSTUNINSTALL`: This hook runs after files, registry keys and shortcuts have been removed.\n\n\n ### Example\n\n ```nsh\n !macro NSIS_HOOK_PREINSTALL\n MessageBox MB_OK \"PreInstall\"\n !macroend\n\n !macro NSIS_HOOK_POSTINSTALL\n MessageBox MB_OK \"PostInstall\"\n !macroend\n\n !macro NSIS_HOOK_PREUNINSTALL\n MessageBox MB_OK \"PreUnInstall\"\n !macroend\n\n !macro NSIS_HOOK_POSTUNINSTALL\n MessageBox MB_OK \"PostUninstall\"\n !macroend\n\n ```", + "type": [ + "string", + "null" + ] + }, + "minimumWebview2Version": { + "description": "Try to ensure that the WebView2 version is equal to or newer than this version,\n if the user's WebView2 is older than this version,\n the installer will try to trigger a WebView2 update.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "NSISInstallerMode": { + "description": "Install Modes for the NSIS installer.", + "oneOf": [ + { + "description": "Default mode for the installer.\n\n Install the app by default in a directory that doesn't require Administrator access.\n\n Installer metadata will be saved under the `HKCU` registry path.", + "type": "string", + "enum": [ + "currentUser" + ] + }, + { + "description": "Install the app by default in the `Program Files` folder directory requires Administrator\n access for the installation.\n\n Installer metadata will be saved under the `HKLM` registry path.", + "type": "string", + "enum": [ + "perMachine" + ] + }, + { + "description": "Combines both modes and allows the user to choose at install time\n whether to install for the current user or per machine. Note that this mode\n will require Administrator access even if the user wants to install it for the current user only.\n\n Installer metadata will be saved under the `HKLM` or `HKCU` registry path based on the user's choice.", + "type": "string", + "enum": [ + "both" + ] + } + ] + }, + "NsisCompression": { + "description": "Compression algorithms used in the NSIS installer.\n\n See ", + "oneOf": [ + { + "description": "ZLIB uses the deflate algorithm, it is a quick and simple method. With the default compression level it uses about 300 KB of memory.", + "type": "string", + "enum": [ + "zlib" + ] + }, + { + "description": "BZIP2 usually gives better compression ratios than ZLIB, but it is a bit slower and uses more memory. With the default compression level it uses about 4 MB of memory.", + "type": "string", + "enum": [ + "bzip2" + ] + }, + { + "description": "LZMA (default) is a new compression method that gives very good compression ratios. The decompression speed is high (10-20 MB/s on a 2 GHz CPU), the compression speed is lower. The memory size that will be used for decompression is the dictionary size plus a few KBs, the default is 8 MB.", + "type": "string", + "enum": [ + "lzma" + ] + }, + { + "description": "Disable compression", + "type": "string", + "enum": [ + "none" + ] + } + ] + }, + "CustomSignCommandConfig": { + "description": "Custom Signing Command configuration.", + "anyOf": [ + { + "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].", + "type": "string" + }, + { + "description": "An object notation of the command.\n\n This is more complex notation for the command but\n this allows you to use whitespace in the command and arguments.", + "type": "object", + "required": [ + "args", + "cmd" + ], + "properties": { + "cmd": { + "description": "The command to run to sign the binary.", + "type": "string" + }, + "args": { + "description": "The arguments to pass to the command.\n\n \"%1\" will be replaced with the path to the binary to be signed.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + ] + }, + "LinuxConfig": { + "description": "Configuration for Linux bundles.\n\n See more: ", + "type": "object", + "properties": { + "appimage": { + "description": "Configuration for the AppImage bundle.", + "default": { + "bundleMediaFramework": false, + "files": {} + }, + "allOf": [ + { + "$ref": "#/definitions/AppImageConfig" + } + ] + }, + "deb": { + "description": "Configuration for the Debian bundle.", + "default": { + "files": {} + }, + "allOf": [ + { + "$ref": "#/definitions/DebConfig" + } + ] + }, + "rpm": { + "description": "Configuration for the RPM bundle.", + "default": { + "epoch": 0, + "files": {}, + "release": "1" + }, + "allOf": [ + { + "$ref": "#/definitions/RpmConfig" + } + ] + } + }, + "additionalProperties": false + }, + "AppImageConfig": { + "description": "Configuration for AppImage bundles.\n\n See more: ", + "type": "object", + "properties": { + "bundleMediaFramework": { + "description": "Include additional gstreamer dependencies needed for audio and video playback.\n This increases the bundle size by ~15-35MB depending on your build system.", + "default": false, + "type": "boolean" + }, + "files": { + "description": "The files to include in the Appimage Binary.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "DebConfig": { + "description": "Configuration for Debian (.deb) bundles.\n\n See more: ", + "type": "object", + "properties": { + "depends": { + "description": "The list of deb dependencies your application relies on.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "provides": { + "description": "The list of dependencies the package provides.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "conflicts": { + "description": "The list of package conflicts.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "replaces": { + "description": "The list of package replaces.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "files": { + "description": "The files to include on the package.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "section": { + "description": "Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections", + "type": [ + "string", + "null" + ] + }, + "priority": { + "description": "Change the priority of the Debian Package. By default, it is set to `optional`.\n Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`", + "type": [ + "string", + "null" + ] + }, + "changelog": { + "description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n ", + "type": [ + "string", + "null" + ] + }, + "desktopTemplate": { + "description": "Path to a custom desktop file Handlebars template.\n\n Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.", + "type": [ + "string", + "null" + ] + }, + "preInstallScript": { + "description": "Path to script that will be executed before the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "postInstallScript": { + "description": "Path to script that will be executed after the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "preRemoveScript": { + "description": "Path to script that will be executed before the package is removed. See\n ", + "type": [ + "string", + "null" + ] + }, + "postRemoveScript": { + "description": "Path to script that will be executed after the package is removed. See\n ", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "RpmConfig": { + "description": "Configuration for RPM bundles.", + "type": "object", + "properties": { + "depends": { + "description": "The list of RPM dependencies your application relies on.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "provides": { + "description": "The list of RPM dependencies your application provides.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "conflicts": { + "description": "The list of RPM dependencies your application conflicts with. They must not be present\n in order for the package to be installed.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "obsoletes": { + "description": "The list of RPM dependencies your application supersedes - if this package is installed,\n packages listed as “obsoletes” will be automatically removed (if they are present).", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "release": { + "description": "The RPM release tag.", + "default": "1", + "type": "string" + }, + "epoch": { + "description": "The RPM epoch.", + "default": 0, + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "files": { + "description": "The files to include on the package.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "desktopTemplate": { + "description": "Path to a custom desktop file Handlebars template.\n\n Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.", + "type": [ + "string", + "null" + ] + }, + "preInstallScript": { + "description": "Path to script that will be executed before the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "postInstallScript": { + "description": "Path to script that will be executed after the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "preRemoveScript": { + "description": "Path to script that will be executed before the package is removed. See\n ", + "type": [ + "string", + "null" + ] + }, + "postRemoveScript": { + "description": "Path to script that will be executed after the package is removed. See\n ", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "MacConfig": { + "description": "Configuration for the macOS bundles.\n\n See more: ", + "type": "object", + "properties": { + "frameworks": { + "description": "A list of strings indicating any macOS X frameworks that need to be bundled with the application.\n\n If a name is used, \".framework\" must be omitted and it will look for standard install locations. You may also use a path to a specific framework.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "files": { + "description": "The files to include in the application relative to the Contents directory.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "minimumSystemVersion": { + "description": "A version string indicating the minimum macOS X version that the bundled application supports. Defaults to `10.13`.\n\n Setting it to `null` completely removes the `LSMinimumSystemVersion` field on the bundle's `Info.plist`\n and the `MACOSX_DEPLOYMENT_TARGET` environment variable.\n\n An empty string is considered an invalid value so the default value is used.", + "default": "10.13", + "type": [ + "string", + "null" + ] + }, + "exceptionDomain": { + "description": "Allows your application to communicate with the outside world.\n It should be a lowercase, without port and protocol domain name.", + "type": [ + "string", + "null" + ] + }, + "signingIdentity": { + "description": "Identity to use for code signing.", + "type": [ + "string", + "null" + ] + }, + "hardenedRuntime": { + "description": "Whether the codesign should enable [hardened runtime] (for executables) or not.\n\n [hardened runtime]: ", + "default": true, + "type": "boolean" + }, + "providerShortName": { + "description": "Provider short name for notarization.", + "type": [ + "string", + "null" + ] + }, + "entitlements": { + "description": "Path to the entitlements file.", + "type": [ + "string", + "null" + ] + }, + "dmg": { + "description": "DMG-specific settings.", + "default": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "allOf": [ + { + "$ref": "#/definitions/DmgConfig" + } + ] + } + }, + "additionalProperties": false + }, + "DmgConfig": { + "description": "Configuration for Apple Disk Image (.dmg) bundles.\n\n See more: ", + "type": "object", + "properties": { + "background": { + "description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.", + "type": [ + "string", + "null" + ] + }, + "windowPosition": { + "description": "Position of volume window on screen.", + "anyOf": [ + { + "$ref": "#/definitions/Position" + }, + { + "type": "null" + } + ] + }, + "windowSize": { + "description": "Size of volume window.", + "default": { + "height": 400, + "width": 660 + }, + "allOf": [ + { + "$ref": "#/definitions/Size" + } + ] + }, + "appPosition": { + "description": "Position of app file on window.", + "default": { + "x": 180, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + }, + "applicationFolderPosition": { + "description": "Position of application folder on window.", + "default": { + "x": 480, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + } + }, + "additionalProperties": false + }, + "Position": { + "description": "Position coordinates struct.", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "y": { + "description": "Y coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Size": { + "description": "Size of the window.", + "type": "object", + "required": [ + "height", + "width" + ], + "properties": { + "width": { + "description": "Width of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "height": { + "description": "Height of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "IosConfig": { + "description": "General configuration for the iOS target.", + "type": "object", + "properties": { + "template": { + "description": "A custom [XcodeGen] project.yml template to use.\n\n [XcodeGen]: ", + "type": [ + "string", + "null" + ] + }, + "frameworks": { + "description": "A list of strings indicating any iOS frameworks that need to be bundled with the application.\n\n Note that you need to recreate the iOS project for the changes to be applied.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "developmentTeam": { + "description": "The development team. This value is required for iOS development because code signing is enforced.\n The `APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.", + "type": [ + "string", + "null" + ] + }, + "minimumSystemVersion": { + "description": "A version string indicating the minimum iOS version that the bundled application supports. Defaults to `13.0`.\n\n Maps to the IPHONEOS_DEPLOYMENT_TARGET value.", + "default": "13.0", + "type": "string" + } + }, + "additionalProperties": false + }, + "AndroidConfig": { + "description": "General configuration for the iOS target.", + "type": "object", + "properties": { + "minSdkVersion": { + "description": "The minimum API level required for the application to run.\n The Android system will prevent the user from installing the application if the system's API level is lower than the value specified.", + "default": 24, + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "versionCode": { + "description": "The version code of the application.\n It is limited to 2,100,000,000 as per Google Play Store requirements.\n\n By default we use your configured version and perform the following math:\n versionCode = version.major * 1000000 + version.minor * 1000 + version.patch", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "maximum": 2100000000.0, + "minimum": 1.0 + } + }, + "additionalProperties": false + }, + "PluginConfig": { + "description": "The plugin configs holds a HashMap mapping a plugin name to its configuration object.\n\n See more: ", + "type": "object", + "additionalProperties": true + } + } +} \ No newline at end of file diff --git a/crates/tauri-cli/tauri.gitignore b/crates/tauri-cli/tauri.gitignore new file mode 100644 index 000000000000..b38a7f1e3d41 --- /dev/null +++ b/crates/tauri-cli/tauri.gitignore @@ -0,0 +1,3 @@ +node_modules/ +target/ +.DS_Store diff --git a/crates/tauri-cli/templates/app/src-tauri/.gitignore b/crates/tauri-cli/templates/app/src-tauri/.gitignore new file mode 100644 index 000000000000..502406b4eda7 --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/.gitignore @@ -0,0 +1,4 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ +/gen/schemas diff --git a/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest b/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest new file mode 100644 index 000000000000..e7fcaafd3572 --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/Cargo.crate-manifest @@ -0,0 +1,29 @@ +[package] +name = "app" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.77.2" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[lib] +name = "app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +[build-dependencies] +tauri-build = {{ tauri_build_dep }} + +[dependencies] +serde_json = "1.0" +serde = { version = "1.0", features = ["derive"] } +log = "0.4" +tauri = {{ tauri_dep }} +tauri-plugin-log = "2.0.0-rc" +{{#if patch_tauri_dep}} +[patch.crates-io] +tauri = {{ tauri_dep }} +{{/if}} diff --git a/tooling/cli/templates/app/src-tauri/build.rs b/crates/tauri-cli/templates/app/src-tauri/build.rs similarity index 100% rename from tooling/cli/templates/app/src-tauri/build.rs rename to crates/tauri-cli/templates/app/src-tauri/build.rs diff --git a/crates/tauri-cli/templates/app/src-tauri/capabilities/default.json b/crates/tauri-cli/templates/app/src-tauri/capabilities/default.json new file mode 100644 index 000000000000..c135d7f15d4f --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/capabilities/default.json @@ -0,0 +1,11 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:default" + ] +} diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/128x128.png b/crates/tauri-cli/templates/app/src-tauri/icons/128x128.png new file mode 100644 index 000000000000..77e7d2338e9d Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/128x128.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/128x128@2x.png b/crates/tauri-cli/templates/app/src-tauri/icons/128x128@2x.png new file mode 100644 index 000000000000..0f7976f1a004 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/128x128@2x.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/32x32.png b/crates/tauri-cli/templates/app/src-tauri/icons/32x32.png new file mode 100644 index 000000000000..98fda06fcb02 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/32x32.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square107x107Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square107x107Logo.png new file mode 100644 index 000000000000..f35d84ff1334 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square107x107Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square142x142Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square142x142Logo.png new file mode 100644 index 000000000000..1823bb2696be Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square142x142Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square150x150Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square150x150Logo.png new file mode 100644 index 000000000000..dc2b22cea563 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square150x150Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square284x284Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square284x284Logo.png new file mode 100644 index 000000000000..0ed3984c5fb4 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square284x284Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square30x30Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square30x30Logo.png new file mode 100644 index 000000000000..60bf0eadf75c Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square30x30Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square310x310Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square310x310Logo.png new file mode 100644 index 000000000000..c8ca0ad132e0 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square310x310Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square44x44Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square44x44Logo.png new file mode 100644 index 000000000000..8756459b63d6 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square44x44Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square71x71Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square71x71Logo.png new file mode 100644 index 000000000000..2c8023cc8244 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square71x71Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/Square89x89Logo.png b/crates/tauri-cli/templates/app/src-tauri/icons/Square89x89Logo.png new file mode 100644 index 000000000000..2c5e6034ff53 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/Square89x89Logo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/StoreLogo.png b/crates/tauri-cli/templates/app/src-tauri/icons/StoreLogo.png new file mode 100644 index 000000000000..17d142c0a432 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/StoreLogo.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/icon.icns b/crates/tauri-cli/templates/app/src-tauri/icons/icon.icns new file mode 100644 index 000000000000..a2993adc87ff Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/icon.icns differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/icon.ico b/crates/tauri-cli/templates/app/src-tauri/icons/icon.ico new file mode 100644 index 000000000000..06c23c82fea6 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/icon.ico differ diff --git a/crates/tauri-cli/templates/app/src-tauri/icons/icon.png b/crates/tauri-cli/templates/app/src-tauri/icons/icon.png new file mode 100644 index 000000000000..d1756ce45d62 Binary files /dev/null and b/crates/tauri-cli/templates/app/src-tauri/icons/icon.png differ diff --git a/crates/tauri-cli/templates/app/src-tauri/src/lib.rs b/crates/tauri-cli/templates/app/src-tauri/src/lib.rs new file mode 100644 index 000000000000..9c3118c5d49e --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/src/lib.rs @@ -0,0 +1,16 @@ +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .setup(|app| { + if cfg!(debug_assertions) { + app.handle().plugin( + tauri_plugin_log::Builder::default() + .level(log::LevelFilter::Info) + .build(), + )?; + } + Ok(()) + }) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/crates/tauri-cli/templates/app/src-tauri/src/main.rs b/crates/tauri-cli/templates/app/src-tauri/src/main.rs new file mode 100644 index 000000000000..ad5fe8399171 --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + app_lib::run(); +} diff --git a/crates/tauri-cli/templates/app/src-tauri/tauri.conf.json b/crates/tauri-cli/templates/app/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..4707e24cee9a --- /dev/null +++ b/crates/tauri-cli/templates/app/src-tauri/tauri.conf.json @@ -0,0 +1 @@ +{{ tauri_config }} diff --git a/crates/tauri-cli/templates/mobile/android/.editorconfig b/crates/tauri-cli/templates/mobile/android/.editorconfig new file mode 100644 index 000000000000..ebe51d3bfa47 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/.editorconfig @@ -0,0 +1,12 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/.gitignore b/crates/tauri-cli/templates/mobile/android/.gitignore new file mode 100644 index 000000000000..b24820317285 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/.gitignore @@ -0,0 +1,19 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +build +/captures +.externalNativeBuild +.cxx +local.properties +key.properties + +/.tauri +/tauri.settings.gradle \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/.gitignore b/crates/tauri-cli/templates/mobile/android/app/.gitignore new file mode 100644 index 000000000000..439b71f0e392 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/.gitignore @@ -0,0 +1,6 @@ +/src/main/{{package-path}}/generated +/src/main/jniLibs/**/*.so +/src/main/assets/tauri.conf.json +/tauri.build.gradle.kts +/proguard-tauri.pro +/tauri.properties \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts b/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts new file mode 100644 index 000000000000..6f408f536091 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/build.gradle.kts @@ -0,0 +1,75 @@ +import java.util.Properties + +plugins { + id("com.android.application") + id("org.jetbrains.kotlin.android") + id("rust") + {{~#each android-app-plugins}} + id("{{this}}"){{/each}} +} + +val tauriProperties = Properties().apply { + val propFile = file("tauri.properties") + if (propFile.exists()) { + propFile.inputStream().use { load(it) } + } +} + +android { + compileSdk = 34 + namespace = "{{app.identifier}}" + defaultConfig { + manifestPlaceholders["usesCleartextTraffic"] = "false" + applicationId = "{{app.identifier}}" + minSdk = {{android.min-sdk-version}} + targetSdk = 34 + versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() + versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") + } + buildTypes { + getByName("debug") { + manifestPlaceholders["usesCleartextTraffic"] = "true" + isDebuggable = true + isJniDebuggable = true + isMinifyEnabled = false + packaging { + {{~#each abi-list}} + jniLibs.keepDebugSymbols.add("*/{{this}}/*.so") + {{/each}} + } + } + getByName("release") { + isMinifyEnabled = true + proguardFiles( + *fileTree(".") { include("**/*.pro") } + .plus(getDefaultProguardFile("proguard-android-optimize.txt")) + .toList().toTypedArray() + ) + } + } + kotlinOptions { + jvmTarget = "1.8" + } + buildFeatures { + buildConfig = true + } +} + +rust { + rootDirRel = "{{root-dir-rel}}" +} + +dependencies { + {{~#each android-app-dependencies-platform}} + implementation(platform("{{this}}")){{/each}} + {{~#each android-app-dependencies}} + implementation("{{this}}"){{/each}} + implementation("androidx.webkit:webkit:1.6.1") + implementation("androidx.appcompat:appcompat:1.6.1") + implementation("com.google.android.material:material:1.8.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.4") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0") +} + +apply(from = "tauri.build.gradle.kts") \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/proguard-rules.pro b/crates/tauri-cli/templates/mobile/android/app/proguard-rules.pro new file mode 100644 index 000000000000..481bb4348141 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/AndroidManifest.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..c03c5d80f93b --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/MainActivity.kt b/crates/tauri-cli/templates/mobile/android/app/src/main/MainActivity.kt new file mode 100644 index 000000000000..24d37ded4492 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/MainActivity.kt @@ -0,0 +1,3 @@ +package {{escape-kotlin-keyword app.identifier}} + +class MainActivity : TauriActivity() \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000000..2b068d11462a --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000000..07d5da9cbf14 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/layout/activity_main.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000000..4fc244418b5f --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,18 @@ + + + + + + \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 000000000000..28f1aa119119 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 000000000000..85d0c88af65b Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100644 index 000000000000..28f1aa119119 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 000000000000..73e48dbfb7dc Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 000000000000..13dd21476b5c Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100644 index 000000000000..73e48dbfb7dc Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 000000000000..1d98044f13bd Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000000..a888b336b5bc Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100644 index 000000000000..1d98044f13bd Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 000000000000..081832466b4a Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000000..a2a838e7b550 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100644 index 000000000000..081832466b4a Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 000000000000..b18bceb64d25 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 000000000000..3f8a57f38e02 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100644 index 000000000000..b18bceb64d25 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml new file mode 100644 index 000000000000..d4abdc82e8c9 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values-night/themes.xml @@ -0,0 +1,6 @@ + + + + diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/colors.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/colors.xml new file mode 100644 index 000000000000..f8c6127d3276 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/strings.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/strings.xml new file mode 100644 index 000000000000..d5b7ddb4cddc --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/strings.xml @@ -0,0 +1,4 @@ + + {{app.stylized-name}} + {{app.stylized-name}} + \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml new file mode 100644 index 000000000000..d4abdc82e8c9 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/values/themes.xml @@ -0,0 +1,6 @@ + + + + diff --git a/crates/tauri-cli/templates/mobile/android/app/src/main/res/xml/file_paths.xml b/crates/tauri-cli/templates/mobile/android/app/src/main/res/xml/file_paths.xml new file mode 100644 index 000000000000..782d63b9932c --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/app/src/main/res/xml/file_paths.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/crates/tauri-cli/templates/mobile/android/build.gradle.kts b/crates/tauri-cli/templates/mobile/android/build.gradle.kts new file mode 100644 index 000000000000..0bf63ab7d9f6 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/build.gradle.kts @@ -0,0 +1,24 @@ +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath("com.android.tools.build:gradle:8.5.1") + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25") + {{~#each android-project-dependencies}} + classpath("{{this}}"){{/each}} + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} + +tasks.register("clean").configure { + delete("build") +} + diff --git a/crates/tauri-cli/templates/mobile/android/buildSrc/build.gradle.kts b/crates/tauri-cli/templates/mobile/android/buildSrc/build.gradle.kts new file mode 100644 index 000000000000..39e90b05430f --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/buildSrc/build.gradle.kts @@ -0,0 +1,23 @@ +plugins { + `kotlin-dsl` +} + +gradlePlugin { + plugins { + create("pluginsForCoolKids") { + id = "rust" + implementationClass = "RustPlugin" + } + } +} + +repositories { + google() + mavenCentral() +} + +dependencies { + compileOnly(gradleApi()) + implementation("com.android.tools.build:gradle:8.5.1") +} + diff --git a/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/BuildTask.kt b/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/BuildTask.kt new file mode 100644 index 000000000000..8bbef994aab8 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/BuildTask.kt @@ -0,0 +1,52 @@ +import java.io.File +import org.apache.tools.ant.taskdefs.condition.Os +import org.gradle.api.DefaultTask +import org.gradle.api.GradleException +import org.gradle.api.logging.LogLevel +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.TaskAction + +open class BuildTask : DefaultTask() { + @Input + var rootDirRel: String? = null + @Input + var target: String? = null + @Input + var release: Boolean? = null + + @TaskAction + fun assemble() { + val executable = """{{tauri-binary}}"""; + try { + runTauriCli(executable) + } catch (e: Exception) { + if (Os.isFamily(Os.FAMILY_WINDOWS)) { + runTauriCli("$executable.cmd") + } else { + throw e; + } + } + } + + fun runTauriCli(executable: String) { + val rootDirRel = rootDirRel ?: throw GradleException("rootDirRel cannot be null") + val target = target ?: throw GradleException("target cannot be null") + val release = release ?: throw GradleException("release cannot be null") + val args = listOf({{quote-and-join tauri-binary-args}}); + + project.exec { + workingDir(File(project.projectDir, rootDirRel)) + executable(executable) + args(args) + if (project.logger.isEnabled(LogLevel.DEBUG)) { + args("-vv") + } else if (project.logger.isEnabled(LogLevel.INFO)) { + args("-v") + } + if (release) { + args("--release") + } + args(listOf("--target", target)) + }.assertNormalExitValue() + } +} \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/RustPlugin.kt b/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/RustPlugin.kt new file mode 100644 index 000000000000..a13834927fb0 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/buildSrc/src/main/kotlin/RustPlugin.kt @@ -0,0 +1,85 @@ +import com.android.build.api.dsl.ApplicationExtension +import org.gradle.api.DefaultTask +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.get + +const val TASK_GROUP = "rust" + +open class Config { + lateinit var rootDirRel: String +} + +open class RustPlugin : Plugin { + private lateinit var config: Config + + override fun apply(project: Project) = with(project) { + config = extensions.create("rust", Config::class.java) + + val defaultAbiList = listOf({{quote-and-join abi-list}}); + val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList + + val defaultArchList = listOf({{quote-and-join arch-list}}); + val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList + + val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf({{quote-and-join target-list}}) + + extensions.configure { + @Suppress("UnstableApiUsage") + flavorDimensions.add("abi") + productFlavors { + create("universal") { + dimension = "abi" + ndk { + abiFilters += abiList + } + } + defaultArchList.forEachIndexed { index, arch -> + create(arch) { + dimension = "abi" + ndk { + abiFilters.add(defaultAbiList[index]) + } + } + } + } + } + + afterEvaluate { + for (profile in listOf("debug", "release")) { + val profileCapitalized = profile.replaceFirstChar { it.uppercase() } + val buildTask = tasks.maybeCreate( + "rustBuildUniversal$profileCapitalized", + DefaultTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for all targets" + } + + tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask) + + for (targetPair in targetsList.withIndex()) { + val targetName = targetPair.value + val targetArch = archList[targetPair.index] + val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() } + val targetBuildTask = project.tasks.maybeCreate( + "rustBuild$targetArchCapitalized$profileCapitalized", + BuildTask::class.java + ).apply { + group = TASK_GROUP + description = "Build dynamic library in $profile mode for $targetArch" + rootDirRel = config.rootDirRel + target = targetName + release = profile == "release" + } + + buildTask.dependsOn(targetBuildTask) + tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn( + targetBuildTask + ) + } + } + } + } +} \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/gradle.properties b/crates/tauri-cli/templates/mobile/android/gradle.properties new file mode 100644 index 000000000000..2a7ec6959df9 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/gradle.properties @@ -0,0 +1,24 @@ +# Project-wide Gradle settings. +# IDE (e.g. Android Studio) users: +# Gradle settings configured through the IDE *will override* +# any settings specified in this file. +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8 +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +# AndroidX package structure to make it clearer which packages are bundled with the +# Android operating system, and which are packaged with your app"s APK +# https://developer.android.com/topic/libraries/support-library/androidx-rn +android.useAndroidX=true +# Kotlin code style for this project: "official" or "obsolete": +kotlin.code.style=official +# Enables namespacing of each library's R class so that its R class includes only the +# resources declared in the library itself and none from the library's dependencies, +# thereby reducing the size of the R class for that library +android.nonTransitiveRClass=true +android.nonFinalResIds=false \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.jar b/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 000000000000..e708b1c023ec Binary files /dev/null and b/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.properties b/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 000000000000..0df10d556cca --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue May 10 19:22:52 CST 2022 +distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip +distributionPath=wrapper/dists +zipStorePath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME diff --git a/crates/tauri-cli/templates/mobile/android/gradlew b/crates/tauri-cli/templates/mobile/android/gradlew new file mode 100644 index 000000000000..4f906e0c811f --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/crates/tauri-cli/templates/mobile/android/gradlew.bat b/crates/tauri-cli/templates/mobile/android/gradlew.bat new file mode 100644 index 000000000000..107acd32c4e6 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/crates/tauri-cli/templates/mobile/android/settings.gradle b/crates/tauri-cli/templates/mobile/android/settings.gradle new file mode 100644 index 000000000000..672366b37701 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/android/settings.gradle @@ -0,0 +1,5 @@ +include ':app' +{{~#each asset-packs}} +include ':{{this}}'{{/each}} + +apply from: 'tauri.settings.gradle' diff --git a/crates/tauri-cli/templates/mobile/ios/.gitignore b/crates/tauri-cli/templates/mobile/ios/.gitignore new file mode 100644 index 000000000000..6726e2f89b04 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/.gitignore @@ -0,0 +1,3 @@ +xcuserdata/ +build/ +Externals/ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png new file mode 100644 index 000000000000..a6ac2a8ccf0a Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png new file mode 100644 index 000000000000..2869541f735d Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x-1.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png new file mode 100644 index 000000000000..2869541f735d Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png new file mode 100644 index 000000000000..cf265a45d341 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png new file mode 100644 index 000000000000..29c9746c0539 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png new file mode 100644 index 000000000000..a4e68c8d6d5c Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x-1.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png new file mode 100644 index 000000000000..a4e68c8d6d5c Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png new file mode 100644 index 000000000000..e4adcbcedc37 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png new file mode 100644 index 000000000000..2869541f735d Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png new file mode 100644 index 000000000000..a414e65bb05f Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x-1.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png new file mode 100644 index 000000000000..a414e65bb05f Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png new file mode 100644 index 000000000000..a0807e5dfdad Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png new file mode 100644 index 000000000000..704c929133f2 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png new file mode 100644 index 000000000000..a0807e5dfdad Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png new file mode 100644 index 000000000000..2a9fbc26ef1e Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png new file mode 100644 index 000000000000..2cdf18485f69 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png new file mode 100644 index 000000000000..4723e4b45ea6 Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png new file mode 100644 index 000000000000..f26fee45c06c Binary files /dev/null and b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png differ diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/Contents.json b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000000..90eea7ec7e21 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,116 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "AppIcon-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "AppIcon-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "AppIcon-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "AppIcon-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "AppIcon-20x20@2x-1.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "AppIcon-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "AppIcon-40x40@2x-1.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "AppIcon-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "AppIcon-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "AppIcon-512@2x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/Contents.json b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/Contents.json new file mode 100644 index 000000000000..da4a164c9186 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/crates/tauri-cli/templates/mobile/ios/ExportOptions.plist b/crates/tauri-cli/templates/mobile/ios/ExportOptions.plist new file mode 100644 index 000000000000..0428a171b341 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/ExportOptions.plist @@ -0,0 +1,8 @@ + + + + + method + debugging + + diff --git a/crates/tauri-cli/templates/mobile/ios/LaunchScreen.storyboard b/crates/tauri-cli/templates/mobile/ios/LaunchScreen.storyboard new file mode 100644 index 000000000000..dd79351ec8d1 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/LaunchScreen.storyboard @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/crates/tauri-cli/templates/mobile/ios/Podfile b/crates/tauri-cli/templates/mobile/ios/Podfile new file mode 100644 index 000000000000..0c0df4e64628 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/Podfile @@ -0,0 +1,25 @@ +# Uncomment the next line to define a global platform for your project + +target '{{app.name}}_iOS' do +platform :ios, '{{apple.ios-version}}' + # Pods for {{app.name}}_iOS + {{~#each ios-pods}} + pod '{{this.name}}'{{#if this.version}}, '{{this.version}}'{{/if}}{{/each}} +end + +target '{{app.name}}_macOS' do +platform :osx, '{{apple.macos-version}}' + # Pods for {{app.name}}_macOS + {{~#each macos-pods}} + pod '{{this.name}}'{{#if this.version}}, '{{this.version}}'{{/if}}{{/each}} +end + +# Delete the deployment target for iOS and macOS, causing it to be inherited from the Podfile +post_install do |installer| + installer.pods_project.targets.each do |target| + target.build_configurations.each do |config| + config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET' + config.build_settings.delete 'MACOSX_DEPLOYMENT_TARGET' + end + end +end diff --git a/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/bindings/bindings.h b/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/bindings/bindings.h new file mode 100644 index 000000000000..51522007b6a5 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/bindings/bindings.h @@ -0,0 +1,8 @@ +#pragma once + +namespace ffi { + extern "C" { + void start_app(); + } +} + diff --git a/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/main.mm b/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/main.mm new file mode 100644 index 000000000000..7793a9d5cfae --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/Sources/{{app.name}}/main.mm @@ -0,0 +1,6 @@ +#include "bindings/bindings.h" + +int main(int argc, char * argv[]) { + ffi::start_app(); + return 0; +} diff --git a/crates/tauri-cli/templates/mobile/ios/project.yml b/crates/tauri-cli/templates/mobile/ios/project.yml new file mode 100644 index 000000000000..1a4712bae9c7 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/project.yml @@ -0,0 +1,172 @@ +name: {{app.name}} +options: + bundleIdPrefix: {{app.identifier}} + deploymentTarget: + iOS: {{apple.ios-version}} +fileGroups: [{{join file-groups}}] +configs: + debug: debug + release: release +settingGroups: + app: + base: + PRODUCT_NAME: {{app.stylized-name}} + PRODUCT_BUNDLE_IDENTIFIER: {{app.identifier}} + {{#if apple.development-team}} + DEVELOPMENT_TEAM: {{apple.development-team}} + {{/if}} +targetTemplates: + app: + type: application + sources: + - path: Sources + scheme: + environmentVariables: + RUST_BACKTRACE: full + RUST_LOG: info + settings: + groups: [app] +targets: + {{app.name}}_iOS: + type: application + platform: iOS + sources: + - path: Sources + - path: Assets.xcassets + - path: Externals + - path: {{app.name}}_iOS + - path: {{app.asset-dir}} + buildPhase: resources + type: folder + {{~#each asset-catalogs}} + - {{prefix-path this}}{{/each}} + {{~#each ios-additional-targets}} + - path: {{prefix-path this}}{{/each}} + - path: LaunchScreen.storyboard + info: + path: {{app.name}}_iOS/Info.plist + properties: + LSRequiresIPhoneOS: true + UILaunchStoryboardName: LaunchScreen + UIRequiredDeviceCapabilities: [arm64, metal] + UISupportedInterfaceOrientations: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + UISupportedInterfaceOrientations~ipad: + - UIInterfaceOrientationPortrait + - UIInterfaceOrientationPortraitUpsideDown + - UIInterfaceOrientationLandscapeLeft + - UIInterfaceOrientationLandscapeRight + CFBundleShortVersionString: {{apple.bundle-version-short}} + CFBundleVersion: {{apple.bundle-version}} + {{~#each apple.plist-pairs}} + {{this.key}}: {{this.value}}{{/each}} + entitlements: + path: {{app.name}}_iOS/{{app.name}}_iOS.entitlements + scheme: + environmentVariables: + RUST_BACKTRACE: full + RUST_LOG: info + {{~#if ios-command-line-arguments}} + commandLineArguments: + {{~#each ios-command-line-arguments}} + "{{this}}": true + {{/each}}{{~/if}} + settings: + base: + ENABLE_BITCODE: false + ARCHS: [{{join ios-valid-archs}}] + VALID_ARCHS: {{~#each ios-valid-archs}} {{this}} {{/each}} + LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) + LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) + LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES: true + EXCLUDED_ARCHS[sdk=iphonesimulator*]: arm64 + EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64 + groups: [app] + dependencies: + - framework: {{ lib-output-file-name }} + embed: false + {{~#each ios-libraries}} + - framework: {{this}} + embed: false{{/each}}{{#if ios-vendor-frameworks}}{{~#each ios-vendor-frameworks}} + - framework: {{this}}{{/each}}{{/if}}{{#if ios-vendor-sdks}}{{~#each ios-vendor-sdks}} + - sdk: {{prefix-path this}}{{/each}}{{/if}} + - sdk: CoreGraphics.framework + - sdk: Metal.framework + - sdk: MetalKit.framework + - sdk: QuartzCore.framework + - sdk: Security.framework + - sdk: UIKit.framework{{#if this.ios-frameworks}}{{~#each ios-frameworks}} + - sdk: {{this}}.framework{{/each}}{{/if}} + - sdk: WebKit.framework + preBuildScripts: + {{~#each ios-pre-build-scripts}}{{#if this.path}} + - path {{this.path}}{{/if}}{{#if this.script}} + - script: {{this.script}}{{/if}}{{#if this.name}} + name: {{this.name}}{{/if}}{{#if this.input-files}} + inputFiles: {{~#each this.input-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-files}} + outputFiles: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.input-file-lists}} + inputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-file-lists}} + outputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.shell}} + shell: {{this.shell}}{{/if}}{{#if this.show-env-vars}} + showEnvVars: {{this.show_env_vars}}{{/if}}{{#if this.run-only-when-installing}} + runOnlyWhenInstalling: {{this.run-only-when-installing}}{{/if}}{{#if this.based-on-dependency-analysis}} + basedOnDependencyAnalysis: {{this.based-on-dependency-analysis}}{{/if}}{{#if this.discovered-dependency-file}} + discoveredDependencyFile: {{this.discovered-dependency-file}}{{/if}} + {{~/each}} + + - script: {{ tauri-binary }} {{ tauri-binary-args-str }} -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths "${FRAMEWORK_SEARCH_PATHS:?}" --header-search-paths "${HEADER_SEARCH_PATHS:?}" --gcc-preprocessor-definitions "${GCC_PREPROCESSOR_DEFINITIONS:-}" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?} + name: Build Rust Code + basedOnDependencyAnalysis: false + outputFiles: + - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/{{ lib-output-file-name }} + - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/{{ lib-output-file-name }} + - $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/{{ lib-output-file-name }} + {{~#if ios-post-compile-scripts}} + postCompileScripts: + {{~#each ios-post-compile-scripts}}{{#if this.path}} + - path {{this.path}}{{/if}}{{#if this.script}} + - script: {{this.script}}{{/if}}{{#if this.name}} + name: {{this.name}}{{/if}}{{#if this.input-files}} + inputFiles: {{~#each this.input-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-files}} + outputFiles: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.input-file-lists}} + inputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-file-lists}} + outputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.shell}} + shell: {{this.shell}}{{/if}}{{#if this.show-env-vars}} + showEnvVars: {{this.show_env_vars}}{{/if}}{{#if this.run-only-when-installing}} + runOnlyWhenInstalling: {{this.run-only-when-installing}}{{/if}}{{#if this.based-on-dependency-analysis}} + basedOnDependencyAnalysis: {{this.based-on-dependency-analysis}}{{/if}}{{#if this.discovered-dependency-file}} + discoveredDependencyFile: {{this.discovered-dependency-file}}{{/if}} + {{~/each~}} + {{~/if~}} + {{~#if ios-post-build-scripts}} + postBuildScripts: + {{~#each ios-post-build-scripts}}{{#if this.path}} + - path {{this.path}}{{/if}}{{#if this.script}} + - script: {{this.script}}{{/if}}{{#if this.name}} + name: {{this.name}}{{/if}}{{#if this.input-files}} + inputFiles: {{~#each this.input-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-files}} + outputFiles: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.input-file-lists}} + inputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.output-file-lists}} + outputFileLists: {{~#each this.output-files}} + - {{this}}{{/each}}{{/if}}{{#if this.shell}} + shell: {{this.shell}}{{/if}}{{#if this.show-env-vars}} + showEnvVars: {{this.show_env_vars}}{{/if}}{{#if this.run-only-when-installing}} + runOnlyWhenInstalling: {{this.run-only-when-installing}}{{/if}}{{#if this.based-on-dependency-analysis}} + basedOnDependencyAnalysis: {{this.based-on-dependency-analysis}}{{/if}}{{#if this.discovered-dependency-file}} + discoveredDependencyFile: {{this.discovered-dependency-file}}{{/if}} + {{~/each~}} + {{~/if}} diff --git a/crates/tauri-cli/templates/mobile/ios/{{app.name}}.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/crates/tauri-cli/templates/mobile/ios/{{app.name}}.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 000000000000..0225e8973168 --- /dev/null +++ b/crates/tauri-cli/templates/mobile/ios/{{app.name}}.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,12 @@ + + + + +{{#if apple.use-legacy-build-system}} + BuildSystemType + Original + DisableBuildSystemDeprecationDiagnostic + +{{/if}} + + diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml b/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml new file mode 100644 index 000000000000..4121fa6470da --- /dev/null +++ b/crates/tauri-cli/templates/plugin/.github/workflows/audit.yml @@ -0,0 +1,34 @@ +{{{{raw}}}} +name: Audit + +on: + schedule: + - cron: '0 0 * * *' + push: + branches: + - main + paths: + - ".github/workflows/audit.yml" + - "**/Cargo.lock" + - "**/Cargo.toml" + pull_request: + branches: + - main + paths: + - ".github/workflows/audit.yml" + - "**/Cargo.lock" + - "**/Cargo.toml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + audit: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rustsec/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} +{{{{/raw}}}} diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml b/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml new file mode 100644 index 000000000000..23556aeb345a --- /dev/null +++ b/crates/tauri-cli/templates/plugin/.github/workflows/clippy.yml @@ -0,0 +1,55 @@ +{{{{raw}}}} +name: Check + +on: + push: + branches: + - main + paths: + - ".github/workflows/check.yml" + - "**/*.rs" + - "**/Cargo.toml" + pull_request: + branches: + - main + paths: + - ".github/workflows/check.yml" + - "**/*.rs" + - "**/Cargo.toml" + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + fmt: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + + clippy: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - name: install webkit2gtk + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 + - uses: Swatinem/rust-cache@v2 + - run: cargo clippy --all-targets --all-features -- -D warnings +{{{{/raw}}}} diff --git a/crates/tauri-cli/templates/plugin/.github/workflows/test.yml b/crates/tauri-cli/templates/plugin/.github/workflows/test.yml new file mode 100644 index 000000000000..c528a4506fde --- /dev/null +++ b/crates/tauri-cli/templates/plugin/.github/workflows/test.yml @@ -0,0 +1,35 @@ +{{{{raw}}}} +name: Test + +on: + push: + branches: + - main + pull_request: + branches: + - main + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, macos-latest, windows-latest] + + runs-on: ${{ matrix.platform }} + + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + - name: install webkit2gtk + if: matrix.platform == 'ubuntu-latest' + run: | + sudo apt-get update + sudo apt-get install -y webkit2gtk-4.1 + - uses: Swatinem/rust-cache@v2 + - run: cargo test --all-targets --all-features -- -D warnings +{{{{/raw}}}} diff --git a/crates/tauri-cli/templates/plugin/.gitignore b/crates/tauri-cli/templates/plugin/.gitignore new file mode 100644 index 000000000000..50d8e32e8976 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/.gitignore @@ -0,0 +1,17 @@ +/.vs +.DS_Store +.Thumbs.db +*.sublime* +.idea/ +debug.log +package-lock.json +.vscode/settings.json +yarn.lock + +/.tauri +/target +Cargo.lock +node_modules/ + +dist-js +dist diff --git a/crates/tauri-cli/templates/plugin/Cargo.crate-manifest b/crates/tauri-cli/templates/plugin/Cargo.crate-manifest new file mode 100644 index 000000000000..ecb96e65d770 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/Cargo.crate-manifest @@ -0,0 +1,17 @@ +[package] +name = "tauri-plugin-{{ plugin_name }}" +version = "0.1.0" +authors = [ "{{ author }}" ] +description = "" +edition = "2021" +rust-version = "1.77.2" +exclude = ["/examples", "/dist-js", "/guest-js", "/node_modules"] +links = "tauri-plugin-{{ plugin_name }}" + +[dependencies] +tauri = {{ tauri_dep }} +serde = "1.0" +thiserror = "2" + +[build-dependencies] +tauri-plugin = {{{ tauri_plugin_dep }}} diff --git a/tooling/cli/templates/plugin/backend/README.md b/crates/tauri-cli/templates/plugin/README.md similarity index 100% rename from tooling/cli/templates/plugin/backend/README.md rename to crates/tauri-cli/templates/plugin/README.md diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.gitignore b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.gitignore new file mode 100644 index 000000000000..a547bf36d8d1 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.gitignore @@ -0,0 +1,24 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.vscode/extensions.json b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.vscode/extensions.json new file mode 100644 index 000000000000..61343e9b89ef --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + "recommendations": [ + "svelte.svelte-vscode", + "tauri-apps.tauri-vscode", + "rust-lang.rust-analyzer" + ] +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/README.md b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/README.md new file mode 100644 index 000000000000..72726a1fa45d --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/README.md @@ -0,0 +1,8 @@ +# Svelte + Vite + +This template should help get you started developing with Tauri and Svelte in Vite. + +## Recommended IDE Setup + +[VS Code](https://code.visualstudio.com/) + [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode) + [Tauri](https://marketplace.visualstudio.com/items?itemName=tauri-apps.tauri-vscode) + [rust-analyzer](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer). + diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/index.html b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/index.html new file mode 100644 index 000000000000..fad1c5d9c250 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/index.html @@ -0,0 +1,14 @@ + + + + + + + Tauri + Svelte + + + +
+ + + diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/jsconfig.json b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/jsconfig.json new file mode 100644 index 000000000000..ee5e92f298e4 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/jsconfig.json @@ -0,0 +1,34 @@ +{ + "compilerOptions": { + "moduleResolution": "Node", + "target": "ESNext", + "module": "ESNext", + /** + * svelte-preprocess cannot figure out whether you have + * a value or a type, so tell TypeScript to enforce using + * `import type` instead of `import` for Types. + */ + "importsNotUsedAsValues": "error", + "isolatedModules": true, + "resolveJsonModule": true, + /** + * To have warnings / errors of the Svelte compiler at the + * correct position, enable source maps by default. + */ + "sourceMap": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "baseUrl": ".", + /** + * Typecheck JS in `.svelte` and `.js` files by default. + * Disable this if you'd like to use dynamic types. + */ + "checkJs": true + }, + /** + * Use global.d.ts instead of compilerOptions.types + * to avoid limiting type declarations. + */ + "include": ["src/**/*.d.ts", "src/**/*.js", "src/**/*.svelte"] +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/package.json b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/package.json new file mode 100644 index 000000000000..47858f2c0716 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/package.json @@ -0,0 +1,22 @@ +{ + "name": "tauri-app", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "tauri": "tauri" + }, + "dependencies": { + "@tauri-apps/api": "^2.0.0-alpha.11", + "tauri-plugin-{{ plugin_name }}-api": "file:../../" + }, + "devDependencies": { + "@sveltejs/vite-plugin-svelte": "^1.0.1", + "svelte": "^3.49.0", + "vite": "^3.0.2", + "@tauri-apps/cli": "^2.0.0-alpha.17" + } +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/svelte.svg b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/svelte.svg new file mode 100644 index 000000000000..c5e08481f8ae --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/svelte.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/tauri.svg b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/tauri.svg new file mode 100644 index 000000000000..31b62c92804b --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/tauri.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/vite.svg b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/vite.svg new file mode 100644 index 000000000000..e7b8dfb1b2a6 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/.gitignore b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/.gitignore new file mode 100644 index 000000000000..f4dfb82b2cf3 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/.gitignore @@ -0,0 +1,4 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ + diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/Cargo.crate-manifest b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/Cargo.crate-manifest new file mode 100644 index 000000000000..3dfd82a6ad8e --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/Cargo.crate-manifest @@ -0,0 +1,23 @@ +[package] +name = "tauri-app" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.77.2" + +[lib] +name = "tauri_app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +tauri-build = {{ tauri_build_dep }} + +[dependencies] +tauri = {{ tauri_example_dep }} +tauri-plugin-{{ plugin_name }} = { path = "../../../" } + diff --git a/tooling/cli/templates/plugin/backend/examples/vanilla/src-tauri/build.rs b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/build.rs similarity index 100% rename from tooling/cli/templates/plugin/backend/examples/vanilla/src-tauri/build.rs rename to crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/build.rs diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/capabilities/default.json b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/capabilities/default.json new file mode 100644 index 000000000000..2a0c36a19a89 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/capabilities/default.json @@ -0,0 +1,12 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "{{ plugin_name }}:default" + ] +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128.png b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128.png new file mode 100644 index 000000000000..77e7d2338e9d Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128@2x.png b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128@2x.png new file mode 100644 index 000000000000..0f7976f1a004 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/128x128@2x.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/32x32.png b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/32x32.png new file mode 100644 index 000000000000..98fda06fcb02 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/32x32.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.icns b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.icns new file mode 100644 index 000000000000..29d6685ae630 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.icns differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.ico b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.ico new file mode 100644 index 000000000000..06c23c82fea6 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.ico differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.png b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.png new file mode 100644 index 000000000000..d1756ce45d62 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/icons/icon.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/lib.rs b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/lib.rs new file mode 100644 index 000000000000..cfe473dc233c --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/lib.rs @@ -0,0 +1,14 @@ +// Learn more about Tauri commands at https://v2.tauri.app/develop/calling-rust/#commands +#[tauri::command] +fn greet(name: &str) -> String { + format!("Hello, {}! You've been greeted from Rust!", name) +} + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .invoke_handler(tauri::generate_handler![greet]) + .plugin(tauri_plugin_{{ plugin_name_snake_case }}::init()) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/main.rs b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/main.rs new file mode 100644 index 000000000000..455963eea09b --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + tauri_app_lib::run(); +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/tauri.conf.json b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..72ebf4001033 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src-tauri/tauri.conf.json @@ -0,0 +1,37 @@ +{ + "productName": "tauri-app", + "version": "0.1.0", + "identifier": "com.tauri.dev", + "build": { + "beforeDevCommand": "pnpm dev", + "beforeBuildCommand": "pnpm build", + "devUrl": "http://localhost:1420", + "frontendDist": "../dist" + }, + "app": { + "withGlobalTauri": false, + "security": { + "csp": null + }, + "windows": [ + { + "fullscreen": false, + "height": 600, + "resizable": true, + "title": "tauri-app", + "width": 800 + } + ] + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/App.svelte b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/App.svelte new file mode 100644 index 000000000000..df696ffbf783 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/App.svelte @@ -0,0 +1,54 @@ + + +
+

Welcome to Tauri!

+ + + +

+ Click on the Tauri, Vite, and Svelte logos to learn more. +

+ +
+ +
+ +
+ +
{@html response}
+
+ +
+ + diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/lib/Greet.svelte b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/lib/Greet.svelte new file mode 100644 index 000000000000..41e901b54bc8 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/lib/Greet.svelte @@ -0,0 +1,22 @@ + + +
+
+ + +
+

{greetMsg}

+
+ diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/main.js b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/main.js new file mode 100644 index 000000000000..6b4e1a969ec1 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/main.js @@ -0,0 +1,8 @@ +import "./style.css"; +import App from "./App.svelte"; + +const app = new App({ + target: document.getElementById("app"), +}); + +export default app; diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/style.css b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/style.css new file mode 100644 index 000000000000..c0f9e3bc8e2f --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/style.css @@ -0,0 +1,102 @@ +:root { + font-family: Inter, Avenir, Helvetica, Arial, sans-serif; + font-size: 16px; + line-height: 24px; + font-weight: 400; + + color: #0f0f0f; + background-color: #f6f6f6; + + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + -webkit-text-size-adjust: 100%; +} + +.container { + margin: 0; + padding-top: 10vh; + display: flex; + flex-direction: column; + justify-content: center; + text-align: center; +} + +.logo { + height: 6em; + padding: 1.5em; + will-change: filter; + transition: 0.75s; +} + +.logo.tauri:hover { + filter: drop-shadow(0 0 2em #24c8db); +} + +.row { + display: flex; + justify-content: center; +} + +a { + font-weight: 500; + color: #646cff; + text-decoration: inherit; +} + +a:hover { + color: #535bf2; +} + +h1 { + text-align: center; +} + +input, +button { + border-radius: 8px; + border: 1px solid transparent; + padding: 0.6em 1.2em; + font-size: 1em; + font-weight: 500; + font-family: inherit; + color: #0f0f0f; + background-color: #ffffff; + transition: border-color 0.25s; + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.2); +} + +button { + cursor: pointer; +} + +button:hover { + border-color: #396cd8; +} + +input, +button { + outline: none; +} + +#greet-input { + margin-right: 5px; +} + +@media (prefers-color-scheme: dark) { + :root { + color: #f6f6f6; + background-color: #2f2f2f; + } + + a:hover { + color: #24c8db; + } + + input, + button { + color: #ffffff; + background-color: #0f0f0f98; + } +} diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/vite-env.d.ts b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/vite-env.d.ts new file mode 100644 index 000000000000..4078e7476a2e --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/src/vite-env.d.ts @@ -0,0 +1,2 @@ +/// +/// diff --git a/crates/tauri-cli/templates/plugin/__example-api/tauri-app/vite.config.js b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/vite.config.js new file mode 100644 index 000000000000..3b85afb95aad --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-api/tauri-app/vite.config.js @@ -0,0 +1,24 @@ +import { defineConfig } from "vite"; +import { svelte } from "@sveltejs/vite-plugin-svelte"; + +const host = process.env.TAURI_DEV_HOST; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [svelte()], + + // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` + // prevent vite from obscuring rust errors + clearScreen: false, + // tauri expects a fixed port, fail if that port is not available + server: { + host: host || false, + port: 1420, + strictPort: true, + hmr: host ? { + protocol: 'ws', + host, + port: 1421 + } : undefined, + }, +}) diff --git a/tooling/cli/templates/plugin/backend/examples/vanilla/.gitignore b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/.gitignore similarity index 100% rename from tooling/cli/templates/plugin/backend/examples/vanilla/.gitignore rename to crates/tauri-cli/templates/plugin/__example-basic/vanilla/.gitignore diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/package.json b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/package.json new file mode 100644 index 000000000000..ee8a00206389 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/package.json @@ -0,0 +1,14 @@ +{ + "name": "app", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "MIT", + "dependencies": { + "@tauri-apps/cli": "^2.0.0-alpha.17" + } +} diff --git a/tooling/cli/templates/plugin/backend/examples/vanilla/public/index.html b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/public/index.html similarity index 100% rename from tooling/cli/templates/plugin/backend/examples/vanilla/public/index.html rename to crates/tauri-cli/templates/plugin/__example-basic/vanilla/public/index.html diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/.gitignore b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/.gitignore new file mode 100644 index 000000000000..aba21e242c95 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/.gitignore @@ -0,0 +1,3 @@ +# Generated by Cargo +# will have compiled files and executables +/target/ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/Cargo.crate-manifest b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/Cargo.crate-manifest new file mode 100644 index 000000000000..4f854da7bdd4 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/Cargo.crate-manifest @@ -0,0 +1,22 @@ +[package] +name = "tauri-app" +version = "0.1.0" +description = "A Tauri App" +authors = ["you"] +license = "" +repository = "" +edition = "2021" +rust-version = "1.77.2" + +[lib] +name = "tauri_app_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[build-dependencies] +tauri-build = {{ tauri_build_dep }} + +[dependencies] +tauri = {{ tauri_example_dep }} +tauri-plugin-{{ plugin_name }} = { path = "../../../" } diff --git a/tooling/cli/templates/plugin/with-api/examples/svelte-app/src-tauri/build.rs b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/build.rs similarity index 100% rename from tooling/cli/templates/plugin/with-api/examples/svelte-app/src-tauri/build.rs rename to crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/build.rs diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/capabilities/default.json b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/capabilities/default.json new file mode 100644 index 000000000000..86275c413c54 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/capabilities/default.json @@ -0,0 +1,12 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "default", + "description": "enables the default permissions", + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "{{ plugin_name }}:default" + ] +} \ No newline at end of file diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128.png b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128.png new file mode 100644 index 000000000000..77e7d2338e9d Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128@2x.png b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128@2x.png new file mode 100644 index 000000000000..0f7976f1a004 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/128x128@2x.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/32x32.png b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/32x32.png new file mode 100644 index 000000000000..98fda06fcb02 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/32x32.png differ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.icns b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.icns new file mode 100644 index 000000000000..67e10d961a8f Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.icns differ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.ico b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.ico new file mode 100644 index 000000000000..06c23c82fea6 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.ico differ diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.png b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.png new file mode 100644 index 000000000000..d1756ce45d62 Binary files /dev/null and b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/icons/icon.png differ diff --git a/tooling/cli/node/test/jest/fixtures/app/src-tauri/rustfmt.toml b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/rustfmt.toml similarity index 100% rename from tooling/cli/node/test/jest/fixtures/app/src-tauri/rustfmt.toml rename to crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/rustfmt.toml diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/lib.rs b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/lib.rs new file mode 100644 index 000000000000..67e77323c121 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + tauri::Builder::default() + .plugin(tauri_plugin_{{ plugin_name_snake_case }}::init()) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/main.rs b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/main.rs new file mode 100644 index 000000000000..455963eea09b --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/src/main.rs @@ -0,0 +1,6 @@ +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] + +fn main() { + tauri_app_lib::run(); +} diff --git a/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/tauri.conf.json b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..6e8341e8b78f --- /dev/null +++ b/crates/tauri-cli/templates/plugin/__example-basic/vanilla/src-tauri/tauri.conf.json @@ -0,0 +1,33 @@ +{ + "productName": "app", + "version": "0.1.0", + "identifier": "com.tauri.{{ plugin_name }}", + "build": { + "frontendDist": "../public" + }, + "app": { + "windows": [ + { + "title": "app", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'; connect-src ipc: http://ipc.localhost" + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/crates/tauri-cli/templates/plugin/android/.gitignore b/crates/tauri-cli/templates/plugin/android/.gitignore new file mode 100644 index 000000000000..c0f21ec2fd95 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/.gitignore @@ -0,0 +1,2 @@ +/build +/.tauri diff --git a/crates/tauri-cli/templates/plugin/android/build.gradle.kts b/crates/tauri-cli/templates/plugin/android/build.gradle.kts new file mode 100644 index 000000000000..77fc80d08bc5 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "{{android_package_id}}" + compileSdk = 34 + + defaultConfig { + minSdk = 21 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.appcompat:appcompat:1.6.0") + implementation("com.google.android.material:material:1.7.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + implementation(project(":tauri-android")) +} diff --git a/crates/tauri-cli/templates/plugin/android/proguard-rules.pro b/crates/tauri-cli/templates/plugin/android/proguard-rules.pro new file mode 100644 index 000000000000..481bb4348141 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/crates/tauri-cli/templates/plugin/android/settings.gradle b/crates/tauri-cli/templates/plugin/android/settings.gradle new file mode 100644 index 000000000000..d7782a40dd6c --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/settings.gradle @@ -0,0 +1,31 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + google() + } + resolutionStrategy { + eachPlugin { + switch (requested.id.id) { + case "com.android.library": + useVersion("8.0.2") + break + case "org.jetbrains.kotlin.android": + useVersion("1.8.20") + break + } + } + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + google() + + } +} + +include ':tauri-android' +project(':tauri-android').projectDir = new File('./.tauri/tauri-api') diff --git a/crates/tauri-cli/templates/plugin/android/src/androidTest/java/ExampleInstrumentedTest.kt b/crates/tauri-cli/templates/plugin/android/src/androidTest/java/ExampleInstrumentedTest.kt new file mode 100644 index 000000000000..24e699cc71ef --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/src/androidTest/java/ExampleInstrumentedTest.kt @@ -0,0 +1,24 @@ +package {{android_package_id}} + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("{{android_package_id}}", appContext.packageName) + } +} diff --git a/crates/tauri-cli/templates/plugin/android/src/main/AndroidManifest.xml b/crates/tauri-cli/templates/plugin/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..9a40236b9471 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/src/main/AndroidManifest.xml @@ -0,0 +1,3 @@ + + + diff --git a/crates/tauri-cli/templates/plugin/android/src/main/java/Example.kt b/crates/tauri-cli/templates/plugin/android/src/main/java/Example.kt new file mode 100644 index 000000000000..4133f05f1d66 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/src/main/java/Example.kt @@ -0,0 +1,10 @@ +package {{android_package_id}} + +import android.util.Log + +class Example { + fun pong(value: String): String { + Log.i("Pong", value) + return value + } +} diff --git a/crates/tauri-cli/templates/plugin/android/src/main/java/ExamplePlugin.kt b/crates/tauri-cli/templates/plugin/android/src/main/java/ExamplePlugin.kt new file mode 100644 index 000000000000..68a36ca01cab --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/src/main/java/ExamplePlugin.kt @@ -0,0 +1,28 @@ +package {{android_package_id}} + +import android.app.Activity +import app.tauri.annotation.Command +import app.tauri.annotation.InvokeArg +import app.tauri.annotation.TauriPlugin +import app.tauri.plugin.JSObject +import app.tauri.plugin.Plugin +import app.tauri.plugin.Invoke + +@InvokeArg +class PingArgs { + var value: String? = null +} + +@TauriPlugin +class ExamplePlugin(private val activity: Activity): Plugin(activity) { + private val implementation = Example() + + @Command + fun ping(invoke: Invoke) { + val args = invoke.parseArgs(PingArgs::class.java) + + val ret = JSObject() + ret.put("value", implementation.pong(args.value ?: "default value :(")) + invoke.resolve(ret) + } +} diff --git a/crates/tauri-cli/templates/plugin/android/src/test/java/ExampleUnitTest.kt b/crates/tauri-cli/templates/plugin/android/src/test/java/ExampleUnitTest.kt new file mode 100644 index 000000000000..50792fe644f6 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/android/src/test/java/ExampleUnitTest.kt @@ -0,0 +1,17 @@ +package {{android_package_id}} + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/crates/tauri-cli/templates/plugin/build.rs b/crates/tauri-cli/templates/plugin/build.rs new file mode 100644 index 000000000000..e0ff2ccce229 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/build.rs @@ -0,0 +1,8 @@ +const COMMANDS: &[&str] = &["ping"]; + +fn main() { + tauri_plugin::Builder::new(COMMANDS) + .android_path("android") + .ios_path("ios") + .build(); +} diff --git a/crates/tauri-cli/templates/plugin/guest-js/index.ts b/crates/tauri-cli/templates/plugin/guest-js/index.ts new file mode 100644 index 000000000000..cbbafe2ed8de --- /dev/null +++ b/crates/tauri-cli/templates/plugin/guest-js/index.ts @@ -0,0 +1,12 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +import { invoke } from '@tauri-apps/api/core' + +export async function ping(value: string): Promise { + return await invoke<{value?: string}>('plugin:{{ plugin_name }}|ping', { + payload: { + value, + }, + }).then((r) => (r.value ? r.value : null)); +} diff --git a/crates/tauri-cli/templates/plugin/ios-spm/.gitignore b/crates/tauri-cli/templates/plugin/ios-spm/.gitignore new file mode 100644 index 000000000000..5922fdaa5638 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-spm/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +Package.resolved diff --git a/crates/tauri-cli/templates/plugin/ios-spm/Package.swift b/crates/tauri-cli/templates/plugin/ios-spm/Package.swift new file mode 100644 index 000000000000..faf3d3d6f5d7 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-spm/Package.swift @@ -0,0 +1,32 @@ +// swift-tools-version:5.3 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +import PackageDescription + +let package = Package( + name: "tauri-plugin-{{ plugin_name }}", + platforms: [ + .macOS(.v10_13), + .iOS(.v13), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "tauri-plugin-{{ plugin_name }}", + type: .static, + targets: ["tauri-plugin-{{ plugin_name }}"]), + ], + dependencies: [ + .package(name: "Tauri", path: "../.tauri/tauri-api") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "tauri-plugin-{{ plugin_name }}", + dependencies: [ + .byName(name: "Tauri") + ], + path: "Sources") + ] +) diff --git a/crates/tauri-cli/templates/plugin/ios-spm/README.md b/crates/tauri-cli/templates/plugin/ios-spm/README.md new file mode 100644 index 000000000000..f4900bdd5037 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-spm/README.md @@ -0,0 +1,3 @@ +# Tauri Plugin {{ plugin_name_original }} + +A description of this package. diff --git a/crates/tauri-cli/templates/plugin/ios-spm/Sources/ExamplePlugin.swift b/crates/tauri-cli/templates/plugin/ios-spm/Sources/ExamplePlugin.swift new file mode 100644 index 000000000000..526d730631ad --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-spm/Sources/ExamplePlugin.swift @@ -0,0 +1,20 @@ +import SwiftRs +import Tauri +import UIKit +import WebKit + +class PingArgs: Decodable { + let value: String? +} + +class ExamplePlugin: Plugin { + @objc public func ping(_ invoke: Invoke) throws { + let args = try invoke.parseArgs(PingArgs.self) + invoke.resolve(["value": args.value ?? ""]) + } +} + +@_cdecl("init_plugin_{{ plugin_name_snake_case }}") +func initPlugin() -> Plugin { + return ExamplePlugin() +} diff --git a/crates/tauri-cli/templates/plugin/ios-spm/Tests/PluginTests/PluginTests.swift b/crates/tauri-cli/templates/plugin/ios-spm/Tests/PluginTests/PluginTests.swift new file mode 100644 index 000000000000..4f8e9ace3305 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-spm/Tests/PluginTests/PluginTests.swift @@ -0,0 +1,8 @@ +import XCTest +@testable import ExamplePlugin + +final class ExamplePluginTests: XCTestCase { + func testExample() throws { + let plugin = ExamplePlugin() + } +} diff --git a/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.pbxproj b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.pbxproj new file mode 100644 index 000000000000..dc9db42a62d8 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.pbxproj @@ -0,0 +1,319 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 60; + objects = { + +/* Begin PBXBuildFile section */ + A0E2115A2BF552D2003BCF4D /* ExamplePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0E211592BF552D2003BCF4D /* ExamplePlugin.swift */; }; + A0E211622BF55305003BCF4D /* Tauri in Frameworks */ = {isa = PBXBuildFile; productRef = A0E211612BF55305003BCF4D /* Tauri */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + A0E211542BF552D2003BCF4D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + A0E211562BF552D2003BCF4D /* libtauri-plugin-{{ plugin_name }}.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libtauri-plugin-{{ plugin_name }}.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + A0E211592BF552D2003BCF4D /* ExamplePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExamplePlugin.swift; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + A0E211532BF552D2003BCF4D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + A0E211622BF55305003BCF4D /* Tauri in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + A0E2114D2BF552D2003BCF4D = { + isa = PBXGroup; + children = ( + A0E211582BF552D2003BCF4D /* tauri-plugin-{{ plugin_name }} */, + A0E211572BF552D2003BCF4D /* Products */, + ); + sourceTree = ""; + }; + A0E211572BF552D2003BCF4D /* Products */ = { + isa = PBXGroup; + children = ( + A0E211562BF552D2003BCF4D /* libtauri-plugin-{{ plugin_name }}.a */, + ); + name = Products; + sourceTree = ""; + }; + A0E211582BF552D2003BCF4D /* tauri-plugin-{{ plugin_name }} */ = { + isa = PBXGroup; + children = ( + A0E211592BF552D2003BCF4D /* ExamplePlugin.swift */, + ); + path = "tauri-plugin-{{ plugin_name }}"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + A0E211552BF552D2003BCF4D /* tauri-plugin-{{ plugin_name }} */ = { + isa = PBXNativeTarget; + buildConfigurationList = A0E2115D2BF552D2003BCF4D /* Build configuration list for PBXNativeTarget "tauri-plugin-{{ plugin_name }}" */; + buildPhases = ( + A0E211522BF552D2003BCF4D /* Sources */, + A0E211532BF552D2003BCF4D /* Frameworks */, + A0E211542BF552D2003BCF4D /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "tauri-plugin-{{ plugin_name }}"; + packageProductDependencies = ( + A0E211612BF55305003BCF4D /* Tauri */, + ); + productName = "tauri-plugin-{{ plugin_name }}"; + productReference = A0E211562BF552D2003BCF4D /* libtauri-plugin-{{ plugin_name }}.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + A0E2114E2BF552D2003BCF4D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastSwiftUpdateCheck = 1540; + LastUpgradeCheck = 1540; + TargetAttributes = { + A0E211552BF552D2003BCF4D = { + CreatedOnToolsVersion = 15.4; + }; + }; + }; + buildConfigurationList = A0E211512BF552D2003BCF4D /* Build configuration list for PBXProject "tauri-plugin-{{ plugin_name }}" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = A0E2114D2BF552D2003BCF4D; + packageReferences = ( + A0E211602BF55305003BCF4D /* XCLocalSwiftPackageReference "../.tauri/tauri-api" */, + ); + productRefGroup = A0E211572BF552D2003BCF4D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + A0E211552BF552D2003BCF4D /* tauri-plugin-{{ plugin_name }} */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + A0E211522BF552D2003BCF4D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + A0E2115A2BF552D2003BCF4D /* ExamplePlugin.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + A0E2115B2BF552D2003BCF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + A0E2115C2BF552D2003BCF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + A0E2115E2BF552D2003BCF4D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + A0E2115F2BF552D2003BCF4D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + A0E211512BF552D2003BCF4D /* Build configuration list for PBXProject "tauri-plugin-{{ plugin_name }}" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A0E2115B2BF552D2003BCF4D /* Debug */, + A0E2115C2BF552D2003BCF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + A0E2115D2BF552D2003BCF4D /* Build configuration list for PBXNativeTarget "tauri-plugin-{{ plugin_name }}" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + A0E2115E2BF552D2003BCF4D /* Debug */, + A0E2115F2BF552D2003BCF4D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + +/* Begin XCLocalSwiftPackageReference section */ + A0E211602BF55305003BCF4D /* XCLocalSwiftPackageReference "../.tauri/tauri-api" */ = { + isa = XCLocalSwiftPackageReference; + relativePath = "../.tauri/tauri-api"; + }; +/* End XCLocalSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + A0E211612BF55305003BCF4D /* Tauri */ = { + isa = XCSwiftPackageProductDependency; + productName = Tauri; + }; +/* End XCSwiftPackageProductDependency section */ + }; + rootObject = A0E2114E2BF552D2003BCF4D /* Project object */; +} diff --git a/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 000000000000..919434a6254f --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 000000000000..18d981003d68 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}/ExamplePlugin.swift b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}/ExamplePlugin.swift new file mode 100644 index 000000000000..526d730631ad --- /dev/null +++ b/crates/tauri-cli/templates/plugin/ios-xcode/tauri-plugin-{{ plugin_name }}/ExamplePlugin.swift @@ -0,0 +1,20 @@ +import SwiftRs +import Tauri +import UIKit +import WebKit + +class PingArgs: Decodable { + let value: String? +} + +class ExamplePlugin: Plugin { + @objc public func ping(_ invoke: Invoke) throws { + let args = try invoke.parseArgs(PingArgs.self) + invoke.resolve(["value": args.value ?? ""]) + } +} + +@_cdecl("init_plugin_{{ plugin_name_snake_case }}") +func initPlugin() -> Plugin { + return ExamplePlugin() +} diff --git a/crates/tauri-cli/templates/plugin/package.json b/crates/tauri-cli/templates/plugin/package.json new file mode 100644 index 000000000000..4c1d6fd727c8 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/package.json @@ -0,0 +1,33 @@ +{ + "name": "tauri-plugin-{{ plugin_name }}-api", + "version": "0.1.0", + "author": "{{ author }}", + "description": "", + "type": "module", + "types": "./dist-js/index.d.ts", + "main": "./dist-js/index.cjs", + "module": "./dist-js/index.js", + "exports": { + "types": "./dist-js/index.d.ts", + "import": "./dist-js/index.js", + "require": "./dist-js/index.cjs" + }, + "files": [ + "dist-js", + "README.md" + ], + "scripts": { + "build": "rollup -c", + "prepublishOnly": "pnpm build", + "pretest": "pnpm build" + }, + "dependencies": { + "@tauri-apps/api": ">=2.0.0-beta.6" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^11.1.6", + "rollup": "^4.9.6", + "typescript": "^5.3.3", + "tslib": "^2.6.2" + } +} diff --git a/crates/tauri-cli/templates/plugin/rollup.config.js b/crates/tauri-cli/templates/plugin/rollup.config.js new file mode 100644 index 000000000000..d83436352af8 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/rollup.config.js @@ -0,0 +1,31 @@ +import { readFileSync } from 'fs' +import { join } from 'path' +import { cwd } from 'process' +import typescript from '@rollup/plugin-typescript' + +const pkg = JSON.parse(readFileSync(join(cwd(), 'package.json'), 'utf8')) + +export default { + input: 'guest-js/index.ts', + output: [ + { + file: pkg.exports.import, + format: 'esm' + }, + { + file: pkg.exports.require, + format: 'cjs' + } + ], + plugins: [ + typescript({ + declaration: true, + declarationDir: `./${pkg.exports.import.split('/')[0]}` + }) + ], + external: [ + /^@tauri-apps\/api/, + ...Object.keys(pkg.dependencies || {}), + ...Object.keys(pkg.peerDependencies || {}) + ] +} diff --git a/crates/tauri-cli/templates/plugin/src/commands.rs b/crates/tauri-cli/templates/plugin/src/commands.rs new file mode 100644 index 000000000000..80c544642ad7 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/commands.rs @@ -0,0 +1,16 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use tauri::{AppHandle, command, Runtime}; + +use crate::models::*; +use crate::Result; +use crate::{{ plugin_name_pascal_case }}Ext; + +#[command] +pub(crate) async fn ping( + app: AppHandle, + payload: PingRequest, +) -> Result { + app.{{ plugin_name_snake_case }}().ping(payload) +} diff --git a/crates/tauri-cli/templates/plugin/src/desktop.rs b/crates/tauri-cli/templates/plugin/src/desktop.rs new file mode 100644 index 000000000000..0fe5b8521f23 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/desktop.rs @@ -0,0 +1,25 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use serde::de::DeserializeOwned; +use tauri::{plugin::PluginApi, AppHandle, Runtime}; + +use crate::models::*; + +pub fn init( + app: &AppHandle, + _api: PluginApi, +) -> crate::Result<{{ plugin_name_pascal_case }}> { + Ok({{ plugin_name_pascal_case }}(app.clone())) +} + +/// Access to the {{ plugin_name }} APIs. +pub struct {{ plugin_name_pascal_case }}(AppHandle); + +impl {{ plugin_name_pascal_case }} { + pub fn ping(&self, payload: PingRequest) -> crate::Result { + Ok(PingResponse { + value: payload.value, + }) + } +} diff --git a/crates/tauri-cli/templates/plugin/src/error.rs b/crates/tauri-cli/templates/plugin/src/error.rs new file mode 100644 index 000000000000..cb29d4653114 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/error.rs @@ -0,0 +1,24 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use serde::{ser::Serializer, Serialize}; + +pub type Result = std::result::Result; + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[error(transparent)] + Io(#[from] std::io::Error), + #[cfg(mobile)] + #[error(transparent)] + PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError), +} + +impl Serialize for Error { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + serializer.serialize_str(self.to_string().as_ref()) + } +} diff --git a/crates/tauri-cli/templates/plugin/src/lib.rs b/crates/tauri-cli/templates/plugin/src/lib.rs new file mode 100644 index 000000000000..874b99f67f10 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/lib.rs @@ -0,0 +1,51 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use tauri::{ + plugin::{Builder, TauriPlugin}, + Manager, Runtime, +}; + +pub use models::*; + +#[cfg(desktop)] +mod desktop; +#[cfg(mobile)] +mod mobile; + +mod commands; +mod error; +mod models; + +pub use error::{Error, Result}; + +#[cfg(desktop)] +use desktop::{{ plugin_name_pascal_case }}; +#[cfg(mobile)] +use mobile::{{ plugin_name_pascal_case }}; + +/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the {{ plugin_name }} APIs. +pub trait {{ plugin_name_pascal_case }}Ext { + fn {{ plugin_name_snake_case }}(&self) -> &{{ plugin_name_pascal_case }}; +} + +impl> crate::{{ plugin_name_pascal_case }}Ext for T { + fn {{ plugin_name_snake_case }}(&self) -> &{{ plugin_name_pascal_case }} { + self.state::<{{ plugin_name_pascal_case }}>().inner() + } +} + +/// Initializes the plugin. +pub fn init() -> TauriPlugin { + Builder::new("{{ plugin_name }}") + .invoke_handler(tauri::generate_handler![commands::ping]) + .setup(|app, api| { + #[cfg(mobile)] + let {{ plugin_name_snake_case }} = mobile::init(app, api)?; + #[cfg(desktop)] + let {{ plugin_name_snake_case }} = desktop::init(app, api)?; + app.manage({{ plugin_name_snake_case }}); + Ok(()) + }) + .build() +} diff --git a/crates/tauri-cli/templates/plugin/src/mobile.rs b/crates/tauri-cli/templates/plugin/src/mobile.rs new file mode 100644 index 000000000000..9277ec353bd6 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/mobile.rs @@ -0,0 +1,37 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use serde::de::DeserializeOwned; +use tauri::{ + plugin::{PluginApi, PluginHandle}, + AppHandle, Runtime, +}; + +use crate::models::*; + +#[cfg(target_os = "ios")] +tauri::ios_plugin_binding!(init_plugin_{{ plugin_name_snake_case }}); + +// initializes the Kotlin or Swift plugin classes +pub fn init( + _app: &AppHandle, + api: PluginApi, +) -> crate::Result<{{ plugin_name_pascal_case }}> { + #[cfg(target_os = "android")] + let handle = api.register_android_plugin("{{ android_package_id }}", "ExamplePlugin")?; + #[cfg(target_os = "ios")] + let handle = api.register_ios_plugin(init_plugin_{{ plugin_name_snake_case }})?; + Ok({{ plugin_name_pascal_case }}(handle)) +} + +/// Access to the {{ plugin_name }} APIs. +pub struct {{ plugin_name_pascal_case }}(PluginHandle); + +impl {{ plugin_name_pascal_case }} { + pub fn ping(&self, payload: PingRequest) -> crate::Result { + self + .0 + .run_mobile_plugin("ping", payload) + .map_err(Into::into) + } +} diff --git a/crates/tauri-cli/templates/plugin/src/models.rs b/crates/tauri-cli/templates/plugin/src/models.rs new file mode 100644 index 000000000000..914fb2388828 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/src/models.rs @@ -0,0 +1,16 @@ +{{#if license_header}} +{{ license_header }} +{{/if}} +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PingRequest { + pub value: Option, +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PingResponse { + pub value: Option, +} diff --git a/crates/tauri-cli/templates/plugin/tsconfig.json b/crates/tauri-cli/templates/plugin/tsconfig.json new file mode 100644 index 000000000000..0591122701b9 --- /dev/null +++ b/crates/tauri-cli/templates/plugin/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "target": "es2021", + "module": "esnext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "strict": true, + "noUnusedLocals": true, + "noImplicitAny": true, + "noEmit": true + }, + "include": ["guest-js/*.ts"], + "exclude": ["dist-js", "node_modules"] +} diff --git a/crates/tauri-cli/templates/tauri.conf.json b/crates/tauri-cli/templates/tauri.conf.json new file mode 100644 index 000000000000..e7f0514a5c9d --- /dev/null +++ b/crates/tauri-cli/templates/tauri.conf.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://schema.tauri.app/config/2.0.0-rc", + "productName": "{{ app_name }}", + "version": "0.1.0", + "identifier": "com.tauri.dev", + "build": { + "frontendDist": "{{ frontend_dist }}"{{#if dev_url}}, + "devUrl": "{{ dev_url }}"{{/if}}{{#if before_dev_command}}, + "beforeDevCommand": "{{ before_dev_command }}"{{/if}}{{#if before_build_command}}, + "beforeBuildCommand": "{{ before_build_command }}"{{/if}} + }, + "app": { + "windows": [ + { + "title": "{{ window_title }}", + "width": 800, + "height": 600, + "resizable": true, + "fullscreen": false + } + ], + "security": { + "csp": null + } + }, + "bundle": { + "active": true, + "targets": "all", + "icon": [ + "icons/32x32.png", + "icons/128x128.png", + "icons/128x128@2x.png", + "icons/icon.icns", + "icons/icon.ico" + ] + } +} diff --git a/crates/tauri-cli/tests/fixtures/pbxproj/project.pbxproj b/crates/tauri-cli/tests/fixtures/pbxproj/project.pbxproj new file mode 100644 index 000000000000..2c8428472407 --- /dev/null +++ b/crates/tauri-cli/tests/fixtures/pbxproj/project.pbxproj @@ -0,0 +1,474 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */; }; + 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; }; + 328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; }; + 6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; }; + 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; }; + 9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; }; + AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; }; + AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 384966E551417F94A02D2706 /* Security.framework */; }; + B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC377692DC31A070A0188C9D /* QuartzCore.framework */; }; + C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */; }; + DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 338E66700FD330B99D434DD7 /* MetalKit.framework */; }; + F86717F05E27C72C9FA1FB27 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 74A8FDFB350B966F5AAD4A24 /* assets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = ""; }; + 1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; path = tray.rs; sourceTree = ""; }; + 2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; + 384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 3CA88F22095BE63D88585625 /* menu_plugin.rs */ = {isa = PBXFileReference; path = menu_plugin.rs; sourceTree = ""; }; + 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapi_lib.a; sourceTree = ""; }; + 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 5AC703CEBA41A121596066F3 /* api_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = api_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + 6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; }; + 785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = ""; }; + 879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = ""; }; + 90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; + B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = ""; }; + F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; path = cmd.rs; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 11E18DCDB3ADFE87C18915EF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */, + 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */, + 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */, + DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */, + B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */, + AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */, + 9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */, + C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0677CEAF1F282F38CBA0F140 = { + isa = PBXGroup; + children = ( + 74A8FDFB350B966F5AAD4A24 /* assets */, + 6B7E79E23E646BA7968B457C /* Assets.xcassets */, + 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */, + F2116A6428EED18BE2A07E2B /* api_iOS */, + 86D903732E10FAC4D300E8DF /* Externals */, + 7A9A7AC155D9E22E54D6D847 /* Sources */, + CF9AA87D2F6E9C389B7AB70B /* src */, + 10C9FC3FA3E12D6A4A67999D /* Frameworks */, + 4AC51E67B71E27F15B02C5CD /* Products */, + ); + sourceTree = ""; + }; + 07051859D6E2D8109C8FB128 /* bindings */ = { + isa = PBXGroup; + children = ( + EC8C7948C50C3C9B5D96CB61 /* bindings.h */, + ); + path = bindings; + sourceTree = ""; + }; + 10C9FC3FA3E12D6A4A67999D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */, + 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */, + 62601E25FA39E62BE119B74D /* Metal.framework */, + 338E66700FD330B99D434DD7 /* MetalKit.framework */, + DC377692DC31A070A0188C9D /* QuartzCore.framework */, + 384966E551417F94A02D2706 /* Security.framework */, + B6082E363D51372A7658C351 /* UIKit.framework */, + 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4AC51E67B71E27F15B02C5CD /* Products */ = { + isa = PBXGroup; + children = ( + 5AC703CEBA41A121596066F3 /* api_iOS.app */, + ); + name = Products; + sourceTree = ""; + }; + 7A9A7AC155D9E22E54D6D847 /* Sources */ = { + isa = PBXGroup; + children = ( + A3574F52DBC5463B9C3D043D /* api */, + ); + path = Sources; + sourceTree = ""; + }; + 86D903732E10FAC4D300E8DF /* Externals */ = { + isa = PBXGroup; + children = ( + ); + path = Externals; + sourceTree = ""; + }; + A3574F52DBC5463B9C3D043D /* api */ = { + isa = PBXGroup; + children = ( + 90D3B673AFAB8D8AB561F616 /* main.mm */, + 07051859D6E2D8109C8FB128 /* bindings */, + ); + path = api; + sourceTree = ""; + }; + CF9AA87D2F6E9C389B7AB70B /* src */ = { + isa = PBXGroup; + children = ( + F835F52713CE8F029D5D252C /* cmd.rs */, + 785D025E9542F7E098BF22B5 /* lib.rs */, + 0E96CE07CD20273DD46BF325 /* main.rs */, + 3CA88F22095BE63D88585625 /* menu_plugin.rs */, + 1C1AB1B414CA2795AFBEDDB9 /* tray.rs */, + ); + name = src; + path = ../../src; + sourceTree = ""; + }; + F2116A6428EED18BE2A07E2B /* api_iOS */ = { + isa = PBXGroup; + children = ( + 879941AE3DAA14534BBC6391 /* api_iOS.entitlements */, + 2F63E2AA460089BB58D40C79 /* Info.plist */, + ); + path = api_iOS; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 54DC6E273C78071F3BA12EF3 /* api_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */; + buildPhases = ( + FF948951157DE71465B5BD5F /* Build Rust Code */, + 71E73CC9AB5F1323EC1F6365 /* Sources */, + CA2BEC44B6EDA1F21B6155CD /* Resources */, + 11E18DCDB3ADFE87C18915EF /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = api_iOS; + productName = api_iOS; + productReference = 5AC703CEBA41A121596066F3 /* api_iOS.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9BC88C3717DA5D4B78A51C15 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + TargetAttributes = { + 54DC6E273C78071F3BA12EF3 = { + DevelopmentTeam = Q93MBH6S2F; + }; + }; + }; + buildConfigurationList = 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = 0677CEAF1F282F38CBA0F140; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 54DC6E273C78071F3BA12EF3 /* api_iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CA2BEC44B6EDA1F21B6155CD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */, + AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */, + F86717F05E27C72C9FA1FB27 /* assets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + FF948951157DE71465B5BD5F /* Build Rust Code */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Build Rust Code"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a", + "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a", + "$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cargo tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 71E73CC9AB5F1323EC1F6365 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 328B4ADB3700C1873BEB7B10 /* main.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + A83F70B4C02DD0222038C7F1 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = release; + }; + B6AD77E490F315562F75D3D7 /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = debug; + }; + BF284FE6E7AE0C8DDCCE398B /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + "arm64-sim", + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = Q93MBH6S2F; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = api_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; + PRODUCT_NAME = "Tauri API"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64-sim"; + }; + name = debug; + }; + DB_0E254D0FD84970B57F6410 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + "arm64-sim", + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = Q93MBH6S2F; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = api_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; + PRODUCT_NAME = "Tauri API"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64-sim"; + }; + name = release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF284FE6E7AE0C8DDCCE398B /* debug */, + DB_0E254D0FD84970B57F6410 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; + 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B6AD77E490F315562F75D3D7 /* debug */, + A83F70B4C02DD0222038C7F1 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9BC88C3717DA5D4B78A51C15 /* Project object */; +} diff --git a/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project-modified.pbxproj.snap b/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project-modified.pbxproj.snap new file mode 100644 index 000000000000..b2b539be00a5 --- /dev/null +++ b/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project-modified.pbxproj.snap @@ -0,0 +1,479 @@ +--- +source: src/helpers/pbxproj.rs +expression: pbxproj.serialize() +--- +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */; }; + 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; }; + 328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; }; + 6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; }; + 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; }; + 9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; }; + AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; }; + AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 384966E551417F94A02D2706 /* Security.framework */; }; + B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DC377692DC31A070A0188C9D /* QuartzCore.framework */; }; + C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */; }; + DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 338E66700FD330B99D434DD7 /* MetalKit.framework */; }; + F86717F05E27C72C9FA1FB27 /* assets in Resources */ = {isa = PBXBuildFile; fileRef = 74A8FDFB350B966F5AAD4A24 /* assets */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = ""; }; + 1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; path = tray.rs; sourceTree = ""; }; + 2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; + 384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; + 3CA88F22095BE63D88585625 /* menu_plugin.rs */ = {isa = PBXFileReference; path = menu_plugin.rs; sourceTree = ""; }; + 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapi_lib.a; sourceTree = ""; }; + 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; + 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; + 5AC703CEBA41A121596066F3 /* api_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = api_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; + 6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; }; + 785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = ""; }; + 879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = ""; }; + 90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = ""; }; + B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; + EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = ""; }; + F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; path = cmd.rs; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 11E18DCDB3ADFE87C18915EF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */, + 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */, + 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */, + DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */, + B60763BD194DFACA215EC7DA /* QuartzCore.framework in Frameworks */, + AFA0CA286325FD7A34968CA2 /* Security.framework in Frameworks */, + 9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */, + C6D80743F168BDF017B7769E /* WebKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0677CEAF1F282F38CBA0F140 = { + isa = PBXGroup; + children = ( + 74A8FDFB350B966F5AAD4A24 /* assets */, + 6B7E79E23E646BA7968B457C /* Assets.xcassets */, + 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */, + F2116A6428EED18BE2A07E2B /* api_iOS */, + 86D903732E10FAC4D300E8DF /* Externals */, + 7A9A7AC155D9E22E54D6D847 /* Sources */, + CF9AA87D2F6E9C389B7AB70B /* src */, + 10C9FC3FA3E12D6A4A67999D /* Frameworks */, + 4AC51E67B71E27F15B02C5CD /* Products */, + ); + sourceTree = ""; + }; + 07051859D6E2D8109C8FB128 /* bindings */ = { + isa = PBXGroup; + children = ( + EC8C7948C50C3C9B5D96CB61 /* bindings.h */, + ); + path = bindings; + sourceTree = ""; + }; + 10C9FC3FA3E12D6A4A67999D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */, + 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */, + 62601E25FA39E62BE119B74D /* Metal.framework */, + 338E66700FD330B99D434DD7 /* MetalKit.framework */, + DC377692DC31A070A0188C9D /* QuartzCore.framework */, + 384966E551417F94A02D2706 /* Security.framework */, + B6082E363D51372A7658C351 /* UIKit.framework */, + 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; + 4AC51E67B71E27F15B02C5CD /* Products */ = { + isa = PBXGroup; + children = ( + 5AC703CEBA41A121596066F3 /* api_iOS.app */, + ); + name = Products; + sourceTree = ""; + }; + 7A9A7AC155D9E22E54D6D847 /* Sources */ = { + isa = PBXGroup; + children = ( + A3574F52DBC5463B9C3D043D /* api */, + ); + path = Sources; + sourceTree = ""; + }; + 86D903732E10FAC4D300E8DF /* Externals */ = { + isa = PBXGroup; + children = ( + ); + path = Externals; + sourceTree = ""; + }; + A3574F52DBC5463B9C3D043D /* api */ = { + isa = PBXGroup; + children = ( + 90D3B673AFAB8D8AB561F616 /* main.mm */, + 07051859D6E2D8109C8FB128 /* bindings */, + ); + path = api; + sourceTree = ""; + }; + CF9AA87D2F6E9C389B7AB70B /* src */ = { + isa = PBXGroup; + children = ( + F835F52713CE8F029D5D252C /* cmd.rs */, + 785D025E9542F7E098BF22B5 /* lib.rs */, + 0E96CE07CD20273DD46BF325 /* main.rs */, + 3CA88F22095BE63D88585625 /* menu_plugin.rs */, + 1C1AB1B414CA2795AFBEDDB9 /* tray.rs */, + ); + name = src; + path = ../../src; + sourceTree = ""; + }; + F2116A6428EED18BE2A07E2B /* api_iOS */ = { + isa = PBXGroup; + children = ( + 879941AE3DAA14534BBC6391 /* api_iOS.entitlements */, + 2F63E2AA460089BB58D40C79 /* Info.plist */, + ); + path = api_iOS; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 54DC6E273C78071F3BA12EF3 /* api_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */; + buildPhases = ( + FF948951157DE71465B5BD5F /* Build Rust Code */, + 71E73CC9AB5F1323EC1F6365 /* Sources */, + CA2BEC44B6EDA1F21B6155CD /* Resources */, + 11E18DCDB3ADFE87C18915EF /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = api_iOS; + productName = api_iOS; + productReference = 5AC703CEBA41A121596066F3 /* api_iOS.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 9BC88C3717DA5D4B78A51C15 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1430; + TargetAttributes = { + 54DC6E273C78071F3BA12EF3 = { + DevelopmentTeam = Q93MBH6S2F; + }; + }; + }; + buildConfigurationList = 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */; + compatibilityVersion = "Xcode 14.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + Base, + en, + ); + mainGroup = 0677CEAF1F282F38CBA0F140; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 54DC6E273C78071F3BA12EF3 /* api_iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + CA2BEC44B6EDA1F21B6155CD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */, + AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */, + F86717F05E27C72C9FA1FB27 /* assets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + FF948951157DE71465B5BD5F /* Build Rust Code */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "Build Rust Code"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a", + "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a", + "$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cargo tauri ios xcode-script -v --platform ${PLATFORM_DISPLAY_NAME:?} --sdk-root ${SDKROOT:?} --framework-search-paths \"${FRAMEWORK_SEARCH_PATHS:?}\" --header-search-paths \"${HEADER_SEARCH_PATHS:?}\" --gcc-preprocessor-definitions \"${GCC_PREPROCESSOR_DEFINITIONS:-}\" --configuration ${CONFIGURATION:?} ${FORCE_COLOR} ${ARCHS:?}"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 71E73CC9AB5F1323EC1F6365 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 328B4ADB3700C1873BEB7B10 /* main.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + A83F70B4C02DD0222038C7F1 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + }; + name = release; + }; + B6AD77E490F315562F75D3D7 /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "DEBUG=1", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = debug; + }; + BF284FE6E7AE0C8DDCCE398B /* debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + "arm64-sim", + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = Q93MBH6S2F; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = api_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; + PRODUCT_NAME = "Tauri API"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64-sim"; + }; + name = debug; + }; + DB_0E254D0FD84970B57F6410 /* release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ARCHS = ( + arm64, + "arm64-sim", + ); + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = api_iOS/api_iOS.entitlements; + CODE_SIGN_IDENTITY = "iPhone Developer"; + DEVELOPMENT_TEAM = Q93MBH6S2F; + ENABLE_BITCODE = NO; + "EXCLUDED_ARCHS[sdk=iphoneos*]" = "arm64-sim x86_64"; + "EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "\".\"", + ); + INFOPLIST_FILE = api_iOS/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + "LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; + PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; + PRODUCT_NAME = "Tauri Test"; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALID_ARCHS = "arm64 arm64-sim"; + UNKNOWN = 9283j49238h; + }; + name = release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 01CBC40275452376830D79B1 /* Build configuration list for PBXNativeTarget "api_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + BF284FE6E7AE0C8DDCCE398B /* debug */, + DB_0E254D0FD84970B57F6410 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; + 8FA67D0F928A09CD639137D1 /* Build configuration list for PBXProject "api" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B6AD77E490F315562F75D3D7 /* debug */, + A83F70B4C02DD0222038C7F1 /* release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = debug; + }; +/* End XCConfigurationList section */ + }; + rootObject = 9BC88C3717DA5D4B78A51C15 /* Project object */; +} diff --git a/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project.pbxproj.snap b/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project.pbxproj.snap new file mode 100644 index 000000000000..a30dd82c6f2f --- /dev/null +++ b/crates/tauri-cli/tests/fixtures/pbxproj/snapshots/tauri_cli__helpers__pbxproj__tests__project.pbxproj.snap @@ -0,0 +1,916 @@ +--- +source: src/helpers/pbxproj.rs +expression: "super::parse(fixtures_path.join(\"project.pbxproj\")).expect(\"failed to parse pbxproj\")" +--- +Pbxproj { + xc_build_configuration: { + "A83F70B4C02DD0222038C7F1": XCBuildConfiguration { + build_settings: [ + BuildSettings { + identation: "\t\t\t\t", + line_number: 263, + key: "ALWAYS_SEARCH_USER_PATHS", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 264, + key: "CLANG_ANALYZER_NONNULL", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 265, + key: "CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 266, + key: "CLANG_CXX_LANGUAGE_STANDARD", + value: "\"gnu++14\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 267, + key: "CLANG_CXX_LIBRARY", + value: "\"libc++\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 268, + key: "CLANG_ENABLE_MODULES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 269, + key: "CLANG_ENABLE_OBJC_ARC", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 270, + key: "CLANG_ENABLE_OBJC_WEAK", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 271, + key: "CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 272, + key: "CLANG_WARN_BOOL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 273, + key: "CLANG_WARN_COMMA", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 274, + key: "CLANG_WARN_CONSTANT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 275, + key: "CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 276, + key: "CLANG_WARN_DIRECT_OBJC_ISA_USAGE", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 277, + key: "CLANG_WARN_DOCUMENTATION_COMMENTS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 278, + key: "CLANG_WARN_EMPTY_BODY", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 279, + key: "CLANG_WARN_ENUM_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 280, + key: "CLANG_WARN_INFINITE_RECURSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 281, + key: "CLANG_WARN_INT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 282, + key: "CLANG_WARN_NON_LITERAL_NULL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 283, + key: "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 284, + key: "CLANG_WARN_OBJC_LITERAL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 285, + key: "CLANG_WARN_OBJC_ROOT_CLASS", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 286, + key: "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 287, + key: "CLANG_WARN_RANGE_LOOP_ANALYSIS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 288, + key: "CLANG_WARN_STRICT_PROTOTYPES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 289, + key: "CLANG_WARN_SUSPICIOUS_MOVE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 290, + key: "CLANG_WARN_UNGUARDED_AVAILABILITY", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 291, + key: "CLANG_WARN_UNREACHABLE_CODE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 292, + key: "CLANG_WARN__DUPLICATE_METHOD_MATCH", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 293, + key: "COPY_PHASE_STRIP", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 294, + key: "DEBUG_INFORMATION_FORMAT", + value: "\"dwarf-with-dsym\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 295, + key: "ENABLE_NS_ASSERTIONS", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 296, + key: "ENABLE_STRICT_OBJC_MSGSEND", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 297, + key: "GCC_C_LANGUAGE_STANDARD", + value: "gnu11", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 298, + key: "GCC_NO_COMMON_BLOCKS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 299, + key: "GCC_WARN_64_TO_32_BIT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 300, + key: "GCC_WARN_ABOUT_RETURN_TYPE", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 301, + key: "GCC_WARN_UNDECLARED_SELECTOR", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 302, + key: "GCC_WARN_UNINITIALIZED_AUTOS", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 303, + key: "GCC_WARN_UNUSED_FUNCTION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 304, + key: "GCC_WARN_UNUSED_VARIABLE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 305, + key: "IPHONEOS_DEPLOYMENT_TARGET", + value: "13.0", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 306, + key: "MTL_ENABLE_DEBUG_INFO", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 307, + key: "MTL_FAST_MATH", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 308, + key: "PRODUCT_NAME", + value: "\"$(TARGET_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 309, + key: "SDKROOT", + value: "iphoneos", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 310, + key: "SWIFT_COMPILATION_MODE", + value: "wholemodule", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 311, + key: "SWIFT_OPTIMIZATION_LEVEL", + value: "\"-O\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 312, + key: "SWIFT_VERSION", + value: "5.0", + }, + ], + }, + "B6AD77E490F315562F75D3D7": XCBuildConfiguration { + build_settings: [ + BuildSettings { + identation: "\t\t\t\t", + line_number: 319, + key: "ALWAYS_SEARCH_USER_PATHS", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 320, + key: "CLANG_ANALYZER_NONNULL", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 321, + key: "CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 322, + key: "CLANG_CXX_LANGUAGE_STANDARD", + value: "\"gnu++14\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 323, + key: "CLANG_CXX_LIBRARY", + value: "\"libc++\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 324, + key: "CLANG_ENABLE_MODULES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 325, + key: "CLANG_ENABLE_OBJC_ARC", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 326, + key: "CLANG_ENABLE_OBJC_WEAK", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 327, + key: "CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 328, + key: "CLANG_WARN_BOOL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 329, + key: "CLANG_WARN_COMMA", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 330, + key: "CLANG_WARN_CONSTANT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 331, + key: "CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 332, + key: "CLANG_WARN_DIRECT_OBJC_ISA_USAGE", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 333, + key: "CLANG_WARN_DOCUMENTATION_COMMENTS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 334, + key: "CLANG_WARN_EMPTY_BODY", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 335, + key: "CLANG_WARN_ENUM_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 336, + key: "CLANG_WARN_INFINITE_RECURSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 337, + key: "CLANG_WARN_INT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 338, + key: "CLANG_WARN_NON_LITERAL_NULL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 339, + key: "CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 340, + key: "CLANG_WARN_OBJC_LITERAL_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 341, + key: "CLANG_WARN_OBJC_ROOT_CLASS", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 342, + key: "CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 343, + key: "CLANG_WARN_RANGE_LOOP_ANALYSIS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 344, + key: "CLANG_WARN_STRICT_PROTOTYPES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 345, + key: "CLANG_WARN_SUSPICIOUS_MOVE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 346, + key: "CLANG_WARN_UNGUARDED_AVAILABILITY", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 347, + key: "CLANG_WARN_UNREACHABLE_CODE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 348, + key: "CLANG_WARN__DUPLICATE_METHOD_MATCH", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 349, + key: "COPY_PHASE_STRIP", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 350, + key: "DEBUG_INFORMATION_FORMAT", + value: "dwarf", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 351, + key: "ENABLE_STRICT_OBJC_MSGSEND", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 352, + key: "ENABLE_TESTABILITY", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 353, + key: "GCC_C_LANGUAGE_STANDARD", + value: "gnu11", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 354, + key: "GCC_DYNAMIC_NO_PIC", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 355, + key: "GCC_NO_COMMON_BLOCKS", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 356, + key: "GCC_OPTIMIZATION_LEVEL", + value: "0", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 357, + key: "GCC_PREPROCESSOR_DEFINITIONS", + value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"DEBUG=1\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 361, + key: "GCC_WARN_64_TO_32_BIT_CONVERSION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 362, + key: "GCC_WARN_ABOUT_RETURN_TYPE", + value: "YES_ERROR", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 363, + key: "GCC_WARN_UNDECLARED_SELECTOR", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 364, + key: "GCC_WARN_UNINITIALIZED_AUTOS", + value: "YES_AGGRESSIVE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 365, + key: "GCC_WARN_UNUSED_FUNCTION", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 366, + key: "GCC_WARN_UNUSED_VARIABLE", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 367, + key: "IPHONEOS_DEPLOYMENT_TARGET", + value: "13.0", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 368, + key: "MTL_ENABLE_DEBUG_INFO", + value: "INCLUDE_SOURCE", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 369, + key: "MTL_FAST_MATH", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 370, + key: "ONLY_ACTIVE_ARCH", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 371, + key: "PRODUCT_NAME", + value: "\"$(TARGET_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 372, + key: "SDKROOT", + value: "iphoneos", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 373, + key: "SWIFT_ACTIVE_COMPILATION_CONDITIONS", + value: "DEBUG", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 374, + key: "SWIFT_OPTIMIZATION_LEVEL", + value: "\"-Onone\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 375, + key: "SWIFT_VERSION", + value: "5.0", + }, + ], + }, + "BF284FE6E7AE0C8DDCCE398B": XCBuildConfiguration { + build_settings: [ + BuildSettings { + identation: "\t\t\t\t", + line_number: 382, + key: "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 383, + key: "ARCHS", + value: "(\t\t\t\t\tarm64,\n\t\t\t\t\t\"arm64-sim\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 387, + key: "ASSETCATALOG_COMPILER_APPICON_NAME", + value: "AppIcon", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 388, + key: "CODE_SIGN_ENTITLEMENTS", + value: "api_iOS/api_iOS.entitlements", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 389, + key: "CODE_SIGN_IDENTITY", + value: "\"iPhone Developer\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 390, + key: "DEVELOPMENT_TEAM", + value: "Q93MBH6S2F", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 391, + key: "ENABLE_BITCODE", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 392, + key: "\"EXCLUDED_ARCHS[sdk=iphoneos*]\"", + value: "\"arm64-sim x86_64\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 393, + key: "\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\"", + value: "arm64", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 394, + key: "FRAMEWORK_SEARCH_PATHS", + value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\".\\\"\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 398, + key: "INFOPLIST_FILE", + value: "api_iOS/Info.plist", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 399, + key: "LD_RUNPATH_SEARCH_PATHS", + value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 403, + key: "\"LIBRARY_SEARCH_PATHS[arch=arm64-sim]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 404, + key: "\"LIBRARY_SEARCH_PATHS[arch=arm64]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 405, + key: "\"LIBRARY_SEARCH_PATHS[arch=x86_64]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 406, + key: "PRODUCT_BUNDLE_IDENTIFIER", + value: "com.tauri.api", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 407, + key: "PRODUCT_NAME", + value: "\"Tauri API\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 408, + key: "SDKROOT", + value: "iphoneos", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 409, + key: "TARGETED_DEVICE_FAMILY", + value: "\"1,2\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 410, + key: "VALID_ARCHS", + value: "\"arm64 arm64-sim\"", + }, + ], + }, + "DB_0E254D0FD84970B57F6410": XCBuildConfiguration { + build_settings: [ + BuildSettings { + identation: "\t\t\t\t", + line_number: 417, + key: "ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES", + value: "YES", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 418, + key: "ARCHS", + value: "(\t\t\t\t\tarm64,\n\t\t\t\t\t\"arm64-sim\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 422, + key: "ASSETCATALOG_COMPILER_APPICON_NAME", + value: "AppIcon", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 423, + key: "CODE_SIGN_ENTITLEMENTS", + value: "api_iOS/api_iOS.entitlements", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 424, + key: "CODE_SIGN_IDENTITY", + value: "\"iPhone Developer\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 425, + key: "DEVELOPMENT_TEAM", + value: "Q93MBH6S2F", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 426, + key: "ENABLE_BITCODE", + value: "NO", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 427, + key: "\"EXCLUDED_ARCHS[sdk=iphoneos*]\"", + value: "\"arm64-sim x86_64\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 428, + key: "\"EXCLUDED_ARCHS[sdk=iphonesimulator*]\"", + value: "arm64", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 429, + key: "FRAMEWORK_SEARCH_PATHS", + value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"\\\".\\\"\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 433, + key: "INFOPLIST_FILE", + value: "api_iOS/Info.plist", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 434, + key: "LD_RUNPATH_SEARCH_PATHS", + value: "(\t\t\t\t\t\"$(inherited)\",\n\t\t\t\t\t\"@executable_path/Frameworks\",\n\t\t\t\t);\n", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 438, + key: "\"LIBRARY_SEARCH_PATHS[arch=arm64-sim]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 439, + key: "\"LIBRARY_SEARCH_PATHS[arch=arm64]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 440, + key: "\"LIBRARY_SEARCH_PATHS[arch=x86_64]\"", + value: "\"$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 441, + key: "PRODUCT_BUNDLE_IDENTIFIER", + value: "com.tauri.api", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 442, + key: "PRODUCT_NAME", + value: "\"Tauri API\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 443, + key: "SDKROOT", + value: "iphoneos", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 444, + key: "TARGETED_DEVICE_FAMILY", + value: "\"1,2\"", + }, + BuildSettings { + identation: "\t\t\t\t", + line_number: 445, + key: "VALID_ARCHS", + value: "\"arm64 arm64-sim\"", + }, + ], + }, + }, + xc_configuration_list: { + "01CBC40275452376830D79B1": XCConfigurationList { + comment: "/* Build configuration list for PBXNativeTarget \"api_iOS\" */", + build_configurations: [ + BuildConfigurationRef { + id: "BF284FE6E7AE0C8DDCCE398B", + comments: "/* debug */", + }, + BuildConfigurationRef { + id: "DB_0E254D0FD84970B57F6410", + comments: "/* release */", + }, + ], + }, + "8FA67D0F928A09CD639137D1": XCConfigurationList { + comment: "/* Build configuration list for PBXProject \"api\" */", + build_configurations: [ + BuildConfigurationRef { + id: "B6AD77E490F315562F75D3D7", + comments: "/* debug */", + }, + BuildConfigurationRef { + id: "A83F70B4C02DD0222038C7F1", + comments: "/* release */", + }, + ], + }, + }, +} diff --git a/crates/tauri-codegen/CHANGELOG.md b/crates/tauri-codegen/CHANGELOG.md new file mode 100644 index 000000000000..95a0fb544b90 --- /dev/null +++ b/crates/tauri-codegen/CHANGELOG.md @@ -0,0 +1,671 @@ +# Changelog + +## \[2.0.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.1.0` + +## \[2.0.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.2` + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.1` + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0` + +## \[2.0.0-rc.13] + +### Bug Fixes + +- [`1efa5e718`](https://www.github.com/tauri-apps/tauri/commit/1efa5e7184009537b688a395596c696173ae0231) ([#11099](https://www.github.com/tauri-apps/tauri/pull/11099) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Rerun build script if the platform-specific configuration file changes. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.13` + +## \[2.0.0-rc.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.12` + +## \[2.0.0-rc.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.11` + +## \[2.0.0-rc.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.10` + +## \[2.0.0-rc.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.9` + +## \[2.0.0-rc.8] + +### What's Changed + +- [`27d018343`](https://www.github.com/tauri-apps/tauri/commit/27d01834312ee7953b6ccd5b0a368e7a69b225e9) ([#10844](https://www.github.com/tauri-apps/tauri/pull/10844) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Changes how the Info.plist is embedded on macOS development to avoid a clippy warning. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.8` + +## \[2.0.0-rc.7] + +### Bug Fixes + +- [`88bc35732`](https://www.github.com/tauri-apps/tauri/commit/88bc357325ba278527d8cba956e828f5744c8a34) ([#10734](https://www.github.com/tauri-apps/tauri/pull/10734) by [@chippers](https://www.github.com/tauri-apps/tauri/../../chippers)) Generate context in a separate thread to prevent a stack overflow. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.7` + +## \[2.0.0-rc.6] + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.6` + +## \[2.0.0-rc.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.5` + +## \[2.0.0-rc.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.4` + +## \[2.0.0-rc.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.3` +- [`0afee5ed8`](https://www.github.com/tauri-apps/tauri/commit/0afee5ed80265c95c4581e173c4886677cfed593) ([#10436](https://www.github.com/tauri-apps/tauri/pull/10436) by [@nyurik](https://www.github.com/tauri-apps/tauri/../../nyurik)) Updated brotli to v6. + +## \[2.0.0-rc.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.2` + +## \[2.0.0-rc.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.1` + +## \[2.0.0-rc.0] + +### Enhancements + +- [`1e0793b68`](https://www.github.com/tauri-apps/tauri/commit/1e0793b6821799829e380c88066b3415cc9006df) ([#10357](https://www.github.com/tauri-apps/tauri/pull/10357)) Enhance `AssetResolver::get` in development mode by reading distDir directly as a fallback to the embedded assets. + +### Bug Fixes + +- [`24445d71d`](https://www.github.com/tauri-apps/tauri/commit/24445d71de92d526d0ccaecb54f13003ddc6f6b4)([#10432](https://www.github.com/tauri-apps/tauri/pull/10432)) Fixes asset resolving when not using the `compression` feature. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.0` + +## \[2.0.0-beta.19] + +### Bug Fixes + +- [`5d2922985`](https://www.github.com/tauri-apps/tauri/commit/5d2922985801908e4b929a7a0e387806ff02ab89) ([#10268](https://www.github.com/tauri-apps/tauri/pull/10268) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix icon rewriting always triggering build to rerun due to conflicts between file names. + +### What's Changed + +- [`4c239729c`](https://www.github.com/tauri-apps/tauri/commit/4c239729c3e1b899ecbc6793c3682848e8de1729) ([#10167](https://www.github.com/tauri-apps/tauri/pull/10167) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add support for `test = true` in `generate_context!` macro to skip some code generation that could affect some tests, for now it only skips empedding a plist on macOS. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.19` + +## \[2.0.0-beta.18] + +### New Features + +- [`5b769948a`](https://www.github.com/tauri-apps/tauri/commit/5b769948a81cac333f64c870a470ba6525bd5cd3) ([#9959](https://www.github.com/tauri-apps/tauri/pull/9959)) Add `include_image_codegen` function to help embedding instances of `Image` struct at compile-time in rust to be used with window, menu or tray icons. + +### Bug Fixes + +- [`1f6e478c8`](https://www.github.com/tauri-apps/tauri/commit/1f6e478c842a16219798b9962718e9ddb969c041) ([#9878](https://www.github.com/tauri-apps/tauri/pull/9878)) Fixes Info.plist rewriting always triggering build to rerun. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.18` + +## \[2.0.0-beta.17] + +### What's Changed + +- [`ccc3ea729`](https://www.github.com/tauri-apps/tauri/commit/ccc3ea729de205ef467f737f1feeb5bf02d9cd72)([#9646](https://www.github.com/tauri-apps/tauri/pull/9646)) Use `TAURI_ENV_TARGET_TRIPLE` (which is set by `tauri-build`) to determine the target when reading the config file. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.17` + +## \[2.0.0-beta.16] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.16` + +## \[2.0.0-beta.15] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.15` + +## \[2.0.0-beta.14] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.14` + +## \[2.0.0-beta.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.13` + +## \[2.0.0-beta.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.12` + +## \[2.0.0-beta.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.11` + +## \[2.0.0-beta.10] + +### New Features + +- [`e227fe02f`](https://www.github.com/tauri-apps/tauri/commit/e227fe02f986e145c0731a64693e1c830a9eb5b0)([#9156](https://www.github.com/tauri-apps/tauri/pull/9156)) Allow plugins to define (at compile time) JavaScript that are initialized when `withGlobalTauri` is true. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.10` + +## \[2.0.0-beta.9] + +### New Features + +- [`ba0206d8a`](https://www.github.com/tauri-apps/tauri/commit/ba0206d8a30a9b43ec5090dcaabd1a23baa1420c)([#9141](https://www.github.com/tauri-apps/tauri/pull/9141)) The `Context` codegen now accepts a `assets` input to define a custom `tauri::Assets` implementation. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.9` + +## \[2.0.0-beta.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.8` + +### Breaking Changes + +- [`ed48e2b3c`](https://www.github.com/tauri-apps/tauri/commit/ed48e2b3c7fa914e4c9af432c02b8154f872c68a)([#9122](https://www.github.com/tauri-apps/tauri/pull/9122)) Expose `tauri::image` module to export the `JsImage` type and removed the `Image` root re-export. + +## \[2.0.0-beta.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.7` + +### Breaking Changes + +- [`d1e77acd8`](https://www.github.com/tauri-apps/tauri/commit/d1e77acd8dfdf554b90b542513a58a2de1ef2360)([#9011](https://www.github.com/tauri-apps/tauri/pull/9011)) Change the generated context code to use the new `Image` type in tauri. + +## \[2.0.0-beta.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.6` + +### Breaking Changes + +- [`3657ad82`](https://www.github.com/tauri-apps/tauri/commit/3657ad82f88ce528551d032d521c52eed3f396b4)([#9008](https://www.github.com/tauri-apps/tauri/pull/9008)) Allow defining permissions for the application commands via `tauri_build::Attributes::app_manifest`. + +## \[2.0.0-beta.5] + +### Enhancements + +- [`bc5b5e67`](https://www.github.com/tauri-apps/tauri/commit/bc5b5e671a546512f823f1c157421b4c3311dfc0)([#8984](https://www.github.com/tauri-apps/tauri/pull/8984)) Do not include a CSP tag in the application HTML and rely on the custom protocol response header instead. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.5` + +## \[2.0.0-beta.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.4` + +## \[2.0.0-beta.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.3` + +## \[2.0.0-beta.2] + +### Enhancements + +- [`83a68deb`](https://www.github.com/tauri-apps/tauri/commit/83a68deb5676d39cd4728d2e140f6b46d5f787ed)([#8797](https://www.github.com/tauri-apps/tauri/pull/8797)) Added a new configuration option `tauri.conf.json > app > security > capabilities` to reference existing capabilities and inline new ones. If it is empty, all capabilities are still included preserving the current behavior. +- [`8d16a80d`](https://www.github.com/tauri-apps/tauri/commit/8d16a80d2fb2468667e7987d0cc99dbc7e3b9d0a)([#8802](https://www.github.com/tauri-apps/tauri/pull/8802)) The `generate_context` proc macro now accepts a `capabilities` attribute where the value is an array of file paths that can be [conditionally compiled](https://doc.rust-lang.org/reference/conditional-compilation.html). These capabilities are added to the application along the capabilities defined in the Tauri configuration file. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.2` + +## \[2.0.0-beta.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.1` + +## \[2.0.0-beta.0] + +### New Features + +- [`74a2a603`](https://www.github.com/tauri-apps/tauri/commit/74a2a6036a5e57462f161d728cbd8a6f121028ca)([#8661](https://www.github.com/tauri-apps/tauri/pull/8661)) Implement access control list for IPC usage. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.0` + +### Breaking Changes + +- [`8de308d1`](https://www.github.com/tauri-apps/tauri/commit/8de308d1bf6a855d7a26af58bd0e744938ba47d8)([#8723](https://www.github.com/tauri-apps/tauri/pull/8723)) Restructured Tauri config per [RFC#5](https://github.com/tauri-apps/rfcs/blob/f3e82a6b0c5390401e855850d47dc7b7d9afd684/texts/0005-tauri-config-restructure.md): + + - Moved `package.productName`, `package.version` and `tauri.bundle.identifier` fields to the top-level. + - Removed `package` object. + - Renamed `tauri` object to `app`. + - Moved `tauri.bundle` object to the top-level. + - Renamed `build.distDir` field to `frontendDist`. + - Renamed `build.devPath` field to `devUrl` and will no longer accepts paths, it will only accept URLs. + - Moved `tauri.pattern` to `app.security.pattern`. + - Removed `tauri.bundle.updater` object, and its fields have been moved to the updater plugin under `plugins.updater` object. + - Moved `build.withGlobalTauri` to `app.withGlobalTauri`. + - Moved `tauri.bundle.dmg` object to `bundle.macOS.dmg`. + - Moved `tauri.bundle.deb` object to `bundle.linux.deb`. + - Moved `tauri.bundle.appimage` object to `bundle.linux.appimage`. + - Removed all license fields from each bundle configuration object and instead added `bundle.license` and `bundle.licenseFile`. + - Renamed `AppUrl` to `FrontendDist` and refactored its variants to be more explicit. + +## \[2.0.0-alpha.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.13` + +## \[2.0.0-alpha.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.12` + +## \[2.0.0-alpha.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.11` + +## \[2.0.0-alpha.10] + +### Enhancements + +- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.10` + +## \[2.0.0-alpha.9] + +### New Features + +- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.9` + +### Breaking Changes + +- [`ebcc21e4`](https://www.github.com/tauri-apps/tauri/commit/ebcc21e4b95f4e8c27639fb1bca545b432f52d5e)([#8057](https://www.github.com/tauri-apps/tauri/pull/8057)) Renamed the beforeDevCommand, beforeBuildCommand and beforeBundleCommand hooks environment variables from `TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG` to `TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG` to differentiate the prefix with other CLI environment variables. + +## \[2.0.0-alpha.8] + +### Enhancements + +- [`100d9ede`](https://www.github.com/tauri-apps/tauri/commit/100d9ede35995d9db21d2087dd5606adfafb89a5)([#7802](https://www.github.com/tauri-apps/tauri/pull/7802)) Use `Target` enum from `tauri_utils::platform`. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.8` + +## \[2.0.0-alpha.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.7` + +## \[2.0.0-alpha.6] + +### Dependencies + +- Updated to latest `tauri-utils` + +## \[2.0.0-alpha.5] + +- [`96639ca2`](https://www.github.com/tauri-apps/tauri/commit/96639ca239c9e4f75142fc07868ac46822111cff)([#6749](https://www.github.com/tauri-apps/tauri/pull/6749)) Moved the `shell` functionality to its own plugin in the plugins-workspace repository. +- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65. +- [`ae102980`](https://www.github.com/tauri-apps/tauri/commit/ae102980fcdde3f55effdc0623ea425b48d07dd1)([#6719](https://www.github.com/tauri-apps/tauri/pull/6719)) Refactor the `Context` conditional fields and only parse the tray icon on desktop. + +## \[2.0.0-alpha.4] + +- Added `android` configuration object under `tauri > bundle`. + - Bumped due to a bump in tauri-utils. + - [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07 + +## \[2.0.0-alpha.3] + +- Pull changes from Tauri 1.3 release. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[2.0.0-alpha.2] + +- Return `bool` in the invoke handler. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 + +## \[2.0.0-alpha.1] + +- Bump the MSRV to 1.64. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Added `crate_name` field on `PackageInfo`. + - [630a7f4b](https://www.github.com/tauri-apps/tauri/commit/630a7f4b18cef169bfd48673609306fec434e397) refactor: remove mobile log initialization, ref [#6049](https://www.github.com/tauri-apps/tauri/pull/6049) ([#6081](https://www.github.com/tauri-apps/tauri/pull/6081)) on 2023-01-17 + +## \[2.0.0-alpha.0] + +- Change `devPath` URL to use the local IP address on iOS and Android. + - [6f061504](https://www.github.com/tauri-apps/tauri/commit/6f0615044d09ec58393a7ebca5e45bb175e20db3) feat(cli): add `android dev` and `ios dev` commands ([#4982](https://www.github.com/tauri-apps/tauri/pull/4982)) on 2022-08-20 +- First mobile alpha release! + - [fa3a1098](https://www.github.com/tauri-apps/tauri/commit/fa3a10988a03aed1b66fb17d893b1a9adb90f7cd) feat(ci): prepare 2.0.0-alpha.0 ([#5786](https://www.github.com/tauri-apps/tauri/pull/5786)) on 2022-12-08 + +## \[1.4.2] + +### Dependencies + +- Upgraded to `tauri-utils@1.5.2` + +## \[1.4.1] + +### Dependencies + +- Upgraded to `tauri-utils@1.5.0` + +## \[1.4.0] + +### Enhancements + +- [`17d5a4f5`](https://www.github.com/tauri-apps/tauri/commit/17d5a4f51f244d3ff42014b5d1b075fad7c636a5)([#6706](https://www.github.com/tauri-apps/tauri/pull/6706)) Early panic if the PNG icon is not RGBA. +- [`d2710e9d`](https://www.github.com/tauri-apps/tauri/commit/d2710e9d2e8fd93975ef6494512370faa8cb3b7e)([#6944](https://www.github.com/tauri-apps/tauri/pull/6944)) Unpin `time`, `ignore`, and `winnow` crate versions. Developers now have to pin crates if needed themselves. A list of crates that need pinning to adhere to Tauri's MSRV will be visible in Tauri's GitHub workflow: https://github.com/tauri-apps/tauri/blob/dev/.github/workflows/test-core.yml#L85. + +## \[1.3.0] + +- Bump minimum supported Rust version to 1.60. + - [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31 +- Pin `time` to `0.3.15`. + - [3d16461b](https://www.github.com/tauri-apps/tauri/commit/3d16461b68583ba7db037fbc217786e79b46ddf2) fix(core): pin time to 0.3.15 ([#6312](https://www.github.com/tauri-apps/tauri/pull/6312)) on 2023-02-19 + +## \[1.2.1] + +- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`. + - Bumped due to a bump in tauri-utils. + - [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18 + +## \[1.2.0] + +- Properly serialize HTML template tags. + - [aec5537d](https://www.github.com/tauri-apps/tauri/commit/aec5537de0205f62b2ae5c89da04d21930a6fc2e) fix(codegen): serialize template tags, closes [#4410](https://www.github.com/tauri-apps/tauri/pull/4410) ([#5247](https://www.github.com/tauri-apps/tauri/pull/5247)) on 2022-09-28 +- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28 + +## \[1.1.1] + +- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs. + - Bumped due to a bump in tauri-utils. + - [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16 + +## \[1.1.0] + +- Use `TARGET` environment variable for code generation inside build scripts. + - [6ba99689](https://www.github.com/tauri-apps/tauri/commit/6ba99689aa7ed0ffa9072a1c8ab5db12c9bf95af) feat(codegen): use TARGET environment variable if set ([#4921](https://www.github.com/tauri-apps/tauri/pull/4921)) on 2022-08-12 +- Added support to configuration files in TOML format (Tauri.toml file). + - [ae83d008](https://www.github.com/tauri-apps/tauri/commit/ae83d008f9e1b89bfc8dddaca42aa5c1fbc36f6d) feat: add support to TOML config file `Tauri.toml`, closes [#4806](https://www.github.com/tauri-apps/tauri/pull/4806) ([#4813](https://www.github.com/tauri-apps/tauri/pull/4813)) on 2022-08-02 +- Improve tray icon read error message. + - [52f0c8bb](https://www.github.com/tauri-apps/tauri/commit/52f0c8bb836c6d50b7ce2393161394f4ce78f5ae) feat(core): improve tray icon read error messages ([#4850](https://www.github.com/tauri-apps/tauri/pull/4850)) on 2022-08-03 +- Fix relative paths in `version` field of `tauri.config.json` not being correctly parsed by `generate_context!()`. + - [accbc5e8](https://www.github.com/tauri-apps/tauri/commit/accbc5e8806a32efc555d019634fc2fa14d17f0a) fix(codegen): fix relative paths in `version` field of `tauri.config.json`, closes [#4723](https://www.github.com/tauri-apps/tauri/pull/4723) ([#4725](https://www.github.com/tauri-apps/tauri/pull/4725)) on 2022-07-24 +- Only rewrite temporary icon files when the content change, avoid needless rebuilds. + - [f957cbb5](https://www.github.com/tauri-apps/tauri/commit/f957cbb56ccbd8d1c047a978b4579946252a6fd2) fix(codegen): write output file when contents change ([#4889](https://www.github.com/tauri-apps/tauri/pull/4889)) on 2022-08-09 + +## \[1.0.4] + +- Validate `__TAURI_ISOLATION_HOOK__` being set by a file in the isolation application. + - [3b4ed970](https://www.github.com/tauri-apps/tauri/commit/3b4ed970e663f5bffbfe0358610f9c3f157c513f) feat(codegen): validate `__TAURI_ISOLATION_HOOK__` is referenced ([#4631](https://www.github.com/tauri-apps/tauri/pull/4631)) on 2022-07-11 + +## \[1.0.3] + +- The `TAURI_CONFIG` environment variable now represents the configuration to be merged instead of the entire JSON. + - [fa028ebf](https://www.github.com/tauri-apps/tauri/commit/fa028ebf3c8ca7b43a70d283a01dbea86217594f) refactor: do not pass entire config from CLI to core, send patch instead ([#4598](https://www.github.com/tauri-apps/tauri/pull/4598)) on 2022-07-06 + +## \[1.0.2] + +- Expose `platform::windows_version` function. + - Bumped due to a bump in tauri-utils. + - [bf764e83](https://www.github.com/tauri-apps/tauri/commit/bf764e83e01e7443e6cc54572001e1c98c357465) feat(utils): expose `windows_version` function ([#4534](https://www.github.com/tauri-apps/tauri/pull/4534)) on 2022-06-30 + +## \[1.0.1] + +- Set the bundle name and app metadata in the Info.plist file in development mode. + - [38f5db6e](https://www.github.com/tauri-apps/tauri/commit/38f5db6e6a8b496b50d486db6fd8204266de3a69) feat(codegen): fill app metadata in development Info.plist on 2022-06-21 +- Set the application icon in development mode on macOS. + - [307c2ebf](https://www.github.com/tauri-apps/tauri/commit/307c2ebfb68238dacab6088f9c6ba310c727c68c) feat(core): set macOS app icon in development ([#4385](https://www.github.com/tauri-apps/tauri/pull/4385)) on 2022-06-19 + +## \[1.0.0] + +- Upgrade to `stable`! + - [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15 + +## \[1.0.0-rc.11] + +- Read the tray icon path relatively to the config directory. + - [562e8ca2](https://www.github.com/tauri-apps/tauri/commit/562e8ca23facf1a8e5fa6c8cdf872357d3523a78) fix(codegen): tray icon path is relative to the config directory on 2022-06-15 + +## \[1.0.0-rc.10] + +- **Breaking change:** The `TrayIcon` enum has been removed and now `Icon` is used instead. + This allows you to use more image formats and use embedded icons on Linux. + - [4ce8e228](https://www.github.com/tauri-apps/tauri/commit/4ce8e228134cd3f22973b74ef26ca0d165fbbbd9) refactor(core): use `Icon` for tray icons ([#4342](https://www.github.com/tauri-apps/tauri/pull/4342)) on 2022-06-14 + +## \[1.0.0-rc.9] + +- Added a config flag to bundle the media framework used by webkit2gtk `tauri.conf.json > tauri > bundle > appimage > bundleMediaFramework`. + - Bumped due to a bump in tauri-utils. + - [d335fae9](https://www.github.com/tauri-apps/tauri/commit/d335fae92cdcbb0ee18aad4e54558914afa3e778) feat(bundler): bundle additional gstreamer files, closes [#4092](https://www.github.com/tauri-apps/tauri/pull/4092) ([#4271](https://www.github.com/tauri-apps/tauri/pull/4271)) on 2022-06-10 + +## \[1.0.0-rc.8] + +- **Breaking change:** `PackageInfo::version` is now a `semver::Version` instead of a `String`. + - [2badbd2d](https://www.github.com/tauri-apps/tauri/commit/2badbd2d7ed51bf33c1b547b4c837b600574bd4a) refactor: force semver versions, change updater `should_install` sig ([#4215](https://www.github.com/tauri-apps/tauri/pull/4215)) on 2022-05-25 + - [a7388e23](https://www.github.com/tauri-apps/tauri/commit/a7388e23c3b9019d48b078cae00a75c74d74d11b) fix(ci): adjust change file to include tauri-utils and tauri-codegen on 2022-05-27 + +## \[1.0.0-rc.7] + +- Allow configuring the display options for the MSI execution allowing quieter updates. + - Bumped due to a bump in tauri-utils. + - [9f2c3413](https://www.github.com/tauri-apps/tauri/commit/9f2c34131952ea83c3f8e383bc3cec7e1450429f) feat(core): configure msiexec display options, closes [#3951](https://www.github.com/tauri-apps/tauri/pull/3951) ([#4061](https://www.github.com/tauri-apps/tauri/pull/4061)) on 2022-05-15 + +## \[1.0.0-rc.6] + +- The `dangerous_allow_asset_csp_modification` configuration value has been changed to allow a list of CSP directives to disable. + - [164078c0](https://www.github.com/tauri-apps/tauri/commit/164078c0b719ccbc12e956fecf8a7d4a3c5044e1) feat: allow limiting dangerousDisableAssetCspModification, closes [#3831](https://www.github.com/tauri-apps/tauri/pull/3831) ([#4021](https://www.github.com/tauri-apps/tauri/pull/4021)) on 2022-05-02 + +## \[1.0.0-rc.5] + +- Read platform-specific configuration files when generating code without the `TAURI_CONFIG` env var. + - [edf85bc1](https://www.github.com/tauri-apps/tauri/commit/edf85bc1d18450c92aee17f7f99c163abe432ebd) fix(codegen): read platform-specific config file ([#3966](https://www.github.com/tauri-apps/tauri/pull/3966)) on 2022-04-25 + +## \[1.0.0-rc.4] + +- Added an option to disable the CSP injection of distributable assets nonces and hashes. + - [f6e32ee1](https://www.github.com/tauri-apps/tauri/commit/f6e32ee1880eb364ed76beb937c9d12e14d54910) feat(core): add dangerous option to disable compile time CSP injection ([#3775](https://www.github.com/tauri-apps/tauri/pull/3775)) on 2022-03-28 + +- Replace multiple dependencies who's C code compiled concurrently and caused + the other ones to bloat compile time significantly. + +- `zstd` -> `brotli` + +- `blake3` -> a vendored version of the blake3 reference + +- `ring` -> `getrandom` + +See https://github.com/tauri-apps/tauri/pull/3773 for more information about +these specific choices. + +- [8661e3e2](https://www.github.com/tauri-apps/tauri/commit/8661e3e24d96c399bfbcdee5d8e9d6beba2265a7) replace dependencies with long build times when used together (closes [#3571](https://www.github.com/tauri-apps/tauri/pull/3571)) ([#3773](https://www.github.com/tauri-apps/tauri/pull/3773)) on 2022-03-27 + +## \[1.0.0-rc.3] + +- Parse window icons at compile time. + - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 + +## \[1.0.0-rc.2] + +- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. + - Bumped due to a bump in tauri-utils. + - [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17 + +## \[1.0.0-rc.1] + +- Change default value for the `freezePrototype` configuration to `false`. + - Bumped due to a bump in tauri-utils. + - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 + +## \[1.0.0-rc.0] + +- Apply `nonce` to `script` and `style` tags and set them on the `CSP` (`script-src` and `style-src` fetch directives). + - [cf54dcf9](https://www.github.com/tauri-apps/tauri/commit/cf54dcf9c81730e42c9171daa9c8aa474c95b522) feat: improve `CSP` security with nonces and hashes, add `devCsp` \[TRI-004] ([#8](https://www.github.com/tauri-apps/tauri/pull/8)) on 2022-01-09 +- Added the `isolation` pattern. + - [d5d6d2ab](https://www.github.com/tauri-apps/tauri/commit/d5d6d2abc17cd89c3a079d2ce01581193469dbc0) Isolation Pattern ([#43](https://www.github.com/tauri-apps/tauri/pull/43)) Co-authored-by: Ngo Iok Ui (Wu Yu Wei) Co-authored-by: Lucas Fernandes Nogueira on 2022-01-17 +- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. + +Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: + +1. Check if `tauri.conf.json` exists + a. Parse it with `serde_json` + b. Parse it with `json5` if `serde_json` fails + c. Return original `serde_json` error if all above steps failed +2. Check if `tauri.conf.json5` exists + a. Parse it with `json5` + b. Return error if all above steps failed +3. Return error if all above steps failed + +- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 + +## \[1.0.0-beta.4] + +- Embed Info.plist file contents on binary on dev. + - [537ab1b6](https://www.github.com/tauri-apps/tauri/commit/537ab1b6d5a792c550a535619965c9e4126292e6) feat(core): inject src-tauri/Info.plist file on dev and merge on bundle, closes [#1570](https://www.github.com/tauri-apps/tauri/pull/1570) [#2338](https://www.github.com/tauri-apps/tauri/pull/2338) ([#2444](https://www.github.com/tauri-apps/tauri/pull/2444)) on 2021-08-15 +- Fix ES Module detection for default imports with relative paths or scoped packages and exporting of async functions. + - [b2b36cfe](https://www.github.com/tauri-apps/tauri/commit/b2b36cfe8dfcccb341638a4cb6dc23a514c54148) fix(core): fixes ES Module detection for default imports with relative paths or scoped packages ([#2380](https://www.github.com/tauri-apps/tauri/pull/2380)) on 2021-08-10 + - [fbf8caf5](https://www.github.com/tauri-apps/tauri/commit/fbf8caf5c419cb4fc3d123be910e094a8e8c4bef) fix(core): ESM detection when using `export async function` ([#2425](https://www.github.com/tauri-apps/tauri/pull/2425)) on 2021-08-14 + +## \[1.0.0-beta.3] + +- Improve ESM detection with regexes. + - [4b0ec018](https://www.github.com/tauri-apps/tauri/commit/4b0ec0188078a8fefd4119fe5e19ebc30191f802) fix(core): improve JS ESM detection ([#2139](https://www.github.com/tauri-apps/tauri/pull/2139)) on 2021-07-02 +- Inject invoke key on `script` tags with `type="module"`. + - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on ``). Maps a HTML path to a list of hashes. + pub(crate) inline_scripts: HashMap>, + /// A list of hashes of the contents of all `style` elements. + pub(crate) styles: Vec, +} + +impl CspHashes { + /// Only add a CSP hash to the appropriate category if we think the file matches + /// + /// Note: this only checks the file extension, much like how a browser will assume a .js file is + /// a JavaScript file unless HTTP headers tell it otherwise. + pub fn add_if_applicable( + &mut self, + entry: &DirEntry, + dangerous_disable_asset_csp_modification: &DisabledCspModificationKind, + ) -> Result<(), EmbeddedAssetsError> { + let path = entry.path(); + + // we only hash JavaScript files for now, may expand to other CSP hashable types in the future + if let Some("js") | Some("mjs") = path.extension().and_then(|os| os.to_str()) { + if dangerous_disable_asset_csp_modification.can_modify("script-src") { + let mut hasher = Sha256::new(); + hasher.update( + &std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead { + path: path.to_path_buf(), + error, + })?, + ); + let hash = hasher.finalize(); + self.scripts.push(format!( + "'sha256-{}'", + base64::engine::general_purpose::STANDARD.encode(hash) + )); + } + } + + Ok(()) + } +} + +/// Options used to embed assets. +#[derive(Default)] +pub struct AssetOptions { + pub(crate) csp: bool, + pub(crate) pattern: PatternKind, + pub(crate) freeze_prototype: bool, + pub(crate) dangerous_disable_asset_csp_modification: DisabledCspModificationKind, + #[cfg(feature = "isolation")] + pub(crate) isolation_schema: String, +} + +impl AssetOptions { + /// Creates the default asset options. + pub fn new(pattern: PatternKind) -> Self { + Self { + csp: false, + pattern, + freeze_prototype: false, + dangerous_disable_asset_csp_modification: DisabledCspModificationKind::Flag(false), + #[cfg(feature = "isolation")] + isolation_schema: format!("isolation-{}", uuid::Uuid::new_v4()), + } + } + + /// Instruct the asset handler to inject the CSP token to HTML files (Linux only) and add asset nonces and hashes to the policy. + #[must_use] + pub fn with_csp(mut self) -> Self { + self.csp = true; + self + } + + /// Instruct the asset handler to include a script to freeze the `Object.prototype` on all HTML files. + #[must_use] + pub fn freeze_prototype(mut self, freeze: bool) -> Self { + self.freeze_prototype = freeze; + self + } + + /// Instruct the asset handler to **NOT** modify the CSP. This is **NOT** recommended. + pub fn dangerous_disable_asset_csp_modification( + mut self, + dangerous_disable_asset_csp_modification: DisabledCspModificationKind, + ) -> Self { + self.dangerous_disable_asset_csp_modification = dangerous_disable_asset_csp_modification; + self + } +} + +impl EmbeddedAssets { + /// Compress a collection of files and directories, ready to be generated into [`Assets`]. + /// + /// [`Assets`]: tauri_utils::assets::Assets + pub fn new( + input: impl Into, + options: &AssetOptions, + mut map: impl FnMut( + &AssetKey, + &Path, + &mut Vec, + &mut CspHashes, + ) -> Result<(), EmbeddedAssetsError>, + ) -> Result { + // we need to pre-compute all files now, so that we can inject data from all files into a few + let RawEmbeddedAssets { paths, csp_hashes } = RawEmbeddedAssets::new(input.into(), options)?; + + struct CompressState { + csp_hashes: CspHashes, + assets: HashMap, + } + + let CompressState { assets, csp_hashes } = paths.into_iter().try_fold( + CompressState { + csp_hashes, + assets: HashMap::new(), + }, + move |mut state, (prefix, entry)| { + let (key, asset) = + Self::compress_file(&prefix, entry.path(), &mut map, &mut state.csp_hashes)?; + state.assets.insert(key, asset); + Result::<_, EmbeddedAssetsError>::Ok(state) + }, + )?; + + Ok(Self { assets, csp_hashes }) + } + + /// Use highest compression level for release, the fastest one for everything else + #[cfg(feature = "compression")] + fn compression_settings() -> BrotliEncoderParams { + let mut settings = BrotliEncoderParams::default(); + + // the following compression levels are hand-picked and are not min-maxed. + // they have a good balance of runtime vs size for the respective profile goals. + // see the "brotli" section of this comment https://github.com/tauri-apps/tauri/issues/3571#issuecomment-1054847558 + if cfg!(debug_assertions) { + settings.quality = 2 + } else { + settings.quality = 9 + } + + settings + } + + /// Compress a file and spit out the information in a [`HashMap`] friendly form. + fn compress_file( + prefix: &Path, + path: &Path, + map: &mut impl FnMut( + &AssetKey, + &Path, + &mut Vec, + &mut CspHashes, + ) -> Result<(), EmbeddedAssetsError>, + csp_hashes: &mut CspHashes, + ) -> Result { + let mut input = std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead { + path: path.to_owned(), + error, + })?; + + // get a key to the asset path without the asset directory prefix + let key = path + .strip_prefix(prefix) + .map(AssetKey::from) // format the path for use in assets + .map_err(|_| EmbeddedAssetsError::PrefixInvalid { + prefix: prefix.to_owned(), + path: path.to_owned(), + })?; + + // perform any caller-requested input manipulation + map(&key, path, &mut input, csp_hashes)?; + + // we must canonicalize the base of our paths to allow long paths on windows + let out_dir = std::env::var("OUT_DIR") + .map_err(|_| EmbeddedAssetsError::OutDir) + .map(PathBuf::from) + .and_then(|p| p.canonicalize().map_err(|_| EmbeddedAssetsError::OutDir)) + .map(|p| p.join(TARGET_PATH))?; + + // make sure that our output directory is created + std::fs::create_dir_all(&out_dir).map_err(|_| EmbeddedAssetsError::OutDir)?; + + // get a hash of the input - allows for caching existing files + let hash = crate::checksum(&input).map_err(EmbeddedAssetsError::Hex)?; + + // use the content hash to determine filename, keep extensions that exist + let out_path = if let Some(ext) = path.extension().and_then(|e| e.to_str()) { + out_dir.join(format!("{hash}.{ext}")) + } else { + out_dir.join(hash) + }; + + // only compress and write to the file if it doesn't already exist. + if !out_path.exists() { + #[allow(unused_mut)] + let mut out_file = + File::create(&out_path).map_err(|error| EmbeddedAssetsError::AssetWrite { + path: out_path.clone(), + error, + })?; + + #[cfg(not(feature = "compression"))] + { + use std::io::Write; + out_file + .write_all(&input) + .map_err(|error| EmbeddedAssetsError::AssetWrite { + path: path.to_owned(), + error, + })?; + } + + #[cfg(feature = "compression")] + { + let mut input = std::io::Cursor::new(input); + // entirely write input to the output file path with compression + brotli::BrotliCompress(&mut input, &mut out_file, &Self::compression_settings()).map_err( + |error| EmbeddedAssetsError::AssetWrite { + path: path.to_owned(), + error, + }, + )?; + } + } + + Ok((key, (path.into(), out_path))) + } +} + +impl ToTokens for EmbeddedAssets { + fn to_tokens(&self, tokens: &mut TokenStream) { + let mut assets = TokenStream::new(); + for (key, (input, output)) in &self.assets { + let key: &str = key.as_ref(); + let input = input.display().to_string(); + let output = output.display().to_string(); + + // add original asset as a compiler dependency, rely on dead code elimination to clean it up + assets.append_all(quote!(#key => { + const _: &[u8] = include_bytes!(#input); + include_bytes!(#output) + },)); + } + + let mut global_hashes = TokenStream::new(); + for script_hash in &self.csp_hashes.scripts { + let hash = script_hash.as_str(); + global_hashes.append_all(quote!(CspHash::Script(#hash),)); + } + + for style_hash in &self.csp_hashes.styles { + let hash = style_hash.as_str(); + global_hashes.append_all(quote!(CspHash::Style(#hash),)); + } + + let mut html_hashes = TokenStream::new(); + for (path, hashes) in &self.csp_hashes.inline_scripts { + let key = path.as_str(); + let mut value = TokenStream::new(); + for script_hash in hashes { + let hash = script_hash.as_str(); + value.append_all(quote!(CspHash::Script(#hash),)); + } + html_hashes.append_all(quote!(#key => &[#value],)); + } + + // we expect phf related items to be in path when generating the path code + tokens.append_all(quote! {{ + #[allow(unused_imports)] + use ::tauri::utils::assets::{CspHash, EmbeddedAssets, phf, phf::phf_map}; + EmbeddedAssets::new(phf_map! { #assets }, &[#global_hashes], phf_map! { #html_hashes }) + }}); + } +} + +pub(crate) fn ensure_out_dir() -> EmbeddedAssetsResult { + let out_dir = std::env::var("OUT_DIR") + .map_err(|_| EmbeddedAssetsError::OutDir) + .map(PathBuf::from) + .and_then(|p| p.canonicalize().map_err(|_| EmbeddedAssetsError::OutDir))?; + + // make sure that our output directory is created + std::fs::create_dir_all(&out_dir).map_err(|_| EmbeddedAssetsError::OutDir)?; + Ok(out_dir) +} diff --git a/crates/tauri-codegen/src/image.rs b/crates/tauri-codegen/src/image.rs new file mode 100644 index 000000000000..49546082a9b7 --- /dev/null +++ b/crates/tauri-codegen/src/image.rs @@ -0,0 +1,118 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use crate::{ + embedded_assets::{EmbeddedAssetsError, EmbeddedAssetsResult}, + Cached, +}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens, TokenStreamExt}; +use std::{ffi::OsStr, io::Cursor, path::Path}; + +/// The format the Icon is consumed as. +pub(crate) enum IconFormat { + /// The image, completely unmodified. + Raw, + + /// RGBA raw data, meant to be consumed by [`tauri::image::Image`]. + Image { width: u32, height: u32 }, +} + +pub struct CachedIcon { + cache: Cached, + format: IconFormat, + root: TokenStream, +} + +impl CachedIcon { + pub fn new(root: &TokenStream, icon: &Path) -> EmbeddedAssetsResult { + match icon.extension().map(OsStr::to_string_lossy).as_deref() { + Some("png") => Self::new_png(root, icon), + Some("ico") => Self::new_ico(root, icon), + unknown => Err(EmbeddedAssetsError::InvalidImageExtension { + extension: unknown.unwrap_or_default().into(), + path: icon.to_path_buf(), + }), + } + } + + /// Cache the icon without any manipulation. + pub fn new_raw(root: &TokenStream, icon: &Path) -> EmbeddedAssetsResult { + let buf = Self::open(icon); + Cached::try_from(buf).map(|cache| Self { + cache, + root: root.clone(), + format: IconFormat::Raw, + }) + } + + /// Cache an ICO icon as RGBA data, see [`ImageFormat::Image`]. + pub fn new_ico(root: &TokenStream, icon: &Path) -> EmbeddedAssetsResult { + let buf = Self::open(icon); + + let icon_dir = ico::IconDir::read(Cursor::new(&buf)) + .unwrap_or_else(|e| panic!("failed to parse icon {}: {}", icon.display(), e)); + + let entry = &icon_dir.entries()[0]; + let rgba = entry + .decode() + .unwrap_or_else(|e| panic!("failed to decode icon {}: {}", icon.display(), e)) + .rgba_data() + .to_vec(); + + Cached::try_from(rgba).map(|cache| Self { + cache, + root: root.clone(), + format: IconFormat::Image { + width: entry.width(), + height: entry.height(), + }, + }) + } + + /// Cache a PNG icon as RGBA data, see [`ImageFormat::Image`]. + pub fn new_png(root: &TokenStream, icon: &Path) -> EmbeddedAssetsResult { + let buf = Self::open(icon); + let decoder = png::Decoder::new(Cursor::new(&buf)); + let mut reader = decoder + .read_info() + .unwrap_or_else(|e| panic!("failed to read icon {}: {}", icon.display(), e)); + + if reader.output_color_type().0 != png::ColorType::Rgba { + panic!("icon {} is not RGBA", icon.display()); + } + + let mut rgba = Vec::with_capacity(reader.output_buffer_size()); + while let Ok(Some(row)) = reader.next_row() { + rgba.extend(row.data()); + } + + Cached::try_from(rgba).map(|cache| Self { + cache, + root: root.clone(), + format: IconFormat::Image { + width: reader.info().width, + height: reader.info().height, + }, + }) + } + + fn open(path: &Path) -> Vec { + std::fs::read(path).unwrap_or_else(|e| panic!("failed to open icon {}: {}", path.display(), e)) + } +} + +impl ToTokens for CachedIcon { + fn to_tokens(&self, tokens: &mut TokenStream) { + let root = &self.root; + let cache = &self.cache; + let raw = quote!(::std::include_bytes!(#cache)); + tokens.append_all(match self.format { + IconFormat::Raw => raw, + IconFormat::Image { width, height } => { + quote!(#root::image::Image::new(#raw, #width, #height)) + } + }) + } +} diff --git a/crates/tauri-codegen/src/lib.rs b/crates/tauri-codegen/src/lib.rs new file mode 100644 index 000000000000..762804f5fc65 --- /dev/null +++ b/crates/tauri-codegen/src/lib.rs @@ -0,0 +1,150 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! - Embed, hash, and compress assets, including icons for the app as well as the tray icon. +//! - Parse `tauri.conf.json` at compile time and generate the Config struct. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +pub use self::context::{context_codegen, ContextData}; +use crate::embedded_assets::{ensure_out_dir, EmbeddedAssetsError}; +use proc_macro2::TokenStream; +use quote::{quote, ToTokens, TokenStreamExt}; +use std::{ + borrow::Cow, + fmt::{self, Write}, + path::{Path, PathBuf}, +}; +pub use tauri_utils::config::{parse::ConfigError, Config}; +use tauri_utils::platform::Target; +use tauri_utils::write_if_changed; + +mod context; +pub mod embedded_assets; +pub mod image; +#[doc(hidden)] +pub mod vendor; + +/// Represents all the errors that can happen while reading the config during codegen. +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum CodegenConfigError { + #[error("unable to access current working directory: {0}")] + CurrentDir(std::io::Error), + + // this error should be "impossible" because we use std::env::current_dir() - cover it anyways + #[error("Tauri config file has no parent, this shouldn't be possible. file an issue on https://github.com/tauri-apps/tauri - target {0}")] + Parent(PathBuf), + + #[error("unable to parse inline JSON TAURI_CONFIG env var: {0}")] + FormatInline(serde_json::Error), + + #[error(transparent)] + Json(#[from] serde_json::Error), + + #[error("{0}")] + ConfigError(#[from] ConfigError), +} + +/// Get the [`Config`] from the `TAURI_CONFIG` environmental variable, or read from the passed path. +/// +/// If the passed path is relative, it should be relative to the current working directory of the +/// compiling crate. +pub fn get_config(path: &Path) -> Result<(Config, PathBuf), CodegenConfigError> { + let path = if path.is_relative() { + let cwd = std::env::current_dir().map_err(CodegenConfigError::CurrentDir)?; + Cow::Owned(cwd.join(path)) + } else { + Cow::Borrowed(path) + }; + + // this should be impossible because of the use of `current_dir()` above, but handle it anyways + let parent = path + .parent() + .map(ToOwned::to_owned) + .ok_or_else(|| CodegenConfigError::Parent(path.into_owned()))?; + + let target = std::env::var("TAURI_ENV_TARGET_TRIPLE") + .as_deref() + .map(Target::from_triple) + .unwrap_or_else(|_| Target::current()); + + // in the future we may want to find a way to not need the TAURI_CONFIG env var so that + // it is impossible for the content of two separate configs to get mixed up. The chances are + // already unlikely unless the developer goes out of their way to run the cli on a different + // project than the target crate. + let mut config = + serde_json::from_value(tauri_utils::config::parse::read_from(target, parent.clone())?.0)?; + + if let Ok(env) = std::env::var("TAURI_CONFIG") { + let merge_config: serde_json::Value = + serde_json::from_str(&env).map_err(CodegenConfigError::FormatInline)?; + json_patch::merge(&mut config, &merge_config); + } + + // Set working directory to where `tauri.config.json` is, so that relative paths in it are parsed correctly. + let old_cwd = std::env::current_dir().map_err(CodegenConfigError::CurrentDir)?; + std::env::set_current_dir(parent.clone()).map_err(CodegenConfigError::CurrentDir)?; + + let config = serde_json::from_value(config)?; + + // Reset working directory. + std::env::set_current_dir(old_cwd).map_err(CodegenConfigError::CurrentDir)?; + + Ok((config, parent)) +} + +/// Create a blake3 checksum of the passed bytes. +fn checksum(bytes: &[u8]) -> Result { + let mut hasher = vendor::blake3_reference::Hasher::default(); + hasher.update(bytes); + + let mut bytes = [0u8; 32]; + hasher.finalize(&mut bytes); + + let mut hex = String::with_capacity(2 * bytes.len()); + for b in bytes { + write!(hex, "{b:02x}")?; + } + Ok(hex) +} + +/// Cache the data to `$OUT_DIR`, only if it does not already exist. +/// +/// Due to using a checksum as the filename, an existing file should be the exact same content +/// as the data being checked. +struct Cached { + checksum: String, +} + +impl TryFrom for Cached { + type Error = EmbeddedAssetsError; + + fn try_from(value: String) -> Result { + Self::try_from(Vec::from(value)) + } +} + +impl TryFrom> for Cached { + type Error = EmbeddedAssetsError; + + fn try_from(content: Vec) -> Result { + let checksum = checksum(content.as_ref()).map_err(EmbeddedAssetsError::Hex)?; + let path = ensure_out_dir()?.join(&checksum); + + write_if_changed(&path, &content) + .map(|_| Self { checksum }) + .map_err(|error| EmbeddedAssetsError::AssetWrite { path, error }) + } +} + +impl ToTokens for Cached { + fn to_tokens(&self, tokens: &mut TokenStream) { + let path = &self.checksum; + tokens.append_all(quote!(::std::concat!(::std::env!("OUT_DIR"), "/", #path))) + } +} diff --git a/crates/tauri-codegen/src/vendor/blake3_reference.rs b/crates/tauri-codegen/src/vendor/blake3_reference.rs new file mode 100644 index 000000000000..c783a81e573a --- /dev/null +++ b/crates/tauri-codegen/src/vendor/blake3_reference.rs @@ -0,0 +1,377 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! This is a lightly modified version of the BLAKE3 reference implementation. +//! The changes applied are to remove unused item warnings due to using it +//! vendored along with some minor clippy suggestions. No logic changes. I +//! suggest diffing against the original to find all the changes. +//! +//! ## Original Header +//! This is the reference implementation of BLAKE3. It is used for testing and +//! as a readable example of the algorithms involved. Section 5.1 of [the BLAKE3 +//! spec](https://github.com/BLAKE3-team/BLAKE3-specs/blob/master/blake3.pdf) +//! discusses this implementation. You can render docs for this implementation +//! by running `cargo doc --open` in this directory. +//! +//! # Example +//! +//! ``` +//! let mut hasher = tauri_codegen::vendor::blake3_reference::Hasher::new(); +//! hasher.update(b"abc"); +//! hasher.update(b"def"); +//! let mut hash = [0; 32]; +//! hasher.finalize(&mut hash); +//! let mut extended_hash = [0; 500]; +//! hasher.finalize(&mut extended_hash); +//! assert_eq!(hash, extended_hash[..32]); +//! ``` +//! +//! CC0-1.0 OR Apache-2.0 + +use core::cmp::min; +use core::convert::TryInto; + +const OUT_LEN: usize = 32; +const BLOCK_LEN: usize = 64; +const CHUNK_LEN: usize = 1024; + +const CHUNK_START: u32 = 1 << 0; +const CHUNK_END: u32 = 1 << 1; +const PARENT: u32 = 1 << 2; +const ROOT: u32 = 1 << 3; + +const IV: [u32; 8] = [ + 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19, +]; + +const MSG_PERMUTATION: [usize; 16] = [2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8]; + +// The mixing function, G, which mixes either a column or a diagonal. +fn g(state: &mut [u32; 16], a: usize, b: usize, c: usize, d: usize, mx: u32, my: u32) { + state[a] = state[a].wrapping_add(state[b]).wrapping_add(mx); + state[d] = (state[d] ^ state[a]).rotate_right(16); + state[c] = state[c].wrapping_add(state[d]); + state[b] = (state[b] ^ state[c]).rotate_right(12); + state[a] = state[a].wrapping_add(state[b]).wrapping_add(my); + state[d] = (state[d] ^ state[a]).rotate_right(8); + state[c] = state[c].wrapping_add(state[d]); + state[b] = (state[b] ^ state[c]).rotate_right(7); +} + +fn round(state: &mut [u32; 16], m: &[u32; 16]) { + // Mix the columns. + g(state, 0, 4, 8, 12, m[0], m[1]); + g(state, 1, 5, 9, 13, m[2], m[3]); + g(state, 2, 6, 10, 14, m[4], m[5]); + g(state, 3, 7, 11, 15, m[6], m[7]); + // Mix the diagonals. + g(state, 0, 5, 10, 15, m[8], m[9]); + g(state, 1, 6, 11, 12, m[10], m[11]); + g(state, 2, 7, 8, 13, m[12], m[13]); + g(state, 3, 4, 9, 14, m[14], m[15]); +} + +fn permute(m: &mut [u32; 16]) { + let mut permuted = [0; 16]; + for i in 0..16 { + permuted[i] = m[MSG_PERMUTATION[i]]; + } + *m = permuted; +} + +fn compress( + chaining_value: &[u32; 8], + block_words: &[u32; 16], + counter: u64, + block_len: u32, + flags: u32, +) -> [u32; 16] { + let mut state = [ + chaining_value[0], + chaining_value[1], + chaining_value[2], + chaining_value[3], + chaining_value[4], + chaining_value[5], + chaining_value[6], + chaining_value[7], + IV[0], + IV[1], + IV[2], + IV[3], + counter as u32, + (counter >> 32) as u32, + block_len, + flags, + ]; + let mut block = *block_words; + + round(&mut state, &block); // round 1 + permute(&mut block); + round(&mut state, &block); // round 2 + permute(&mut block); + round(&mut state, &block); // round 3 + permute(&mut block); + round(&mut state, &block); // round 4 + permute(&mut block); + round(&mut state, &block); // round 5 + permute(&mut block); + round(&mut state, &block); // round 6 + permute(&mut block); + round(&mut state, &block); // round 7 + + for i in 0..8 { + state[i] ^= state[i + 8]; + state[i + 8] ^= chaining_value[i]; + } + state +} + +fn first_8_words(compression_output: [u32; 16]) -> [u32; 8] { + compression_output[0..8].try_into().unwrap() +} + +fn words_from_little_endian_bytes(bytes: &[u8], words: &mut [u32]) { + debug_assert_eq!(bytes.len(), 4 * words.len()); + for (four_bytes, word) in bytes.chunks_exact(4).zip(words) { + *word = u32::from_le_bytes(four_bytes.try_into().unwrap()); + } +} + +// Each chunk or parent node can produce either an 8-word chaining value or, by +// setting the ROOT flag, any number of final output bytes. The Output struct +// captures the state just prior to choosing between those two possibilities. +struct Output { + input_chaining_value: [u32; 8], + block_words: [u32; 16], + counter: u64, + block_len: u32, + flags: u32, +} + +impl Output { + fn chaining_value(&self) -> [u32; 8] { + first_8_words(compress( + &self.input_chaining_value, + &self.block_words, + self.counter, + self.block_len, + self.flags, + )) + } + + fn root_output_bytes(&self, out_slice: &mut [u8]) { + for (output_block_counter, out_block) in (0u64..).zip(out_slice.chunks_mut(2 * OUT_LEN)) { + let words = compress( + &self.input_chaining_value, + &self.block_words, + output_block_counter, + self.block_len, + self.flags | ROOT, + ); + // The output length might not be a multiple of 4. + for (word, out_word) in words.iter().zip(out_block.chunks_mut(4)) { + out_word.copy_from_slice(&word.to_le_bytes()[..out_word.len()]); + } + } + } +} + +struct ChunkState { + chaining_value: [u32; 8], + chunk_counter: u64, + block: [u8; BLOCK_LEN], + block_len: u8, + blocks_compressed: u8, + flags: u32, +} + +impl ChunkState { + fn new(key_words: [u32; 8], chunk_counter: u64, flags: u32) -> Self { + Self { + chaining_value: key_words, + chunk_counter, + block: [0; BLOCK_LEN], + block_len: 0, + blocks_compressed: 0, + flags, + } + } + + fn len(&self) -> usize { + BLOCK_LEN * self.blocks_compressed as usize + self.block_len as usize + } + + fn start_flag(&self) -> u32 { + if self.blocks_compressed == 0 { + CHUNK_START + } else { + 0 + } + } + + fn update(&mut self, mut input: &[u8]) { + while !input.is_empty() { + // If the block buffer is full, compress it and clear it. More + // input is coming, so this compression is not CHUNK_END. + if self.block_len as usize == BLOCK_LEN { + let mut block_words = [0; 16]; + words_from_little_endian_bytes(&self.block, &mut block_words); + self.chaining_value = first_8_words(compress( + &self.chaining_value, + &block_words, + self.chunk_counter, + BLOCK_LEN as u32, + self.flags | self.start_flag(), + )); + self.blocks_compressed += 1; + self.block = [0; BLOCK_LEN]; + self.block_len = 0; + } + + // Copy input bytes into the block buffer. + let want = BLOCK_LEN - self.block_len as usize; + let take = min(want, input.len()); + self.block[self.block_len as usize..][..take].copy_from_slice(&input[..take]); + self.block_len += take as u8; + input = &input[take..]; + } + } + + fn output(&self) -> Output { + let mut block_words = [0; 16]; + words_from_little_endian_bytes(&self.block, &mut block_words); + Output { + input_chaining_value: self.chaining_value, + block_words, + counter: self.chunk_counter, + block_len: self.block_len as u32, + flags: self.flags | self.start_flag() | CHUNK_END, + } + } +} + +fn parent_output( + left_child_cv: [u32; 8], + right_child_cv: [u32; 8], + key_words: [u32; 8], + flags: u32, +) -> Output { + let mut block_words = [0; 16]; + block_words[..8].copy_from_slice(&left_child_cv); + block_words[8..].copy_from_slice(&right_child_cv); + Output { + input_chaining_value: key_words, + block_words, + counter: 0, // Always 0 for parent nodes. + block_len: BLOCK_LEN as u32, // Always BLOCK_LEN (64) for parent nodes. + flags: PARENT | flags, + } +} + +fn parent_cv( + left_child_cv: [u32; 8], + right_child_cv: [u32; 8], + key_words: [u32; 8], + flags: u32, +) -> [u32; 8] { + parent_output(left_child_cv, right_child_cv, key_words, flags).chaining_value() +} + +/// An incremental hasher that can accept any number of writes. +pub struct Hasher { + chunk_state: ChunkState, + key_words: [u32; 8], + cv_stack: [[u32; 8]; 54], // Space for 54 subtree chaining values: + cv_stack_len: u8, // 2^54 * CHUNK_LEN = 2^64 + flags: u32, +} + +impl Hasher { + fn new_internal(key_words: [u32; 8], flags: u32) -> Self { + Self { + chunk_state: ChunkState::new(key_words, 0, flags), + key_words, + cv_stack: [[0; 8]; 54], + cv_stack_len: 0, + flags, + } + } + + /// Construct a new `Hasher` for the regular hash function. + pub fn new() -> Self { + Self::new_internal(IV, 0) + } + + fn push_stack(&mut self, cv: [u32; 8]) { + self.cv_stack[self.cv_stack_len as usize] = cv; + self.cv_stack_len += 1; + } + + fn pop_stack(&mut self) -> [u32; 8] { + self.cv_stack_len -= 1; + self.cv_stack[self.cv_stack_len as usize] + } + + // Section 5.1.2 of the BLAKE3 spec explains this algorithm in more detail. + fn add_chunk_chaining_value(&mut self, mut new_cv: [u32; 8], mut total_chunks: u64) { + // This chunk might complete some subtrees. For each completed subtree, + // its left child will be the current top entry in the CV stack, and + // its right child will be the current value of `new_cv`. Pop each left + // child off the stack, merge it with `new_cv`, and overwrite `new_cv` + // with the result. After all these merges, push the final value of + // `new_cv` onto the stack. The number of completed subtrees is given + // by the number of trailing 0-bits in the new total number of chunks. + while total_chunks & 1 == 0 { + new_cv = parent_cv(self.pop_stack(), new_cv, self.key_words, self.flags); + total_chunks >>= 1; + } + self.push_stack(new_cv); + } + + /// Add input to the hash state. This can be called any number of times. + pub fn update(&mut self, mut input: &[u8]) { + while !input.is_empty() { + // If the current chunk is complete, finalize it and reset the + // chunk state. More input is coming, so this chunk is not ROOT. + if self.chunk_state.len() == CHUNK_LEN { + let chunk_cv = self.chunk_state.output().chaining_value(); + let total_chunks = self.chunk_state.chunk_counter + 1; + self.add_chunk_chaining_value(chunk_cv, total_chunks); + self.chunk_state = ChunkState::new(self.key_words, total_chunks, self.flags); + } + + // Compress input bytes into the current chunk state. + let want = CHUNK_LEN - self.chunk_state.len(); + let take = min(want, input.len()); + self.chunk_state.update(&input[..take]); + input = &input[take..]; + } + } + + /// Finalize the hash and write any number of output bytes. + pub fn finalize(&self, out_slice: &mut [u8]) { + // Starting with the Output from the current chunk, compute all the + // parent chaining values along the right edge of the tree, until we + // have the root Output. + let mut output = self.chunk_state.output(); + let mut parent_nodes_remaining = self.cv_stack_len as usize; + while parent_nodes_remaining > 0 { + parent_nodes_remaining -= 1; + output = parent_output( + self.cv_stack[parent_nodes_remaining], + output.chaining_value(), + self.key_words, + self.flags, + ); + } + output.root_output_bytes(out_slice); + } +} + +impl Default for Hasher { + fn default() -> Self { + Self::new() + } +} diff --git a/crates/tauri-codegen/src/vendor/mod.rs b/crates/tauri-codegen/src/vendor/mod.rs new file mode 100644 index 000000000000..323fa5884338 --- /dev/null +++ b/crates/tauri-codegen/src/vendor/mod.rs @@ -0,0 +1,11 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Manual vendored dependencies - NOT STABLE. +//! +//! This module and all submodules are not considered part of the public +//! api. They can and will change at any time for any reason in any +//! version. + +pub mod blake3_reference; diff --git a/crates/tauri-driver/CHANGELOG.md b/crates/tauri-driver/CHANGELOG.md new file mode 100644 index 000000000000..c685fef21f59 --- /dev/null +++ b/crates/tauri-driver/CHANGELOG.md @@ -0,0 +1,57 @@ +# Changelog + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +## \[0.1.5] + +### Bug Fixes + +- [`5f64ed2b7`](https://www.github.com/tauri-apps/tauri/commit/5f64ed2b78201b7e379b6234f7a799d9695b11d7) ([#10738](https://www.github.com/tauri-apps/tauri/pull/10738) by [@chippers](https://www.github.com/tauri-apps/tauri/../../chippers)) support both 1.x and 2.x automation env vars in `tauri-driver` + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +## \[0.1.4] + +### New Features + +- [`435d7513`](https://www.github.com/tauri-apps/tauri/commit/435d7513e45eab8b512e9a7e695a1adef8a98a46)([#8609](https://www.github.com/tauri-apps/tauri/pull/8609)) Added `webviewOptions` object to the `tauri:options` capability to configure the [Edge webview options](https://learn.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options#webviewoptions-object) on Windows. + +## \[0.1.3] + +### What's Changed + +- [`9edebbba`](https://www.github.com/tauri-apps/tauri/commit/9edebbba4ec472772b2f6307232e8d256f62c8ba)([#7475](https://www.github.com/tauri-apps/tauri/pull/7475)) Update locked dependencies to fix a Windows build issue when using them with a recent Rust compiler. +- [`9edebbba`](https://www.github.com/tauri-apps/tauri/commit/9edebbba4ec472772b2f6307232e8d256f62c8ba)([#7475](https://www.github.com/tauri-apps/tauri/pull/7475)) Bump minimum Rust version to `1.60` to be in line with the rest of the Tauri project. + +## \[0.1.2] + +- Expose `native-host` option in tauri-driver and set default to `127.0.0.1`. + - [cd9dfc7b](https://www.github.com/tauri-apps/tauri/commit/cd9dfc7b9a3fe0e04e40d9b0f9be674aefd0d725) fix(driver): expose native-host option and set default to 127.0.0.1 ([#3816](https://www.github.com/tauri-apps/tauri/pull/3816)) on 2022-03-31 + +## \[0.1.1] + +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 +- Add `args` field (array of application CLI arguments) to the `tauri:options` capabilities. + - [d0970e34](https://www.github.com/tauri-apps/tauri/commit/d0970e3499297a6c102a36f2dc479d3d657bfaf3) feat(driver): add `args` to `tauri:options` ([#3154](https://www.github.com/tauri-apps/tauri/pull/3154)) on 2022-01-03 + +## \[0.1.0] + +- Initial release including Linux and Windows support. + - [be76fb1d](https://www.github.com/tauri-apps/tauri/commit/be76fb1dfe73a1605cc2ad246418579f4c2e1999) WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972)) on 2021-06-23 + - [c22e5a7c](https://www.github.com/tauri-apps/tauri/commit/c22e5a7c2ebede41657973b80eff6b68106817fc) fix(covector): keep `tauri-driver` version as alpha on 2021-06-23 + - [b4426eda](https://www.github.com/tauri-apps/tauri/commit/b4426eda9e64fcdd25a2d72e548b8b0fbfa09619) Revert "WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972))" on 2021-06-23 + - [4b2aa356](https://www.github.com/tauri-apps/tauri/commit/4b2aa35684632ed2afd7dec4ad848df5704868e4) Add back WebDriver support ([#2324](https://www.github.com/tauri-apps/tauri/pull/2324)) on 2021-08-01 diff --git a/crates/tauri-driver/Cargo.toml b/crates/tauri-driver/Cargo.toml new file mode 100644 index 000000000000..38a5716a7aa8 --- /dev/null +++ b/crates/tauri-driver/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "tauri-driver" +version = "2.0.1" +authors = ["Tauri Programme within The Commons Conservancy"] +categories = ["gui", "web-programming"] +license = "Apache-2.0 OR MIT" +homepage = "https://tauri.app" +repository = "https://github.com/tauri-apps/tauri" +description = "Webdriver server for Tauri applications" +readme = "README.md" +edition = "2021" +rust-version = "1.77.2" + +[dependencies] +anyhow = "1" +hyper = { version = "0.14", features = [ + "client", + "http1", + "runtime", + "server", + "stream", + "tcp", +] } +futures = "0.3" +futures-util = "0.3" +pico-args = "0.4" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tokio = { version = "1", features = ["macros"] } +which = "4" + +[target."cfg(unix)".dependencies] +signal-hook = "0.3" +signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } diff --git a/crates/tauri-driver/LICENSE.spdx b/crates/tauri-driver/LICENSE.spdx new file mode 100644 index 000000000000..12947c5c4b77 --- /dev/null +++ b/crates/tauri-driver/LICENSE.spdx @@ -0,0 +1 @@ +../../LICENSE.spdx \ No newline at end of file diff --git a/crates/tauri-driver/LICENSE_APACHE-2.0 b/crates/tauri-driver/LICENSE_APACHE-2.0 new file mode 100644 index 000000000000..c7abb8c4f6aa --- /dev/null +++ b/crates/tauri-driver/LICENSE_APACHE-2.0 @@ -0,0 +1 @@ +../../LICENSE_APACHE-2.0 \ No newline at end of file diff --git a/crates/tauri-driver/LICENSE_MIT b/crates/tauri-driver/LICENSE_MIT new file mode 100644 index 000000000000..0304881f49d7 --- /dev/null +++ b/crates/tauri-driver/LICENSE_MIT @@ -0,0 +1 @@ +../../LICENSE_MIT \ No newline at end of file diff --git a/crates/tauri-driver/README.md b/crates/tauri-driver/README.md new file mode 100644 index 000000000000..b3867bbf5489 --- /dev/null +++ b/crates/tauri-driver/README.md @@ -0,0 +1,36 @@ +# `tauri-driver` _(pre-alpha)_ + +Cross-platform WebDriver server for Tauri applications. + +This is a [WebDriver Intermediary Node] that wraps the native WebDriver server +for platforms that [Tauri] supports. Your WebDriver client will connect to the +running `tauri-driver` server, and `tauri-driver` will handle starting the +native WebDriver server for you behind the scenes. It requires two separate +ports to be used since two distinct [WebDriver Remote Ends] run. + +You can configure the ports used with arguments when starting the binary: + +- `--port` (default: `4444`) +- `--native-port` (default: `4445`) + +Supported platforms: + +- **[pre-alpha]** Linux w/ `WebKitWebDriver` +- **[pre-alpha]** Windows w/ [Microsoft Edge Driver] +- **[Todo]** macOS w/ [Appium Mac2 Driver] (probably) + +_note: the (probably) items haven't been proof-of-concept'd yet, and if it is +not possible to use the listed native webdriver, then a custom implementation +will be used that wraps around [wry]._ + +## Trying it out + +Check out the documentation at https://tauri.app/docs/testing/webdriver/introduction, +including a small example application with WebDriver tests. + +[WebDriver Intermediary Node]: https://www.w3.org/TR/webdriver/#dfn-intermediary-nodes +[WebDriver Remote Ends]: https://www.w3.org/TR/webdriver/#dfn-remote-ends +[Microsoft Edge Driver]: https://developer.microsoft.com/en-us/microsoft-edge/tools/webdriver/ +[Appium Mac2 Driver]: https://github.com/appium/appium-mac2-driver +[wry]: https://github.com/tauri-apps/wry +[Tauri]: https://github.com/tauri-apps/tauri diff --git a/crates/tauri-driver/src/cli.rs b/crates/tauri-driver/src/cli.rs new file mode 100644 index 000000000000..f8e81b46fba7 --- /dev/null +++ b/crates/tauri-driver/src/cli.rs @@ -0,0 +1,63 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::path::PathBuf; + +const HELP: &str = "\ +USAGE: tauri-driver [FLAGS] [OPTIONS] + +FLAGS: + -h, --help Prints help information + +OPTIONS: + --port NUMBER Sets the tauri-driver intermediary port + --native-port NUMBER Sets the port of the underlying WebDriver + --native-host HOST Sets the host of the underlying WebDriver (Linux only) + --native-driver PATH Sets the path to the native WebDriver binary +"; + +#[derive(Debug, Clone)] +pub struct Args { + pub port: u16, + pub native_port: u16, + pub native_host: String, + pub native_driver: Option, +} + +impl From for Args { + fn from(mut args: pico_args::Arguments) -> Self { + // if the user wanted help, we don't care about parsing the rest of the args + if args.contains(["-h", "--help"]) { + println!("{}", HELP); + std::process::exit(0); + } + + let native_driver = match args.opt_value_from_str("--native-driver") { + Ok(native_driver) => native_driver, + Err(e) => { + eprintln!("Error while parsing option --native-driver: {}", e); + std::process::exit(1); + } + }; + + let parsed = Args { + port: args.value_from_str("--port").unwrap_or(4444), + native_port: args.value_from_str("--native-port").unwrap_or(4445), + native_host: args + .value_from_str("--native-host") + .unwrap_or(String::from("127.0.0.1")), + native_driver, + }; + + // be strict about accepting args, error for anything extraneous + let rest = args.finish(); + if !rest.is_empty() { + eprintln!("Error: unused arguments left: {:?}", rest); + eprintln!("{}", HELP); + std::process::exit(1); + } + + parsed + } +} diff --git a/crates/tauri-driver/src/main.rs b/crates/tauri-driver/src/main.rs new file mode 100644 index 000000000000..6967b2ccf03b --- /dev/null +++ b/crates/tauri-driver/src/main.rs @@ -0,0 +1,42 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Cross-platform WebDriver server for Tauri applications. +//! +//! This is a [WebDriver Intermediary Node](https://www.w3.org/TR/webdriver/#dfn-intermediary-nodes) that wraps the native WebDriver server for platforms that [Tauri](https://github.com/tauri-apps/tauri) supports. Your WebDriver client will connect to the running `tauri-driver` server, and `tauri-driver` will handle starting the native WebDriver server for you behind the scenes. It requires two separate ports to be used since two distinct [WebDriver Remote Ends](https://www.w3.org/TR/webdriver/#dfn-remote-ends) run. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +#[cfg(any(target_os = "linux", windows))] +mod cli; +#[cfg(any(target_os = "linux", windows))] +mod server; +#[cfg(any(target_os = "linux", windows))] +mod webdriver; + +#[cfg(not(any(target_os = "linux", windows)))] +fn main() { + println!("tauri-driver is not supported on this platform"); + std::process::exit(1); +} + +#[cfg(any(target_os = "linux", windows))] +fn main() { + let args = pico_args::Arguments::from_env().into(); + + // start the native webdriver on the port specified in args + let mut driver = webdriver::native(&args); + let driver = driver + .spawn() + .expect("error while running native webdriver"); + + // start our webdriver intermediary node + if let Err(e) = server::run(args, driver) { + eprintln!("error while running server: {}", e); + std::process::exit(1); + } +} diff --git a/tooling/webdriver/src/server.rs b/crates/tauri-driver/src/server.rs similarity index 91% rename from tooling/webdriver/src/server.rs rename to crates/tauri-driver/src/server.rs index be87e238a884..93366b2994d9 100644 --- a/tooling/webdriver/src/server.rs +++ b/crates/tauri-driver/src/server.rs @@ -1,10 +1,10 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT use crate::cli::Args; use anyhow::Error; -use futures::TryFutureExt; +use futures_util::TryFutureExt; use hyper::header::CONTENT_LENGTH; use hyper::http::uri::Authority; use hyper::service::{make_service_fn, service_fn}; @@ -20,10 +20,14 @@ type HttpClient = Client; const TAURI_OPTIONS: &str = "tauri:options"; #[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] struct TauriOptions { application: PathBuf, #[serde(default)] args: Vec, + #[cfg(target_os = "windows")] + #[serde(default)] + webview_options: Option, } impl TauriOptions { @@ -44,7 +48,7 @@ impl TauriOptions { map.insert("browserName".into(), json!("webview2")); map.insert( "ms:edgeOptions".into(), - json!({"binary": self.application, "args": self.args}), + json!({"binary": self.application, "args": self.args, "webviewOptions": self.webview_options}), ); map } @@ -141,13 +145,14 @@ fn map_capabilities(mut json: Value) -> Value { pub async fn run(args: Args, mut _driver: Child) -> Result<(), Error> { #[cfg(unix)] let (signals_handle, signals_task) = { - use futures::StreamExt; + use futures_util::StreamExt; use signal_hook::consts::signal::*; - let signals = signal_hook_tokio::Signals::new(&[SIGTERM, SIGINT, SIGQUIT])?; + let signals = signal_hook_tokio::Signals::new([SIGTERM, SIGINT, SIGQUIT])?; let signals_handle = signals.handle(); let signals_task = tokio::spawn(async move { let mut signals = signals.fuse(); + #[allow(clippy::never_loop)] while let Some(signal) = signals.next().await { match signal { SIGTERM | SIGINT | SIGQUIT => { diff --git a/tooling/webdriver/src/webdriver.rs b/crates/tauri-driver/src/webdriver.rs similarity index 87% rename from tooling/webdriver/src/webdriver.rs rename to crates/tauri-driver/src/webdriver.rs index 177b17d18704..6de4d41422d2 100644 --- a/tooling/webdriver/src/webdriver.rs +++ b/crates/tauri-driver/src/webdriver.rs @@ -1,4 +1,4 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT @@ -45,7 +45,9 @@ pub fn native(args: &Args) -> Command { }; let mut cmd = Command::new(native_binary); - cmd.env("TAURI_AUTOMATION", "true"); + cmd.env("TAURI_AUTOMATION", "true"); // 1.x + cmd.env("TAURI_WEBVIEW_AUTOMATION", "true"); // 2.x cmd.arg(format!("--port={}", args.native_port)); + cmd.arg(format!("--host={}", args.native_host)); cmd } diff --git a/crates/tauri-macos-sign/CHANGELOG.md b/crates/tauri-macos-sign/CHANGELOG.md new file mode 100644 index 000000000000..b8250b5e15a8 --- /dev/null +++ b/crates/tauri-macos-sign/CHANGELOG.md @@ -0,0 +1,32 @@ +# Changelog + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +## \[0.1.1-rc.1] + +### Enhancements + +- [`f5d61822b`](https://www.github.com/tauri-apps/tauri/commit/f5d61822bf5988827776dd58bed75c19364e86bd) ([#11184](https://www.github.com/tauri-apps/tauri/pull/11184) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Added `Keychain::with_certificate_file` and `certificate::generate_self_signed`. + +## \[0.1.1-rc.0] + +### Bug Fixes + +- [`1b0c447fc`](https://www.github.com/tauri-apps/tauri/commit/1b0c447fcbc424e08e4260277ec178df86f45d1d) ([#10654](https://www.github.com/tauri-apps/tauri/pull/10654) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fixes output not visible when running on Node.js via NAPI. + +## \[0.1.0-beta.0] + +### New Features + +- [`7c7fa0964`](https://www.github.com/tauri-apps/tauri/commit/7c7fa0964db3403037fdb9a34de2b877ddb8df1c) ([#9963](https://www.github.com/tauri-apps/tauri/pull/9963) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Initial release. diff --git a/crates/tauri-macos-sign/Cargo.toml b/crates/tauri-macos-sign/Cargo.toml new file mode 100644 index 000000000000..8fd33172827c --- /dev/null +++ b/crates/tauri-macos-sign/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "tauri-macos-sign" +version = "2.0.1" +authors = ["Tauri Programme within The Commons Conservancy"] +license = "Apache-2.0 OR MIT" +keywords = ["codesign", "signing", "macos", "ios", "tauri"] +repository = "https://github.com/tauri-apps/tauri" +description = "Code signing utilities for macOS and iOS apps" +edition = "2021" +rust-version = "1.77.2" + +[dependencies] +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" +tempfile = "3" +x509-certificate = "0.23" +once-cell-regex = "0.2" +os_pipe = "1" +plist = "1" +rand = "0.8" +dirs-next = "2" +log = { version = "0.4.21", features = ["kv"] } +apple-codesign = "0.27" +chrono = "0.4.38" +p12 = "0.6" diff --git a/crates/tauri-macos-sign/README.md b/crates/tauri-macos-sign/README.md new file mode 100644 index 000000000000..b9e4ebe2ea0a --- /dev/null +++ b/crates/tauri-macos-sign/README.md @@ -0,0 +1,3 @@ +# Tauri MacOS Sign + +Utilities for setting up macOS certificates, code signing and notarization for macOS and iOS apps. diff --git a/crates/tauri-macos-sign/src/certificate.rs b/crates/tauri-macos-sign/src/certificate.rs new file mode 100644 index 000000000000..97afa2199eac --- /dev/null +++ b/crates/tauri-macos-sign/src/certificate.rs @@ -0,0 +1,65 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use anyhow::{Context, Result}; +use apple_codesign::create_self_signed_code_signing_certificate; +use x509_certificate::{EcdsaCurve, KeyAlgorithm}; + +pub use apple_codesign::CertificateProfile; + +/// Self signed certificate options. +pub struct SelfSignedCertificateRequest { + /// Which key type to use + pub algorithm: String, + + /// Profile + pub profile: CertificateProfile, + + /// Team ID (this is a short string attached to your Apple Developer account) + pub team_id: String, + + /// The name of the person this certificate is for + pub person_name: String, + + /// Country Name (C) value for certificate identifier + pub country_name: String, + + /// How many days the certificate should be valid for + pub validity_days: i64, + + /// Certificate password. + pub password: String, +} + +pub fn generate_self_signed(request: SelfSignedCertificateRequest) -> Result> { + let algorithm = match request.algorithm.as_str() { + "ecdsa" => KeyAlgorithm::Ecdsa(EcdsaCurve::Secp256r1), + "ed25519" => KeyAlgorithm::Ed25519, + "rsa" => KeyAlgorithm::Rsa, + value => panic!("algorithm values should have been validated by arg parser: {value}"), + }; + + let validity_duration = chrono::Duration::days(request.validity_days); + + let (cert, key_pair) = create_self_signed_code_signing_certificate( + algorithm, + request.profile, + &request.team_id, + &request.person_name, + &request.country_name, + validity_duration, + )?; + + let pfx = p12::PFX::new( + &cert.encode_der()?, + &key_pair.to_pkcs8_one_asymmetric_key_der(), + None, + &request.password, + "code-signing", + ) + .context("failed to create PFX structure")?; + let der = pfx.to_der(); + + Ok(der) +} diff --git a/crates/tauri-macos-sign/src/keychain.rs b/crates/tauri-macos-sign/src/keychain.rs new file mode 100644 index 000000000000..2ef256d32cd9 --- /dev/null +++ b/crates/tauri-macos-sign/src/keychain.rs @@ -0,0 +1,223 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{ + ffi::OsString, + path::{Path, PathBuf}, + process::Command, +}; + +use crate::{assert_command, CommandExt}; +use anyhow::Result; +use rand::distributions::{Alphanumeric, DistString}; + +mod identity; + +pub use identity::Team; + +pub enum SigningIdentity { + Team(Team), + Identifier(String), +} + +pub struct Keychain { + // none means the default keychain must be used + path: Option, + signing_identity: SigningIdentity, +} + +impl Drop for Keychain { + fn drop(&mut self) { + if let Some(path) = &self.path { + let _ = Command::new("security") + .arg("delete-keychain") + .arg(path) + .piped(); + } + } +} + +impl Keychain { + /// Use a certificate in the default keychain. + pub fn with_signing_identity(identity: impl Into) -> Self { + Self { + path: None, + signing_identity: SigningIdentity::Identifier(identity.into()), + } + } + + /// Import certificate from base64 string. + /// certificate_encoded is the p12 certificate base64 encoded. + /// By example you can use; openssl base64 -in MyCertificate.p12 -out MyCertificate-base64.txt + /// Then use the value of the base64 as `certificate_encoded`. + /// You need to set certificate_password to the password you set when you exported your certificate. + /// see: `Export a signing certificate` + pub fn with_certificate( + certificate_encoded: &OsString, + certificate_password: &OsString, + ) -> Result { + let tmp_dir = tempfile::tempdir()?; + let cert_path = tmp_dir.path().join("cert.p12"); + super::decode_base64(certificate_encoded, &cert_path)?; + Self::with_certificate_file(&cert_path, certificate_password) + } + + pub fn with_certificate_file(cert_path: &Path, certificate_password: &OsString) -> Result { + let home_dir = + dirs_next::home_dir().ok_or_else(|| anyhow::anyhow!("failed to resolve home dir"))?; + let keychain_path = home_dir.join("Library").join("Keychains").join(format!( + "{}.keychain-db", + Alphanumeric.sample_string(&mut rand::thread_rng(), 16) + )); + let keychain_password = Alphanumeric.sample_string(&mut rand::thread_rng(), 16); + + let keychain_list_output = Command::new("security") + .args(["list-keychain", "-d", "user"]) + .output()?; + + assert_command( + Command::new("security") + .args(["create-keychain", "-p", &keychain_password]) + .arg(&keychain_path) + .piped(), + "failed to create keychain", + )?; + + assert_command( + Command::new("security") + .args(["unlock-keychain", "-p", &keychain_password]) + .arg(&keychain_path) + .piped(), + "failed to set unlock keychain", + )?; + + assert_command( + Command::new("security") + .arg("import") + .arg(cert_path) + .arg("-P") + .arg(certificate_password) + .args([ + "-T", + "/usr/bin/codesign", + "-T", + "/usr/bin/pkgbuild", + "-T", + "/usr/bin/productbuild", + ]) + .arg("-k") + .arg(&keychain_path) + .piped(), + "failed to import keychain certificate", + )?; + + assert_command( + Command::new("security") + .args(["set-keychain-settings", "-t", "3600", "-u"]) + .arg(&keychain_path) + .piped(), + "failed to set keychain settings", + )?; + + assert_command( + Command::new("security") + .args([ + "set-key-partition-list", + "-S", + "apple-tool:,apple:,codesign:", + "-s", + "-k", + &keychain_password, + ]) + .arg(&keychain_path) + .piped(), + "failed to set keychain settings", + )?; + + let current_keychains = String::from_utf8_lossy(&keychain_list_output.stdout) + .split('\n') + .map(|line| { + line + .trim_matches(|c: char| c.is_whitespace() || c == '"') + .to_string() + }) + .filter(|l| !l.is_empty()) + .collect::>(); + + assert_command( + Command::new("security") + .args(["list-keychain", "-d", "user", "-s"]) + .args(current_keychains) + .arg(&keychain_path) + .piped(), + "failed to list keychain", + )?; + + let signing_identity = identity::list(&keychain_path) + .map(|l| l.first().cloned())? + .ok_or_else(|| anyhow::anyhow!("failed to resolve signing identity"))?; + + Ok(Self { + path: Some(keychain_path), + signing_identity: SigningIdentity::Team(signing_identity), + }) + } + + pub fn signing_identity(&self) -> String { + match &self.signing_identity { + SigningIdentity::Team(t) => t.certificate_name(), + SigningIdentity::Identifier(i) => i.to_string(), + } + } + + pub fn team_id(&self) -> Option<&str> { + match &self.signing_identity { + SigningIdentity::Team(t) => Some(&t.id), + SigningIdentity::Identifier(_) => None, + } + } + + pub fn sign( + &self, + path: &Path, + entitlements_path: Option<&Path>, + hardened_runtime: bool, + ) -> Result<()> { + let identity = match &self.signing_identity { + SigningIdentity::Team(t) => t.certificate_name(), + SigningIdentity::Identifier(i) => i.clone(), + }; + println!("Signing with identity \"{}\"", identity); + + println!("Signing {}", path.display()); + + let mut args = vec!["--force", "-s", &identity]; + + if hardened_runtime { + args.push("--options"); + args.push("runtime"); + } + + let mut codesign = Command::new("codesign"); + codesign.args(args); + if let Some(p) = &self.path { + codesign.arg("--keychain").arg(p); + } + + if let Some(entitlements_path) = entitlements_path { + codesign.arg("--entitlements"); + codesign.arg(entitlements_path); + } + + codesign.arg(path); + + assert_command(codesign.piped(), "failed to sign app")?; + + Ok(()) + } + + pub fn path(&self) -> Option<&Path> { + self.path.as_deref() + } +} diff --git a/crates/tauri-macos-sign/src/keychain/identity.rs b/crates/tauri-macos-sign/src/keychain/identity.rs new file mode 100644 index 000000000000..3e57a90722f9 --- /dev/null +++ b/crates/tauri-macos-sign/src/keychain/identity.rs @@ -0,0 +1,118 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use anyhow::Context; +use once_cell_regex::regex; +use std::{collections::BTreeSet, path::Path, process::Command}; +use x509_certificate::certificate::X509Certificate; + +use crate::Result; + +fn get_pem_list(keychain_path: &Path, name_substr: &str) -> std::io::Result { + Command::new("security") + .arg("find-certificate") + .args(["-p", "-a"]) + .arg("-c") + .arg(name_substr) + .arg(keychain_path) + .stdin(os_pipe::dup_stdin().unwrap()) + .stderr(os_pipe::dup_stderr().unwrap()) + .output() +} + +#[derive(Debug, Clone, Eq, Ord, PartialEq, PartialOrd)] +pub struct Team { + pub name: String, + pub certificate_name: String, + pub id: String, + pub cert_prefix: &'static str, +} + +impl Team { + fn from_x509(cert_prefix: &'static str, cert: X509Certificate) -> Result { + let common_name = cert + .subject_common_name() + .ok_or_else(|| anyhow::anyhow!("skipping cert, missing common name"))?; + + let organization = cert + .subject_name() + .iter_organization() + .next() + .and_then(|v| v.to_string().ok()); + + let name = if let Some(organization) = organization { + println!( + "found cert {:?} with organization {:?}", + common_name, organization + ); + organization + } else { + println!( + "found cert {:?} but failed to get organization; falling back to displaying common name", + common_name + ); + regex!(r"Apple Develop\w+: (.*) \(.+\)") + .captures(&common_name) + .map(|caps| caps[1].to_owned()) + .unwrap_or_else(|| { + println!("regex failed to capture nice part of name in cert {:?}; falling back to displaying full name", common_name); + common_name.clone() + }) + }; + + let id = cert + .subject_name() + .iter_organizational_unit() + .next() + .and_then(|v| v.to_string().ok()) + .ok_or_else(|| anyhow::anyhow!("skipping cert {common_name}: missing Organization Unit"))?; + + Ok(Self { + name, + certificate_name: common_name, + id, + cert_prefix, + }) + } + + pub fn certificate_name(&self) -> String { + self.certificate_name.clone() + } +} + +pub fn list(keychain_path: &Path) -> Result> { + let certs = { + let mut certs = Vec::new(); + for cert_prefix in [ + "iOS Distribution:", + "Apple Distribution:", + "Developer ID Application:", + "Mac App Distribution:", + "Apple Development:", + "iOS App Development:", + "Mac Development:", + ] { + let pem_list_out = + get_pem_list(keychain_path, cert_prefix).context("Failed to call `security` command")?; + let cert_list = X509Certificate::from_pem_multiple(pem_list_out.stdout) + .context("Failed to parse X509 cert")?; + certs.extend(cert_list.into_iter().map(|cert| (cert_prefix, cert))); + } + certs + }; + Ok( + certs + .into_iter() + .flat_map(|(cert_prefix, cert)| { + Team::from_x509(cert_prefix, cert).map_err(|err| { + eprintln!("{}", err); + err + }) + }) + // Silly way to sort this and ensure no dupes + .collect::>() + .into_iter() + .collect(), + ) +} diff --git a/crates/tauri-macos-sign/src/lib.rs b/crates/tauri-macos-sign/src/lib.rs new file mode 100644 index 000000000000..456fc6cb455e --- /dev/null +++ b/crates/tauri-macos-sign/src/lib.rs @@ -0,0 +1,273 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{ + ffi::{OsStr, OsString}, + path::{Path, PathBuf}, + process::{Command, ExitStatus}, +}; + +use anyhow::{Context, Result}; +use serde::Deserialize; + +pub mod certificate; +mod keychain; +mod provisioning_profile; + +pub use keychain::{Keychain, Team}; +pub use provisioning_profile::ProvisioningProfile; + +trait CommandExt { + // The `pipe` function sets the stdout and stderr to properly + // show the command output in the Node.js wrapper. + fn piped(&mut self) -> std::io::Result; +} + +impl CommandExt for Command { + fn piped(&mut self) -> std::io::Result { + self.stdin(os_pipe::dup_stdin()?); + self.stdout(os_pipe::dup_stdout()?); + self.stderr(os_pipe::dup_stderr()?); + let program = self.get_program().to_string_lossy().into_owned(); + log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}"))); + + self.status().map_err(Into::into) + } +} + +pub enum ApiKey { + Path(PathBuf), + Raw(Vec), +} + +pub enum AppleNotarizationCredentials { + AppleId { + apple_id: OsString, + password: OsString, + team_id: OsString, + }, + ApiKey { + issuer: OsString, + key_id: OsString, + key: ApiKey, + }, +} + +#[derive(Deserialize)] +struct NotarytoolSubmitOutput { + id: String, + status: String, + message: String, +} + +pub fn notarize( + keychain: &Keychain, + app_bundle_path: &Path, + auth: &AppleNotarizationCredentials, +) -> Result<()> { + let bundle_stem = app_bundle_path + .file_stem() + .expect("failed to get bundle filename"); + + let tmp_dir = tempfile::tempdir()?; + let zip_path = tmp_dir + .path() + .join(format!("{}.zip", bundle_stem.to_string_lossy())); + let zip_args = vec![ + "-c", + "-k", + "--keepParent", + "--sequesterRsrc", + app_bundle_path + .to_str() + .expect("failed to convert bundle_path to string"), + zip_path + .to_str() + .expect("failed to convert zip_path to string"), + ]; + + // use ditto to create a PKZip almost identical to Finder + // this remove almost 99% of false alarm in notarization + assert_command( + Command::new("ditto").args(zip_args).piped(), + "failed to zip app with ditto", + )?; + + // sign the zip file + keychain.sign(&zip_path, None, false)?; + + let notarize_args = vec![ + "notarytool", + "submit", + zip_path + .to_str() + .expect("failed to convert zip_path to string"), + "--wait", + "--output-format", + "json", + ]; + + println!("Notarizing {}", app_bundle_path.display()); + + let output = Command::new("xcrun") + .args(notarize_args) + .notarytool_args(auth, tmp_dir.path())? + .output() + .context("failed to upload app to Apple's notarization servers.")?; + + if !output.status.success() { + return Err( + anyhow::anyhow!("failed to notarize app") + .context(String::from_utf8_lossy(&output.stderr).into_owned()), + ); + } + + let output_str = String::from_utf8_lossy(&output.stdout); + if let Ok(submit_output) = serde_json::from_str::(&output_str) { + let log_message = format!( + "Finished with status {} for id {} ({})", + submit_output.status, submit_output.id, submit_output.message + ); + if submit_output.status == "Accepted" { + println!("Notarizing {}", log_message); + staple_app(app_bundle_path.to_path_buf())?; + Ok(()) + } else if let Ok(output) = Command::new("xcrun") + .args(["notarytool", "log"]) + .arg(&submit_output.id) + .notarytool_args(auth, tmp_dir.path())? + .output() + { + Err(anyhow::anyhow!( + "{log_message}\nLog:\n{}", + String::from_utf8_lossy(&output.stdout) + )) + } else { + Err(anyhow::anyhow!("{log_message}")) + } + } else { + Err(anyhow::anyhow!( + "failed to parse notarytool output as JSON: `{output_str}`" + )) + } +} + +fn staple_app(mut app_bundle_path: PathBuf) -> Result<()> { + let app_bundle_path_clone = app_bundle_path.clone(); + let filename = app_bundle_path_clone + .file_name() + .expect("failed to get bundle filename") + .to_str() + .expect("failed to convert bundle filename to string"); + + app_bundle_path.pop(); + + Command::new("xcrun") + .args(vec!["stapler", "staple", "-v", filename]) + .current_dir(app_bundle_path) + .output() + .context("failed to staple app.")?; + + Ok(()) +} + +pub trait NotarytoolCmdExt { + fn notarytool_args( + &mut self, + auth: &AppleNotarizationCredentials, + temp_dir: &Path, + ) -> Result<&mut Self>; +} + +impl NotarytoolCmdExt for Command { + fn notarytool_args( + &mut self, + auth: &AppleNotarizationCredentials, + temp_dir: &Path, + ) -> Result<&mut Self> { + match auth { + AppleNotarizationCredentials::AppleId { + apple_id, + password, + team_id, + } => Ok( + self + .arg("--apple-id") + .arg(apple_id) + .arg("--password") + .arg(password) + .arg("--team-id") + .arg(team_id), + ), + AppleNotarizationCredentials::ApiKey { + key, + key_id, + issuer, + } => { + let key_path = match key { + ApiKey::Raw(k) => { + let key_path = temp_dir.join("AuthKey.p8"); + std::fs::write(&key_path, k)?; + key_path + } + ApiKey::Path(p) => p.to_owned(), + }; + + Ok( + self + .arg("--key-id") + .arg(key_id) + .arg("--key") + .arg(key_path) + .arg("--issuer") + .arg(issuer), + ) + } + } + } +} + +fn decode_base64(base64: &OsStr, out_path: &Path) -> Result<()> { + let tmp_dir = tempfile::tempdir()?; + + let src_path = tmp_dir.path().join("src"); + let base64 = base64 + .to_str() + .expect("failed to convert base64 to string") + .as_bytes(); + + // as base64 contain whitespace decoding may be broken + // https://github.com/marshallpierce/rust-base64/issues/105 + // we'll use builtin base64 command from the OS + std::fs::write(&src_path, base64)?; + + assert_command( + std::process::Command::new("base64") + .arg("--decode") + .arg("-i") + .arg(&src_path) + .arg("-o") + .arg(out_path) + .piped(), + "failed to decode certificate", + )?; + + Ok(()) +} + +fn assert_command( + response: Result, + error_message: &str, +) -> std::io::Result<()> { + let status = + response.map_err(|e| std::io::Error::new(e.kind(), format!("{error_message}: {e}")))?; + if !status.success() { + Err(std::io::Error::new( + std::io::ErrorKind::Other, + error_message, + )) + } else { + Ok(()) + } +} diff --git a/crates/tauri-macos-sign/src/provisioning_profile.rs b/crates/tauri-macos-sign/src/provisioning_profile.rs new file mode 100644 index 000000000000..1e9d0af37596 --- /dev/null +++ b/crates/tauri-macos-sign/src/provisioning_profile.rs @@ -0,0 +1,52 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{ffi::OsStr, path::PathBuf, process::Command}; + +use anyhow::{Context, Result}; +use rand::distributions::{Alphanumeric, DistString}; + +pub struct ProvisioningProfile { + path: PathBuf, +} + +impl ProvisioningProfile { + pub fn from_base64(base64: &OsStr) -> Result { + let home_dir = dirs_next::home_dir().unwrap(); + let provisioning_profiles_folder = home_dir + .join("Library") + .join("MobileDevice") + .join("Provisioning Profiles"); + std::fs::create_dir_all(&provisioning_profiles_folder).unwrap(); + + let provisioning_profile_path = provisioning_profiles_folder.join(format!( + "{}.mobileprovision", + Alphanumeric.sample_string(&mut rand::thread_rng(), 16) + )); + super::decode_base64(base64, &provisioning_profile_path)?; + + Ok(Self { + path: provisioning_profile_path, + }) + } + + pub fn uuid(&self) -> Result { + let output = Command::new("security") + .args(["cms", "-D", "-i"]) + .arg(&self.path) + .output()?; + + if !output.status.success() { + return Err(anyhow::anyhow!("failed to decode provisioning profile")); + } + + let plist = plist::from_bytes::(&output.stdout) + .context("failed to decode provisioning profile as plist")?; + + plist + .get("UUID") + .and_then(|v| v.as_string().map(ToString::to_string)) + .ok_or_else(|| anyhow::anyhow!("could not find provisioning profile UUID")) + } +} diff --git a/crates/tauri-macros/CHANGELOG.md b/crates/tauri-macros/CHANGELOG.md new file mode 100644 index 000000000000..3c80b3359ff7 --- /dev/null +++ b/crates/tauri-macros/CHANGELOG.md @@ -0,0 +1,716 @@ +# Changelog + +## \[2.0.3] + +### Enhancements + +- [`17c6952ae`](https://www.github.com/tauri-apps/tauri/commit/17c6952aec965fa41e6695ad68461a218afc20f1) ([#11522](https://www.github.com/tauri-apps/tauri/pull/11522) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Enhance the error message when using `async` commands with a reference. + +### Dependencies + +- Upgraded to `tauri-utils@2.1.0` +- Upgraded to `tauri-codegen@2.0.3` + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.1` +- Upgraded to `tauri-codegen@2.0.1` + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0` +- Upgraded to `tauri-codegen@2.0.0` + +## \[2.0.0-rc.12] + +### New Features + +- [`1d8b67b29`](https://www.github.com/tauri-apps/tauri/commit/1d8b67b2970a09ec478093e127612fac823de805) ([#11162](https://www.github.com/tauri-apps/tauri/pull/11162) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Support async functions for `mobile_entry_point` macro + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.13` +- Upgraded to `tauri-codegen@2.0.0-rc.13` + +## \[2.0.0-rc.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.12` +- Upgraded to `tauri-codegen@2.0.0-rc.12` + +## \[2.0.0-rc.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.11` +- Upgraded to `tauri-codegen@2.0.0-rc.11` + +## \[2.0.0-rc.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.10` +- Upgraded to `tauri-codegen@2.0.0-rc.10` + +## \[2.0.0-rc.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.9` +- Upgraded to `tauri-codegen@2.0.0-rc.9` + +## \[2.0.0-rc.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.8` +- Upgraded to `tauri-codegen@2.0.0-rc.8` + +## \[2.0.0-rc.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.7` +- Upgraded to `tauri-codegen@2.0.0-rc.7` + +## \[2.0.0-rc.6] + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.6` +- Upgraded to `tauri-codegen@2.0.0-rc.6` + +## \[2.0.0-rc.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.5` +- Upgraded to `tauri-codegen@2.0.0-rc.5` + +## \[2.0.0-rc.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.4` +- Upgraded to `tauri-codegen@2.0.0-rc.4` + +## \[2.0.0-rc.3] + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-rc.3` +- Upgraded to `tauri-utils@2.0.0-rc.3` + +## \[2.0.0-rc.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.2` +- Upgraded to `tauri-codegen@2.0.0-rc.2` + +## \[2.0.0-rc.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.1` +- Upgraded to `tauri-codegen@2.0.0-rc.1` + +## \[2.0.0-rc.0] + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-rc.0` +- Upgraded to `tauri-utils@2.0.0-rc.0` + +## \[2.0.0-beta.19] + +### What's Changed + +- [`4c239729c`](https://www.github.com/tauri-apps/tauri/commit/4c239729c3e1b899ecbc6793c3682848e8de1729) ([#10167](https://www.github.com/tauri-apps/tauri/pull/10167) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add support for `test = true` in `generate_context!` macro to skip some code generation that could affect some tests, for now it only skips empedding a plist on macOS. + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-beta.19` +- Upgraded to `tauri-utils@2.0.0-beta.19` + +## \[2.0.0-beta.18] + +### New Features + +- [`5b769948a`](https://www.github.com/tauri-apps/tauri/commit/5b769948a81cac333f64c870a470ba6525bd5cd3) ([#9959](https://www.github.com/tauri-apps/tauri/pull/9959)) Add `include_image` macro to help embedding instances of `Image` struct at compile-time in rust to be used with window, menu or tray icons. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.18` +- Upgraded to `tauri-codegen@2.0.0-beta.18` + +## \[2.0.0-beta.17] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.17` +- Upgraded to `tauri-codegen@2.0.0-beta.17` + +### Breaking Changes + +- [`1df5cdeb0`](https://www.github.com/tauri-apps/tauri/commit/1df5cdeb06f5464e0eec4055e21b7b7bc8739eed)([#9858](https://www.github.com/tauri-apps/tauri/pull/9858)) Use `tauri.conf.json > identifier` to set the `PackageName` in Android and `BundleId` in iOS. + +## \[2.0.0-beta.16] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.16` +- Upgraded to `tauri-codegen@2.0.0-beta.16` + +## \[2.0.0-beta.15] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.15` +- Upgraded to `tauri-codegen@2.0.0-beta.15` + +## \[2.0.0-beta.14] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.14` +- Upgraded to `tauri-codegen@2.0.0-beta.14` + +## \[2.0.0-beta.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.13` +- Upgraded to `tauri-codegen@2.0.0-beta.13` + +## \[2.0.0-beta.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.12` +- Upgraded to `tauri-codegen@2.0.0-beta.12` + +## \[2.0.0-beta.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.11` +- Upgraded to `tauri-codegen@2.0.0-beta.11` + +## \[2.0.0-beta.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.10` +- Upgraded to `tauri-codegen@2.0.0-beta.10` + +## \[2.0.0-beta.9] + +### New Features + +- [`ba0206d8a`](https://www.github.com/tauri-apps/tauri/commit/ba0206d8a30a9b43ec5090dcaabd1a23baa1420c)([#9141](https://www.github.com/tauri-apps/tauri/pull/9141)) The `Context` codegen now accepts a `assets` input to define a custom `tauri::Assets` implementation. + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-beta.9` +- Upgraded to `tauri-utils@2.0.0-beta.9` + +## \[2.0.0-beta.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.8` +- Upgraded to `tauri-codegen@2.0.0-beta.8` + +## \[2.0.0-beta.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.7` +- Upgraded to `tauri-codegen@2.0.0-beta.7` + +## \[2.0.0-beta.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.6` +- Upgraded to `tauri-codegen@2.0.0-beta.6` + +## \[2.0.0-beta.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.5` +- Upgraded to `tauri-codegen@2.0.0-beta.5` + +## \[2.0.0-beta.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.4` +- Upgraded to `tauri-codegen@2.0.0-beta.4` + +## \[2.0.0-beta.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.3` +- Upgraded to `tauri-codegen@2.0.0-beta.3` + +## \[2.0.0-beta.2] + +### Enhancements + +- [`8d16a80d`](https://www.github.com/tauri-apps/tauri/commit/8d16a80d2fb2468667e7987d0cc99dbc7e3b9d0a)([#8802](https://www.github.com/tauri-apps/tauri/pull/8802)) The `generate_context` proc macro now accepts a `capabilities` attribute where the value is an array of file paths that can be [conditionally compiled](https://doc.rust-lang.org/reference/conditional-compilation.html). These capabilities are added to the application along the capabilities defined in the Tauri configuration file. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.2` +- Upgraded to `tauri-codegen@2.0.0-beta.2` + +## \[2.0.0-beta.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.1` +- Upgraded to `tauri-codegen@2.0.0-beta.1` + +## \[2.0.0-beta.0] + +### New Features + +- [`74a2a603`](https://www.github.com/tauri-apps/tauri/commit/74a2a6036a5e57462f161d728cbd8a6f121028ca)([#8661](https://www.github.com/tauri-apps/tauri/pull/8661)) Implement access control list for IPC usage. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.0` +- Upgraded to `tauri-codegen@2.0.0-beta.0` + +## \[2.0.0-alpha.13] + +### Enhancements + +- [`d621d343`](https://www.github.com/tauri-apps/tauri/commit/d621d3437ce3947175eecf345b2c6d1c4c7ce020)([#8607](https://www.github.com/tauri-apps/tauri/pull/8607)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.13` +- Upgraded to `tauri-codegen@2.0.0-alpha.13` + +## \[2.0.0-alpha.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.12` +- Upgraded to `tauri-codegen@2.0.0-alpha.12` + +## \[2.0.0-alpha.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.11` +- Upgraded to `tauri-codegen@2.0.0-alpha.11` +- [`b6ed4ecb`](https://www.github.com/tauri-apps/tauri/commit/b6ed4ecb3730c346c973f1b34aa0de1b7d43ac44)([#7634](https://www.github.com/tauri-apps/tauri/pull/7634)) Update to syn v2. + +## \[2.0.0-alpha.10] + +### Enhancements + +- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release. + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-alpha.10` +- Upgraded to `tauri-utils@2.0.0-alpha.10` + +## \[2.0.0-alpha.9] + +### New Features + +- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.9` +- Upgraded to `tauri-codegen@2.0.0-alpha.9` + +### Breaking Changes + +- [`ebcc21e4`](https://www.github.com/tauri-apps/tauri/commit/ebcc21e4b95f4e8c27639fb1bca545b432f52d5e)([#8057](https://www.github.com/tauri-apps/tauri/pull/8057)) Renamed the beforeDevCommand, beforeBuildCommand and beforeBundleCommand hooks environment variables from `TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG` to `TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG` to differentiate the prefix with other CLI environment variables. + +## \[2.0.0-alpha.8] + +### Enhancements + +- [`100d9ede`](https://www.github.com/tauri-apps/tauri/commit/100d9ede35995d9db21d2087dd5606adfafb89a5)([#7802](https://www.github.com/tauri-apps/tauri/pull/7802)) Use `Target` enum from `tauri_utils::platform`. + +### Dependencies + +- Upgraded to `tauri-codegen@2.0.0-alpha.8` +- Upgraded to `tauri-utils@2.0.0-alpha.8` + +## \[2.0.0-alpha.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.7` +- Upgraded to `tauri-codegen@2.0.0-alpha.7` + +### Breaking Changes + +- [`fbeb5b91`](https://www.github.com/tauri-apps/tauri/commit/fbeb5b9185baeda19e865228179e3e44c165f1d9)([#7170](https://www.github.com/tauri-apps/tauri/pull/7170)) Moved `tauri::api::ipc` to `tauri::ipc` and refactored all types. + +## \[2.0.0-alpha.6] + +### Dependencies + +- Updated to latest `tauri-utils` + +## \[2.0.0-alpha.5] + +- [`7a4b1fb9`](https://www.github.com/tauri-apps/tauri/commit/7a4b1fb96da475053c61960f362bbecf18cd00d4)([#6839](https://www.github.com/tauri-apps/tauri/pull/6839)) Added support to attibutes for each command path in the `generate_handler` macro. +- [`96639ca2`](https://www.github.com/tauri-apps/tauri/commit/96639ca239c9e4f75142fc07868ac46822111cff)([#6749](https://www.github.com/tauri-apps/tauri/pull/6749)) Moved the `shell` functionality to its own plugin in the plugins-workspace repository. +- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65. +- [`9a79dc08`](https://www.github.com/tauri-apps/tauri/commit/9a79dc085870e0c1a5df13481ff271b8c6cc3b78)([#6947](https://www.github.com/tauri-apps/tauri/pull/6947)) Removed the module command macros. + +## \[2.0.0-alpha.4] + +- Added `android` configuration object under `tauri > bundle`. + - Bumped due to a bump in tauri-utils. + - [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07 + +## \[2.0.0-alpha.3] + +- Pull changes from Tauri 1.3 release. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[2.0.0-alpha.2] + +- Resolve Android package name from single word bundle identifiers. + - [60a8b07d](https://www.github.com/tauri-apps/tauri/commit/60a8b07dc7c56c9c45331cb57d9afb410e7eadf3) fix: handle single word bundle identifier when resolving Android domain ([#6313](https://www.github.com/tauri-apps/tauri/pull/6313)) on 2023-02-19 +- Return `bool` in the invoke handler. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 +- Refactored the implementation of the `mobile_entry_point` macro. + - [9feab904](https://www.github.com/tauri-apps/tauri/commit/9feab904bf08b5c168d4779c21d0419409a68d30) feat(core): add API to call Android plugin ([#6239](https://www.github.com/tauri-apps/tauri/pull/6239)) on 2023-02-10 + +## \[2.0.0-alpha.1] + +- Refactor mobile environment variables. + - [dee9460f](https://www.github.com/tauri-apps/tauri/commit/dee9460f9c9bc92e9c638e7691e616849ac2085b) feat: keep CLI alive when iOS app exits, show logs, closes [#5855](https://www.github.com/tauri-apps/tauri/pull/5855) ([#5902](https://www.github.com/tauri-apps/tauri/pull/5902)) on 2022-12-27 +- Bump the MSRV to 1.64. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Removed mobile logging initialization, which will be handled by `tauri-plugin-log`. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[2.0.0-alpha.0] + +- Added the `mobile_entry_point` macro. + - [98904863](https://www.github.com/tauri-apps/tauri/commit/9890486321c9c79ccfb7c547fafee85b5c3ffa71) feat(core): add `mobile_entry_point` macro ([#4983](https://www.github.com/tauri-apps/tauri/pull/4983)) on 2022-08-21 +- First mobile alpha release! + - [fa3a1098](https://www.github.com/tauri-apps/tauri/commit/fa3a10988a03aed1b66fb17d893b1a9adb90f7cd) feat(ci): prepare 2.0.0-alpha.0 ([#5786](https://www.github.com/tauri-apps/tauri/pull/5786)) on 2022-12-08 + +## \[1.4.3] + +### Dependencies + +- Upgraded to `tauri-utils@1.5.2` +- Upgraded to `tauri-codegen@1.4.2` + +## \[1.4.2] + +### Enhancements + +- [`5e05236b`](https://www.github.com/tauri-apps/tauri/commit/5e05236b4987346697c7caae0567d3c50714c198)([#8289](https://www.github.com/tauri-apps/tauri/pull/8289)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag. + +## \[1.4.1] + +### Dependencies + +- Upgraded to `tauri-utils@1.5.0` +- Upgraded to `tauri-codegen@1.4.1` + +## \[1.4.0] + +### Enhancements + +- [`d68a25e3`](https://www.github.com/tauri-apps/tauri/commit/d68a25e32e012e57a9e5225b589b9ecbea70a887)([#6124](https://www.github.com/tauri-apps/tauri/pull/6124)) Improve compiler error message when generating an async command that has a reference input and don't return a Result. + +## \[1.3.0] + +- Bump minimum supported Rust version to 1.60. + - [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31 + +## \[1.2.1] + +- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`. + - Bumped due to a bump in tauri-utils. + - [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18 + +## \[1.2.0] + +- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28 + +## \[1.1.1] + +- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs. + - Bumped due to a bump in tauri-utils. + - [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16 + +## \[1.1.0] + +- Added support to configuration files in TOML format (Tauri.toml file). + - [ae83d008](https://www.github.com/tauri-apps/tauri/commit/ae83d008f9e1b89bfc8dddaca42aa5c1fbc36f6d) feat: add support to TOML config file `Tauri.toml`, closes [#4806](https://www.github.com/tauri-apps/tauri/pull/4806) ([#4813](https://www.github.com/tauri-apps/tauri/pull/4813)) on 2022-08-02 + +## \[1.0.4] + +- Adjust command imports to fix `items_after_statements` Clippy warning. + - [d3e19e34](https://www.github.com/tauri-apps/tauri/commit/d3e19e3420a023cddc46173a2d1f1e6c5a390a1b) fix(macros): `items_after_statements` Clippy warning, closes [#4639](https://www.github.com/tauri-apps/tauri/pull/4639) on 2022-07-11 +- Remove raw identifier (`r#`) prefix from command arguments. + - [ac72800f](https://www.github.com/tauri-apps/tauri/commit/ac72800fb630738e2502569935ecdc83e3e78055) fix(macros): strip `r#` from command arguments, closes [#4654](https://www.github.com/tauri-apps/tauri/pull/4654) ([#4657](https://www.github.com/tauri-apps/tauri/pull/4657)) on 2022-07-12 + +## \[1.0.3] + +- Add `#[doc(hidden)]` attribute to the `#[command]` generated macro. + - [d4cdf807](https://www.github.com/tauri-apps/tauri/commit/d4cdf80781a7955ac620fe6d394e82d067178c4d) feat(macros): hide command macro from docs, closes [#4550](https://www.github.com/tauri-apps/tauri/pull/4550) ([#4556](https://www.github.com/tauri-apps/tauri/pull/4556)) on 2022-07-01 + +## \[1.0.2] + +- Expose `platform::windows_version` function. + - Bumped due to a bump in tauri-utils. + - [bf764e83](https://www.github.com/tauri-apps/tauri/commit/bf764e83e01e7443e6cc54572001e1c98c357465) feat(utils): expose `windows_version` function ([#4534](https://www.github.com/tauri-apps/tauri/pull/4534)) on 2022-06-30 + +## \[1.0.1] + +- Set the bundle name and app metadata in the Info.plist file in development mode. + - [38f5db6e](https://www.github.com/tauri-apps/tauri/commit/38f5db6e6a8b496b50d486db6fd8204266de3a69) feat(codegen): fill app metadata in development Info.plist on 2022-06-21 +- Set the application icon in development mode on macOS. + - [307c2ebf](https://www.github.com/tauri-apps/tauri/commit/307c2ebfb68238dacab6088f9c6ba310c727c68c) feat(core): set macOS app icon in development ([#4385](https://www.github.com/tauri-apps/tauri/pull/4385)) on 2022-06-19 + +## \[1.0.0] + +- Upgrade to `stable`! + - [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15 + +## \[1.0.0-rc.11] + +- Read the tray icon path relatively to the config directory. + - Bumped due to a bump in tauri-codegen. + - [562e8ca2](https://www.github.com/tauri-apps/tauri/commit/562e8ca23facf1a8e5fa6c8cdf872357d3523a78) fix(codegen): tray icon path is relative to the config directory on 2022-06-15 + +## \[1.0.0-rc.10] + +- **Breaking change:** The `TrayIcon` enum has been removed and now `Icon` is used instead. + This allows you to use more image formats and use embedded icons on Linux. + - Bumped due to a bump in tauri-codegen. + - [4ce8e228](https://www.github.com/tauri-apps/tauri/commit/4ce8e228134cd3f22973b74ef26ca0d165fbbbd9) refactor(core): use `Icon` for tray icons ([#4342](https://www.github.com/tauri-apps/tauri/pull/4342)) on 2022-06-14 + +## \[1.0.0-rc.9] + +- Added a config flag to bundle the media framework used by webkit2gtk `tauri.conf.json > tauri > bundle > appimage > bundleMediaFramework`. + - Bumped due to a bump in tauri-utils. + - [d335fae9](https://www.github.com/tauri-apps/tauri/commit/d335fae92cdcbb0ee18aad4e54558914afa3e778) feat(bundler): bundle additional gstreamer files, closes [#4092](https://www.github.com/tauri-apps/tauri/pull/4092) ([#4271](https://www.github.com/tauri-apps/tauri/pull/4271)) on 2022-06-10 + +## \[1.0.0-rc.8] + +- **Breaking change:** `PackageInfo::version` is now a `semver::Version` instead of a `String`. + - Bumped due to a bump in tauri-utils. + - [2badbd2d](https://www.github.com/tauri-apps/tauri/commit/2badbd2d7ed51bf33c1b547b4c837b600574bd4a) refactor: force semver versions, change updater `should_install` sig ([#4215](https://www.github.com/tauri-apps/tauri/pull/4215)) on 2022-05-25 + - [a7388e23](https://www.github.com/tauri-apps/tauri/commit/a7388e23c3b9019d48b078cae00a75c74d74d11b) fix(ci): adjust change file to include tauri-utils and tauri-codegen on 2022-05-27 + +## \[1.0.0-rc.7] + +- Allow configuring the display options for the MSI execution allowing quieter updates. + - Bumped due to a bump in tauri-utils. + - [9f2c3413](https://www.github.com/tauri-apps/tauri/commit/9f2c34131952ea83c3f8e383bc3cec7e1450429f) feat(core): configure msiexec display options, closes [#3951](https://www.github.com/tauri-apps/tauri/pull/3951) ([#4061](https://www.github.com/tauri-apps/tauri/pull/4061)) on 2022-05-15 + +## \[1.0.0-rc.6] + +- Added `$schema` support to `tauri.conf.json`. + - Bumped due to a bump in tauri-utils. + - [715cbde3](https://www.github.com/tauri-apps/tauri/commit/715cbde3842a916c4ebeab2cab348e1774b5c192) feat(config): add `$schema` to `tauri.conf.json`, closes [#3464](https://www.github.com/tauri-apps/tauri/pull/3464) ([#4031](https://www.github.com/tauri-apps/tauri/pull/4031)) on 2022-05-03 +- The `dangerous_allow_asset_csp_modification` configuration value has been changed to allow a list of CSP directives to disable. + - Bumped due to a bump in tauri-utils. + - [164078c0](https://www.github.com/tauri-apps/tauri/commit/164078c0b719ccbc12e956fecf8a7d4a3c5044e1) feat: allow limiting dangerousDisableAssetCspModification, closes [#3831](https://www.github.com/tauri-apps/tauri/pull/3831) ([#4021](https://www.github.com/tauri-apps/tauri/pull/4021)) on 2022-05-02 + +## \[1.0.0-rc.5] + +- Read platform-specific configuration files when generating code without the `TAURI_CONFIG` env var. + - Bumped due to a bump in tauri-codegen. + - [edf85bc1](https://www.github.com/tauri-apps/tauri/commit/edf85bc1d18450c92aee17f7f99c163abe432ebd) fix(codegen): read platform-specific config file ([#3966](https://www.github.com/tauri-apps/tauri/pull/3966)) on 2022-04-25 + +## \[1.0.0-rc.4] + +- Replace multiple dependencies who's C code compiled concurrently and caused + the other ones to bloat compile time significantly. + +- `zstd` -> `brotli` + +- `blake3` -> a vendored version of the blake3 reference + +- `ring` -> `getrandom` + +See for more information about +these specific choices. + +- [8661e3e2](https://www.github.com/tauri-apps/tauri/commit/8661e3e24d96c399bfbcdee5d8e9d6beba2265a7) replace dependencies with long build times when used together (closes [#3571](https://www.github.com/tauri-apps/tauri/pull/3571)) ([#3773](https://www.github.com/tauri-apps/tauri/pull/3773)) on 2022-03-27 + +## \[1.0.0-rc.3] + +- Parse window icons at compile time. + - Bumped due to a bump in tauri-codegen. + - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 + +## \[1.0.0-rc.2] + +- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. + - Bumped due to a bump in tauri-utils. + - [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17 + +## \[1.0.0-rc.1] + +- Change default value for the `freezePrototype` configuration to `false`. + - Bumped due to a bump in tauri-utils. + - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 + +## \[1.0.0-rc.0] + +- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. + +Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: + +1. Check if `tauri.conf.json` exists + a. Parse it with `serde_json` + b. Parse it with `json5` if `serde_json` fails + c. Return original `serde_json` error if all above steps failed +2. Check if `tauri.conf.json5` exists + a. Parse it with `json5` + b. Return error if all above steps failed +3. Return error if all above steps failed + +- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 + +## \[1.0.0-beta.5] + +- Embed Info.plist file contents on binary on dev. + - Bumped due to a bump in tauri-codegen. + - [537ab1b6](https://www.github.com/tauri-apps/tauri/commit/537ab1b6d5a792c550a535619965c9e4126292e6) feat(core): inject src-tauri/Info.plist file on dev and merge on bundle, closes [#1570](https://www.github.com/tauri-apps/tauri/pull/1570) [#2338](https://www.github.com/tauri-apps/tauri/pull/2338) ([#2444](https://www.github.com/tauri-apps/tauri/pull/2444)) on 2021-08-15 +- Fix ES Module detection for default imports with relative paths or scoped packages and exporting of async functions. + - Bumped due to a bump in tauri-codegen. + - [b2b36cfe](https://www.github.com/tauri-apps/tauri/commit/b2b36cfe8dfcccb341638a4cb6dc23a514c54148) fix(core): fixes ES Module detection for default imports with relative paths or scoped packages ([#2380](https://www.github.com/tauri-apps/tauri/pull/2380)) on 2021-08-10 + - [fbf8caf5](https://www.github.com/tauri-apps/tauri/commit/fbf8caf5c419cb4fc3d123be910e094a8e8c4bef) fix(core): ESM detection when using `export async function` ([#2425](https://www.github.com/tauri-apps/tauri/pull/2425)) on 2021-08-14 + +## \[1.0.0-beta.4] + +- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those + associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If + you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the + explicit type and let the compiler infer it instead. + +`tauri`: + +- See `Params` note +- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a + simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition + of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type + to these functions. +- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all + methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already + required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change + affects you. + +`tauri-macros`: + +- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when + the specified feature is enabled. + +`tauri-runtime`: + +- See `Params` note +- Removed `Params`, `MenuId`, `Tag`, `TagRef`. +- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. + - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. +- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the + `Runtime` type directly +- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. +- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. + +`tauri-runtime-wry`: + +- See `Params` note +- update menu and runtime related types to the ones changed in `tauri-runtime`. + +`tauri-utils`: + +- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object + safe. +- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 + +## \[1.0.0-beta.3] + +- Detect ESM scripts and inject the invoke key directly instead of using an IIFE. + - Bumped due to a bump in tauri-codegen. + - [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27 +- Improve invoke key code injection performance time rewriting code at compile time. + - Bumped due to a bump in tauri-codegen. + - [7765c7fa](https://www.github.com/tauri-apps/tauri/commit/7765c7fa281853ddfb26b6b17534df95eaede804) fix(core): invoke key injection on ES module, improve performance ([#2094](https://www.github.com/tauri-apps/tauri/pull/2094)) on 2021-06-27 + +## \[1.0.0-beta.2] + +- internal: Refactor all macro code that expects specific bindings to be passed Idents + - [39f8f269](https://www.github.com/tauri-apps/tauri/commit/39f8f269164d2fda3d5b614a193b12bb266e4b4b) refactor(macros): explicitly pass idents ([#1812](https://www.github.com/tauri-apps/tauri/pull/1812)) on 2021-05-13 + +## \[1.0.0-beta.1] + +- Fixes a name collision when the command function is named `invoke`. + - [7862ec5](https://www.github.com/tauri-apps/tauri/commit/7862ec562fa70e3733263ce1f690d6cd2943c0b4) fix(macros): change invoke binding in generate handler ([#1804](https://www.github.com/tauri-apps/tauri/pull/1804)) on 2021-05-12 +- Fixes a name collision when the command function is named `message` or `resolver`. + - [0b87532](https://www.github.com/tauri-apps/tauri/commit/0b875327067ca825ff6f6f26c9b2ce6fcb001e79) fix(macros): fix rest of command collisions ([#1805](https://www.github.com/tauri-apps/tauri/pull/1805)) on 2021-05-12 +- Fixes a name collision when the command function is named `cmd`. + - [d36b726](https://www.github.com/tauri-apps/tauri/commit/d36b7269261d329dd7d7fcd4d5098f3fca167364) fix(macros): collision when command is named `cmd` ([#1802](https://www.github.com/tauri-apps/tauri/pull/1802)) on 2021-05-12 + +## \[1.0.0-beta.0] + +- Only commands with a `async fn` are executed on a separate task. `#[command] fn command_name` runs on the main thread. + - [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09 +- `#[command]` now generates a macro instead of a function to allow passing through `Params` and other generics. + `generate_handler!` has been changed to consume the generated `#[command]` macro + - [1453d4b](https://www.github.com/tauri-apps/tauri/commit/1453d4bf842ed6891ec604e0635344c930282189) feat(core): support generics (especially Param) in #\[command] ([#1622](https://www.github.com/tauri-apps/tauri/pull/1622)) on 2021-05-05 +- Improves support for commands returning `Result`. + - [bb8dafb](https://www.github.com/tauri-apps/tauri/commit/bb8dafbe1ea6edde7385631d41ac05e96a3309ef) feat(core): #\[command] return with autoref specialization workaround fix [#1672](https://www.github.com/tauri-apps/tauri/pull/1672) ([#1734](https://www.github.com/tauri-apps/tauri/pull/1734)) on 2021-05-09 +- Adds support to command state, triggered when a command argument is `arg: State<'_, StateType>`. + - [8b6f3de](https://www.github.com/tauri-apps/tauri/commit/8b6f3de0ad47684e72a2ae5f884d8675acfaeeac) feat(core): add state management, closes [#1655](https://www.github.com/tauri-apps/tauri/pull/1655) ([#1665](https://www.github.com/tauri-apps/tauri/pull/1665)) on 2021-05-02 + +## \[1.0.0-beta-rc.1] + +- Fixes the Message `command` name value on plugin invoke handler. + - [422dd5e](https://www.github.com/tauri-apps/tauri/commit/422dd5e2a0a03bb1556915c78f110bfab092c874) fix(core): command name on plugin invoke handler ([#1577](https://www.github.com/tauri-apps/tauri/pull/1577)) on 2021-04-21 + - [f575aaa](https://www.github.com/tauri-apps/tauri/commit/f575aaad71f23d44b2f89cf9ee5d84817dc3bb7a) fix: change files not referencing core packages ([#1619](https://www.github.com/tauri-apps/tauri/pull/1619)) on 2021-04-25 + +## \[1.0.0-beta-rc.0] + +- Update all code files to have our license header. + - [bf82136](https://www.github.com/tauri-apps/tauri/commit/bf8213646689175f8a158b956911f3a43e360690) feat(license): SPDX Headers ([#1449](https://www.github.com/tauri-apps/tauri/pull/1449)) on 2021-04-11 + - [a6def70](https://www.github.com/tauri-apps/tauri/commit/a6def7066eec19c889b0f14cc1e475bf209a332e) Refactor(tauri): move tauri-api and tauri-updater to tauri ([#1455](https://www.github.com/tauri-apps/tauri/pull/1455)) on 2021-04-11 + - [aea6145](https://www.github.com/tauri-apps/tauri/commit/aea614587bddab930d552512b54e18624fbf573e) refactor(repo): add /tooling folder ([#1457](https://www.github.com/tauri-apps/tauri/pull/1457)) on 2021-04-12 +- Added new macros to simplify the creation of commands that can be called by the webview. + - [1f2e7a3](https://www.github.com/tauri-apps/tauri/commit/1f2e7a3226ccf0ee3e30ae0cba3c67f7e219d1f2) feat(core): improved command matching with macros, fixes [#1157](https://www.github.com/tauri-apps/tauri/pull/1157) ([#1301](https://www.github.com/tauri-apps/tauri/pull/1301)) on 2021-02-28 diff --git a/crates/tauri-macros/Cargo.toml b/crates/tauri-macros/Cargo.toml new file mode 100644 index 000000000000..adf7d9806f76 --- /dev/null +++ b/crates/tauri-macros/Cargo.toml @@ -0,0 +1,32 @@ +[package] +name = "tauri-macros" +version = "2.0.3" +description = "Macros for the tauri crate." +exclude = ["CHANGELOG.md", "/target"] +readme = "README.md" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +categories.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = { version = "1", features = ["span-locations"] } +quote = "1" +syn = { version = "2", features = ["full"] } +heck = "0.5" +tauri-codegen = { version = "2.0.3", default-features = false, path = "../tauri-codegen" } +tauri-utils = { version = "2.1.0", path = "../tauri-utils" } + +[features] +custom-protocol = [] +compression = ["tauri-codegen/compression"] +isolation = ["tauri-codegen/isolation"] +config-json5 = ["tauri-codegen/config-json5", "tauri-utils/config-json5"] +config-toml = ["tauri-codegen/config-toml", "tauri-utils/config-toml"] +tracing = [] diff --git a/core/tauri-runtime-wry/LICENSE_APACHE-2.0 b/crates/tauri-macros/LICENSE_APACHE-2.0 similarity index 100% rename from core/tauri-runtime-wry/LICENSE_APACHE-2.0 rename to crates/tauri-macros/LICENSE_APACHE-2.0 diff --git a/core/tauri-runtime-wry/LICENSE_MIT b/crates/tauri-macros/LICENSE_MIT similarity index 100% rename from core/tauri-runtime-wry/LICENSE_MIT rename to crates/tauri-macros/LICENSE_MIT diff --git a/crates/tauri-macros/README.md b/crates/tauri-macros/README.md new file mode 100644 index 000000000000..98cd9c71166b --- /dev/null +++ b/crates/tauri-macros/README.md @@ -0,0 +1,42 @@ +# tauri-macros + + + +[![status](https://img.shields.io/badge/status-stable-blue.svg)](https://github.com/tauri-apps/tauri/tree/dev) +[![License](https://img.shields.io/badge/License-MIT%20or%20Apache%202-green.svg)](https://opencollective.com/tauri) +[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml) +[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Ftauri-apps%2Ftauri?ref=badge_shield) +[![Chat Server](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/SpmNs4S) +[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app) +[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) +[![support](https://img.shields.io/badge/sponsor-Open%20Collective-blue.svg)](https://opencollective.com/tauri) + +| Component | Version | +| ------------ | ------------------------------------------------------------------------------------------------------------ | +| tauri-macros | [![](https://img.shields.io/crates/v/tauri-macros?style=flat-square)](https://crates.io/crates/tauri-macros) | + +## About Tauri + +Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. + +Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. + +## This module + +Create macros for the context, handler, and commands by leveraging the `tauri-codegen` crate. + +To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. + +## Semver + +**tauri** is following [Semantic Versioning 2.0](https://semver.org/). + +## Licenses + +Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. + +MIT or MIT/Apache 2.0 where applicable. + +Logo: CC-BY-NC-ND + +- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/crates/tauri-macros/src/command/handler.rs b/crates/tauri-macros/src/command/handler.rs new file mode 100644 index 000000000000..f422e8bace0c --- /dev/null +++ b/crates/tauri-macros/src/command/handler.rs @@ -0,0 +1,86 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use quote::format_ident; +use syn::{ + parse::{Parse, ParseBuffer, ParseStream}, + Attribute, Ident, Path, Token, +}; + +struct CommandDef { + path: Path, + attrs: Vec, +} + +impl Parse for CommandDef { + fn parse(input: ParseStream) -> syn::Result { + let attrs = input.call(Attribute::parse_outer)?; + let path = input.parse()?; + + Ok(CommandDef { path, attrs }) + } +} + +/// The items parsed from [`generate_handle!`](crate::generate_handle). +pub struct Handler { + command_defs: Vec, + commands: Vec, + wrappers: Vec, +} + +impl Parse for Handler { + fn parse(input: &ParseBuffer<'_>) -> syn::Result { + let command_defs = input.parse_terminated(CommandDef::parse, Token![,])?; + + // parse the command names and wrappers from the passed paths + let (commands, wrappers) = command_defs + .iter() + .map(|command_def| { + let mut wrapper = command_def.path.clone(); + let last = super::path_to_command(&mut wrapper); + + // the name of the actual command function + let command = last.ident.clone(); + + // set the path to the command function wrapper + last.ident = super::format_command_wrapper(&command); + + (command, wrapper) + }) + .unzip(); + + Ok(Self { + command_defs: command_defs.into_iter().collect(), // remove punctuation separators + commands, + wrappers, + }) + } +} + +impl From for proc_macro::TokenStream { + fn from( + Handler { + command_defs, + commands, + wrappers, + }: Handler, + ) -> Self { + let cmd = format_ident!("__tauri_cmd__"); + let invoke = format_ident!("__tauri_invoke__"); + let (paths, attrs): (Vec, Vec>) = command_defs + .into_iter() + .map(|def| (def.path, def.attrs)) + .unzip(); + quote::quote!(move |#invoke| { + let #cmd = #invoke.message.command(); + match #cmd { + #(#(#attrs)* stringify!(#commands) => #wrappers!(#paths, #invoke),)* + _ => { + return false; + }, + } + }) + .into() + } +} diff --git a/crates/tauri-macros/src/command/mod.rs b/crates/tauri-macros/src/command/mod.rs new file mode 100644 index 000000000000..fc3bbb681d74 --- /dev/null +++ b/crates/tauri-macros/src/command/mod.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro2::Ident; +use syn::{Path, PathSegment}; + +pub use self::{handler::Handler, wrapper::wrapper}; + +mod handler; +mod wrapper; + +/// The autogenerated wrapper ident. +fn format_command_wrapper(function: &Ident) -> Ident { + quote::format_ident!("__cmd__{}", function) +} + +/// This function will panic if the passed [`syn::Path`] does not have any segments. +fn path_to_command(path: &mut Path) -> &mut PathSegment { + path + .segments + .last_mut() + .expect("parsed syn::Path has no segment") +} diff --git a/crates/tauri-macros/src/command/wrapper.rs b/crates/tauri-macros/src/command/wrapper.rs new file mode 100644 index 000000000000..4babd0dbb325 --- /dev/null +++ b/crates/tauri-macros/src/command/wrapper.rs @@ -0,0 +1,502 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::env::var; + +use heck::{ToLowerCamelCase, ToSnakeCase}; +use proc_macro::TokenStream; +use proc_macro2::{Ident, Span, TokenStream as TokenStream2}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{ + ext::IdentExt, + parse::{Parse, ParseStream}, + parse_macro_input, + punctuated::Punctuated, + spanned::Spanned, + Expr, ExprLit, FnArg, ItemFn, Lit, Meta, Pat, Token, Visibility, +}; + +enum WrapperAttributeKind { + Meta(Meta), + Async, +} + +impl Parse for WrapperAttributeKind { + fn parse(input: ParseStream) -> syn::Result { + match input.parse::() { + Ok(m) => Ok(Self::Meta(m)), + Err(e) => match input.parse::() { + Ok(_) => Ok(Self::Async), + Err(_) => Err(e), + }, + } + } +} + +struct WrapperAttributes { + root: TokenStream2, + execution_context: ExecutionContext, + argument_case: ArgumentCase, +} + +impl Parse for WrapperAttributes { + fn parse(input: ParseStream) -> syn::Result { + let mut wrapper_attributes = WrapperAttributes { + root: quote!(::tauri), + execution_context: ExecutionContext::Blocking, + argument_case: ArgumentCase::Camel, + }; + + let attrs = Punctuated::::parse_terminated(input)?; + for attr in attrs { + match attr { + WrapperAttributeKind::Meta(Meta::List(_)) => { + return Err(syn::Error::new(input.span(), "unexpected list input")); + } + WrapperAttributeKind::Meta(Meta::NameValue(v)) => { + if v.path.is_ident("rename_all") { + if let Expr::Lit(ExprLit { + lit: Lit::Str(s), + attrs: _, + }) = v.value + { + wrapper_attributes.argument_case = match s.value().as_str() { + "snake_case" => ArgumentCase::Snake, + "camelCase" => ArgumentCase::Camel, + _ => { + return Err(syn::Error::new( + s.span(), + "expected \"camelCase\" or \"snake_case\"", + )) + } + }; + } + } else if v.path.is_ident("root") { + if let Expr::Lit(ExprLit { + lit: Lit::Str(s), + attrs: _, + }) = v.value + { + let lit = s.value(); + + wrapper_attributes.root = if lit == "crate" { + quote!($crate) + } else { + let ident = Ident::new(&lit, Span::call_site()); + quote!(#ident) + }; + } + } + } + WrapperAttributeKind::Meta(Meta::Path(_)) => { + return Err(syn::Error::new( + input.span(), + "unexpected input, expected one of `rename_all`, `root`, `async`", + )); + } + WrapperAttributeKind::Async => { + wrapper_attributes.execution_context = ExecutionContext::Async; + } + } + } + + Ok(wrapper_attributes) + } +} + +/// The execution context of the command. +enum ExecutionContext { + Async, + Blocking, +} + +/// The case of each argument name. +#[derive(Copy, Clone)] +enum ArgumentCase { + Snake, + Camel, +} + +/// The bindings we attach to `tauri::Invoke`. +struct Invoke { + message: Ident, + resolver: Ident, + acl: Ident, +} + +/// Create a new [`Wrapper`] from the function and the generated code parsed from the function. +pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { + let mut attrs = parse_macro_input!(attributes as WrapperAttributes); + let function = parse_macro_input!(item as ItemFn); + let wrapper = super::format_command_wrapper(&function.sig.ident); + let visibility = &function.vis; + + if function.sig.asyncness.is_some() { + attrs.execution_context = ExecutionContext::Async; + } + + // macros used with `pub use my_macro;` need to be exported with `#[macro_export]` + let maybe_macro_export = match &function.vis { + Visibility::Public(_) | Visibility::Restricted(_) => quote!(#[macro_export]), + _ => TokenStream2::default(), + }; + + let invoke = Invoke { + message: format_ident!("__tauri_message__"), + resolver: format_ident!("__tauri_resolver__"), + acl: format_ident!("__tauri_acl__"), + }; + + // Tauri currently doesn't support async commands that take a reference as input and don't return + // a result. See: https://github.com/tauri-apps/tauri/issues/2533 + // + // For now, we provide an informative error message to the user in that case. Once #2533 is + // resolved, this check can be removed. + let mut async_command_check = TokenStream2::new(); + if function.sig.asyncness.is_some() { + // This check won't catch all possible problems but it should catch the most common ones. + let mut ref_argument_span = None; + + for arg in &function.sig.inputs { + if let syn::FnArg::Typed(pat) = arg { + match &*pat.ty { + syn::Type::Reference(_) => { + ref_argument_span = Some(pat.span()); + } + syn::Type::Path(path) => { + // Check if the type contains a lifetime argument + let last = path.path.segments.last().unwrap(); + if let syn::PathArguments::AngleBracketed(args) = &last.arguments { + if args + .args + .iter() + .any(|arg| matches!(arg, syn::GenericArgument::Lifetime(_))) + { + ref_argument_span = Some(pat.span()); + } + } + } + _ => {} + } + + if let Some(span) = ref_argument_span { + if let syn::ReturnType::Type(_, return_type) = &function.sig.output { + // To check if the return type is `Result` we require it to check a trait that is + // only implemented by `Result`. That way we don't exclude renamed result types + // which we wouldn't otherwise be able to detect purely from the token stream. + // The "error message" displayed to the user is simply the trait name. + // + // TODO: remove this check once our MSRV is high enough + let diagnostic = if is_rustc_at_least(1, 78) { + quote!(#[diagnostic::on_unimplemented(message = "async commands that contain references as inputs must return a `Result`")]) + } else { + quote!() + }; + + async_command_check = quote_spanned! {return_type.span() => + #[allow(unreachable_code, clippy::diverging_sub_expression)] + const _: () = if false { + #diagnostic + trait AsyncCommandMustReturnResult {} + impl AsyncCommandMustReturnResult for ::std::result::Result {} + let _check: #return_type = unreachable!(); + let _: &dyn AsyncCommandMustReturnResult = &_check; + }; + }; + } else { + return quote_spanned! { + span => compile_error!("async commands that contain references as inputs must return a `Result`"); + }.into(); + } + } + } + } + } + + let plugin_name = var("CARGO_PKG_NAME") + .expect("missing `CARGO_PKG_NAME` environment variable") + .strip_prefix("tauri-plugin-") + .map(|name| quote!(::core::option::Option::Some(#name))) + .unwrap_or_else(|| quote!(::core::option::Option::None)); + + let body = match attrs.execution_context { + ExecutionContext::Async => body_async(&plugin_name, &function, &invoke, &attrs) + .unwrap_or_else(syn::Error::into_compile_error), + ExecutionContext::Blocking => body_blocking(&plugin_name, &function, &invoke, &attrs) + .unwrap_or_else(syn::Error::into_compile_error), + }; + + let Invoke { + message, + resolver, + acl, + } = invoke; + + let root = attrs.root; + + let kind = match attrs.execution_context { + ExecutionContext::Async if function.sig.asyncness.is_none() => "sync_threadpool", + ExecutionContext::Async => "async", + ExecutionContext::Blocking => "sync", + }; + + let loc = function.span().start(); + let line = loc.line; + let col = loc.column; + + let maybe_span = if cfg!(feature = "tracing") { + quote!({ + let _span = tracing::debug_span!( + "ipc::request::handler", + cmd = #message.command(), + kind = #kind, + loc.line = #line, + loc.col = #col, + is_internal = false, + ) + .entered(); + }) + } else { + quote!() + }; + + // Rely on rust 2018 edition to allow importing a macro from a path. + quote!( + #async_command_check + + #function + + #maybe_macro_export + #[doc(hidden)] + macro_rules! #wrapper { + // double braces because the item is expected to be a block expression + ($path:path, $invoke:ident) => {{ + #[allow(unused_imports)] + use #root::ipc::private::*; + // prevent warnings when the body is a `compile_error!` or if the command has no arguments + #[allow(unused_variables)] + let #root::ipc::Invoke { message: #message, resolver: #resolver, acl: #acl } = $invoke; + + #maybe_span + + #body + }}; + } + + // allow the macro to be resolved with the same path as the command function + #[allow(unused_imports)] + #visibility use #wrapper; + ) + .into() +} + +/// Generates an asynchronous command response from the arguments and return value of a function. +/// +/// See the [`tauri::command`] module for all the items and traits that make this possible. +/// +/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html +fn body_async( + plugin_name: &TokenStream2, + function: &ItemFn, + invoke: &Invoke, + attributes: &WrapperAttributes, +) -> syn::Result { + let Invoke { + message, + resolver, + acl, + } = invoke; + parse_args(plugin_name, function, message, acl, attributes).map(|args| { + #[cfg(feature = "tracing")] + quote! { + use tracing::Instrument; + + let span = tracing::debug_span!("ipc::request::run"); + #resolver.respond_async_serialized(async move { + let result = $path(#(#args?),*); + let kind = (&result).async_kind(); + kind.future(result).await + } + .instrument(span)); + return true; + } + + #[cfg(not(feature = "tracing"))] + quote! { + #resolver.respond_async_serialized(async move { + let result = $path(#(#args?),*); + let kind = (&result).async_kind(); + kind.future(result).await + }); + return true; + } + }) +} + +/// Generates a blocking command response from the arguments and return value of a function. +/// +/// See the [`tauri::command`] module for all the items and traits that make this possible. +/// +/// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html +fn body_blocking( + plugin_name: &TokenStream2, + function: &ItemFn, + invoke: &Invoke, + attributes: &WrapperAttributes, +) -> syn::Result { + let Invoke { + message, + resolver, + acl, + } = invoke; + let args = parse_args(plugin_name, function, message, acl, attributes)?; + + // the body of a `match` to early return any argument that wasn't successful in parsing. + let match_body = quote!({ + Ok(arg) => arg, + Err(err) => { #resolver.invoke_error(err); return true }, + }); + + let maybe_span = if cfg!(feature = "tracing") { + quote!(let _span = tracing::debug_span!("ipc::request::run").entered();) + } else { + quote!() + }; + + Ok(quote! { + #maybe_span + let result = $path(#(match #args #match_body),*); + let kind = (&result).blocking_kind(); + kind.block(result, #resolver); + return true; + }) +} + +/// Parse all arguments for the command wrapper to use from the signature of the command function. +fn parse_args( + plugin_name: &TokenStream2, + function: &ItemFn, + message: &Ident, + acl: &Ident, + attributes: &WrapperAttributes, +) -> syn::Result> { + function + .sig + .inputs + .iter() + .map(|arg| { + parse_arg( + plugin_name, + &function.sig.ident, + arg, + message, + acl, + attributes, + ) + }) + .collect() +} + +/// Transform a [`FnArg`] into a command argument. +fn parse_arg( + plugin_name: &TokenStream2, + command: &Ident, + arg: &FnArg, + message: &Ident, + acl: &Ident, + attributes: &WrapperAttributes, +) -> syn::Result { + // we have no use for self arguments + let mut arg = match arg { + FnArg::Typed(arg) => arg.pat.as_ref().clone(), + FnArg::Receiver(arg) => { + return Err(syn::Error::new( + arg.span(), + "unable to use self as a command function parameter", + )) + } + }; + + // we only support patterns that allow us to extract some sort of keyed identifier + let mut key = match &mut arg { + Pat::Ident(arg) => arg.ident.unraw().to_string(), + Pat::Wild(_) => "".into(), // we always convert to camelCase, so "_" will end up empty anyways + Pat::Struct(s) => super::path_to_command(&mut s.path).ident.to_string(), + Pat::TupleStruct(s) => super::path_to_command(&mut s.path).ident.to_string(), + err => { + return Err(syn::Error::new( + err.span(), + "only named, wildcard, struct, and tuple struct arguments allowed", + )) + } + }; + + // also catch self arguments that use FnArg::Typed syntax + if key == "self" { + return Err(syn::Error::new( + key.span(), + "unable to use self as a command function parameter", + )); + } + + match attributes.argument_case { + ArgumentCase::Camel => { + key = key.to_lower_camel_case(); + } + ArgumentCase::Snake => { + key = key.to_snake_case(); + } + } + + let root = &attributes.root; + + Ok(quote!(#root::ipc::CommandArg::from_command( + #root::ipc::CommandItem { + plugin: #plugin_name, + name: stringify!(#command), + key: #key, + message: &#message, + acl: &#acl, + } + ))) +} + +fn is_rustc_at_least(major: u32, minor: u32) -> bool { + let version = rustc_version(); + version.0 >= major && version.1 >= minor +} + +fn rustc_version() -> (u32, u32) { + cross_command("rustc") + .arg("-V") + .output() + .ok() + .and_then(|o| { + let version = String::from_utf8_lossy(&o.stdout) + .trim() + .split(' ') + .nth(1) + .unwrap_or_default() + .split(".") + .take(2) + .flat_map(|p| p.parse::().ok()) + .collect::>(); + version + .first() + .and_then(|major| version.get(1).map(|minor| (*major, *minor))) + }) + .unwrap_or((1, 0)) +} + +fn cross_command(bin: &str) -> std::process::Command { + #[cfg(target_os = "windows")] + let cmd = { + let mut cmd = std::process::Command::new("cmd"); + cmd.arg("/c").arg(bin); + cmd + }; + #[cfg(not(target_os = "windows"))] + let cmd = std::process::Command::new(bin); + cmd +} diff --git a/crates/tauri-macros/src/context.rs b/crates/tauri-macros/src/context.rs new file mode 100644 index 000000000000..9469ea17f5e7 --- /dev/null +++ b/crates/tauri-macros/src/context.rs @@ -0,0 +1,169 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::{quote, ToTokens}; +use std::path::PathBuf; +use syn::{ + parse::{Parse, ParseBuffer}, + punctuated::Punctuated, + Expr, ExprLit, Lit, LitBool, LitStr, Meta, PathArguments, PathSegment, Token, +}; +use tauri_codegen::{context_codegen, get_config, ContextData}; +use tauri_utils::{config::parse::does_supported_file_name_exist, platform::Target}; + +pub(crate) struct ContextItems { + config_file: PathBuf, + root: syn::Path, + capabilities: Option>, + assets: Option, + test: bool, +} + +impl Parse for ContextItems { + fn parse(input: &ParseBuffer<'_>) -> syn::parse::Result { + let target = std::env::var("TARGET") + .or_else(|_| std::env::var("TAURI_ENV_TARGET_TRIPLE")) + .as_deref() + .map(Target::from_triple) + .unwrap_or_else(|_| Target::current()); + + let mut root = None; + let mut capabilities = None; + let mut assets = None; + let mut test = false; + let config_file = input.parse::().ok().map(|raw| { + let _ = input.parse::(); + let path = PathBuf::from(raw.value()); + if path.is_relative() { + std::env::var("CARGO_MANIFEST_DIR") + .map(|m| PathBuf::from(m).join(path)) + .map_err(|e| e.to_string()) + } else { + Ok(path) + } + .and_then(|path| { + if does_supported_file_name_exist(target, &path) { + Ok(path) + } else { + Err(format!( + "no file at path {} exists, expected tauri config file", + path.display() + )) + } + }) + }); + + while let Ok(meta) = input.parse::() { + match meta { + Meta::Path(p) => { + root.replace(p); + } + Meta::NameValue(v) => { + let ident = v.path.require_ident()?; + match ident.to_string().as_str() { + "capabilities" => { + if let Expr::Array(array) = v.value { + capabilities.replace( + array + .elems + .into_iter() + .map(|e| { + if let Expr::Lit(ExprLit { + attrs: _, + lit: Lit::Str(s), + }) = e + { + Ok(s.value().into()) + } else { + Err(syn::Error::new( + input.span(), + "unexpected expression for capability", + )) + } + }) + .collect::, syn::Error>>()?, + ); + } else { + return Err(syn::Error::new( + input.span(), + "unexpected value for capabilities", + )); + } + } + "assets" => { + assets.replace(v.value); + } + "test" => { + if let Expr::Lit(ExprLit { + lit: Lit::Bool(LitBool { value, .. }), + .. + }) = v.value + { + test = value; + } else { + return Err(syn::Error::new(input.span(), "unexpected value for test")); + } + } + name => { + return Err(syn::Error::new( + input.span(), + format!("unknown attribute {name}"), + )); + } + } + } + Meta::List(_) => { + return Err(syn::Error::new(input.span(), "unexpected list input")); + } + } + + let _ = input.parse::(); + } + + Ok(Self { + config_file: config_file + .unwrap_or_else(|| { + std::env::var("CARGO_MANIFEST_DIR") + .map(|m| PathBuf::from(m).join("tauri.conf.json")) + .map_err(|e| e.to_string()) + }) + .map_err(|e| input.error(e))?, + root: root.unwrap_or_else(|| { + let mut segments = Punctuated::new(); + segments.push(PathSegment { + ident: Ident::new("tauri", Span::call_site()), + arguments: PathArguments::None, + }); + syn::Path { + leading_colon: Some(Token![::](Span::call_site())), + segments, + } + }), + capabilities, + assets, + test, + }) + } +} + +pub(crate) fn generate_context(context: ContextItems) -> TokenStream { + let context = get_config(&context.config_file) + .map_err(|e| e.to_string()) + .map(|(config, config_parent)| ContextData { + dev: cfg!(not(feature = "custom-protocol")), + config, + config_parent, + root: context.root.to_token_stream(), + capabilities: context.capabilities, + assets: context.assets, + test: context.test, + }) + .and_then(|data| context_codegen(data).map_err(|e| e.to_string())); + + match context { + Ok(code) => code, + Err(error) => quote!(compile_error!(#error)), + } +} diff --git a/crates/tauri-macros/src/lib.rs b/crates/tauri-macros/src/lib.rs new file mode 100644 index 000000000000..b2df245bfd3a --- /dev/null +++ b/crates/tauri-macros/src/lib.rs @@ -0,0 +1,211 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Create macros for `tauri::Context`, invoke handler and commands leveraging the `tauri-codegen` crate. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +use std::path::PathBuf; + +use crate::context::ContextItems; +use proc_macro::TokenStream; +use quote::{quote, ToTokens}; +use syn::{parse2, parse_macro_input, LitStr}; +use tauri_codegen::image::CachedIcon; + +mod command; +mod menu; +mod mobile; +mod runtime; + +#[macro_use] +mod context; + +/// Mark a function as a command handler. It creates a wrapper function with the necessary glue code. +/// +/// # Stability +/// The output of this macro is managed internally by Tauri, +/// and should not be accessed directly on normal applications. +/// It may have breaking changes in the future. +#[proc_macro_attribute] +pub fn command(attributes: TokenStream, item: TokenStream) -> TokenStream { + command::wrapper(attributes, item) +} + +#[proc_macro_attribute] +pub fn mobile_entry_point(attributes: TokenStream, item: TokenStream) -> TokenStream { + mobile::entry_point(attributes, item) +} + +/// Accepts a list of command functions. Creates a handler that allows commands to be called from JS with invoke(). +/// +/// # Examples +/// ```rust,ignore +/// use tauri_macros::{command, generate_handler}; +/// #[command] +/// fn command_one() { +/// println!("command one called"); +/// } +/// #[command] +/// fn command_two() { +/// println!("command two called"); +/// } +/// fn main() { +/// let _handler = generate_handler![command_one, command_two]; +/// } +/// ``` +/// # Stability +/// The output of this macro is managed internally by Tauri, +/// and should not be accessed directly on normal applications. +/// It may have breaking changes in the future. +#[proc_macro] +pub fn generate_handler(item: TokenStream) -> TokenStream { + parse_macro_input!(item as command::Handler).into() +} + +/// Reads a Tauri config file and generates a `::tauri::Context` based on the content. +/// +/// # Stability +/// The output of this macro is managed internally by Tauri, +/// and should not be accessed directly on normal applications. +/// It may have breaking changes in the future. +#[proc_macro] +pub fn generate_context(items: TokenStream) -> TokenStream { + // this macro is exported from the context module + let path = parse_macro_input!(items as ContextItems); + context::generate_context(path).into() +} + +/// Adds the default type for the last parameter (assumed to be runtime) for a specific feature. +/// +/// e.g. To default the runtime generic to type `crate::Wry` when the `wry` feature is enabled, the +/// syntax would look like `#[default_runtime(crate::Wry, wry)`. This is **always** set for the last +/// generic, so make sure the last generic is the runtime when using this macro. +#[doc(hidden)] +#[proc_macro_attribute] +pub fn default_runtime(attributes: TokenStream, input: TokenStream) -> TokenStream { + let attributes = parse_macro_input!(attributes as runtime::Attributes); + let input = parse_macro_input!(input as runtime::Input); + runtime::default_runtime(attributes, input).into() +} + +/// Accepts a closure-like syntax to call arbitrary code on a menu item +/// after matching against `kind` and retrieving it from `resources_table` using `rid`. +/// +/// You can optionally pass a 5th parameter to select which item kinds +/// to match against, by providing a `|` separated list of item kinds +/// ```ignore +/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), Check | Submenu); +/// ``` +/// You could also provide a negated list +/// ```ignore +/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check); +/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check | !Submenu); +/// ``` +/// but you can't have mixed negations and positive kinds. +/// ```ignore +/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text), !Check | Submenu); +/// ``` +/// +/// #### Example +/// +/// ```ignore +/// let rid = 23; +/// let kind = ItemKind::Check; +/// let resources_table = app.resources_table(); +/// do_menu_item!(resources_table, rid, kind, |i| i.set_text(text)) +/// ``` +/// which will expand into: +/// ```ignore +/// let rid = 23; +/// let kind = ItemKind::Check; +/// let resources_table = app.resources_table(); +/// match kind { +/// ItemKind::Submenu => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::MenuItem => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Predefined => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Check => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// ItemKind::Icon => { +/// let i = resources_table.get::>(rid)?; +/// i.set_text(text) +/// } +/// _ => unreachable!(), +/// } +/// ``` +#[proc_macro] +pub fn do_menu_item(input: TokenStream) -> TokenStream { + let tokens = parse_macro_input!(input as menu::DoMenuItemInput); + menu::do_menu_item(tokens).into() +} + +/// Convert a .png or .ico icon to an Image +/// for things like `tauri::tray::TrayIconBuilder` to consume, +/// relative paths are resolved from `CARGO_MANIFEST_DIR`, not current file +/// +/// ### Examples +/// +/// ```ignore +/// const APP_ICON: Image<'_> = include_image!("./icons/32x32.png"); +/// +/// // then use it with tray +/// TrayIconBuilder::new().icon(APP_ICON).build().unwrap(); +/// +/// // or with window +/// WebviewWindowBuilder::new(app, "main", WebviewUrl::default()) +/// .icon(APP_ICON) +/// .unwrap() +/// .build() +/// .unwrap(); +/// +/// // or with any other functions that takes `Image` struct +/// ``` +/// +/// Note: this stores the image in raw pixels to the final binary, +/// so keep the icon size (width and height) small +/// or else it's going to bloat your final executable +#[proc_macro] +pub fn include_image(tokens: TokenStream) -> TokenStream { + let path = match parse2::(tokens.into()) { + Ok(path) => path, + Err(err) => return err.into_compile_error().into(), + }; + let path = PathBuf::from(path.value()); + let resolved_path = if path.is_relative() { + if let Ok(base_dir) = std::env::var("CARGO_MANIFEST_DIR").map(PathBuf::from) { + base_dir.join(path) + } else { + return quote!(compile_error!("$CARGO_MANIFEST_DIR is not defined")).into(); + } + } else { + path + }; + if !resolved_path.exists() { + let error_string = format!( + "Provided Image path \"{}\" doesn't exists", + resolved_path.display() + ); + return quote!(compile_error!(#error_string)).into(); + } + + match CachedIcon::new("e!(::tauri), &resolved_path).map_err(|error| error.to_string()) { + Ok(icon) => icon.into_token_stream(), + Err(error) => quote!(compile_error!(#error)), + } + .into() +} diff --git a/crates/tauri-macros/src/menu.rs b/crates/tauri-macros/src/menu.rs new file mode 100644 index 000000000000..1e230d152324 --- /dev/null +++ b/crates/tauri-macros/src/menu.rs @@ -0,0 +1,136 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::{ + parse::{Parse, ParseStream}, + punctuated::Punctuated, + Expr, Token, +}; + +pub struct DoMenuItemInput { + resources_table: Ident, + rid: Ident, + kind: Ident, + var: Ident, + expr: Expr, + kinds: Vec, +} + +#[derive(Clone)] +struct NegatedIdent { + negated: bool, + ident: Ident, +} + +impl NegatedIdent { + fn new(ident: &str) -> Self { + Self { + negated: false, + ident: Ident::new(ident, Span::call_site()), + } + } + + fn is_negated(&self) -> bool { + self.negated + } +} + +impl Parse for NegatedIdent { + fn parse(input: ParseStream) -> syn::Result { + let negated_token = input.parse::(); + let ident: Ident = input.parse()?; + Ok(NegatedIdent { + negated: negated_token.is_ok(), + ident, + }) + } +} + +impl Parse for DoMenuItemInput { + fn parse(input: ParseStream) -> syn::Result { + let resources_table: Ident = input.parse()?; + let _: Token![,] = input.parse()?; + let rid: Ident = input.parse()?; + let _: Token![,] = input.parse()?; + let kind: Ident = input.parse()?; + let _: Token![,] = input.parse()?; + let _: Token![|] = input.parse()?; + let var: Ident = input.parse()?; + let _: Token![|] = input.parse()?; + let expr: Expr = input.parse()?; + let _: syn::Result = input.parse(); + let kinds = Punctuated::::parse_terminated(input)?; + + Ok(Self { + resources_table, + rid, + kind, + var, + expr, + kinds: kinds.into_iter().collect(), + }) + } +} + +pub fn do_menu_item(input: DoMenuItemInput) -> TokenStream { + let DoMenuItemInput { + rid, + resources_table, + kind, + expr, + var, + mut kinds, + } = input; + + let defaults = vec![ + NegatedIdent::new("Submenu"), + NegatedIdent::new("MenuItem"), + NegatedIdent::new("Predefined"), + NegatedIdent::new("Check"), + NegatedIdent::new("Icon"), + ]; + + if kinds.is_empty() { + kinds.extend(defaults.clone()); + } + + let has_negated = kinds.iter().any(|n| n.is_negated()); + if has_negated { + kinds.extend(defaults); + kinds.sort_by(|a, b| a.ident.cmp(&b.ident)); + kinds.dedup_by(|a, b| a.ident == b.ident); + } + + let (kinds, types): (Vec, Vec) = kinds + .into_iter() + .filter_map(|nident| { + if nident.is_negated() { + None + } else { + match nident.ident { + i if i == "MenuItem" => Some((i, Ident::new("MenuItem", Span::call_site()))), + i if i == "Submenu" => Some((i, Ident::new("Submenu", Span::call_site()))), + i if i == "Predefined" => Some((i, Ident::new("PredefinedMenuItem", Span::call_site()))), + i if i == "Check" => Some((i, Ident::new("CheckMenuItem", Span::call_site()))), + i if i == "Icon" => Some((i, Ident::new("IconMenuItem", Span::call_site()))), + _ => None, + } + } + }) + .unzip(); + + quote! { + match #kind { + #( + ItemKind::#kinds => { + let #var = #resources_table.get::<#types>(#rid)?; + #expr + } + )* + _ => unreachable!(), + } + } +} diff --git a/crates/tauri-macros/src/mobile.rs b/crates/tauri-macros/src/mobile.rs new file mode 100644 index 000000000000..8782717e4eaa --- /dev/null +++ b/crates/tauri-macros/src/mobile.rs @@ -0,0 +1,95 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use quote::{format_ident, quote}; +use std::env::var; +use syn::{parse_macro_input, spanned::Spanned, ItemFn}; + +fn get_env_var(name: &str, error: &mut Option, function: &ItemFn) -> TokenStream2 { + match var(name) { + Ok(value) => { + let ident = format_ident!("{value}"); + quote!(#ident) + } + Err(_) => { + error.replace( + syn::Error::new( + function.span(), + format!("`{name}` env var not set, do you have a build script with tauri-build?",), + ) + .into_compile_error(), + ); + quote!() + } + } +} + +pub fn entry_point(_attributes: TokenStream, item: TokenStream) -> TokenStream { + let function = parse_macro_input!(item as ItemFn); + let function_name = function.sig.ident.clone(); + + let mut error = None; + let domain = get_env_var("TAURI_ANDROID_PACKAGE_NAME_PREFIX", &mut error, &function); + let app_name = get_env_var("TAURI_ANDROID_PACKAGE_NAME_APP_NAME", &mut error, &function); + + let (wrapper, wrapper_name) = if function.sig.asyncness.is_some() { + let wrapper_name = syn::Ident::new(&format!("{function_name}_wrapper"), function_name.span()); + ( + quote! { + #function + + fn #wrapper_name() { + ::tauri::async_runtime::block_on(#function_name()); + } + }, + wrapper_name, + ) + } else { + ( + quote! { + #function + }, + function_name, + ) + }; + + if let Some(e) = error { + quote!(#e).into() + } else { + quote!( + fn stop_unwind T, T>(f: F) -> T { + match std::panic::catch_unwind(std::panic::AssertUnwindSafe(f)) { + Ok(t) => t, + Err(err) => { + eprintln!("attempt to unwind out of `rust` with err: {:?}", err); + std::process::abort() + } + } + } + + #wrapper + + fn _start_app() { + #[cfg(target_os = "ios")] + ::tauri::log_stdout(); + #[cfg(target_os = "android")] + { + ::tauri::android_binding!(#domain, #app_name, _start_app, ::tauri::wry); + } + stop_unwind(#wrapper_name); + } + + // be careful when renaming this, the `start_app` symbol is checked by the CLI + #[cfg(not(target_os = "android"))] + #[no_mangle] + #[inline(never)] + pub extern "C" fn start_app() { + _start_app() + } + ) + .into() + } +} diff --git a/crates/tauri-macros/src/runtime.rs b/crates/tauri-macros/src/runtime.rs new file mode 100644 index 000000000000..d7ad940ccf14 --- /dev/null +++ b/crates/tauri-macros/src/runtime.rs @@ -0,0 +1,105 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use proc_macro2::TokenStream; +use quote::{quote, ToTokens}; +use syn::parse::{Parse, ParseStream}; +use syn::{ + parse_quote, DeriveInput, Error, GenericParam, Ident, ItemTrait, ItemType, Token, Type, TypeParam, +}; + +#[derive(Clone)] +pub(crate) enum Input { + Derive(DeriveInput), + Trait(ItemTrait), + Type(ItemType), +} + +impl Parse for Input { + fn parse(input: ParseStream) -> syn::Result { + input + .parse::() + .map(Self::Derive) + .or_else(|_| input.parse().map(Self::Trait)) + .or_else(|_| input.parse().map(Self::Type)) + .map_err(|_| { + Error::new( + input.span(), + "default_runtime only supports `struct`, `enum`, `type`, or `trait` definitions", + ) + }) + } +} + +impl Input { + fn last_param_mut(&mut self) -> Option<&mut GenericParam> { + match self { + Input::Derive(d) => d.generics.params.last_mut(), + Input::Trait(t) => t.generics.params.last_mut(), + Input::Type(t) => t.generics.params.last_mut(), + } + } +} + +impl ToTokens for Input { + fn to_tokens(&self, tokens: &mut TokenStream) { + match self { + Input::Derive(d) => d.to_tokens(tokens), + Input::Trait(t) => t.to_tokens(tokens), + Input::Type(t) => t.to_tokens(tokens), + } + } +} + +/// The default runtime type to enable when the provided feature is enabled. +pub(crate) struct Attributes { + default_type: Type, + feature: Ident, +} + +impl Parse for Attributes { + fn parse(input: ParseStream<'_>) -> syn::Result { + let default_type = input.parse()?; + input.parse::()?; + Ok(Attributes { + default_type, + feature: input.parse()?, + }) + } +} + +pub(crate) fn default_runtime(attributes: Attributes, input: Input) -> TokenStream { + // create a new copy to manipulate for the wry feature flag + let mut wry = input.clone(); + let wry_runtime = wry + .last_param_mut() + .expect("default_runtime requires the item to have at least 1 generic parameter"); + + // set the default value of the last generic parameter to the provided runtime type + match wry_runtime { + GenericParam::Type( + param @ TypeParam { + eq_token: None, + default: None, + .. + }, + ) => { + param.eq_token = Some(parse_quote!(=)); + param.default = Some(attributes.default_type); + } + _ => { + panic!("DefaultRuntime requires the last parameter to not have a default value") + } + }; + + let feature = attributes.feature.to_string(); + + quote!( + #[cfg(feature = #feature)] + #wry + + #[cfg(not(feature = #feature))] + #input + ) +} diff --git a/crates/tauri-plugin/CHANGELOG.md b/crates/tauri-plugin/CHANGELOG.md new file mode 100644 index 000000000000..26976234ab45 --- /dev/null +++ b/crates/tauri-plugin/CHANGELOG.md @@ -0,0 +1,276 @@ +# Changelog + +## \[2.0.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.1.0` + +## \[2.0.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.2` + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.1` + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0` + +## \[2.0.0-rc.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.13` + +## \[2.0.0-rc.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.12` + +## \[2.0.0-rc.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.11` + +## \[2.0.0-rc.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.10` + +## \[2.0.0-rc.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.9` + +## \[2.0.0-rc.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.8` + +## \[2.0.0-rc.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.7` + +## \[2.0.0-rc.6] + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.6` + +## \[2.0.0-rc.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.5` + +## \[2.0.0-rc.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.4` + +## \[2.0.0-rc.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.3` + +## \[2.0.0-rc.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.2` + +## \[2.0.0-rc.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.1` + +## \[2.0.0-rc.0] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.0` + +### Breaking Changes + +- [`758d28c8a`](https://www.github.com/tauri-apps/tauri/commit/758d28c8a2d5c9567158e339326b765f72da983e) ([#10390](https://www.github.com/tauri-apps/tauri/pull/10390)) Core plugin permissions are now prefixed with `core:`, the `core:default` permission set can now be used and the `core` plugin name is reserved. + The `tauri migrate` tool will automate the migration process, which involves prefixing all `app`, `event`, `image`, `menu`, `path`, `resources`, `tray`, `webview` and `window` permissions with `core:`. + +## \[2.0.0-beta.19] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.19` + +## \[2.0.0-beta.18] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.18` + +## \[2.0.0-beta.17] + +### New Features + +- [`8a1ae2dea`](https://www.github.com/tauri-apps/tauri/commit/8a1ae2deaf3086e531ada25b1627f900e2e421fb)([#9843](https://www.github.com/tauri-apps/tauri/pull/9843)) Added an option to use a Xcode project for the iOS plugin instead of a plain SwiftPM project. + +### What's Changed + +- [`9ac930380`](https://www.github.com/tauri-apps/tauri/commit/9ac930380a5df3fe700e68e75df8684d261ca292)([#9850](https://www.github.com/tauri-apps/tauri/pull/9850)) Emit `cargo:rustc-check-cfg` instruction so Cargo validates custom cfg attributes on Rust 1.80 (or nightly-2024-05-05). + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.17` + +## \[2.0.0-beta.16] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.16` + +## \[2.0.0-beta.15] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.15` + +## \[2.0.0-beta.14] + +### Enhancements + +- [`bf2635ab6`](https://www.github.com/tauri-apps/tauri/commit/bf2635ab6241a5b82569eafc939046d6e245f3ad)([#9632](https://www.github.com/tauri-apps/tauri/pull/9632)) Improve the error message that is shown when the `links` property is missing from a Tauri Plugin. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.14` + +## \[2.0.0-beta.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.13` + +## \[2.0.0-beta.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.12` + +## \[2.0.0-beta.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.11` + +## \[2.0.0-beta.10] + +### New Features + +- [`e227fe02f`](https://www.github.com/tauri-apps/tauri/commit/e227fe02f986e145c0731a64693e1c830a9eb5b0)([#9156](https://www.github.com/tauri-apps/tauri/pull/9156)) Allow plugins to define (at compile time) JavaScript that are initialized when `withGlobalTauri` is true. +- [`e227fe02f`](https://www.github.com/tauri-apps/tauri/commit/e227fe02f986e145c0731a64693e1c830a9eb5b0)([#9156](https://www.github.com/tauri-apps/tauri/pull/9156)) Added `Builder::global_api_script_path` to define a JavaScript file containing the initialization script for the plugin API bindings when `withGlobalTauri` is used. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.10` + +## \[2.0.0-beta.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.9` + +## \[2.0.0-beta.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.8` + +## \[2.0.0-beta.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.7` + +## \[2.0.0-beta.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.6` + +### Breaking Changes + +- [`3657ad82`](https://www.github.com/tauri-apps/tauri/commit/3657ad82f88ce528551d032d521c52eed3f396b4)([#9008](https://www.github.com/tauri-apps/tauri/pull/9008)) Allow defining permissions for the application commands via `tauri_build::Attributes::app_manifest`. + +## \[2.0.0-beta.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.5` + +## \[2.0.0-beta.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.4` + +## \[2.0.0-beta.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.3` + +## \[2.0.0-beta.2] + +### Enhancements + +- [`dd7571a7`](https://www.github.com/tauri-apps/tauri/commit/dd7571a7808676c8063a4983b9c6687dfaf03a09)([#8815](https://www.github.com/tauri-apps/tauri/pull/8815)) Do not generate JSON schema and markdown reference file if the plugin does not define any permissions and delete those files if they exist. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.2` + +## \[2.0.0-beta.1] + +### Bug Fixes + +- [`4e101f80`](https://www.github.com/tauri-apps/tauri/commit/4e101f801657e7d01ce8c22f9c6468067d0caab2)([#8756](https://www.github.com/tauri-apps/tauri/pull/8756)) Rerun build script when a new permission is added. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.1` + +## \[2.0.0-beta.0] + +### New Features + +- [`74a2a603`](https://www.github.com/tauri-apps/tauri/commit/74a2a6036a5e57462f161d728cbd8a6f121028ca)([#8661](https://www.github.com/tauri-apps/tauri/pull/8661)) Implement access control list for IPC usage. diff --git a/crates/tauri-plugin/Cargo.toml b/crates/tauri-plugin/Cargo.toml new file mode 100644 index 000000000000..b572e55ff1ac --- /dev/null +++ b/crates/tauri-plugin/Cargo.toml @@ -0,0 +1,43 @@ +[package] +name = "tauri-plugin" +version = "2.0.3" +description = "Build script and runtime Tauri plugin definitions" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +categories.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[package.metadata.docs.rs] +features = ["build", "runtime"] +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs"] + +[features] +build = [ + "dep:anyhow", + "dep:serde", + "dep:serde_json", + "dep:glob", + "dep:toml", + "dep:plist", + "dep:walkdir", +] +runtime = [] + +[dependencies] +anyhow = { version = "1", optional = true } +serde = { version = "1", optional = true } +tauri-utils = { version = "2.1.0", default-features = false, features = [ + "build", +], path = "../tauri-utils" } +serde_json = { version = "1", optional = true } +glob = { version = "0.3", optional = true } +toml = { version = "0.8", optional = true } +schemars = { version = "0.8.18", features = ["preserve_order"] } +walkdir = { version = "2", optional = true } + +[target."cfg(target_os = \"macos\")".dependencies] +plist = { version = "1", optional = true } diff --git a/crates/tauri-plugin/src/build/mobile.rs b/crates/tauri-plugin/src/build/mobile.rs new file mode 100644 index 000000000000..3d4d3cec6e82 --- /dev/null +++ b/crates/tauri-plugin/src/build/mobile.rs @@ -0,0 +1,232 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Mobile-specific build utilities. + +use std::{ + env::var_os, + fs::{copy, create_dir, create_dir_all, read_to_string, remove_dir_all, write}, + path::{Path, PathBuf}, +}; + +use anyhow::{Context, Result}; + +use super::{build_var, cfg_alias}; + +#[cfg(target_os = "macos")] +pub fn update_entitlements(f: F) -> Result<()> { + if let (Some(project_path), Ok(app_name)) = ( + var_os("TAURI_IOS_PROJECT_PATH").map(PathBuf::from), + std::env::var("TAURI_IOS_APP_NAME"), + ) { + update_plist_file( + project_path + .join(format!("{app_name}_iOS")) + .join(format!("{app_name}_iOS.entitlements")), + f, + )?; + } + + Ok(()) +} + +pub fn update_android_manifest(block_identifier: &str, parent: &str, insert: String) -> Result<()> { + if let Some(project_path) = var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) { + let manifest_path = project_path.join("app/src/main/AndroidManifest.xml"); + let manifest = read_to_string(&manifest_path)?; + let rewritten = insert_into_xml(&manifest, block_identifier, parent, &insert); + if rewritten != manifest { + write(manifest_path, rewritten)?; + } + } + Ok(()) +} + +pub(crate) fn setup( + android_path: Option, + #[allow(unused_variables)] ios_path: Option, +) -> Result<()> { + let target_os = build_var("CARGO_CFG_TARGET_OS")?; + let mobile = target_os == "android" || target_os == "ios"; + cfg_alias("mobile", mobile); + cfg_alias("desktop", !mobile); + + match target_os.as_str() { + "android" => { + if let Some(path) = android_path { + let manifest_dir = build_var("CARGO_MANIFEST_DIR").map(PathBuf::from)?; + let source = manifest_dir.join(path); + + let tauri_library_path = std::env::var("DEP_TAURI_ANDROID_LIBRARY_PATH") + .expect("missing `DEP_TAURI_ANDROID_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin."); + println!("cargo:rerun-if-env-changed=DEP_TAURI_ANDROID_LIBRARY_PATH"); + + create_dir_all(source.join(".tauri")).context("failed to create .tauri directory")?; + copy_folder( + Path::new(&tauri_library_path), + &source.join(".tauri").join("tauri-api"), + &[], + ) + .context("failed to copy tauri-api to the plugin project")?; + + println!("cargo:android_library_path={}", source.display()); + } + } + #[cfg(target_os = "macos")] + "ios" => { + if let Some(path) = ios_path { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR") + .map(PathBuf::from) + .unwrap(); + let tauri_library_path = std::env::var("DEP_TAURI_IOS_LIBRARY_PATH") + .expect("missing `DEP_TAURI_IOS_LIBRARY_PATH` environment variable. Make sure `tauri` is a dependency of the plugin."); + + let tauri_dep_path = path.parent().unwrap().join(".tauri"); + create_dir_all(&tauri_dep_path).context("failed to create .tauri directory")?; + copy_folder( + Path::new(&tauri_library_path), + &tauri_dep_path.join("tauri-api"), + &[".build", "Package.resolved", "Tests"], + ) + .context("failed to copy tauri-api to the plugin project")?; + tauri_utils::build::link_apple_library( + &std::env::var("CARGO_PKG_NAME").unwrap(), + manifest_dir.join(path), + ); + } + } + _ => (), + } + + Ok(()) +} + +fn copy_folder(source: &Path, target: &Path, ignore_paths: &[&str]) -> Result<()> { + let _ = remove_dir_all(target); + + for entry in walkdir::WalkDir::new(source) { + let entry = entry?; + let rel_path = entry.path().strip_prefix(source)?; + let rel_path_str = rel_path.to_string_lossy(); + if ignore_paths + .iter() + .any(|path| rel_path_str.starts_with(path)) + { + continue; + } + let dest_path = target.join(rel_path); + + if entry.file_type().is_dir() { + create_dir(&dest_path) + .with_context(|| format!("failed to create directory {}", dest_path.display()))?; + } else { + copy(entry.path(), &dest_path).with_context(|| { + format!( + "failed to copy {} to {}", + entry.path().display(), + dest_path.display() + ) + })?; + println!("cargo:rerun-if-changed={}", entry.path().display()); + } + } + + Ok(()) +} + +#[cfg(target_os = "macos")] +fn update_plist_file, F: FnOnce(&mut plist::Dictionary)>( + path: P, + f: F, +) -> Result<()> { + use std::io::Cursor; + + let path = path.as_ref(); + if path.exists() { + let plist_str = read_to_string(path)?; + let mut plist = plist::Value::from_reader(Cursor::new(&plist_str))?; + if let Some(dict) = plist.as_dictionary_mut() { + f(dict); + let mut plist_buf = Vec::new(); + let writer = Cursor::new(&mut plist_buf); + plist::to_writer_xml(writer, &plist)?; + let new_plist_str = String::from_utf8(plist_buf)?; + if new_plist_str != plist_str { + write(path, new_plist_str)?; + } + } + } + + Ok(()) +} + +fn xml_block_comment(id: &str) -> String { + format!("") +} + +fn insert_into_xml(xml: &str, block_identifier: &str, parent_tag: &str, contents: &str) -> String { + let block_comment = xml_block_comment(block_identifier); + + let mut rewritten = Vec::new(); + let mut found_block = false; + let parent_closing_tag = format!(""); + for line in xml.split('\n') { + if line.contains(&block_comment) { + found_block = !found_block; + continue; + } + + // found previous block which should be removed + if found_block { + continue; + } + + if let Some(index) = line.find(&parent_closing_tag) { + let indentation = " ".repeat(index + 4); + rewritten.push(format!("{}{}", indentation, block_comment)); + for l in contents.split('\n') { + rewritten.push(format!("{}{}", indentation, l)); + } + rewritten.push(format!("{}{}", indentation, block_comment)); + } + + rewritten.push(line.to_string()); + } + + rewritten.join("\n") +} + +#[cfg(test)] +mod tests { + #[test] + fn insert_into_xml() { + let manifest = r#" + + + + +"#; + let id = "tauritest"; + let new = super::insert_into_xml(manifest, id, "application", ""); + + let block_id_comment = super::xml_block_comment(id); + let expected = format!( + r#" + + + + {block_id_comment} + + {block_id_comment} + +"# + ); + + assert_eq!(new, expected); + + // assert it's still the same after an empty update + let new = super::insert_into_xml(&expected, id, "application", ""); + assert_eq!(new, expected); + } +} diff --git a/crates/tauri-plugin/src/build/mod.rs b/crates/tauri-plugin/src/build/mod.rs new file mode 100644 index 000000000000..cd582d67f4de --- /dev/null +++ b/crates/tauri-plugin/src/build/mod.rs @@ -0,0 +1,159 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::path::{Path, PathBuf}; + +use anyhow::Result; +use tauri_utils::acl::{self, Error}; + +pub mod mobile; + +use serde::de::DeserializeOwned; + +use std::{env, io::Cursor}; + +const RESERVED_PLUGIN_NAMES: &[&str] = &["core", "tauri"]; + +pub fn plugin_config(name: &str) -> Option { + let config_env_var_name = format!( + "TAURI_{}_PLUGIN_CONFIG", + name.to_uppercase().replace('-', "_") + ); + if let Ok(config_str) = env::var(&config_env_var_name) { + println!("cargo:rerun-if-env-changed={config_env_var_name}"); + serde_json::from_reader(Cursor::new(config_str)) + .map(Some) + .expect("failed to parse configuration") + } else { + None + } +} + +pub struct Builder<'a> { + commands: &'a [&'static str], + global_scope_schema: Option, + global_api_script_path: Option, + android_path: Option, + ios_path: Option, +} + +impl<'a> Builder<'a> { + pub fn new(commands: &'a [&'static str]) -> Self { + Self { + commands, + global_scope_schema: None, + global_api_script_path: None, + android_path: None, + ios_path: None, + } + } + + /// Sets the global scope JSON schema. + pub fn global_scope_schema(mut self, schema: schemars::schema::RootSchema) -> Self { + self.global_scope_schema.replace(schema); + self + } + + /// Sets the path to the script that is injected in the webview when the `withGlobalTauri` configuration is set to true. + /// + /// This is usually an IIFE that injects the plugin API JavaScript bindings to `window.__TAURI__`. + pub fn global_api_script_path>(mut self, path: P) -> Self { + self.global_api_script_path.replace(path.into()); + self + } + + /// Sets the Android project path. + pub fn android_path>(mut self, android_path: P) -> Self { + self.android_path.replace(android_path.into()); + self + } + + /// Sets the iOS project path. + pub fn ios_path>(mut self, ios_path: P) -> Self { + self.ios_path.replace(ios_path.into()); + self + } + + /// [`Self::try_build`] but will exit automatically if an error is found. + pub fn build(self) { + if let Err(error) = self.try_build() { + println!("{}: {error:#}", env!("CARGO_PKG_NAME")); + std::process::exit(1); + } + } + + /// Ensure this crate is properly configured to be a Tauri plugin. + /// + /// # Errors + /// + /// Errors will occur if environmental variables expected to be set inside of [build scripts] + /// are not found, or if the crate violates Tauri plugin conventions. + pub fn try_build(self) -> Result<()> { + // convention: plugin names should not use underscores + let name = build_var("CARGO_PKG_NAME")?; + if name.contains('_') { + anyhow::bail!("plugin names cannot contain underscores"); + } + if RESERVED_PLUGIN_NAMES.contains(&name.as_str()) { + anyhow::bail!("plugin name `{name}` is reserved"); + } + + let out_dir = PathBuf::from(build_var("OUT_DIR")?); + + // requirement: links MUST be set and MUST match the name + let _links = std::env::var("CARGO_MANIFEST_LINKS").map_err(|_| Error::LinksMissing)?; + + let autogenerated = Path::new("permissions").join(acl::build::AUTOGENERATED_FOLDER_NAME); + std::fs::create_dir_all(&autogenerated).expect("unable to create permissions dir"); + + let commands_dir = autogenerated.join("commands"); + if !self.commands.is_empty() { + acl::build::autogenerate_command_permissions(&commands_dir, self.commands, "", true); + } + + println!("cargo:rerun-if-changed=permissions"); + let permissions = + acl::build::define_permissions("./permissions/**/*.*", &name, &out_dir, |_| true)?; + + if permissions.is_empty() { + let _ = std::fs::remove_file(format!( + "./permissions/{}/{}", + acl::PERMISSION_SCHEMAS_FOLDER_NAME, + acl::PERMISSION_SCHEMA_FILE_NAME + )); + let _ = std::fs::remove_file(autogenerated.join(acl::build::PERMISSION_DOCS_FILE_NAME)); + } else { + acl::schema::generate_permissions_schema(&permissions, "./permissions")?; + acl::build::generate_docs( + &permissions, + &autogenerated, + name.strip_prefix("tauri-plugin-").unwrap_or(&name), + )?; + } + + if let Some(global_scope_schema) = self.global_scope_schema { + acl::build::define_global_scope_schema(global_scope_schema, &name, &out_dir)?; + } + + if let Some(path) = self.global_api_script_path { + tauri_utils::plugin::define_global_api_script_path(path); + } + + mobile::setup(self.android_path, self.ios_path)?; + + Ok(()) + } +} + +fn cfg_alias(alias: &str, has_feature: bool) { + println!("cargo:rustc-check-cfg=cfg({alias})"); + if has_feature { + println!("cargo:rustc-cfg={alias}"); + } +} + +/// Grab an env var that is expected to be set inside of build scripts. +fn build_var(key: &'static str) -> Result { + std::env::var(key).map_err(|_| Error::BuildVar(key)) +} diff --git a/crates/tauri-plugin/src/lib.rs b/crates/tauri-plugin/src/lib.rs new file mode 100644 index 000000000000..74c1fb941ed6 --- /dev/null +++ b/crates/tauri-plugin/src/lib.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Interface for building Tauri plugins. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] +#![cfg_attr(docsrs, feature(doc_cfg))] + +#[cfg(feature = "build")] +mod build; +#[cfg(feature = "runtime")] +mod runtime; + +#[cfg(feature = "build")] +#[cfg_attr(docsrs, doc(feature = "build"))] +pub use build::*; +#[cfg(feature = "runtime")] +#[cfg_attr(docsrs, doc(feature = "runtime"))] +#[allow(unused)] +pub use runtime::*; diff --git a/crates/tauri-plugin/src/runtime.rs b/crates/tauri-plugin/src/runtime.rs new file mode 100644 index 000000000000..3d77814f5853 --- /dev/null +++ b/crates/tauri-plugin/src/runtime.rs @@ -0,0 +1,3 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT diff --git a/crates/tauri-runtime-wry/CHANGELOG.md b/crates/tauri-runtime-wry/CHANGELOG.md new file mode 100644 index 000000000000..6fa4627d2914 --- /dev/null +++ b/crates/tauri-runtime-wry/CHANGELOG.md @@ -0,0 +1,1246 @@ +# Changelog + +## \[2.2.0] + +### New Features + +- [`4d545ab3c`](https://www.github.com/tauri-apps/tauri/commit/4d545ab3ca228c8a21b966b709f84a0da2864479) ([#11486](https://www.github.com/tauri-apps/tauri/pull/11486) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `Window::set_background_color` and `WindowBuilder::background_color`. +- [`f37e97d41`](https://www.github.com/tauri-apps/tauri/commit/f37e97d410c4a219e99f97692da05ca9d8e0ba3a) ([#11477](https://www.github.com/tauri-apps/tauri/pull/11477) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindowBuilder/WebviewBuilder::use_https_scheme` to choose whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost` on Windows and Android +- [`cbc095ec5`](https://www.github.com/tauri-apps/tauri/commit/cbc095ec5fe7de29b5c9265576d4e071ec159c1c) ([#11451](https://www.github.com/tauri-apps/tauri/pull/11451) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindowBuilder::devtools` and `WebviewBuilder::devtools` to enable or disable devtools for a specific webview. +- [`2a75c64b5`](https://www.github.com/tauri-apps/tauri/commit/2a75c64b5431284e7340e8743d4ea56a62c75466) ([#11469](https://www.github.com/tauri-apps/tauri/pull/11469) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `WindowBuilder/WebviewWindowBuilder::window_classname` method to specify the name of the window class on Windows. + +### Bug Fixes + +- [`229d7f8e2`](https://www.github.com/tauri-apps/tauri/commit/229d7f8e220cc8d5ca06eff1ed85cb7d047c1d6c) ([#11616](https://www.github.com/tauri-apps/tauri/pull/11616) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix regression in creating child webviews on macOS and Windows, covering the whole window. +- [`8c6d1e8e6`](https://www.github.com/tauri-apps/tauri/commit/8c6d1e8e6c852667bb223b5f4823948868c26d98) ([#11401](https://www.github.com/tauri-apps/tauri/pull/11401) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter method failing on Linux with `GDK may only be used from the main thread`. +- [`129414faa`](https://www.github.com/tauri-apps/tauri/commit/129414faa4e027c9035d56614682cacc0335a6a0) ([#11569](https://www.github.com/tauri-apps/tauri/pull/11569) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix webview not focused by default. + +### Dependencies + +- Upgraded to `tauri-utils@2.1.0` +- Upgraded to `tauri-runtime@2.2.0` + +## \[2.1.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.2` + +## \[2.1.1] + +### Bug Fixes + +- [`ef2482dde`](https://www.github.com/tauri-apps/tauri/commit/ef2482ddecf533181211ee435931fac650495bc5) ([#11366](https://www.github.com/tauri-apps/tauri/pull/11366)) Update wry to 0.46.1 to fix a crash on macOS older than Sequoia. + +## \[2.1.0] + +### Bug Fixes + +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix commands, that use `Webview` or `WebviewWindow` as an argument, receiving an incorrect webview when using multi webviews. +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix events only emitted to first webview only when using multi webviews. +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix custom protocols receiving an incorrect webview label when using multi webviews + +### Dependencies + +- Upgraded to `tauri-runtime@2.1.0` + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.1` +- Upgraded to `tauri-runtime@2.0.1` + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0` +- Upgraded to `tauri-runtime@2.0.0` + +## \[2.0.0-rc.14] + +### New Features + +- [`a247170e1`](https://www.github.com/tauri-apps/tauri/commit/a247170e1f620a9b012274b11cfe51e90327d6e9) ([#11056](https://www.github.com/tauri-apps/tauri/pull/11056) by [@SpikeHD](https://www.github.com/tauri-apps/tauri/../../SpikeHD)) Expose the ability to enabled browser extensions in WebView2 on Windows. +- [`9014a3f17`](https://www.github.com/tauri-apps/tauri/commit/9014a3f1765ca406ea5c3e5224267a79c52cd53d) ([#11066](https://www.github.com/tauri-apps/tauri/pull/11066) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindow::clear_all_browsing_data` and `Webview::clear_all_browsing_data` to clear the webview browsing data. +- [`95df53a2e`](https://www.github.com/tauri-apps/tauri/commit/95df53a2ed96873cd35a4b14a5e312d07e4e3004) ([#11143](https://www.github.com/tauri-apps/tauri/pull/11143) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Add the ability to set theme dynamically using `Window::set_theme`, `App::set_theme` +- [`d9d2502b4`](https://www.github.com/tauri-apps/tauri/commit/d9d2502b41e39efde679e30c8955006e2ba9ea64) ([#11140](https://www.github.com/tauri-apps/tauri/pull/11140) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewDispatch::hide` and `WebviewDispatch::show` methods. +- [`de7414aab`](https://www.github.com/tauri-apps/tauri/commit/de7414aab935e45540594ea930eb60bae4dbc979) ([#11154](https://www.github.com/tauri-apps/tauri/pull/11154) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `Window::set_enabled` and `Window::is_enabled` methods + +### Bug Fixes + +- [`62b3a5cd1`](https://www.github.com/tauri-apps/tauri/commit/62b3a5cd1c804440c2130ab36cc3eadb3baf61cb) ([#11043](https://www.github.com/tauri-apps/tauri/pull/11043) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix `localStorage` not shared between webviews that use the same data directory. + +### Dependencies + +- Upgraded to `tauri-runtime@2.0.0-rc.13` +- Upgraded to `tauri-utils@2.0.0-rc.13` + +## \[2.0.0-rc.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.12` +- Upgraded to `tauri-runtime@2.0.0-rc.12` + +## \[2.0.0-rc.12] + +### Enhancements + +- [`bc4804d48`](https://www.github.com/tauri-apps/tauri/commit/bc4804d4841efefd57fd1f3e147550a3340e2b31) ([#10924](https://www.github.com/tauri-apps/tauri/pull/10924) by [@madsmtm](https://www.github.com/tauri-apps/tauri/../../madsmtm)) Use `objc2` internally and in examples, leading to better memory safety. + +### Breaking Changes + +- [`bc4804d48`](https://www.github.com/tauri-apps/tauri/commit/bc4804d4841efefd57fd1f3e147550a3340e2b31) ([#10924](https://www.github.com/tauri-apps/tauri/pull/10924) by [@madsmtm](https://www.github.com/tauri-apps/tauri/../../madsmtm)) Change the pointer type of `PlatformWebview`'s `inner`, `controller`, `ns_window` and `view_controller` to `c_void`, to avoid publically depending on `objc`. + +## \[2.0.0-rc.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.11` +- Upgraded to `tauri-runtime@2.0.0-rc.11` + +## \[2.0.0-rc.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.10` +- Upgraded to `tauri-runtime@2.0.0-rc.10` + +## \[2.0.0-rc.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.9` +- Upgraded to `tauri-runtime@2.0.0-rc.9` + +## \[2.0.0-rc.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.8` +- Upgraded to `tauri-runtime@2.0.0-rc.8` +- [`77056b194`](https://www.github.com/tauri-apps/tauri/commit/77056b194a2aa8be1b9865d707b741a6ed72ec56) ([#10895](https://www.github.com/tauri-apps/tauri/pull/10895) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Update tao to 0.30 and wry to 0.43. + +### Breaking Changes + +- [`5048a7293`](https://www.github.com/tauri-apps/tauri/commit/5048a7293b87b5b93aaefd42dedc0e551e08086c) ([#10840](https://www.github.com/tauri-apps/tauri/pull/10840) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) The `linux-ipc-protocol` feature is now always enabled, so the Cargo feature flag was removed. + This increases the minimum webkit2gtk version to a release that does not affect the minimum target Linux distros for Tauri apps. + +## \[2.0.0-rc.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.7` +- Upgraded to `tauri-runtime@2.0.0-rc.7` + +## \[2.0.0-rc.6] + +### Bug Fixes + +- [`793ee0531`](https://www.github.com/tauri-apps/tauri/commit/793ee0531730597e6008c9c0dedabbab7a2bef53) ([#10700](https://www.github.com/tauri-apps/tauri/pull/10700) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Allow hyphens and underscores on app identifiers. + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.6` +- Upgraded to `tauri-runtime@2.0.0-rc.6` + +## \[2.0.0-rc.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.5` +- Upgraded to `tauri-runtime@2.0.0-rc.5` + +## \[2.0.0-rc.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.4` +- Upgraded to `tauri-runtime@2.0.0-rc.4` + +## \[2.0.0-rc.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.3` +- Upgraded to `tauri-runtime@2.0.0-rc.3` +- [`d39c392b7`](https://www.github.com/tauri-apps/tauri/commit/d39c392b7cec746da423211f9c74632abe4b6af5) ([#10655](https://www.github.com/tauri-apps/tauri/pull/10655) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Update `tao` to 0.29 and `wry` to 0.42. + +## \[2.0.0-rc.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.2` +- Upgraded to `tauri-runtime@2.0.0-rc.2` + +## \[2.0.0-rc.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.1` +- Upgraded to `tauri-runtime@2.0.0-rc.1` + +## \[2.0.0-rc.0] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.0` +- Upgraded to `tauri-runtime@2.0.0-rc.0` + +## \[2.0.0-beta.21] + +### What's Changed + +- [`9546548ec`](https://www.github.com/tauri-apps/tauri/commit/9546548ec0c83ba620b1bc9d1d424a7009d0b423) ([#10297](https://www.github.com/tauri-apps/tauri/pull/10297) by [@pewsheen](https://www.github.com/tauri-apps/tauri/../../pewsheen)) On macOS, set default titlebar style to `Visible` to prevent webview move out of the view. +- [`da25f7353`](https://www.github.com/tauri-apps/tauri/commit/da25f7353070477ba969851e974379d7666d6806) ([#10242](https://www.github.com/tauri-apps/tauri/pull/10242) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `inner_size_constraints` method on `WindowBuilder` trait and `set_size_constraints` method on `WindowDispatch` trait. + +### Dependencies + +- Upgraded to `tauri-runtime@2.0.0-beta.21` + +## \[2.0.0-beta.20] + +### Bug Fixes + +- [`afb102c59`](https://www.github.com/tauri-apps/tauri/commit/afb102c59ba0de27e330589269001e0d2a01576d) ([#10211](https://www.github.com/tauri-apps/tauri/pull/10211) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix window edge not working after setting resizable false and decorated false dynamically + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.19` +- Upgraded to `tauri-runtime@2.0.0-beta.20` + +## \[2.0.0-beta.19] + +### Bug Fixes + +- [`f29b78811`](https://www.github.com/tauri-apps/tauri/commit/f29b78811080bc8313459f34545152d939c62bf6) ([#9862](https://www.github.com/tauri-apps/tauri/pull/9862)) On Windows, handle resizing undecorated windows natively which improves performance and fixes a couple of annoyances with previous JS implementation: + + - No more cursor flickering when moving the cursor across an edge. + - Can resize from top even when `data-tauri-drag-region` element exists there. + - Upon starting rezing, clicks don't go through elements behind it so no longer accidental clicks. + +### What's Changed + +- [`669b9c6b5`](https://www.github.com/tauri-apps/tauri/commit/669b9c6b5af791129b77ee440dacaa98288c906b) ([#9621](https://www.github.com/tauri-apps/tauri/pull/9621)) Set the gtk application to the identifier defined in `tauri.conf.json` to ensure the app uniqueness. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.18` +- Upgraded to `tauri-runtime@2.0.0-beta.19` +- [`d4c908cfb`](https://www.github.com/tauri-apps/tauri/commit/d4c908cfb8c567abdaf99b85f65f482ea81967e5) ([#10048](https://www.github.com/tauri-apps/tauri/pull/10048)) Update `windows` crate to version `0.57` and `webview2-com` crate to version `0.31` + +## \[2.0.0-beta.18] + +### Enhancements + +- [`276c4b143`](https://www.github.com/tauri-apps/tauri/commit/276c4b14385e17cff15a2e5b57fd2a7cddef9f08)([#9832](https://www.github.com/tauri-apps/tauri/pull/9832)) Added `WindowBuilder::get_theme`. + +### What's Changed + +- [`9ac930380`](https://www.github.com/tauri-apps/tauri/commit/9ac930380a5df3fe700e68e75df8684d261ca292)([#9850](https://www.github.com/tauri-apps/tauri/pull/9850)) Emit `cargo:rustc-check-cfg` instruction so Cargo validates custom cfg attributes on Rust 1.80 (or nightly-2024-05-05). + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.17` +- Upgraded to `tauri-runtime@2.0.0-beta.18` + +## \[2.0.0-beta.17] + +### Security fixes + +- [`d950ac123`](https://www.github.com/tauri-apps/tauri/commit/d950ac1239817d17324c035e5c4769ee71fc197d) Only process IPC commands from the main frame. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.16` +- Upgraded to `tauri-runtime@2.0.0-beta.17` + +## \[2.0.0-beta.16] + +### New Features + +- [`78839b6d2`](https://www.github.com/tauri-apps/tauri/commit/78839b6d2f1005a5e6e1a54b0305136bae0c3a7c)([#4865](https://www.github.com/tauri-apps/tauri/pull/4865)) Add `RunEvent::Reopen` for handle click on dock icon on macOS. + +### Bug Fixes + +- [`c0bcc6c0b`](https://www.github.com/tauri-apps/tauri/commit/c0bcc6c0b74ef7167de85002a5c29b6f731bae41)([#9717](https://www.github.com/tauri-apps/tauri/pull/9717)) Fixes redraw tracing span not closing. + +### What's Changed + +- [`783ef0f2d`](https://www.github.com/tauri-apps/tauri/commit/783ef0f2d331f520fa827c3112f36c0b519b9292)([#9647](https://www.github.com/tauri-apps/tauri/pull/9647)) Changed `WebviewDispatch::url` getter to return a result. + +### Dependencies + +- Upgraded to `tauri-runtime@2.0.0-beta.16` +- Upgraded to `tauri-utils@2.0.0-beta.15` + +## \[2.0.0-beta.15] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.14` +- Upgraded to `tauri-runtime@2.0.0-beta.15` + +## \[2.0.0-beta.14] + +### New Features + +- [`477bb8cd4`](https://www.github.com/tauri-apps/tauri/commit/477bb8cd4ea88ade3f6c1f268ad1701a68150161)([#9297](https://www.github.com/tauri-apps/tauri/pull/9297)) Add `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter to get the current cursor position. + +### Dependencies + +- Upgraded to `tauri-runtime@2.0.0-beta.14` + +## \[2.0.0-beta.13] + +### What's Changed + +- [`005fe8ce1`](https://www.github.com/tauri-apps/tauri/commit/005fe8ce1ef71ea46a7d86f98bdf397ca81eb920)([#9410](https://www.github.com/tauri-apps/tauri/pull/9410)) Fix `closable`, `maximizable` and `minimizable` options not taking effect when used in tauri.conf.json or from JS APIs. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.13` +- Upgraded to `tauri-runtime@2.0.0-beta.13` + +## \[2.0.0-beta.12] + +### New Features + +- [`58a7a552d`](https://www.github.com/tauri-apps/tauri/commit/58a7a552d739b77b71d61af11c53f7f2dc7a6e7e)([#9378](https://www.github.com/tauri-apps/tauri/pull/9378)) Added the `set_zoom` function to the webview API. +- [`58a7a552d`](https://www.github.com/tauri-apps/tauri/commit/58a7a552d739b77b71d61af11c53f7f2dc7a6e7e)([#9378](https://www.github.com/tauri-apps/tauri/pull/9378)) Add `zoom_hotkeys_enabled` to enable browser native zoom controls on creating webviews. + +### Bug Fixes + +- [`2f20fdf1d`](https://www.github.com/tauri-apps/tauri/commit/2f20fdf1d6b92fa8b9b38caf7321c3ce3e895f1b)([#9361](https://www.github.com/tauri-apps/tauri/pull/9361)) Fixes an issue causing compilation to fail for i686 and armv7 32-bit targets. +- [`4c2e7477e`](https://www.github.com/tauri-apps/tauri/commit/4c2e7477e6869e2ce0578265825bbd42a5f28393)([#9309](https://www.github.com/tauri-apps/tauri/pull/9309)) Fix window centering not taking taskbar into account on Windows +- [`02eaf0787`](https://www.github.com/tauri-apps/tauri/commit/02eaf07872b90225eead22ecdd6ff0a9ed5dd0ff)([#9428](https://www.github.com/tauri-apps/tauri/pull/9428)) Fixes `inner_size` crash when the window has no webviews. +- [`f22ea2998`](https://www.github.com/tauri-apps/tauri/commit/f22ea2998619cc09c2d426f7b42211a80eed578e)([#9465](https://www.github.com/tauri-apps/tauri/pull/9465)) Revert the [fix](https://github.com/tauri-apps/tauri/pull/9246) for webview's visibility doesn't change with the app window on Windows as it caused white flashes on show/restore. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.12` +- Upgraded to `tauri-runtime@2.0.0-beta.12` + +## \[2.0.0-beta.11] + +### Bug Fixes + +- [`4c0c780e0`](https://www.github.com/tauri-apps/tauri/commit/4c0c780e00d8851be38cb1c22f636d9e4ed34a23)([#2690](https://www.github.com/tauri-apps/tauri/pull/2690)) Fix window inner size evaluation on macOS. +- [`5bd47b446`](https://www.github.com/tauri-apps/tauri/commit/5bd47b44673f74b1b4e8d704b7a95539915ede76)([#9246](https://www.github.com/tauri-apps/tauri/pull/9246)) Fix webview's visibility doesn't change with the app window + +### What's Changed + +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Updated `http` crate to `1.1` + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.11` +- Upgraded to `tauri-runtime@2.0.0-beta.11` +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Upgraded to `wry@0.38.0` + +### Breaking Changes + +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) The IPC handler closure now receives a `http::Request` instead of a String representing the request body. +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Rename `FileDrop` to `DragDrop` on structs, enums and enum variants. Also renamed `file_drop` to `drag_drop` on fields and function names. + +## \[2.0.0-beta.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.10` +- Upgraded to `tauri-runtime@2.0.0-beta.10` + +## \[2.0.0-beta.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.9` +- Upgraded to `tauri-runtime@2.0.0-beta.9` + +## \[2.0.0-beta.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.8` +- Upgraded to `tauri-runtime@2.0.0-beta.8` + +## \[2.0.0-beta.7] + +### New Features + +- [`46de49aaa`](https://www.github.com/tauri-apps/tauri/commit/46de49aaad4a148fafc31d591be0e2ed12256507)([#9059](https://www.github.com/tauri-apps/tauri/pull/9059)) Added `set_auto_resize` method for the webview. + +### Enhancements + +- [`46de49aaa`](https://www.github.com/tauri-apps/tauri/commit/46de49aaad4a148fafc31d591be0e2ed12256507)([#9059](https://www.github.com/tauri-apps/tauri/pull/9059)) When using the `unstable` feature flag, `WebviewWindow` will internally use the child webview interface for flexibility. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.7` +- Upgraded to `tauri-runtime@2.0.0-beta.7` + +## \[2.0.0-beta.6] + +### Bug Fixes + +- [`222a96b7`](https://www.github.com/tauri-apps/tauri/commit/222a96b74b145fb48d3f0c109897962d56fae57a)([#8999](https://www.github.com/tauri-apps/tauri/pull/8999)) Fixes auto resize and positioning when using the multiwebview mode. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.6` +- Upgraded to `tauri-runtime@2.0.0-beta.6` + +## \[2.0.0-beta.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.5` +- Upgraded to `tauri-runtime@2.0.0-beta.5` + +## \[2.0.0-beta.4] + +### New Features + +- [`fdcaf935`](https://www.github.com/tauri-apps/tauri/commit/fdcaf935fa75ecfa2806939c4faad4fe9e880386)([#8939](https://www.github.com/tauri-apps/tauri/pull/8939)) Added the `reparent` function to the webview API. + +### Bug Fixes + +- [`6e3bd4b9`](https://www.github.com/tauri-apps/tauri/commit/6e3bd4b9f815ddde8b5eaf9f69991d4de80bb584)([#8942](https://www.github.com/tauri-apps/tauri/pull/8942)) Fix window centering not taking monitor scale into account + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.4` +- Upgraded to `tauri-runtime@2.0.0-beta.4` +- [`d75713ac`](https://www.github.com/tauri-apps/tauri/commit/d75713ac6c6115534e520303f5c38aa78704de69)([#8936](https://www.github.com/tauri-apps/tauri/pull/8936)) Upgraded to `wry@0.37.0` + +## \[2.0.0-beta.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.3` +- Upgraded to `tauri-runtime@2.0.0-beta.3` + +## \[2.0.0-beta.2] + +### What's Changed + +- [`76ce9f61`](https://www.github.com/tauri-apps/tauri/commit/76ce9f61dd3c5bdd589c7557543894e1f770dd16)([#3002](https://www.github.com/tauri-apps/tauri/pull/3002)) Enhance centering a newly created window, it will no longer jump to center after being visible. +- [`16e550ec`](https://www.github.com/tauri-apps/tauri/commit/16e550ec1503765158cdc3bb2a20e70ec710e981)([#8844](https://www.github.com/tauri-apps/tauri/pull/8844)) Add `WebviewEvent`, `RunEvent::WebviewEvent` and `WebviewDispatch::on_webview_event`. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.2` +- Upgraded to `tauri-runtime@2.0.0-beta.2` +- [`2f55bfec`](https://www.github.com/tauri-apps/tauri/commit/2f55bfecbf0244f3b5aa1ad7622182fca3fcdcbb)([#8795](https://www.github.com/tauri-apps/tauri/pull/8795)) Update `wry` to 0.36. + +### Breaking Changes + +- [`2f55bfec`](https://www.github.com/tauri-apps/tauri/commit/2f55bfecbf0244f3b5aa1ad7622182fca3fcdcbb)([#8795](https://www.github.com/tauri-apps/tauri/pull/8795)) Update raw-window-handle to 0.6. + +## \[2.0.0-beta.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.1` +- Upgraded to `tauri-runtime@2.0.0-beta.1` + +## \[2.0.0-beta.0] + +### New Features + +- [`af610232`](https://www.github.com/tauri-apps/tauri/commit/af6102327376884364b2075b468bdf08ee0d02aa)([#8710](https://www.github.com/tauri-apps/tauri/pull/8710)) Added `Window::destroy` to force close a window. +- [`c77b4032`](https://www.github.com/tauri-apps/tauri/commit/c77b40324ea9bf580871fc11aed69ba0c9b6b8cf)([#8280](https://www.github.com/tauri-apps/tauri/pull/8280)) Add multiwebview support behind the `unstable` feature flag. See `WindowBuilder` and `WebviewBuilder` for more information. +- [`00e15675`](https://www.github.com/tauri-apps/tauri/commit/00e1567584721644797b587205187f9cbe4e5cd1)([#8708](https://www.github.com/tauri-apps/tauri/pull/8708)) Added `RuntimeHandle::request_exit` function. + +### Bug Fixes + +- [`95da1a27`](https://www.github.com/tauri-apps/tauri/commit/95da1a27476e01e06f6ce0335df8535b662dd9c4)([#8713](https://www.github.com/tauri-apps/tauri/pull/8713)) Fix calling `set_activation_policy` when the event loop is running. + +### What's Changed + +- [`9f8037c2`](https://www.github.com/tauri-apps/tauri/commit/9f8037c2882abac19582025001675370f0d7b669)([#8633](https://www.github.com/tauri-apps/tauri/pull/8633)) On Windows, fix decorated window not transparent initially until resized. +- [`9eaeb5a8`](https://www.github.com/tauri-apps/tauri/commit/9eaeb5a8cd95ae24b5e66205bdc2763cb7f965ce)([#8622](https://www.github.com/tauri-apps/tauri/pull/8622)) Added `WindowBuilder::transient_for` and Renamed `WindowBuilder::owner_window` to `WindowBuilder::owner` and `WindowBuilder::parent_window` to `WindowBuilder::parent`. +- [`7f033f6d`](https://www.github.com/tauri-apps/tauri/commit/7f033f6dcd54c69a4193765a5c1584755ba92c61)([#8537](https://www.github.com/tauri-apps/tauri/pull/8537)) Add `Window::start_resize_dragging` and `ResizeDirection` enum. +- [`6639a579`](https://www.github.com/tauri-apps/tauri/commit/6639a579c76d45210f33a72d37e21d4c5a9d334b)([#8441](https://www.github.com/tauri-apps/tauri/pull/8441)) Added the `WindowConfig::proxy_url` `WebviewBuilder::proxy_url() / WebviewWindowBuilder::proxy_url()` options when creating a webview. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.0` +- Upgraded to `tauri-runtime@2.0.0-beta.0` +- Upgrated to `tao@0.25`. + +### Breaking Changes + +- [`af610232`](https://www.github.com/tauri-apps/tauri/commit/af6102327376884364b2075b468bdf08ee0d02aa)([#8710](https://www.github.com/tauri-apps/tauri/pull/8710)) `WindowDispatch::close` now triggers the `CloseRequested` flow. +- [`9eaeb5a8`](https://www.github.com/tauri-apps/tauri/commit/9eaeb5a8cd95ae24b5e66205bdc2763cb7f965ce)([#8622](https://www.github.com/tauri-apps/tauri/pull/8622)) Changed `WindowBuilder::with_config` to take a reference to a `WindowConfig` instead of an owned value. + +## \[1.0.0-alpha.9] + +### New Features + +- [`29ced5ce`](https://www.github.com/tauri-apps/tauri/commit/29ced5ceec40b2934094ade2db9a8855f294e1d1)([#8159](https://www.github.com/tauri-apps/tauri/pull/8159)) Added download event closure via `PendingWindow::download_handler`. + +### Enhancements + +- [`d621d343`](https://www.github.com/tauri-apps/tauri/commit/d621d3437ce3947175eecf345b2c6d1c4c7ce020)([#8607](https://www.github.com/tauri-apps/tauri/pull/8607)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag. + +### What's Changed + +- [`cb640c8e`](https://www.github.com/tauri-apps/tauri/commit/cb640c8e949a3d78d78162e2e61b51bf8afae983)([#8393](https://www.github.com/tauri-apps/tauri/pull/8393)) Fix `RunEvent::WindowEvent(event: WindowEvent::FileDrop(FileDropEvent))` never triggered and always prevent default OS behavior when `disable_file_drop_handler` is not used. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.13` +- Upgraded to `tauri-runtime@1.0.0-alpha.8` + +## \[1.0.0-alpha.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.12` +- Upgraded to `tauri-runtime@1.0.0-alpha.7` + +## \[1.0.0-alpha.7] + +### Dependencies + +- Upgraded to `tauri-runtime@1.0.0-alpha.6` +- [\`\`](https://www.github.com/tauri-apps/tauri/commit/undefined) Update to wry v0.35. + +## \[1.0.0-alpha.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.11` +- Upgraded to `tauri-runtime@1.0.0-alpha.5` + +## \[1.0.0-alpha.5] + +### New Features + +- [`74d2464d`](https://www.github.com/tauri-apps/tauri/commit/74d2464d0e490fae341ad73bdf2964cf215fe6c5)([#8116](https://www.github.com/tauri-apps/tauri/pull/8116)) Added `on_page_load` hook for `PendingWindow`. + +### Enhancements + +- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.10` +- Upgraded to `tauri-runtime@1.0.0-alpha.4` +- [`9580df1d`](https://www.github.com/tauri-apps/tauri/commit/9580df1d7b027befb9e5f025ea2cbaf2dcc82c8e)([#8084](https://www.github.com/tauri-apps/tauri/pull/8084)) Upgrade `gtk` to 0.18. +- [`c7c2507d`](https://www.github.com/tauri-apps/tauri/commit/c7c2507da16a9beb71bf06745fe7ac1325ab7c2a)([#8035](https://www.github.com/tauri-apps/tauri/pull/8035)) Update `windows` to version `0.51` and `webview2-com` to version `0.27` +- [`9580df1d`](https://www.github.com/tauri-apps/tauri/commit/9580df1d7b027befb9e5f025ea2cbaf2dcc82c8e)([#8084](https://www.github.com/tauri-apps/tauri/pull/8084)) Updated to wry@0.34, removing the `dox` feature flag. + +## \[1.0.0-alpha.4] + +### New Features + +- [`c085adda`](https://www.github.com/tauri-apps/tauri/commit/c085addab58ba851398373c6fd13f9cb026d71e8)([#8009](https://www.github.com/tauri-apps/tauri/pull/8009)) Added `set_progress_bar` to `Window`. +- [`c1ec0f15`](https://www.github.com/tauri-apps/tauri/commit/c1ec0f155118527361dd5645d920becbc8afd569)([#7933](https://www.github.com/tauri-apps/tauri/pull/7933)) Added `Window::set_always_on_bottom` and the `always_on_bottom` option when creating a window. +- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70. + +### Dependencies + +- Upgraded to `tauri-runtime@1.0.0-alpha.3` +- Upgraded to `tauri-utils@2.0.0-alpha.9` + +### Breaking Changes + +- [`8b166e9b`](https://www.github.com/tauri-apps/tauri/commit/8b166e9bf82e69ddb3200a3a825614980bd8d433)([#7949](https://www.github.com/tauri-apps/tauri/pull/7949)) Check if automation is enabled with the `TAURI_WEBVIEW_AUTOMATION` environment variable instead of `TAURI_AUTOMATION`. +- [`2558fab8`](https://www.github.com/tauri-apps/tauri/commit/2558fab861006936296e8511e43ccd69a38f61b0)([#7939](https://www.github.com/tauri-apps/tauri/pull/7939)) Changed `WebviewId` to be an alias for `u32` instead of `u64` + +## \[1.0.0-alpha.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.8` +- Upgraded to `tauri-runtime@1.0.0-alpha.2` + +## \[1.0.0-alpha.2] + +### Bug Fixes + +- [`d5074af5`](https://www.github.com/tauri-apps/tauri/commit/d5074af562b2b5cb6c5711442097c4058af32db6)([#7801](https://www.github.com/tauri-apps/tauri/pull/7801)) Fixes custom protocol not working on Windows. + +## \[1.0.0-alpha.1] + +### Enhancements + +- [`0d63732b`](https://www.github.com/tauri-apps/tauri/commit/0d63732b962e71b98430f8d7b34ea5b59a2e8bb4)([#7754](https://www.github.com/tauri-apps/tauri/pull/7754)) Update wry to 0.32 to include asynchronous custom protocol support. + +### What's Changed + +- [`6177150b`](https://www.github.com/tauri-apps/tauri/commit/6177150b6f83b52ca359d6e20f7e540f7554e4eb)([#7601](https://www.github.com/tauri-apps/tauri/pull/7601)) Changed `FileDropEvent` to include drop and hover position. + +### Dependencies + +- Upgraded to `tauri-runtime@1.0.0-alpha.1` + +### Breaking Changes + +- [`0d63732b`](https://www.github.com/tauri-apps/tauri/commit/0d63732b962e71b98430f8d7b34ea5b59a2e8bb4)([#7754](https://www.github.com/tauri-apps/tauri/pull/7754)) `tauri-runtime` no longer implements its own HTTP types and relies on the `http` crate instead. + +## \[1.0.0-alpha.0] + +### New Features + +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) Add `Dispatch::default_vbox` +- [`84c41597`](https://www.github.com/tauri-apps/tauri/commit/84c4159754b2e59244211ed9e1fc702d851a0562)([#6394](https://www.github.com/tauri-apps/tauri/pull/6394)) Added `primary_monitor` and `available_monitors` to `Runtime` and `RuntimeHandle`. +- [`3b98141a`](https://www.github.com/tauri-apps/tauri/commit/3b98141aa26f74c641a4090874247b97079bd58a)([#3736](https://www.github.com/tauri-apps/tauri/pull/3736)) Added the `Opened` variant to `RunEvent`. +- [`2a000e15`](https://www.github.com/tauri-apps/tauri/commit/2a000e150d02dff28c8b20ad097b29e209160045)([#7235](https://www.github.com/tauri-apps/tauri/pull/7235)) Implement navigate method + +### Dependencies + +- Upgraded to `tauri-runtime@1.0.0-alpha.0` +- Upgraded to `tauri-utils@2.0.0-alpha.7` + +### Breaking Changes + +- [`fbeb5b91`](https://www.github.com/tauri-apps/tauri/commit/fbeb5b9185baeda19e865228179e3e44c165f1d9)([#7170](https://www.github.com/tauri-apps/tauri/pull/7170)) Removed the `linux-headers` feature (now always enabled) and added `linux-protocol-body`. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) `Dispatch::create_window`, `Runtime::create_window` and `RuntimeHandle::create_window` has been changed to accept a 3rd parameter which is a closure that takes `RawWindow` and to be executed right after the window is created and before the webview is added to the window. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) System tray and menu related APIs and structs have all been removed and are now implemented in tauri outside of the runtime-space. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) `Runtime::new` and `Runtime::new_any_thread` now accept a `RuntimeInitArgs`. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) Removed `system-tray` feature flag + +## \[0.13.0-alpha.6] + +### New Features + +- [`e0f0dce2`](https://www.github.com/tauri-apps/tauri/commit/e0f0dce220730e2822fc202463aedf0166145de7)([#6442](https://www.github.com/tauri-apps/tauri/pull/6442)) Added the `window_effects` option when creating a window and `Window::set_effects` to change it at runtime. + +## \[0.13.0-alpha.5] + +- [`39f1b04f`](https://www.github.com/tauri-apps/tauri/commit/39f1b04f7be4966488484829cd54c8ce72a04200)([#6943](https://www.github.com/tauri-apps/tauri/pull/6943)) Moved the `event` JS APIs to a plugin. +- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65. +- [`cebd7526`](https://www.github.com/tauri-apps/tauri/commit/cebd75261ac71b98976314a450cb292eeeec1515)([#6728](https://www.github.com/tauri-apps/tauri/pull/6728)) Moved the `clipboard` feature to its own plugin in the plugins-workspace repository. +- [`3f17ee82`](https://www.github.com/tauri-apps/tauri/commit/3f17ee82f6ff21108806edb7b00500b8512b8dc7)([#6737](https://www.github.com/tauri-apps/tauri/pull/6737)) Moved the `global-shortcut` feature to its own plugin in the plugins-workspace repository. +- [`31444ac1`](https://www.github.com/tauri-apps/tauri/commit/31444ac196add770f2ad18012d7c18bce7538f22)([#6725](https://www.github.com/tauri-apps/tauri/pull/6725)) Update `wry` to `0.28` + +## \[0.13.0-alpha.4] + +- Added `android` configuration object under `tauri > bundle`. + - Bumped due to a bump in tauri-utils. + - [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07 + +## \[0.13.0-alpha.3] + +- Pull changes from Tauri 1.3 release. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[0.13.0-alpha.2] + +- Add `find_class`, `run_on_android_context` on `RuntimeHandle`. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 +- Allow a wry plugin to be registered at runtime. + - [ae296f3d](https://www.github.com/tauri-apps/tauri/commit/ae296f3de16fb6a8badbad5555075a5861681fe5) refactor(tauri-runtime-wry): register runtime plugin after run() ([#6478](https://www.github.com/tauri-apps/tauri/pull/6478)) on 2023-03-17 +- Added the `shadow` option when creating a window and `Window::set_shadow`. + - [a81750d7](https://www.github.com/tauri-apps/tauri/commit/a81750d779bc72f0fdb7de90b7fbddfd8049b328) feat(core): add shadow APIs ([#6206](https://www.github.com/tauri-apps/tauri/pull/6206)) on 2023-02-08 +- Implemented `with_webview` on Android and iOS. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 + +## \[0.13.0-alpha.1] + +- Update gtk to 0.16. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Bump the MSRV to 1.64. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Update wry to 0.26. + - [f0a1d9cd](https://www.github.com/tauri-apps/tauri/commit/f0a1d9cdbcfb645ce1c5f1cdd597f764991772cd) chore: update rfd and wry versions ([#6174](https://www.github.com/tauri-apps/tauri/pull/6174)) on 2023-02-03 + +## \[0.13.0-alpha.0] + +- Support `with_webview` for Android platform alowing execution of JNI code in context. + - [8ea87e9c](https://www.github.com/tauri-apps/tauri/commit/8ea87e9c9ca8ba4c7017c8281f78aacd08f45785) feat(android): with_webview access for jni execution ([#5148](https://www.github.com/tauri-apps/tauri/pull/5148)) on 2022-09-08 + +## \[0.14.5] + +### What's Changed + +- [`d42668ce`](https://www.github.com/tauri-apps/tauri/commit/d42668ce17494ab778f436aaa9b216d6db3f0b31)([#9003](https://www.github.com/tauri-apps/tauri/pull/9003)) Fix panic during intialization on wayland when using `clipboard` feature, instead propagate the error during API usage. + +## \[0.14.4] + +### Bug Fixes + +- [`24210735`](https://www.github.com/tauri-apps/tauri/commit/2421073576a6d45783176be57b0188668558aff7)([#8117](https://www.github.com/tauri-apps/tauri/pull/8117)) Fixes a crash on macOS when accessing the windows map. +- [`510b6226`](https://www.github.com/tauri-apps/tauri/commit/510b62261c70331ce3f5bfd24137dac1bc4a0bbe)([#8822](https://www.github.com/tauri-apps/tauri/pull/8822)) Add missing `arboard` feature flag to prevent panics in wayland session. + +## \[0.14.3] + +### Bug Fixes + +- [`0d0501cb`](https://www.github.com/tauri-apps/tauri/commit/0d0501cb7b5e767c51a3697a148acfe84211a7ad)([#8394](https://www.github.com/tauri-apps/tauri/pull/8394)) Use `arboard` instead of `tao` clipboard implementation to prevent a crash. +- [`b2f83f03`](https://www.github.com/tauri-apps/tauri/commit/b2f83f03a872baa91e2b6bbb22a3e7a5cd975dc0)([#8402](https://www.github.com/tauri-apps/tauri/pull/8402)) Use `Arc` instead of `Rc` to prevent crashes on macOS. + +### Dependencies + +- Upgraded to `tauri-utils@1.5.2` +- Upgraded to `tauri-runtime@0.14.2` + +## \[0.14.2] + +### Enhancements + +- [`5e05236b`](https://www.github.com/tauri-apps/tauri/commit/5e05236b4987346697c7caae0567d3c50714c198)([#8289](https://www.github.com/tauri-apps/tauri/pull/8289)) Added tracing for window startup, plugins, `Window::eval`, events, IPC, updater and custom protocol request handlers behind the `tracing` feature flag. + +## \[0.14.1] + +### Enhancements + +- [`9aa34ada`](https://www.github.com/tauri-apps/tauri/commit/9aa34ada5769dbefa7dfe5f7a6288b3d20b294e4)([#7645](https://www.github.com/tauri-apps/tauri/pull/7645)) Add setting to switch to `http://.localhost/` for custom protocols on Windows. + +### Bug Fixes + +- [`4bf1e85e`](https://www.github.com/tauri-apps/tauri/commit/4bf1e85e6bf85a7ec92d50c8465bc0588a6399d8)([#7722](https://www.github.com/tauri-apps/tauri/pull/7722)) Properly respect the `focused` option when creating the webview. + +### Dependencies + +- Upgraded to `tauri-utils@1.5.0` +- Upgraded to `tauri-runtime@0.14.1` + +## \[0.14.0] + +### New Features + +- [`c4d6fb4b`](https://www.github.com/tauri-apps/tauri/commit/c4d6fb4b1ea8acf02707a9fe5dcab47c1c5bae7b)([#2353](https://www.github.com/tauri-apps/tauri/pull/2353)) Added the `maximizable`, `minimizable` and `closable` methods to `WindowBuilder`. +- [`c4d6fb4b`](https://www.github.com/tauri-apps/tauri/commit/c4d6fb4b1ea8acf02707a9fe5dcab47c1c5bae7b)([#2353](https://www.github.com/tauri-apps/tauri/pull/2353)) Added `set_maximizable`, `set_minimizable`, `set_closable`, `is_maximizable`, `is_minimizable` and `is_closable` methods to the `Dispatch` trait. +- [`000104bc`](https://www.github.com/tauri-apps/tauri/commit/000104bc3bc0c9ff3d20558ab9cf2080f126e9e0)([#6472](https://www.github.com/tauri-apps/tauri/pull/6472)) Add `Window::is_focused` getter. + +### Enhancements + +- [`d2710e9d`](https://www.github.com/tauri-apps/tauri/commit/d2710e9d2e8fd93975ef6494512370faa8cb3b7e)([#6944](https://www.github.com/tauri-apps/tauri/pull/6944)) Unpin `time`, `ignore`, and `winnow` crate versions. Developers now have to pin crates if needed themselves. A list of crates that need pinning to adhere to Tauri's MSRV will be visible in Tauri's GitHub workflow: https://github.com/tauri-apps/tauri/blob/dev/.github/workflows/test-core.yml#L85. + +### Bug Fixes + +- [`b41b57eb`](https://www.github.com/tauri-apps/tauri/commit/b41b57ebb27befd366db5befaafb6043c18fdfef)([#7105](https://www.github.com/tauri-apps/tauri/pull/7105)) Fix panics when registering an invalid global shortcuts or checking it is registered and return proper errors instead. + +### What's Changed + +- [`076e1a81`](https://www.github.com/tauri-apps/tauri/commit/076e1a81a50468e3dfb34ae9ca7e77c5e1758daa)([#7119](https://www.github.com/tauri-apps/tauri/pull/7119)) Use `u32` instead of `u64` for js event listener ids + +## \[0.13.0] + +- Added the `additional_browser_args` option when creating a window. + - [3dc38b15](https://www.github.com/tauri-apps/tauri/commit/3dc38b150ea8c59c8ba67fd586f921016928f47c) feat(core): expose additional_browser_args to window config (fix: [#5757](https://www.github.com/tauri-apps/tauri/pull/5757)) ([#5799](https://www.github.com/tauri-apps/tauri/pull/5799)) on 2022-12-14 +- Added the `content_protected` option when creating a window and `Window::set_content_protected` to change it at runtime. + - [4ab5545b](https://www.github.com/tauri-apps/tauri/commit/4ab5545b7a831c549f3c65e74de487ede3ab7ce5) feat: add content protection api, closes [#5132](https://www.github.com/tauri-apps/tauri/pull/5132) ([#5513](https://www.github.com/tauri-apps/tauri/pull/5513)) on 2022-12-13 +- Added `Builder::device_event_filter` and `App::set_device_event_filter` methods. + - [73fd60ee](https://www.github.com/tauri-apps/tauri/commit/73fd60eef2b60f5dc84525ef9c315f4d80c4414f) expose set_device_event_filter in tauri ([#5562](https://www.github.com/tauri-apps/tauri/pull/5562)) on 2022-12-13 +- Fixes tray events not being delivered. + - [138cb8d7](https://www.github.com/tauri-apps/tauri/commit/138cb8d739b15bccdb388e555c20f17ffe16318c) fix(tauri-runtime-wry): tray event listener not registered ([#6270](https://www.github.com/tauri-apps/tauri/pull/6270)) on 2023-02-14 +- Add `is_minimized()` window method. + - [62144ef3](https://www.github.com/tauri-apps/tauri/commit/62144ef3be63b237869e511826edfb938e2c7174) feat: add is_minimized (fix [#3878](https://www.github.com/tauri-apps/tauri/pull/3878)) ([#5618](https://www.github.com/tauri-apps/tauri/pull/5618)) on 2022-12-13 +- Disable cursor mouse events on Linux. + - [8c842a54](https://www.github.com/tauri-apps/tauri/commit/8c842a54a6f3dc5327b4d737df7123dcddaa5769) feature: disable mouse event when building windows on Linux, closes [#5913](https://www.github.com/tauri-apps/tauri/pull/5913) ([#6025](https://www.github.com/tauri-apps/tauri/pull/6025)) on 2023-01-16 +- Bump minimum supported Rust version to 1.60. + - [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31 +- Pin raw-window-handle to 0.5.0 to keep MSRV. + - [c46c09f3](https://www.github.com/tauri-apps/tauri/commit/c46c09f31d9f5169ca8a7e62406a9ea170e3a5c5) fix(deps): pin raw-window-handle to 0.5.0 ([#6480](https://www.github.com/tauri-apps/tauri/pull/6480)) on 2023-03-17 +- Add `title` getter on window. + - [233e43b0](https://www.github.com/tauri-apps/tauri/commit/233e43b0c34fada1ca025378533a0b76931a6540) feat: add `title` getter on window, closes [#5023](https://www.github.com/tauri-apps/tauri/pull/5023) ([#5515](https://www.github.com/tauri-apps/tauri/pull/5515)) on 2022-12-13 +- Added `TrayHandle::set_tooltip` and `SystemTray::with_tooltip`. + - [2265e097](https://www.github.com/tauri-apps/tauri/commit/2265e09718f6ebfeb1d200f11e1e1e069075af6e) feat(windows): implement `with_tooltip` ([#5938](https://www.github.com/tauri-apps/tauri/pull/5938)) on 2023-01-01 +- Added window's `url()` getter. + - [d17027e1](https://www.github.com/tauri-apps/tauri/commit/d17027e1a0db3e8c5ae81fc4f472c5918fbce611) feat: expose url method ([#5914](https://www.github.com/tauri-apps/tauri/pull/5914)) on 2022-12-26 +- On Windows, change webview theme based on Window theme for more accurate `prefers-color-scheme` support. + - [7a8d570d](https://www.github.com/tauri-apps/tauri/commit/7a8d570db72667367eb24b75ddc5dd07a968f7c0) fix: sync webview theme with window theme on Windows, closes [#5802](https://www.github.com/tauri-apps/tauri/pull/5802) ([#5874](https://www.github.com/tauri-apps/tauri/pull/5874)) on 2022-12-27 +- On Windows, Fix missing `WindowEvent::Focused` in `App::run` callback. + - [ff4ea1ea](https://www.github.com/tauri-apps/tauri/commit/ff4ea1eabbf2874b113c6b4698002929bbac737a) fix: dispatch focus event to app.run on Windows, closes [#6460](https://www.github.com/tauri-apps/tauri/pull/6460) ([#6504](https://www.github.com/tauri-apps/tauri/pull/6504)) on 2023-03-31 +- Implement the webview navigation handler. + - [3f35b452](https://www.github.com/tauri-apps/tauri/commit/3f35b452637ef1c794a423f1eda62a15d2ddaf42) Expose wry navigation_handler via WindowBuilder closes [#4080](https://www.github.com/tauri-apps/tauri/pull/4080) ([#5686](https://www.github.com/tauri-apps/tauri/pull/5686)) on 2022-12-27 + +## \[0.12.3] + +- Block remote URLs from accessing the IPC. + - [9c0593c33](https://www.github.com/tauri-apps/tauri/commit/9c0593c33af52cd9e00ec784d15f63efebdf039c) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.12.2] + +- Fix compatibility with older Linux distributions. + - [b490308c](https://www.github.com/tauri-apps/tauri/commit/b490308c8897b893292951754607c2253abbc6e1) fix(core): compilation error on older Linux versions, fixes [#5684](https://www.github.com/tauri-apps/tauri/pull/5684) ([#5697](https://www.github.com/tauri-apps/tauri/pull/5697)) on 2022-11-28 +- Update wry to 0.23. + - [fdcd7733](https://www.github.com/tauri-apps/tauri/commit/fdcd77338c1a3a7ef8a8ea1907351c5c350ea7ba) chore(deps): update wry to 0.23 on 2022-12-08 + +## \[0.12.1] + +- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`. + - Bumped due to a bump in tauri-utils. + - [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18 + +## \[0.12.0] + +- Add `accept_first_mouse` option for macOS windows. + - [95f467ad](https://www.github.com/tauri-apps/tauri/commit/95f467add51448319983c54e2f382c7c09fb72d6) feat(core): add window `accept_first_mouse` option, closes [#5347](https://www.github.com/tauri-apps/tauri/pull/5347) ([#5374](https://www.github.com/tauri-apps/tauri/pull/5374)) on 2022-10-17 +- Disable automatic window tabbing on macOS when the `tabbing_identifier` option is not defined, the window is transparent or does not have decorations. + - [4137ab44](https://www.github.com/tauri-apps/tauri/commit/4137ab44a81d739556cbc7583485887e78952bf1) feat(macos): add `tabbing_identifier` option, closes [#2804](https://www.github.com/tauri-apps/tauri/pull/2804), [#3912](https://www.github.com/tauri-apps/tauri/pull/3912) ([#5399](https://www.github.com/tauri-apps/tauri/pull/5399)) on 2022-10-19 +- Drop the WebContext when the WebView is dropped. + - [9d8b3774](https://www.github.com/tauri-apps/tauri/commit/9d8b377481abf975dc37f9050d2ac7b63ce353e9) feat(tauri-runtime-wry): drop the WebContext on WebView drop ([#5240](https://www.github.com/tauri-apps/tauri/pull/5240)) on 2022-10-19 +- Readd the option to create an unfocused window via the `focused` method. The `focus` function has been deprecated. + - [4036e15f](https://www.github.com/tauri-apps/tauri/commit/4036e15f5af933bdc0d0913508b5103958afc143) feat(core): reimplement window initial focus flag, closes [#5120](https://www.github.com/tauri-apps/tauri/pull/5120) ([#5338](https://www.github.com/tauri-apps/tauri/pull/5338)) on 2022-10-08 +- Add `hidden_title` option for macOS windows. + - [321f3fed](https://www.github.com/tauri-apps/tauri/commit/321f3fed19df40c1223099bce953332b7f00f7a9) feat(macos): `title_bar_style` and `hidden_title` window options, closes [#2663](https://www.github.com/tauri-apps/tauri/pull/2663) ([#3965](https://www.github.com/tauri-apps/tauri/pull/3965)) on 2022-09-30 +- Custom protocol headers are now implemented on Linux when running on webkit2gtk 2.36 or above. + - [357480f4](https://www.github.com/tauri-apps/tauri/commit/357480f4ae43aa8da99f7ba61ae2ee51b4552c60) feat(core): custom protocol headers on Linux, closes [#4496](https://www.github.com/tauri-apps/tauri/pull/4496) ([#5421](https://www.github.com/tauri-apps/tauri/pull/5421)) on 2022-10-17 +- Added `Runtime::show()`, `RuntimeHandle::show()`, `Runtime::hide()`, `RuntimeHandle::hide()` for hiding/showing the entire application on macOS. + - [39bf895b](https://www.github.com/tauri-apps/tauri/commit/39bf895b73ec6b53f5758815396ba85dda6b9c67) feat(macOS): Add application `show` and `hide` methods ([#3689](https://www.github.com/tauri-apps/tauri/pull/3689)) on 2022-10-03 +- Fix regression in `SystemTray::with_menu_on_left_click` + - [f8a3becb](https://www.github.com/tauri-apps/tauri/commit/f8a3becb287942db7f7b551b5db6aeb5a2e939ee) feat(core): add option to disable tray menu on left click, closes [#4584](https://www.github.com/tauri-apps/tauri/pull/4584) ([#4587](https://www.github.com/tauri-apps/tauri/pull/4587)) on 2022-07-05 + - [7bbf167c](https://www.github.com/tauri-apps/tauri/commit/7bbf167c1c84493ea6e2353f720edafd7daa47e4) Apply Version Updates From Current Changes ([#4560](https://www.github.com/tauri-apps/tauri/pull/4560)) on 2022-07-06 + - [63011ca8](https://www.github.com/tauri-apps/tauri/commit/63011ca84e7a22c8c0d8bd1c1be6592140f93ff2) fix(macos): fix regression in `with_menu_on_left_click`, closes [#5220](https://www.github.com/tauri-apps/tauri/pull/5220) ([#5235](https://www.github.com/tauri-apps/tauri/pull/5235)) on 2022-09-30 +- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28 +- Added `tabbing_identifier` to the window builder on macOS. + - [4137ab44](https://www.github.com/tauri-apps/tauri/commit/4137ab44a81d739556cbc7583485887e78952bf1) feat(macos): add `tabbing_identifier` option, closes [#2804](https://www.github.com/tauri-apps/tauri/pull/2804), [#3912](https://www.github.com/tauri-apps/tauri/pull/3912) ([#5399](https://www.github.com/tauri-apps/tauri/pull/5399)) on 2022-10-19 +- Add `title_bar_style` option for macOS windows. + - [321f3fed](https://www.github.com/tauri-apps/tauri/commit/321f3fed19df40c1223099bce953332b7f00f7a9) feat(macos): `title_bar_style` and `hidden_title` window options, closes [#2663](https://www.github.com/tauri-apps/tauri/pull/2663) ([#3965](https://www.github.com/tauri-apps/tauri/pull/3965)) on 2022-09-30 +- Fix regression introduce in tauri@1.1 which prevented removing tray icon when the app exits on Windows. + - [f756cd5e](https://www.github.com/tauri-apps/tauri/commit/f756cd5e7ecc86f178f8d602eded1e1b6ecb51f3) fix(core): wait for tray cleanup before exiting app, closes [#5244](https://www.github.com/tauri-apps/tauri/pull/5244) ([#5245](https://www.github.com/tauri-apps/tauri/pull/5245)) on 2022-10-04 +- Added methods to set the system tray title on macOS. + - [8f1ace77](https://www.github.com/tauri-apps/tauri/commit/8f1ace77956ac3477826ceb059a191e55b3fff93) feat: expose `set_title` for MacOS tray ([#5182](https://www.github.com/tauri-apps/tauri/pull/5182)) on 2022-09-30 +- Added the `user_agent` option when creating a window. + - [a6c94119](https://www.github.com/tauri-apps/tauri/commit/a6c94119d8545d509723b147c273ca5edfe3729f) feat(core): expose user_agent to window config ([#5317](https://www.github.com/tauri-apps/tauri/pull/5317)) on 2022-10-02 + +## \[0.11.2] + +- Block remote URLs from accessing the IPC. + - [58ea0b452](https://www.github.com/tauri-apps/tauri/commit/58ea0b45268dbd46cbac0ebb0887353d057ca767) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.11.1] + +- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs. + - Bumped due to a bump in tauri-utils. + - [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16 + +## \[0.11.0] + +- Ignore window events with unknown IDs. + - [0668dd42](https://www.github.com/tauri-apps/tauri/commit/0668dd42204b163f11aaf31f45106c8551f15942) fix(tauri-runtime-wry): ignore events on unknown windows on 2022-08-29 +- Implement theme APIs for Linux. + - [f21cbecd](https://www.github.com/tauri-apps/tauri/commit/f21cbecdeb3571ac4ad971b9a865ff62a131a176) feat(core): implement theme APIs for Linux ([#4808](https://www.github.com/tauri-apps/tauri/pull/4808)) on 2022-08-02 +- Changed `windows` map to be stored in a `RefCell` instead of a `Mutex`. + - [64546cb9](https://www.github.com/tauri-apps/tauri/commit/64546cb9cca2fe56cf81cfc4aaf85c4e1d58877c) refactor: use RefCell instead of Mutex for windows map, closes [#4870](https://www.github.com/tauri-apps/tauri/pull/4870) ([#4909](https://www.github.com/tauri-apps/tauri/pull/4909)) on 2022-08-10 +- Added APIs to create a system tray at runtime. + - [4d063ae9](https://www.github.com/tauri-apps/tauri/commit/4d063ae9ee9538cd6fa5e01b80070c6edf8eaeb9) feat(core): create system tray at runtime, closes [#2278](https://www.github.com/tauri-apps/tauri/pull/2278) ([#4862](https://www.github.com/tauri-apps/tauri/pull/4862)) on 2022-08-09 +- Update windows to 0.39.0 and webview2-com to 0.19.1. + - [e6d9b670](https://www.github.com/tauri-apps/tauri/commit/e6d9b670b0b314ed667b0e164f2c8d27048e678f) refactor: remove unneeded focus code ([#5065](https://www.github.com/tauri-apps/tauri/pull/5065)) on 2022-09-03 + +## \[0.10.3] + +- Block remote URLs from accessing the IPC. + - [fa90214b0](https://www.github.com/tauri-apps/tauri/commit/fa90214b052b1a5d38d54fbf1ca422b4c37cfd1f) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.10.2] + +- Disable drag-n-drop of tao based on `fileDropEnabled` value. + - [a1d569bb](https://www.github.com/tauri-apps/tauri/commit/a1d569bbc9cfdd58258916df594911e1c512a75e) fix(core): disable tao's drag-n-drop based on `fileDropEnabled`, closes [#4580](https://www.github.com/tauri-apps/tauri/pull/4580) ([#4592](https://www.github.com/tauri-apps/tauri/pull/4592)) on 2022-07-05 +- Added option to disable tray menu on left click on macOS. + - [f8a3becb](https://www.github.com/tauri-apps/tauri/commit/f8a3becb287942db7f7b551b5db6aeb5a2e939ee) feat(core): add option to disable tray menu on left click, closes [#4584](https://www.github.com/tauri-apps/tauri/pull/4584) ([#4587](https://www.github.com/tauri-apps/tauri/pull/4587)) on 2022-07-05 + +## \[0.10.1] + +- Fixes a deadlock on the file drop handler. + - [23a48007](https://www.github.com/tauri-apps/tauri/commit/23a48007c0df7346fa45c76dfaf9235a157f59ec) fix(tauri-runtime-wry): deadlock on file drop, closes [#4527](https://www.github.com/tauri-apps/tauri/pull/4527) ([#4535](https://www.github.com/tauri-apps/tauri/pull/4535)) on 2022-06-30 +- Send theme value only once on the getter function implementation on macOS. + - [63841c10](https://www.github.com/tauri-apps/tauri/commit/63841c10609c3d7337ba6cd68ae126b18987014d) fix(tauri-runtime-wry): do not send theme twice on macOS, closes [#4532](https://www.github.com/tauri-apps/tauri/pull/4532) ([#4540](https://www.github.com/tauri-apps/tauri/pull/4540)) on 2022-06-30 +- Fixes a deadlock when the window focus change on Windows. + - [185b0e31](https://www.github.com/tauri-apps/tauri/commit/185b0e314ece9563cd7c83a16466b2b8b9167eb3) fix(tauri-runtime-wry): deadlock when window focus change, closes [#4533](https://www.github.com/tauri-apps/tauri/pull/4533) ([#4539](https://www.github.com/tauri-apps/tauri/pull/4539)) on 2022-06-30 + +## \[0.10.0] + +- Implement `raw_window_handle::HasRawWindowHandle` on Linux. + - [3efbc67f](https://www.github.com/tauri-apps/tauri/commit/3efbc67f7469ce65a2d9ea4ff2b60b51d2a36aa5) feat: implement `raw_window_handle` on Linux ([#4469](https://www.github.com/tauri-apps/tauri/pull/4469)) on 2022-06-26 +- Moved the window and menu event listeners to the window struct. + - [46196fe9](https://www.github.com/tauri-apps/tauri/commit/46196fe922f4f1b38057155c6113236cfa4b3597) refactor(tauri-runtime-wry): move window and menu listeners to window ([#4485](https://www.github.com/tauri-apps/tauri/pull/4485)) on 2022-06-27 +- Refactored the `tauri-runtime-wry` plugin interface. + - [e39e2999](https://www.github.com/tauri-apps/tauri/commit/e39e2999e0ab1843a8195ba83aea3d6de705c3d8) refactor(tauri-runtime-wry): enhance plugin interface ([#4476](https://www.github.com/tauri-apps/tauri/pull/4476)) on 2022-06-27 +- Removed the `hwnd` and `ns_window` functions from `Dispatch` in favor of `raw_window_handle`. + - [3efbc67f](https://www.github.com/tauri-apps/tauri/commit/3efbc67f7469ce65a2d9ea4ff2b60b51d2a36aa5) feat: implement `raw_window_handle` on Linux ([#4469](https://www.github.com/tauri-apps/tauri/pull/4469)) on 2022-06-26 +- The theme API is now implemented on macOS 10.14+. + - [6d94ce42](https://www.github.com/tauri-apps/tauri/commit/6d94ce42353204a02fe9c82ed397d349439f75ef) feat(core): theme is now implemented on macOS ([#4380](https://www.github.com/tauri-apps/tauri/pull/4380)) on 2022-06-17 +- Suppress unused variable warning in release builds. + - [45981851](https://www.github.com/tauri-apps/tauri/commit/45981851e35119266c1a079e1ff27a39f1fdfaed) chore(lint): unused variable warnings for release builds ([#4411](https://www.github.com/tauri-apps/tauri/pull/4411)) on 2022-06-22 +- Update tao to 0.12 and wry to 0.19. + - [f6edc6df](https://www.github.com/tauri-apps/tauri/commit/f6edc6df29b1c45b483fa87c481a3b95730b131b) chore(deps): update tao to 0.12, wry to 0.19, closes [#3220](https://www.github.com/tauri-apps/tauri/pull/3220) ([#4502](https://www.github.com/tauri-apps/tauri/pull/4502)) on 2022-06-28 +- Fixes deadlocks when using window setters in the main thread. + - [123f6e69](https://www.github.com/tauri-apps/tauri/commit/123f6e69f60ca6d4b2fd738ca3ff5cf016d8e814) fix(tauri-runtime-wry): release windows lock immediately, closes [#4390](https://www.github.com/tauri-apps/tauri/pull/4390) ([#4392](https://www.github.com/tauri-apps/tauri/pull/4392)) on 2022-06-19 + +## \[0.9.0] + +- Upgrade to `stable`! + - Bumped due to a bump in tauri-utils. + - [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15 + +## \[0.8.1] + +- Add `Menu::os_default` which will create a menu filled with default menu items and submenus. + - Bumped due to a bump in tauri-runtime. + - [4c4acc30](https://www.github.com/tauri-apps/tauri/commit/4c4acc3094218dd9cee0f1ad61810c979e0b41fa) feat: implement `Default` for `Menu`, closes [#2398](https://www.github.com/tauri-apps/tauri/pull/2398) ([#4291](https://www.github.com/tauri-apps/tauri/pull/4291)) on 2022-06-15 + +## \[0.8.0] + +- Removed `TrayIcon` and renamed `WindowIcon` to `Icon`, a shared type for both icons. + - [4ce8e228](https://www.github.com/tauri-apps/tauri/commit/4ce8e228134cd3f22973b74ef26ca0d165fbbbd9) refactor(core): use `Icon` for tray icons ([#4342](https://www.github.com/tauri-apps/tauri/pull/4342)) on 2022-06-14 + +## \[0.7.0] + +- **Breaking change**: Removed the `gtk-tray` and `ayatana-tray` Cargo features. + - [6216eb49](https://www.github.com/tauri-apps/tauri/commit/6216eb49e72863bfb6d4c9edb8827b21406ac393) refactor(core): drop `ayatana-tray` and `gtk-tray` Cargo features ([#4247](https://www.github.com/tauri-apps/tauri/pull/4247)) on 2022-06-02 + +## \[0.6.0] + +- Account the monitor position when centering a window. + - [a7a9fde1](https://www.github.com/tauri-apps/tauri/commit/a7a9fde16fb7c35d48d4f97e83ff95b8baf9e090) fix(core): account for monitor position when centering window ([#4166](https://www.github.com/tauri-apps/tauri/pull/4166)) on 2022-05-21 +- Update `windows-rs` to `0.37.0`, which requires Rust 1.61.0+. + - [2326be39](https://www.github.com/tauri-apps/tauri/commit/2326be39821890cdd4de76e7029a531424dcb26f) feat(core): update windows-rs to 0.37.0 ([#4199](https://www.github.com/tauri-apps/tauri/pull/4199)) on 2022-05-24 + +## \[0.5.2] + +- Use the event loop proxy to create a window so it doesn't deadlock on Windows. + - [61e37652](https://www.github.com/tauri-apps/tauri/commit/61e37652b931520424d6a93a134e67893703d992) fix(core): deadlock when creating window from IPC handler, closes [#4121](https://www.github.com/tauri-apps/tauri/pull/4121) ([#4123](https://www.github.com/tauri-apps/tauri/pull/4123)) on 2022-05-13 + +## \[0.5.1] + +- Added the `plugin` method to the `Wry` runtime, allowing extensions to the event loop. + - [c8e0e5b9](https://www.github.com/tauri-apps/tauri/commit/c8e0e5b97d542e549b37be08b545515c862af0e5) feat(tauri-runtime-wry): add plugin API ([#4094](https://www.github.com/tauri-apps/tauri/pull/4094)) on 2022-05-10 +- Update wry to 0.16.2 and webkit2gtk to 0.18.0. + - [71a553b7](https://www.github.com/tauri-apps/tauri/commit/71a553b715312e2bcceb963c83e42cffca7a63bc) chore(deps): update wry to 0.16.2, webkit2gtk to 0.18.0 ([#4099](https://www.github.com/tauri-apps/tauri/pull/4099)) on 2022-05-10 + +## \[0.5.0] + +- The file drop event payloads are now percent-decoded. + - [a0ecd81a](https://www.github.com/tauri-apps/tauri/commit/a0ecd81a934e1aa8935151a74cad686786054204) fix(core): percent decode file drop payloads, closes [#4034](https://www.github.com/tauri-apps/tauri/pull/4034) ([#4035](https://www.github.com/tauri-apps/tauri/pull/4035)) on 2022-05-03 +- Fixes a crash when using the menu with the inspector window focused on macOS. In this case the `window_id` will be the id of the first app window. + - [891eb748](https://www.github.com/tauri-apps/tauri/commit/891eb748cf590895dc3f1666f8dbd6082b21e04e) fix(tauri-runtime-wry): menu even panic on macOS inspector, closes [#3875](https://www.github.com/tauri-apps/tauri/pull/3875) ([#4027](https://www.github.com/tauri-apps/tauri/pull/4027)) on 2022-05-02 +- Fixes a freeze when calling `set_size` in the main thread on Windows. + - [8f259f4e](https://www.github.com/tauri-apps/tauri/commit/8f259f4ef89be3da11b57222c8b66af9487ab736) fix(core): use EventLoopProxy to prevent set_size freeze closes [#3990](https://www.github.com/tauri-apps/tauri/pull/3990) ([#4014](https://www.github.com/tauri-apps/tauri/pull/4014)) on 2022-04-30 +- Expose methods to access the underlying native handles of the webview. + - [c82b4761](https://www.github.com/tauri-apps/tauri/commit/c82b4761e1660592472dc55308ad69d9efc5855b) feat(core): expose `with_webview` API to access the platform webview ([#4058](https://www.github.com/tauri-apps/tauri/pull/4058)) on 2022-05-04 + +## \[0.4.0] + +- \**Breaking change::* Added the `clipboard` Cargo feature. + - [24e4ff20](https://www.github.com/tauri-apps/tauri/commit/24e4ff208ee0fe1a4cc5b10667ea0922ac63dfb5) refactor(core): add clipboard Cargo feature, enhancing binary size ([#3957](https://www.github.com/tauri-apps/tauri/pull/3957)) on 2022-04-24 +- Expose Window cursor APIs `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position`. + - [c54ddfe9](https://www.github.com/tauri-apps/tauri/commit/c54ddfe9338e7eb90b4d5b02dfde687d432d5bc1) feat: expose window cursor APIs, closes [#3888](https://www.github.com/tauri-apps/tauri/pull/3888) [#3890](https://www.github.com/tauri-apps/tauri/pull/3890) ([#3935](https://www.github.com/tauri-apps/tauri/pull/3935)) on 2022-04-21 +- Fixes a panic when using the `create_tao_window` API. + - [320329a9](https://www.github.com/tauri-apps/tauri/commit/320329a9a7d8a249c0fc9dee6db5669057ca8b39) fix(core): insert to webview_id_map on tao window creation, closes [#3883](https://www.github.com/tauri-apps/tauri/pull/3883) ([#3932](https://www.github.com/tauri-apps/tauri/pull/3932)) on 2022-04-21 +- Fixes a panic when a menu event is triggered when all windows are minimized on macOS. + - [70ff55c1](https://www.github.com/tauri-apps/tauri/commit/70ff55c1aa69ed59cd2a78d865e1cb398ef2a4ba) fix(core): panic on menu event with minimized windows, closes [#3902](https://www.github.com/tauri-apps/tauri/pull/3902) ([#3918](https://www.github.com/tauri-apps/tauri/pull/3918)) on 2022-04-20 +- Fixes a rendering issue when resizing the window with the devtools open. + - [80b714af](https://www.github.com/tauri-apps/tauri/commit/80b714af6b31365b9026bc92f8631b1721950447) fix: rendering issue when resizing with devtools open closes [#3914](https://www.github.com/tauri-apps/tauri/pull/3914) [#3814](https://www.github.com/tauri-apps/tauri/pull/3814) ([#3915](https://www.github.com/tauri-apps/tauri/pull/3915)) on 2022-04-19 +- \**Breaking change::* Added the `global-shortcut` Cargo feature. + - [e11878bc](https://www.github.com/tauri-apps/tauri/commit/e11878bcf7174b261a1fa146fc7d564d12e6312a) refactor(core): add global-shortcut Cargo feature, enhancing binary size ([#3956](https://www.github.com/tauri-apps/tauri/pull/3956)) on 2022-04-24 +- Added `WindowEvent::ThemeChanged(theme)`. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 +- Added `theme` getter on `Window`. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 +- Added `theme` setter to the WindowBuilder. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 +- Create webview immediately when executed in the main thread. + - [fa2baba7](https://www.github.com/tauri-apps/tauri/commit/fa2baba76c8f59c81f2a2f7139033a09d14d89da) feat(core): create webview immediately when running in main thread ([#3891](https://www.github.com/tauri-apps/tauri/pull/3891)) on 2022-04-12 + +## \[0.3.5] + +- Fixes `WindowEvent::Destroyed` not firing. + - [169b5035](https://www.github.com/tauri-apps/tauri/commit/169b5035a93e3f33a420d4b2b0f8943e6404e07f) fix(core): actually fire `WindowEvent::Destroyed` ([#3797](https://www.github.com/tauri-apps/tauri/pull/3797)) on 2022-03-28 + +## \[0.3.4] + +- Added `close_devtools` and `is_devtools_open` APIs to the `Dispatch` trait. + - [e05d718a](https://www.github.com/tauri-apps/tauri/commit/e05d718a7b46476d1fe4817c169008080e84f959) feat(core): add hotkey to toggle devtools, closes [#3776](https://www.github.com/tauri-apps/tauri/pull/3776) ([#3791](https://www.github.com/tauri-apps/tauri/pull/3791)) on 2022-03-28 +- Emit `RunEvent::Exit` on `tao::event::Event::LoopDestroyed` instead of after `RunEvent::ExitRequested`. + - [3c4ee7c9](https://www.github.com/tauri-apps/tauri/commit/3c4ee7c997fa3ff696bcfd5b8c82fecaca16bf49) refactor(wry): emit `RunEvent::Exit` on `Event::LoopDestroyed` ([#3785](https://www.github.com/tauri-apps/tauri/pull/3785)) on 2022-03-27 +- **Breaking change:** The `MenuItem::About` variant is now associated with a tuple value `(String, AboutMetadata)`. + - [5fb74332](https://www.github.com/tauri-apps/tauri/commit/5fb74332ab9210ac062d96b0e9afd1c942ee2911) chore(deps): update wry to 0.14, tao to 0.7 ([#3790](https://www.github.com/tauri-apps/tauri/pull/3790)) on 2022-03-28 +- Support window parenting on macOS + - [4e807a53](https://www.github.com/tauri-apps/tauri/commit/4e807a53e2d6d3f3cd5293d90013d5cdded5454e) Support window parenting on macOS, closes [#3751](https://www.github.com/tauri-apps/tauri/pull/3751) ([#3754](https://www.github.com/tauri-apps/tauri/pull/3754)) on 2022-03-23 +- The file drop event is now part of the `WindowEvent` enum instead of a having a dedicated handler. + - [07d1584c](https://www.github.com/tauri-apps/tauri/commit/07d1584cf06ea326aa45d8044bee1b77ecba5006) feat(core): add `WindowEvent::FileDrop`, closes [#3664](https://www.github.com/tauri-apps/tauri/pull/3664) ([#3686](https://www.github.com/tauri-apps/tauri/pull/3686)) on 2022-03-13 +- **Breaking change:** Use the dedicated `WindowEvent` enum on `RunEvent`. + - [edad9f4f](https://www.github.com/tauri-apps/tauri/commit/edad9f4f55dcc69a06cd9d6d5a5068c94ecb77dd) refactor(core): add `RunEvent::WindowEvent` ([#3793](https://www.github.com/tauri-apps/tauri/pull/3793)) on 2022-03-28 +- Added `create_proxy` to the `Runtime` and `RuntimeHandle` traits. + - [5d538ec2](https://www.github.com/tauri-apps/tauri/commit/5d538ec27c246274df4ff5b8057ff78b6364a43f) refactor(core): use the event loop proxy to send updater events ([#3687](https://www.github.com/tauri-apps/tauri/pull/3687)) on 2022-03-15 +- Allow specifying a user event type for the event loop message. + - [5d538ec2](https://www.github.com/tauri-apps/tauri/commit/5d538ec27c246274df4ff5b8057ff78b6364a43f) refactor(core): use the event loop proxy to send updater events ([#3687](https://www.github.com/tauri-apps/tauri/pull/3687)) on 2022-03-15 +- Use a random window id instead of `tao::window::WindowId` to not block the thread waiting for the event loop to process the window creation. + - [7cd39c70](https://www.github.com/tauri-apps/tauri/commit/7cd39c70c9ecd62cc9b60d0ab93f10ce0a6dd8b4) refactor(core): use random window id to simplify window creation, closes [#3645](https://www.github.com/tauri-apps/tauri/pull/3645) [#3597](https://www.github.com/tauri-apps/tauri/pull/3597) ([#3684](https://www.github.com/tauri-apps/tauri/pull/3684)) on 2022-03-15 +- Update `wry` to `0.14` and `tao` to `0.7`. + - [f2d24ef2](https://www.github.com/tauri-apps/tauri/commit/f2d24ef2fbd95ec7d3433ba651964f4aa3b7f48c) chore(deps): update wry ([#1482](https://www.github.com/tauri-apps/tauri/pull/1482)) on 2021-04-14 + - [e267ebf1](https://www.github.com/tauri-apps/tauri/commit/e267ebf1f1009b99829e0a7d71519925f5792f9f) Apply Version Updates From Current Changes ([#1486](https://www.github.com/tauri-apps/tauri/pull/1486)) on 2021-04-14 + - [5fb74332](https://www.github.com/tauri-apps/tauri/commit/5fb74332ab9210ac062d96b0e9afd1c942ee2911) chore(deps): update wry to 0.14, tao to 0.7 ([#3790](https://www.github.com/tauri-apps/tauri/pull/3790)) on 2022-03-28 +- Added the `WindowEvent::FileDrop` variant. + - [07d1584c](https://www.github.com/tauri-apps/tauri/commit/07d1584cf06ea326aa45d8044bee1b77ecba5006) feat(core): add `WindowEvent::FileDrop`, closes [#3664](https://www.github.com/tauri-apps/tauri/pull/3664) ([#3686](https://www.github.com/tauri-apps/tauri/pull/3686)) on 2022-03-13 + +## \[0.3.3] + +- Fixes a deadlock on the `Focused` event when the window is not visible. + - [c08cc6d5](https://www.github.com/tauri-apps/tauri/commit/c08cc6d50041ec887d3070c41bb2c793dbac5155) fix(core): deadlock on focus events with invisible window,[#3534](https://www.github.com/tauri-apps/tauri/pull/3534) ([#3622](https://www.github.com/tauri-apps/tauri/pull/3622)) on 2022-03-06 +- **Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features. + - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 +- Print a warning to stderr if the window transparency has been set to true but `macos-private-api` is not enabled. + - [080755b5](https://www.github.com/tauri-apps/tauri/commit/080755b5377a3c0a17adf1d03e63555350422f0a) feat(core): warn if private APIs are not enabled, closes [#3481](https://www.github.com/tauri-apps/tauri/pull/3481) ([#3511](https://www.github.com/tauri-apps/tauri/pull/3511)) on 2022-02-19 + +## \[0.3.2] + +- Fix requirements for `RuntimeHandle`, `ClipboardManager`, `GlobalShortcutHandle` and `TrayHandle`. + - Bumped due to a bump in tauri-runtime. + - [84895a9c](https://www.github.com/tauri-apps/tauri/commit/84895a9cd270fc743e236d0f4d4cd6210b24a30f) fix(runtime): trait requirements ([#3489](https://www.github.com/tauri-apps/tauri/pull/3489)) on 2022-02-17 + +## \[0.3.1] + +- Change default value for the `freezePrototype` configuration to `false`. + - Bumped due to a bump in tauri-utils. + - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 + +## \[0.3.0] + +- Fix `window.center` panic when window size is bigger than screen size. + - [76ce9f61](https://www.github.com/tauri-apps/tauri/commit/76ce9f61dd3c5bdd589c7557543894e1f770dd16) fix(core): fix `window.center` panic when window size > screen, closes [#2978](https://www.github.com/tauri-apps/tauri/pull/2978) ([#3002](https://www.github.com/tauri-apps/tauri/pull/3002)) on 2021-12-09 +- Enable non-session cookie persistence on Linux. + - [d7c02a30](https://www.github.com/tauri-apps/tauri/commit/d7c02a30a56de79100804969138b379e703f0e07) feat(core): persist non-session cookies on Linux ([#3052](https://www.github.com/tauri-apps/tauri/pull/3052)) on 2021-12-09 +- Fixes a deadlock when creating a window from a menu event handler. + - [9c82006b](https://www.github.com/tauri-apps/tauri/commit/9c82006b2fe166d20510183e36cee099bf96e8d9) fix(core): deadlock when creating window from menu handler, closes [#3110](https://www.github.com/tauri-apps/tauri/pull/3110) ([#3126](https://www.github.com/tauri-apps/tauri/pull/3126)) on 2021-12-28 +- Fixes `WindowEvent::Focus` and `WindowEvent::Blur` events not firing. + - [3b33d67a](https://www.github.com/tauri-apps/tauri/commit/3b33d67aa4f48dcf4e32b3b8a5f45e83808efc2d) fix: re-adding focus/blur events for linux and macos (fix [#2485](https://www.github.com/tauri-apps/tauri/pull/2485)) ([#2489](https://www.github.com/tauri-apps/tauri/pull/2489)) on 2021-08-24 +- Use webview's inner_size instead of window's value to get the correct size on macOS. + - [4c0c780e](https://www.github.com/tauri-apps/tauri/commit/4c0c780e00d8851be38cb1c22f636d9e4ed34a23) fix(core): window's inner_size usage, closes [#2187](https://www.github.com/tauri-apps/tauri/pull/2187) ([#2690](https://www.github.com/tauri-apps/tauri/pull/2690)) on 2021-09-29 +- Reimplement `remove_system_tray` on Windows to drop the `SystemTray` to run its cleanup code. + - [a03b8554](https://www.github.com/tauri-apps/tauri/commit/a03b85545a4b0b61a598a43eabe96e03565dcaf0) fix(core): tray not closing on Windows ([#3351](https://www.github.com/tauri-apps/tauri/pull/3351)) on 2022-02-07 +- Replace `WindowBuilder`'s `has_menu` with `get_menu`. + - [ac37b56e](https://www.github.com/tauri-apps/tauri/commit/ac37b56ef43c9e97039967a5fd99f0d2dccb5b5a) fix(core): menu id map not reflecting the current window menu ([#2726](https://www.github.com/tauri-apps/tauri/pull/2726)) on 2021-10-08 +- Fix empty header from CORS on Linux. + - [b48487e6](https://www.github.com/tauri-apps/tauri/commit/b48487e6a7b33f5a352e542fae21a2efd53ce295) Fix empty header from CORS on Linux, closes [#2327](https://www.github.com/tauri-apps/tauri/pull/2327) ([#2762](https://www.github.com/tauri-apps/tauri/pull/2762)) on 2021-10-18 +- The `run_return` API is now available on Linux. + - [8483fde9](https://www.github.com/tauri-apps/tauri/commit/8483fde975aac8833d2ce426e42fb40aeaeecba9) feat(core): expose `run_return` on Linux ([#3352](https://www.github.com/tauri-apps/tauri/pull/3352)) on 2022-02-07 +- Allow window, global shortcut and clipboard APIs to be called on the main thread. + - [2812c446](https://www.github.com/tauri-apps/tauri/commit/2812c4464b93a365ab955935d05b5cea8cb03aab) feat(core): window, shortcut and clipboard API calls on main thread ([#2659](https://www.github.com/tauri-apps/tauri/pull/2659)) on 2021-09-26 + - [d24fd8d1](https://www.github.com/tauri-apps/tauri/commit/d24fd8d10242da3da143a971d976b42ec4de6079) feat(tauri-runtime-wry): allow window creation and closing on the main thread ([#2668](https://www.github.com/tauri-apps/tauri/pull/2668)) on 2021-09-27 +- Change event loop callbacks definition to allow callers to move in mutable values. + - [bdbf905e](https://www.github.com/tauri-apps/tauri/commit/bdbf905e5d802b58693d2bd27582ce4269faf79c) Transformed event-loop callback to FnMut to allow mutable values ([#2667](https://www.github.com/tauri-apps/tauri/pull/2667)) on 2021-09-27 +- **Breaking change:** Add `macos-private-api` feature flag, enabled via `tauri.conf.json > tauri > macOSPrivateApi`. + - [6ac21b3c](https://www.github.com/tauri-apps/tauri/commit/6ac21b3cef7f14358df38cc69ea3d277011accaf) feat: add private api feature flag ([#7](https://www.github.com/tauri-apps/tauri/pull/7)) on 2022-01-09 +- Refactor `create_tao_window` API to return `Weak` instead of `Arc`. + - [c1494b35](https://www.github.com/tauri-apps/tauri/commit/c1494b353233c6a9552d7ace962fdf8d5b1f199a) refactor: return Weak on create_tao_window on 2021-08-31 +- Added `any_thread` constructor on the `Runtime` trait (only possible on Linux and Windows). + - [af44bf81](https://www.github.com/tauri-apps/tauri/commit/af44bf8168310cf77fbe102a53e7c433f11641a3) feat(core): allow app run on any thread on Linux & Windows, closes [#3172](https://www.github.com/tauri-apps/tauri/pull/3172) ([#3353](https://www.github.com/tauri-apps/tauri/pull/3353)) on 2022-02-07 +- Added `run_on_main_thread` API on `RuntimeHandle`. + - [53fdfe52](https://www.github.com/tauri-apps/tauri/commit/53fdfe52bb30d52653c72ca9f42506c3863dcf4a) feat(core): expose `run_on_main_thread` API ([#2711](https://www.github.com/tauri-apps/tauri/pull/2711)) on 2021-10-04 +- **Breaking change:** Renamed the `RPC` interface to `IPC`. + - [3420aa50](https://www.github.com/tauri-apps/tauri/commit/3420aa5031b3274a95c6c5fa0f8683ca13213396) refactor: IPC handler \[TRI-019] ([#9](https://www.github.com/tauri-apps/tauri/pull/9)) on 2022-01-09 +- Added `open_devtools` to the `Dispatcher` trait. + - [55aa22de](https://www.github.com/tauri-apps/tauri/commit/55aa22de80c3de873e29bcffcb5b2fe236a637a6) feat(core): add `Window#open_devtools` API, closes [#1213](https://www.github.com/tauri-apps/tauri/pull/1213) ([#3350](https://www.github.com/tauri-apps/tauri/pull/3350)) on 2022-02-07 +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 +- Replace all of the `winapi` crate references with the `windows` crate, and replace `webview2` and `webview2-sys` with `webview2-com` and `webview2-com-sys` built with the `windows` crate. This goes along with updates to the TAO and WRY `next` branches. + - [bb00d5bd](https://www.github.com/tauri-apps/tauri/commit/bb00d5bd6c9dfcb6bdd0d308dadb70e6c6aafe5c) Replace winapi with windows crate and use webview2-com instead of webview2 ([#2615](https://www.github.com/tauri-apps/tauri/pull/2615)) on 2021-09-24 +- Update the `windows` crate to 0.25.0, which comes with pre-built libraries. WRY and Tao can both reference the same types directly from the `windows` crate instead of sharing bindings in `webview2-com-sys`. + - [34be6cf3](https://www.github.com/tauri-apps/tauri/commit/34be6cf37a98ee7cbd66623ebddae08e5a6520fd) Update webview2-com and windows crates ([#2875](https://www.github.com/tauri-apps/tauri/pull/2875)) on 2021-11-11 +- This is a temporary fix of null pointer crash on `get_content` of web resource request. + We will switch it back once upstream is updated. + - [84f6e3e8](https://www.github.com/tauri-apps/tauri/commit/84f6e3e84a34b01b7fa04f5c4719acb921ef4263) Switch to next branch of wry ([#2574](https://www.github.com/tauri-apps/tauri/pull/2574)) on 2021-09-10 +- Update wry to 0.13. + - [343ea3e2](https://www.github.com/tauri-apps/tauri/commit/343ea3e2e8d51bac63ab651289295c26fcc841d8) Update wry to 0.13 ([#3336](https://www.github.com/tauri-apps/tauri/pull/3336)) on 2022-02-06 + +## \[0.2.1] + +- Migrate to latest custom protocol allowing `Partial content` streaming and Header parsing. + - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 + +## \[0.2.0] + +- Fix blur/focus events being incorrect on Windows. + - [d832d575](https://www.github.com/tauri-apps/tauri/commit/d832d575d9b03a0ff78accabe4631cc638c08c3b) fix(windows): use webview events on windows ([#2277](https://www.github.com/tauri-apps/tauri/pull/2277)) on 2021-07-23 + +- Add `ExitRequested` event that allows preventing the app from exiting when all windows are closed, and an `AppHandle.exit()` function to exit the app manually. + - [892c63a0](https://www.github.com/tauri-apps/tauri/commit/892c63a0538f8d62680dce5848657128ad6b7af3) feat([#2287](https://www.github.com/tauri-apps/tauri/pull/2287)): Add `ExitRequested` event to let users prevent app from exiting ([#2293](https://www.github.com/tauri-apps/tauri/pull/2293)) on 2021-08-09 + +- Update gtk and its related libraries to v0.14. This also remove requirements of `clang` as build dependency. + - [63ad3039](https://www.github.com/tauri-apps/tauri/commit/63ad303903bbee7c9a7382413b342e2a05d3ea75) chore(linux): bump gtk to v0.14 ([#2361](https://www.github.com/tauri-apps/tauri/pull/2361)) on 2021-08-07 + +- Implement `Debug` on public API structs and enums. + - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 + +- Fix the error "cannot find type MenuHash in this scope" + - [226414d1](https://www.github.com/tauri-apps/tauri/commit/226414d1a588c8bc2b540a71fcd84c318319d6af) "cannot find type `MenuHash` in this scope" ([#2240](https://www.github.com/tauri-apps/tauri/pull/2240)) on 2021-07-20 + +- Panic when a dispatcher getter method (`Window`, `GlobalShortcutHandle`, `ClipboardManager` and `MenuHandle` APIs) is called on the main thread. + - [50ffdc06](https://www.github.com/tauri-apps/tauri/commit/50ffdc06fbde56aba32b4291fd130104935d1408) feat(core): panic when a dispatcher getter is used on the main thread ([#2455](https://www.github.com/tauri-apps/tauri/pull/2455)) on 2021-08-16 + +- Remove menu feature flag since there's no package dependency need to be installed on any platform anymore. + - [f81ebddf](https://www.github.com/tauri-apps/tauri/commit/f81ebddfcc1aea0d4989706aef43538e8ea98bea) feat: remove menu feature flag ([#2415](https://www.github.com/tauri-apps/tauri/pull/2415)) on 2021-08-13 + +- Adds `Resumed` and `MainEventsCleared` variants to the `RunEvent` enum. + - [6be3f433](https://www.github.com/tauri-apps/tauri/commit/6be3f4339168651fe4e003b09f7d181fd12cd5a8) feat(core): add `Resumed` and `MainEventsCleared` events, closes [#2127](https://www.github.com/tauri-apps/tauri/pull/2127) ([#2439](https://www.github.com/tauri-apps/tauri/pull/2439)) on 2021-08-15 + +- Adds `set_activation_policy` API to the `Runtime` trait (macOS only). + - [4a031add](https://www.github.com/tauri-apps/tauri/commit/4a031add69014a1f3823f4ea19b172a2557f6794) feat(core): expose `set_activation_policy`, closes [#2258](https://www.github.com/tauri-apps/tauri/pull/2258) ([#2420](https://www.github.com/tauri-apps/tauri/pull/2420)) on 2021-08-13 + +- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. + - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 + - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 + +- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. + +- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. + +- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 + +- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. + - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 + +- Add webdriver support to Tauri. + - [be76fb1d](https://www.github.com/tauri-apps/tauri/commit/be76fb1dfe73a1605cc2ad246418579f4c2e1999) WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972)) on 2021-06-23 + - [b4426eda](https://www.github.com/tauri-apps/tauri/commit/b4426eda9e64fcdd25a2d72e548b8b0fbfa09619) Revert "WebDriver support ([#1972](https://www.github.com/tauri-apps/tauri/pull/1972))" on 2021-06-23 + - [4b2aa356](https://www.github.com/tauri-apps/tauri/commit/4b2aa35684632ed2afd7dec4ad848df5704868e4) Add back WebDriver support ([#2324](https://www.github.com/tauri-apps/tauri/pull/2324)) on 2021-08-01 + +## \[0.1.4] + +- Allow preventing window close when the user requests it. + - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 +- Fixes SVG loading on custom protocol. + - [e663bdd5](https://www.github.com/tauri-apps/tauri/commit/e663bdd5938830ab4eba961e69c3985191b499dd) fix(core): svg mime type ([#2129](https://www.github.com/tauri-apps/tauri/pull/2129)) on 2021-06-30 +- Fixes `center` and `focus` not being allowed in `tauri.conf.json > tauri > windows` and ignored in `WindowBuilderWrapper`. + - [bc2c331d](https://www.github.com/tauri-apps/tauri/commit/bc2c331dec3dec44c79e659b082b5fb6b65cc5ea) fix: center and focus not being allowed in config ([#2199](https://www.github.com/tauri-apps/tauri/pull/2199)) on 2021-07-12 +- Expose `gtk_window` getter. + - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 +- Remove a few locks requirement in tauri-runtime-wry + - [6569c2bf](https://www.github.com/tauri-apps/tauri/commit/6569c2bf5caf24b009cad1e2cffba25418d6bb68) refactor(wry): remove a few locks requirements ([#2137](https://www.github.com/tauri-apps/tauri/pull/2137)) on 2021-07-02 +- Fix macOS high CPU usage. + - [a280ee90](https://www.github.com/tauri-apps/tauri/commit/a280ee90af0749ce18d6d0b00939b06473717bc9) Fix high cpu usage on mac, fix [#2074](https://www.github.com/tauri-apps/tauri/pull/2074) ([#2125](https://www.github.com/tauri-apps/tauri/pull/2125)) on 2021-06-30 +- Bump `wry` 0.11 and fix focus integration to make it compatible with tao 0.4. + - [f0a8db62](https://www.github.com/tauri-apps/tauri/commit/f0a8db62e445dbbc5770e7addf0390ce3844c1ea) core(deps): bump `wry` to `0.11` ([#2210](https://www.github.com/tauri-apps/tauri/pull/2210)) on 2021-07-15 +- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those + associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If + you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the + explicit type and let the compiler infer it instead. + +`tauri`: + +- See `Params` note +- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a + simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition + of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type + to these functions. +- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all + methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already + required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change + affects you. + +`tauri-macros`: + +- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when + the specified feature is enabled. + +`tauri-runtime`: + +- See `Params` note +- Removed `Params`, `MenuId`, `Tag`, `TagRef`. +- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. + - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. +- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the + `Runtime` type directly +- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. +- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. + +`tauri-runtime-wry`: + +- See `Params` note +- update menu and runtime related types to the ones changed in `tauri-runtime`. + +`tauri-utils`: + +- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object + safe. +- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 + +## \[0.1.3] + +- `Window` is now `Send + Sync` on Windows. + - [fe32afcc](https://www.github.com/tauri-apps/tauri/commit/fe32afcc933920d6282ae1d63b041b182278a031) fix(core): `Window` must be `Send + Sync` on Windows, closes [#2078](https://www.github.com/tauri-apps/tauri/pull/2078) ([#2093](https://www.github.com/tauri-apps/tauri/pull/2093)) on 2021-06-27 + +## \[0.1.2] + +- Adds `clipboard` APIs (write and read text). + - [285bf64b](https://www.github.com/tauri-apps/tauri/commit/285bf64bf9569efb2df904c69c6df405ff0d62e2) feat(core): add clipboard writeText and readText APIs ([#2035](https://www.github.com/tauri-apps/tauri/pull/2035)) on 2021-06-21 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Fixes window event being emitted to all windows listeners. + - [fca97640](https://www.github.com/tauri-apps/tauri/commit/fca976404e6bec373a81332572458c4c44f7bb3a) fix(wry): window event listeners being emitted to all windows ([#2056](https://www.github.com/tauri-apps/tauri/pull/2056)) on 2021-06-23 +- Panic on window getters usage on the main thread when the event loop is not running and document it. + - [ab3eb44b](https://www.github.com/tauri-apps/tauri/commit/ab3eb44bac7a3bf73a4985df38ccc2b87a913be7) fix(core): deadlock on window getters, fixes [#1893](https://www.github.com/tauri-apps/tauri/pull/1893) ([#1998](https://www.github.com/tauri-apps/tauri/pull/1998)) on 2021-06-16 +- Adds `focus` API to the WindowBuilder. + - [5f351622](https://www.github.com/tauri-apps/tauri/commit/5f351622c7812ad1bb56ddb37364ccaa4124c24b) feat(core): add focus API to the WindowBuilder and WindowOptions, [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds support to PNG icons. + - [40b717ed](https://www.github.com/tauri-apps/tauri/commit/40b717edc57288a1393fad0529390e101ab903c1) feat(core): set window icon on Linux, closes [#1922](https://www.github.com/tauri-apps/tauri/pull/1922) ([#1937](https://www.github.com/tauri-apps/tauri/pull/1937)) on 2021-06-01 +- Adds `is_decorated` getter on Window. + - [f58a2114](https://www.github.com/tauri-apps/tauri/commit/f58a2114fbfd5307c349f05c88f2e08fd8baa8aa) feat(core): add `is_decorated` Window getter on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `is_resizable` getter on Window. + - [1e8af280](https://www.github.com/tauri-apps/tauri/commit/1e8af280c27f381828d6209722b10e889082fa00) feat(core): add `is_resizable` Window getter on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `is_visible` getter on Window. + - [36506c96](https://www.github.com/tauri-apps/tauri/commit/36506c967de82bc7ff453d11e6104ecf66d7a588) feat(core): add `is_visible` API on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Removes `image` dependency. For now only `.ico` icons on Windows are supported, and we'll implement other types on demand to optimize bundle size. + - [1be37a3f](https://www.github.com/tauri-apps/tauri/commit/1be37a3f30ff789d9396ec9009f9c0dd0bb928a7) refactor(core): remove `image` dependency ([#1859](https://www.github.com/tauri-apps/tauri/pull/1859)) on 2021-05-18 +- The `run_on_main_thread` API now uses WRY's UserEvent, so it wakes the event loop. + - [9bf82f0d](https://www.github.com/tauri-apps/tauri/commit/9bf82f0d9261808f58bdb5b5dbd6a255e5dcd333) fix(core): `run_on_main_thread` now wakes the event loop ([#1949](https://www.github.com/tauri-apps/tauri/pull/1949)) on 2021-06-04 +- Adds global shortcut interfaces. + - [3280c4aa](https://www.github.com/tauri-apps/tauri/commit/3280c4aa91e50a8ccdd561a8b48a12a4a13ea8d5) refactor(core): global shortcut is now provided by `tao` ([#2031](https://www.github.com/tauri-apps/tauri/pull/2031)) on 2021-06-21 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `request_user_attention` API to the `Dispatcher` trait. + - [7dcca6e9](https://www.github.com/tauri-apps/tauri/commit/7dcca6e9281182b11ad3d4a79871f09b30b9b419) feat(core): add `request_user_attention` API, closes [#2023](https://www.github.com/tauri-apps/tauri/pull/2023) ([#2026](https://www.github.com/tauri-apps/tauri/pull/2026)) on 2021-06-20 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `fn run_iteration` (macOS and Windows only) to the Runtime trait. + - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 +- Adds `show_menu`, `hide_menu` and `is_menu_visible` APIs to the `Dispatcher` trait. + - [954460c5](https://www.github.com/tauri-apps/tauri/commit/954460c5205d57444ef4b1412051fbedf3e38676) feat(core): MenuHandle `show`, `hide`, `is_visible` and `toggle` APIs ([#1958](https://www.github.com/tauri-apps/tauri/pull/1958)) on 2021-06-15 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `set_focus` API on Window. + - [bb6992f8](https://www.github.com/tauri-apps/tauri/commit/bb6992f888196ca7c87bb2fe74ad2bd8bf393e05) feat(core): add `set_focus` window API, fixes [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `set_skip_taskbar` API on Window. + - [e06aa277](https://www.github.com/tauri-apps/tauri/commit/e06aa277384450cfef617c0e57b0d5d403bb1e7f) feat(core): add `set_skip_taskbar` API on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Update `wry` to v0.10.0 and replace the removed `dispatch_script` and `evaluate_script` methods with the new `evaluate_script` method in `handle_event_loop`. + - [cca8115d](https://www.github.com/tauri-apps/tauri/commit/cca8115d9c813d13efb30a38445d5bda009a7f97) refactor: update wry, simplify script eval ([#1965](https://www.github.com/tauri-apps/tauri/pull/1965)) on 2021-06-16 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `skip_taskbar` API to the WindowBuilder. + - [5525b03a](https://www.github.com/tauri-apps/tauri/commit/5525b03a78a2232c650043fbd9894ce1553cad41) feat(core): add `skip_taskbar` API to the WindowBuilder/WindowOptions on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `Window#center` and `WindowBuilder#center` APIs. + - [5cba6eb4](https://www.github.com/tauri-apps/tauri/commit/5cba6eb4d28d53f06855d60d4d0eae6b95233ccf) feat(core): add window `center` API, closes [#1822](https://www.github.com/tauri-apps/tauri/pull/1822) ([#1954](https://www.github.com/tauri-apps/tauri/pull/1954)) on 2021-06-05 +- Adds `parent_window` and `owner_window` setters to the `WindowBuilder` (Windows only). + - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 +- Adds window native handle getter (HWND on Windows). + - [abf78c58](https://www.github.com/tauri-apps/tauri/commit/abf78c5860cdc52fbfd2bc5dbca29a864e2da8f9) fix(core): set parent window handle on dialogs, closes [#1876](https://www.github.com/tauri-apps/tauri/pull/1876) ([#1889](https://www.github.com/tauri-apps/tauri/pull/1889)) on 2021-05-21 + +## \[0.1.1] + +- Fixes `system-tray` feature usage. + - [1ab8dd9](https://www.github.com/tauri-apps/tauri/commit/1ab8dd93e670d2a2d070c7a6ec48308a0ab32f1a) fix(core): `system-tray` cargo feature usage, fixes [#1798](https://www.github.com/tauri-apps/tauri/pull/1798) ([#1801](https://www.github.com/tauri-apps/tauri/pull/1801)) on 2021-05-12 +- Fixes webview transparency. + - [f5a480f](https://www.github.com/tauri-apps/tauri/commit/f5a480fea34ab3a75751f1ca760a38b3e53da2cc) fix(core): window transparency ([#1800](https://www.github.com/tauri-apps/tauri/pull/1800)) on 2021-05-12 + +## \[0.1.0] + +- **Breaking:** `Context` fields are now private, and is expected to be created through `Context::new(...)`. + All fields previously available through `Context` are now public methods. + - [5542359](https://www.github.com/tauri-apps/tauri/commit/55423590ddbf560684dab6a0214acf95aadfa8d2) refactor(core): Context fields now private, Icon used on all platforms ([#1774](https://www.github.com/tauri-apps/tauri/pull/1774)) on 2021-05-11 +- `tauri-runtime-wry` initial release. + - [45a7a11](https://www.github.com/tauri-apps/tauri/commit/45a7a111e0cf9d9956d713cc9a99fa7a5313eec7) feat(core): add `tauri-wry` crate ([#1756](https://www.github.com/tauri-apps/tauri/pull/1756)) on 2021-05-09 diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml new file mode 100644 index 000000000000..2ac2bf60c5ad --- /dev/null +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -0,0 +1,75 @@ +[package] +name = "tauri-runtime-wry" +version = "2.2.0" +description = "Wry bindings to the Tauri runtime" +exclude = ["CHANGELOG.md", "/target"] +readme = "README.md" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +categories.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[package.metadata.docs.rs] +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +wry = { version = "0.47", default-features = false, features = [ + "drag-drop", + "protocol", + "os-webview", + "linux-body", +] } +tao = { version = "0.31.0", default-features = false, features = ["rwh_06"] } +tauri-runtime = { version = "2.2.0", path = "../tauri-runtime" } +tauri-utils = { version = "2.1.0", path = "../tauri-utils" } +raw-window-handle = "0.6" +http = "1.1" +url = "2" +tracing = { version = "0.1", optional = true } +log = "0.4" + +[target."cfg(windows)".dependencies] +webview2-com = "0.33" +softbuffer = { version = "0.4", default-features = false } + +[target."cfg(windows)".dependencies.windows] +version = "0.58" +features = ["Win32_Foundation", "Win32_Graphics_Dwm"] + +[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] +gtk = { version = "0.18", features = ["v3_24"] } +webkit2gtk = { version = "=2.0", features = ["v2_40"] } +percent-encoding = "2.1" + +[target.'cfg(target_vendor = "apple")'.dependencies] +objc2 = "0.5.2" + +[target.'cfg(target_os = "macos")'.dependencies] +objc2-foundation = { version = "0.2.2", features = [] } +objc2-app-kit = { version = "0.2.2", features = [ + "block2", + "NSApplication", + "NSResponder", + "NSView", + "NSWindow", + "NSGraphics", +] } + +[target."cfg(target_os = \"android\")".dependencies] +jni = "0.21" + +[features] +devtools = ["wry/devtools", "tauri-runtime/devtools"] +macos-private-api = [ + "wry/fullscreen", + "wry/transparent", + "tauri-runtime/macos-private-api", +] +objc-exception = ["wry/objc-exception"] +tracing = ["dep:tracing", "wry/tracing"] +macos-proxy = ["wry/mac-proxy"] +unstable = [] diff --git a/core/tauri-runtime/LICENSE_APACHE-2.0 b/crates/tauri-runtime-wry/LICENSE_APACHE-2.0 similarity index 100% rename from core/tauri-runtime/LICENSE_APACHE-2.0 rename to crates/tauri-runtime-wry/LICENSE_APACHE-2.0 diff --git a/core/tauri-runtime/LICENSE_MIT b/crates/tauri-runtime-wry/LICENSE_MIT similarity index 100% rename from core/tauri-runtime/LICENSE_MIT rename to crates/tauri-runtime-wry/LICENSE_MIT diff --git a/crates/tauri-runtime-wry/README.md b/crates/tauri-runtime-wry/README.md new file mode 100644 index 000000000000..a452527bc3d8 --- /dev/null +++ b/crates/tauri-runtime-wry/README.md @@ -0,0 +1,44 @@ +# tauri-runtime-wry + + + +[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri) +[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) + +[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml) +[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app) + +[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) +[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri) + +| Component | Version | +| ----------------- | ---------------------------------------------------------------------------------------------------------------------- | +| tauri-runtime-wry | [![](https://img.shields.io/crates/v/tauri-runtime-wry?style=flat-square)](https://crates.io/crates/tauri-runtime-wry) | + +## About Tauri + +Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. + +Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. + +## This module + +This crate opens up direct systems-level interactions specifically for WRY, such as printing, monitor detection, and other windowing related tasks. `tauri-runtime` implementation for WRY. +None of the exposed API of this crate is stable, and it may break semver +compatibility in the future. The major version only signifies the intended Tauri version. + +To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. + +## Semver + +**tauri** is following [Semantic Versioning 2.0](https://semver.org/). + +## Licenses + +Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. + +MIT or MIT/Apache 2.0 where applicable. + +Logo: CC-BY-NC-ND + +- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/crates/tauri-runtime-wry/build.rs b/crates/tauri-runtime-wry/build.rs new file mode 100644 index 000000000000..9974c5040b19 --- /dev/null +++ b/crates/tauri-runtime-wry/build.rs @@ -0,0 +1,19 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// creates a cfg alias if `has_feature` is true. +// `alias` must be a snake case string. +fn alias(alias: &str, has_feature: bool) { + println!("cargo:rustc-check-cfg=cfg({alias})"); + if has_feature { + println!("cargo:rustc-cfg={alias}"); + } +} + +fn main() { + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + let mobile = target_os == "ios" || target_os == "android"; + alias("desktop", !mobile); + alias("mobile", mobile); +} diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs new file mode 100644 index 000000000000..82a93edf3c13 --- /dev/null +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -0,0 +1,4587 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! The [`wry`] Tauri [`Runtime`]. +//! +//! None of the exposed API of this crate is stable, and it may break semver +//! compatibility in the future. The major version only signifies the intended Tauri version. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +use http::Request; +use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle}; + +use tauri_runtime::{ + dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize, Position, Size}, + monitor::Monitor, + webview::{DetachedWebview, DownloadEvent, PendingWebview, WebviewIpcHandler}, + window::{ + CursorIcon, DetachedWindow, DetachedWindowWebview, DragDropEvent, PendingWindow, RawWindow, + WebviewEvent, WindowBuilder, WindowBuilderBase, WindowEvent, WindowId, WindowSizeConstraints, + }, + DeviceEventFilter, Error, EventLoopProxy, ExitRequestedEventAction, Icon, ProgressBarState, + ProgressBarStatus, Result, RunEvent, Runtime, RuntimeHandle, RuntimeInitArgs, UserAttentionType, + UserEvent, WebviewDispatch, WebviewEventId, WindowDispatch, WindowEventId, +}; + +#[cfg(any(target_os = "macos", target_os = "ios"))] +use objc2::rc::Retained; +#[cfg(target_os = "macos")] +use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS}; +#[cfg(target_os = "linux")] +use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix}; +#[cfg(windows)] +use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows}; +#[cfg(windows)] +use webview2_com::FocusChangedEventHandler; +#[cfg(windows)] +use windows::Win32::{Foundation::HWND, System::WinRT::EventRegistrationToken}; +#[cfg(any(target_os = "macos", target_os = "ios"))] +use wry::WebViewBuilderExtDarwin; +#[cfg(windows)] +use wry::WebViewBuilderExtWindows; + +use tao::{ + dpi::{ + LogicalPosition as TaoLogicalPosition, LogicalSize as TaoLogicalSize, + PhysicalPosition as TaoPhysicalPosition, PhysicalSize as TaoPhysicalSize, + Position as TaoPosition, Size as TaoSize, + }, + event::{Event, StartCause, WindowEvent as TaoWindowEvent}, + event_loop::{ + ControlFlow, DeviceEventFilter as TaoDeviceEventFilter, EventLoop, EventLoopBuilder, + EventLoopProxy as TaoEventLoopProxy, EventLoopWindowTarget, + }, + monitor::MonitorHandle, + window::{ + CursorIcon as TaoCursorIcon, Fullscreen, Icon as TaoWindowIcon, + ProgressBarState as TaoProgressBarState, ProgressState as TaoProgressState, Theme as TaoTheme, + UserAttentionType as TaoUserAttentionType, + }, +}; +#[cfg(target_os = "macos")] +use tauri_utils::TitleBarStyle; +use tauri_utils::{ + config::{Color, WindowConfig}, + Theme, +}; +use url::Url; +use wry::{ + DragDropEvent as WryDragDropEvent, ProxyConfig, ProxyEndpoint, WebContext as WryWebContext, + WebView, WebViewBuilder, +}; + +pub use tao; +pub use tao::window::{Window, WindowBuilder as TaoWindowBuilder, WindowId as TaoWindowId}; +pub use wry; +pub use wry::webview_version; + +#[cfg(windows)] +use wry::WebViewExtWindows; +#[cfg(target_os = "android")] +use wry::{ + prelude::{dispatch, find_class}, + WebViewBuilderExtAndroid, WebViewExtAndroid, +}; +#[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "ios", + target_os = "android" +)))] +use wry::{WebViewBuilderExtUnix, WebViewExtUnix}; + +#[cfg(target_os = "ios")] +pub use tao::platform::ios::WindowExtIOS; +#[cfg(target_os = "macos")] +pub use tao::platform::macos::{ + ActivationPolicy as TaoActivationPolicy, EventLoopExtMacOS, WindowExtMacOS, +}; +#[cfg(target_os = "macos")] +use tauri_runtime::ActivationPolicy; + +use std::{ + cell::RefCell, + collections::{ + hash_map::Entry::{Occupied, Vacant}, + BTreeMap, HashMap, HashSet, + }, + fmt, + ops::Deref, + path::PathBuf, + rc::Rc, + sync::{ + atomic::{AtomicBool, AtomicU32, Ordering}, + mpsc::{channel, Sender}, + Arc, Mutex, Weak, + }, + thread::{current as current_thread, ThreadId}, +}; + +pub type WebviewId = u32; +type IpcHandler = dyn Fn(Request) + 'static; + +#[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +mod undecorated_resizing; +mod webview; +mod window; + +pub use webview::Webview; +use window::WindowExt as _; + +#[derive(Debug)] +pub struct WebContext { + pub inner: WryWebContext, + pub referenced_by_webviews: HashSet, + // on Linux the custom protocols are associated with the context + // and you cannot register a URI scheme more than once + pub registered_custom_protocols: HashSet, +} + +pub type WebContextStore = Arc, WebContext>>>; +// window +pub type WindowEventHandler = Box; +pub type WindowEventListeners = Arc>>; +pub type WebviewEventHandler = Box; +pub type WebviewEventListeners = Arc>>; + +#[derive(Debug, Clone, Default)] +pub struct WindowIdStore(Arc>>); + +impl WindowIdStore { + pub fn insert(&self, w: TaoWindowId, id: WindowId) { + self.0.lock().unwrap().insert(w, id); + } + + fn get(&self, w: &TaoWindowId) -> Option { + self.0.lock().unwrap().get(w).copied() + } +} + +#[macro_export] +macro_rules! getter { + ($self: ident, $rx: expr, $message: expr) => {{ + $crate::send_user_message(&$self.context, $message)?; + $rx + .recv() + .map_err(|_| $crate::Error::FailedToReceiveMessage) + }}; +} + +macro_rules! window_getter { + ($self: ident, $message: expr) => {{ + let (tx, rx) = channel(); + getter!($self, rx, Message::Window($self.window_id, $message(tx))) + }}; +} + +macro_rules! event_loop_window_getter { + ($self: ident, $message: expr) => {{ + let (tx, rx) = channel(); + getter!($self, rx, Message::EventLoopWindowTarget($message(tx))) + }}; +} + +macro_rules! webview_getter { + ($self: ident, $message: expr) => {{ + let (tx, rx) = channel(); + getter!( + $self, + rx, + Message::Webview( + *$self.window_id.lock().unwrap(), + $self.webview_id, + $message(tx) + ) + ) + }}; +} + +pub(crate) fn send_user_message( + context: &Context, + message: Message, +) -> Result<()> { + if current_thread().id() == context.main_thread_id { + handle_user_message( + &context.main_thread.window_target, + message, + UserMessageContext { + window_id_map: context.window_id_map.clone(), + windows: context.main_thread.windows.clone(), + }, + ); + Ok(()) + } else { + context + .proxy + .send_event(message) + .map_err(|_| Error::FailedToSendMessage) + } +} + +#[derive(Clone)] +pub struct Context { + pub window_id_map: WindowIdStore, + main_thread_id: ThreadId, + pub proxy: TaoEventLoopProxy>, + main_thread: DispatcherMainThreadContext, + plugins: Arc + Send>>>>, + next_window_id: Arc, + next_webview_id: Arc, + next_window_event_id: Arc, + next_webview_event_id: Arc, +} + +impl Context { + pub fn run_threaded(&self, f: F) -> R + where + F: FnOnce(Option<&DispatcherMainThreadContext>) -> R, + { + f(if current_thread().id() == self.main_thread_id { + Some(&self.main_thread) + } else { + None + }) + } + + fn next_window_id(&self) -> WindowId { + self.next_window_id.fetch_add(1, Ordering::Relaxed).into() + } + + fn next_webview_id(&self) -> WebviewId { + self.next_webview_id.fetch_add(1, Ordering::Relaxed) + } + + fn next_window_event_id(&self) -> u32 { + self.next_window_event_id.fetch_add(1, Ordering::Relaxed) + } + + fn next_webview_event_id(&self) -> u32 { + self.next_webview_event_id.fetch_add(1, Ordering::Relaxed) + } +} + +impl Context { + fn create_window( + &self, + pending: PendingWindow>, + after_window_creation: Option, + ) -> Result>> { + let label = pending.label.clone(); + let context = self.clone(); + let window_id = self.next_window_id(); + let (webview_id, use_https_scheme) = pending + .webview + .as_ref() + .map(|w| { + ( + Some(context.next_webview_id()), + w.webview_attributes.use_https_scheme, + ) + }) + .unwrap_or((None, false)); + + send_user_message( + self, + Message::CreateWindow( + window_id, + Box::new(move |event_loop| { + create_window( + window_id, + webview_id.unwrap_or_default(), + event_loop, + &context, + pending, + after_window_creation, + ) + }), + ), + )?; + + let dispatcher = WryWindowDispatcher { + window_id, + context: self.clone(), + }; + + let detached_webview = webview_id.map(|id| { + let webview = DetachedWebview { + label: label.clone(), + dispatcher: WryWebviewDispatcher { + window_id: Arc::new(Mutex::new(window_id)), + webview_id: id, + context: self.clone(), + }, + }; + DetachedWindowWebview { + webview, + use_https_scheme, + } + }); + + Ok(DetachedWindow { + id: window_id, + label, + dispatcher, + webview: detached_webview, + }) + } + + fn create_webview( + &self, + window_id: WindowId, + pending: PendingWebview>, + ) -> Result>> { + let label = pending.label.clone(); + let context = self.clone(); + + let webview_id = self.next_webview_id(); + + let window_id_wrapper = Arc::new(Mutex::new(window_id)); + let window_id_wrapper_ = window_id_wrapper.clone(); + + send_user_message( + self, + Message::CreateWebview( + window_id, + Box::new(move |window| { + create_webview( + WebviewKind::WindowChild, + window, + window_id_wrapper_, + webview_id, + &context, + pending, + ) + }), + ), + )?; + + let dispatcher = WryWebviewDispatcher { + window_id: window_id_wrapper, + webview_id, + context: self.clone(), + }; + + Ok(DetachedWebview { label, dispatcher }) + } +} + +#[cfg(feature = "tracing")] +#[derive(Debug, Clone, Default)] +pub struct ActiveTraceSpanStore(Rc>>); + +#[cfg(feature = "tracing")] +impl ActiveTraceSpanStore { + pub fn remove_window_draw(&self) { + self + .0 + .borrow_mut() + .retain(|t| !matches!(t, ActiveTracingSpan::WindowDraw { id: _, span: _ })); + } +} + +#[cfg(feature = "tracing")] +#[derive(Debug)] +pub enum ActiveTracingSpan { + WindowDraw { + id: TaoWindowId, + span: tracing::span::EnteredSpan, + }, +} + +#[derive(Debug)] +pub struct WindowsStore(RefCell>); + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for WindowsStore {} + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for WindowsStore {} + +#[derive(Debug, Clone)] +pub struct DispatcherMainThreadContext { + pub window_target: EventLoopWindowTarget>, + pub web_context: WebContextStore, + // changing this to an Rc will cause frequent app crashes. + pub windows: Arc, + #[cfg(feature = "tracing")] + pub active_tracing_spans: ActiveTraceSpanStore, +} + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for DispatcherMainThreadContext {} + +// SAFETY: we ensure this type is only used on the main thread. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for DispatcherMainThreadContext {} + +impl fmt::Debug for Context { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Context") + .field("main_thread_id", &self.main_thread_id) + .field("proxy", &self.proxy) + .field("main_thread", &self.main_thread) + .finish() + } +} + +pub struct DeviceEventFilterWrapper(pub TaoDeviceEventFilter); + +impl From for DeviceEventFilterWrapper { + fn from(item: DeviceEventFilter) -> Self { + match item { + DeviceEventFilter::Always => Self(TaoDeviceEventFilter::Always), + DeviceEventFilter::Never => Self(TaoDeviceEventFilter::Never), + DeviceEventFilter::Unfocused => Self(TaoDeviceEventFilter::Unfocused), + } + } +} + +pub struct RectWrapper(pub wry::Rect); +impl From for RectWrapper { + fn from(value: tauri_runtime::Rect) -> Self { + RectWrapper(wry::Rect { + position: value.position, + size: value.size, + }) + } +} + +/// Wrapper around a [`tao::window::Icon`] that can be created from an [`Icon`]. +pub struct TaoIcon(pub TaoWindowIcon); + +impl TryFrom> for TaoIcon { + type Error = Error; + fn try_from(icon: Icon<'_>) -> std::result::Result { + TaoWindowIcon::from_rgba(icon.rgba.to_vec(), icon.width, icon.height) + .map(Self) + .map_err(|e| Error::InvalidIcon(Box::new(e))) + } +} + +pub struct WindowEventWrapper(pub Option); + +impl WindowEventWrapper { + fn parse(window: &WindowWrapper, event: &TaoWindowEvent<'_>) -> Self { + match event { + // resized event from tao doesn't include a reliable size on macOS + // because wry replaces the NSView + TaoWindowEvent::Resized(_) => { + if let Some(w) = &window.inner { + let size = inner_size( + w, + &window.webviews, + window.has_children.load(Ordering::Relaxed), + ); + Self(Some(WindowEvent::Resized(PhysicalSizeWrapper(size).into()))) + } else { + Self(None) + } + } + e => e.into(), + } + } +} + +pub fn map_theme(theme: &TaoTheme) -> Theme { + match theme { + TaoTheme::Light => Theme::Light, + TaoTheme::Dark => Theme::Dark, + _ => Theme::Light, + } +} + +#[cfg(target_os = "macos")] +fn tao_activation_policy(activation_policy: ActivationPolicy) -> TaoActivationPolicy { + match activation_policy { + ActivationPolicy::Regular => TaoActivationPolicy::Regular, + ActivationPolicy::Accessory => TaoActivationPolicy::Accessory, + ActivationPolicy::Prohibited => TaoActivationPolicy::Prohibited, + _ => unimplemented!(), + } +} + +impl<'a> From<&TaoWindowEvent<'a>> for WindowEventWrapper { + fn from(event: &TaoWindowEvent<'a>) -> Self { + let event = match event { + TaoWindowEvent::Resized(size) => WindowEvent::Resized(PhysicalSizeWrapper(*size).into()), + TaoWindowEvent::Moved(position) => { + WindowEvent::Moved(PhysicalPositionWrapper(*position).into()) + } + TaoWindowEvent::Destroyed => WindowEvent::Destroyed, + TaoWindowEvent::ScaleFactorChanged { + scale_factor, + new_inner_size, + } => WindowEvent::ScaleFactorChanged { + scale_factor: *scale_factor, + new_inner_size: PhysicalSizeWrapper(**new_inner_size).into(), + }, + #[cfg(any(target_os = "linux", target_os = "macos"))] + TaoWindowEvent::Focused(focused) => WindowEvent::Focused(*focused), + TaoWindowEvent::ThemeChanged(theme) => WindowEvent::ThemeChanged(map_theme(theme)), + _ => return Self(None), + }; + Self(Some(event)) + } +} + +pub struct MonitorHandleWrapper(pub MonitorHandle); + +impl From for Monitor { + fn from(monitor: MonitorHandleWrapper) -> Monitor { + Self { + name: monitor.0.name(), + position: PhysicalPositionWrapper(monitor.0.position()).into(), + size: PhysicalSizeWrapper(monitor.0.size()).into(), + scale_factor: monitor.0.scale_factor(), + } + } +} + +pub struct PhysicalPositionWrapper(pub TaoPhysicalPosition); + +impl From> for PhysicalPosition { + fn from(position: PhysicalPositionWrapper) -> Self { + Self { + x: position.0.x, + y: position.0.y, + } + } +} + +impl From> for PhysicalPositionWrapper { + fn from(position: PhysicalPosition) -> Self { + Self(TaoPhysicalPosition { + x: position.x, + y: position.y, + }) + } +} + +struct LogicalPositionWrapper(TaoLogicalPosition); + +impl From> for LogicalPositionWrapper { + fn from(position: LogicalPosition) -> Self { + Self(TaoLogicalPosition { + x: position.x, + y: position.y, + }) + } +} + +pub struct PhysicalSizeWrapper(pub TaoPhysicalSize); + +impl From> for PhysicalSize { + fn from(size: PhysicalSizeWrapper) -> Self { + Self { + width: size.0.width, + height: size.0.height, + } + } +} + +impl From> for PhysicalSizeWrapper { + fn from(size: PhysicalSize) -> Self { + Self(TaoPhysicalSize { + width: size.width, + height: size.height, + }) + } +} + +struct LogicalSizeWrapper(TaoLogicalSize); + +impl From> for LogicalSizeWrapper { + fn from(size: LogicalSize) -> Self { + Self(TaoLogicalSize { + width: size.width, + height: size.height, + }) + } +} + +pub struct SizeWrapper(pub TaoSize); + +impl From for SizeWrapper { + fn from(size: Size) -> Self { + match size { + Size::Logical(s) => Self(TaoSize::Logical(LogicalSizeWrapper::from(s).0)), + Size::Physical(s) => Self(TaoSize::Physical(PhysicalSizeWrapper::from(s).0)), + } + } +} + +pub struct PositionWrapper(pub TaoPosition); + +impl From for PositionWrapper { + fn from(position: Position) -> Self { + match position { + Position::Logical(s) => Self(TaoPosition::Logical(LogicalPositionWrapper::from(s).0)), + Position::Physical(s) => Self(TaoPosition::Physical(PhysicalPositionWrapper::from(s).0)), + } + } +} + +#[derive(Debug, Clone)] +pub struct UserAttentionTypeWrapper(pub TaoUserAttentionType); + +impl From for UserAttentionTypeWrapper { + fn from(request_type: UserAttentionType) -> Self { + let o = match request_type { + UserAttentionType::Critical => TaoUserAttentionType::Critical, + UserAttentionType::Informational => TaoUserAttentionType::Informational, + }; + Self(o) + } +} + +#[derive(Debug)] +pub struct CursorIconWrapper(pub TaoCursorIcon); + +impl From for CursorIconWrapper { + fn from(icon: CursorIcon) -> Self { + use CursorIcon::*; + let i = match icon { + Default => TaoCursorIcon::Default, + Crosshair => TaoCursorIcon::Crosshair, + Hand => TaoCursorIcon::Hand, + Arrow => TaoCursorIcon::Arrow, + Move => TaoCursorIcon::Move, + Text => TaoCursorIcon::Text, + Wait => TaoCursorIcon::Wait, + Help => TaoCursorIcon::Help, + Progress => TaoCursorIcon::Progress, + NotAllowed => TaoCursorIcon::NotAllowed, + ContextMenu => TaoCursorIcon::ContextMenu, + Cell => TaoCursorIcon::Cell, + VerticalText => TaoCursorIcon::VerticalText, + Alias => TaoCursorIcon::Alias, + Copy => TaoCursorIcon::Copy, + NoDrop => TaoCursorIcon::NoDrop, + Grab => TaoCursorIcon::Grab, + Grabbing => TaoCursorIcon::Grabbing, + AllScroll => TaoCursorIcon::AllScroll, + ZoomIn => TaoCursorIcon::ZoomIn, + ZoomOut => TaoCursorIcon::ZoomOut, + EResize => TaoCursorIcon::EResize, + NResize => TaoCursorIcon::NResize, + NeResize => TaoCursorIcon::NeResize, + NwResize => TaoCursorIcon::NwResize, + SResize => TaoCursorIcon::SResize, + SeResize => TaoCursorIcon::SeResize, + SwResize => TaoCursorIcon::SwResize, + WResize => TaoCursorIcon::WResize, + EwResize => TaoCursorIcon::EwResize, + NsResize => TaoCursorIcon::NsResize, + NeswResize => TaoCursorIcon::NeswResize, + NwseResize => TaoCursorIcon::NwseResize, + ColResize => TaoCursorIcon::ColResize, + RowResize => TaoCursorIcon::RowResize, + _ => TaoCursorIcon::Default, + }; + Self(i) + } +} + +pub struct ProgressStateWrapper(pub TaoProgressState); + +impl From for ProgressStateWrapper { + fn from(status: ProgressBarStatus) -> Self { + let state = match status { + ProgressBarStatus::None => TaoProgressState::None, + ProgressBarStatus::Normal => TaoProgressState::Normal, + ProgressBarStatus::Indeterminate => TaoProgressState::Indeterminate, + ProgressBarStatus::Paused => TaoProgressState::Paused, + ProgressBarStatus::Error => TaoProgressState::Error, + }; + Self(state) + } +} + +pub struct ProgressBarStateWrapper(pub TaoProgressBarState); + +impl From for ProgressBarStateWrapper { + fn from(progress_state: ProgressBarState) -> Self { + Self(TaoProgressBarState { + progress: progress_state.progress, + state: progress_state + .status + .map(|state| ProgressStateWrapper::from(state).0), + desktop_filename: progress_state.desktop_filename, + }) + } +} + +#[derive(Clone, Default)] +pub struct WindowBuilderWrapper { + inner: TaoWindowBuilder, + center: bool, + #[cfg(target_os = "macos")] + tabbing_identifier: Option, +} + +impl std::fmt::Debug for WindowBuilderWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut s = f.debug_struct("WindowBuilderWrapper"); + s.field("inner", &self.inner).field("center", &self.center); + #[cfg(target_os = "macos")] + { + s.field("tabbing_identifier", &self.tabbing_identifier); + } + s.finish() + } +} + +// SAFETY: this type is `Send` since `menu_items` are read only here +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for WindowBuilderWrapper {} + +impl WindowBuilderBase for WindowBuilderWrapper {} +impl WindowBuilder for WindowBuilderWrapper { + fn new() -> Self { + #[allow(unused_mut)] + let mut builder = Self::default().focused(true); + + #[cfg(target_os = "macos")] + { + // TODO: find a proper way to prevent webview being pushed out of the window. + // Workround for issue: https://github.com/tauri-apps/tauri/issues/10225 + // The window requies `NSFullSizeContentViewWindowMask` flag to prevent devtools + // pushing the content view out of the window. + // By setting the default style to `TitleBarStyle::Visible` should fix the issue for most of the users. + builder = builder.title_bar_style(TitleBarStyle::Visible); + } + + builder = builder.title("Tauri App"); + + #[cfg(windows)] + { + builder = builder.window_classname("Tauri Window"); + } + + builder + } + + fn with_config(config: &WindowConfig) -> Self { + let mut window = WindowBuilderWrapper::new(); + + #[cfg(target_os = "macos")] + { + window = window + .hidden_title(config.hidden_title) + .title_bar_style(config.title_bar_style); + if let Some(identifier) = &config.tabbing_identifier { + window = window.tabbing_identifier(identifier); + } + } + + #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] + { + window = window.transparent(config.transparent); + } + #[cfg(all( + target_os = "macos", + not(feature = "macos-private-api"), + debug_assertions + ))] + if config.transparent { + eprintln!( + "The window is set to be transparent but the `macos-private-api` is not enabled. + This can be enabled via the `tauri.macOSPrivateApi` configuration property + "); + } + + #[cfg(target_os = "linux")] + { + // Mouse event is disabled on Linux since sudden event bursts could block event loop. + window.inner = window.inner.with_cursor_moved_event(false); + } + + #[cfg(desktop)] + { + window = window + .title(config.title.to_string()) + .inner_size(config.width, config.height) + .focused(config.focus) + .visible(config.visible) + .resizable(config.resizable) + .fullscreen(config.fullscreen) + .decorations(config.decorations) + .maximized(config.maximized) + .always_on_bottom(config.always_on_bottom) + .always_on_top(config.always_on_top) + .visible_on_all_workspaces(config.visible_on_all_workspaces) + .content_protected(config.content_protected) + .skip_taskbar(config.skip_taskbar) + .theme(config.theme) + .closable(config.closable) + .maximizable(config.maximizable) + .minimizable(config.minimizable) + .shadow(config.shadow); + + let mut constraints = WindowSizeConstraints::default(); + + if let Some(min_width) = config.min_width { + constraints.min_width = Some(tao::dpi::LogicalUnit::new(min_width).into()); + } + if let Some(min_height) = config.min_height { + constraints.min_height = Some(tao::dpi::LogicalUnit::new(min_height).into()); + } + if let Some(max_width) = config.max_width { + constraints.max_width = Some(tao::dpi::LogicalUnit::new(max_width).into()); + } + if let Some(max_height) = config.max_height { + constraints.max_height = Some(tao::dpi::LogicalUnit::new(max_height).into()); + } + if let Some(color) = config.background_color { + window = window.background_color(color); + } + window = window.inner_size_constraints(constraints); + + if let (Some(x), Some(y)) = (config.x, config.y) { + window = window.position(x, y); + } + + if config.center { + window = window.center(); + } + + if let Some(window_classname) = &config.window_classname { + window = window.window_classname(window_classname); + } + } + + window + } + + fn center(mut self) -> Self { + self.center = true; + self + } + + fn position(mut self, x: f64, y: f64) -> Self { + self.inner = self.inner.with_position(TaoLogicalPosition::new(x, y)); + self + } + + fn inner_size(mut self, width: f64, height: f64) -> Self { + self.inner = self + .inner + .with_inner_size(TaoLogicalSize::new(width, height)); + self + } + + fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { + self.inner = self + .inner + .with_min_inner_size(TaoLogicalSize::new(min_width, min_height)); + self + } + + fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { + self.inner = self + .inner + .with_max_inner_size(TaoLogicalSize::new(max_width, max_height)); + self + } + + fn inner_size_constraints(mut self, constraints: WindowSizeConstraints) -> Self { + self.inner.window.inner_size_constraints = tao::window::WindowSizeConstraints { + min_width: constraints.min_width, + min_height: constraints.min_height, + max_width: constraints.max_width, + max_height: constraints.max_height, + }; + self + } + + fn resizable(mut self, resizable: bool) -> Self { + self.inner = self.inner.with_resizable(resizable); + self + } + + fn maximizable(mut self, maximizable: bool) -> Self { + self.inner = self.inner.with_maximizable(maximizable); + self + } + + fn minimizable(mut self, minimizable: bool) -> Self { + self.inner = self.inner.with_minimizable(minimizable); + self + } + + fn closable(mut self, closable: bool) -> Self { + self.inner = self.inner.with_closable(closable); + self + } + + fn title>(mut self, title: S) -> Self { + self.inner = self.inner.with_title(title.into()); + self + } + + fn fullscreen(mut self, fullscreen: bool) -> Self { + self.inner = if fullscreen { + self + .inner + .with_fullscreen(Some(Fullscreen::Borderless(None))) + } else { + self.inner.with_fullscreen(None) + }; + self + } + + fn focused(mut self, focused: bool) -> Self { + self.inner = self.inner.with_focused(focused); + self + } + + fn maximized(mut self, maximized: bool) -> Self { + self.inner = self.inner.with_maximized(maximized); + self + } + + fn visible(mut self, visible: bool) -> Self { + self.inner = self.inner.with_visible(visible); + self + } + + #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] + fn transparent(mut self, transparent: bool) -> Self { + self.inner = self.inner.with_transparent(transparent); + self + } + + fn decorations(mut self, decorations: bool) -> Self { + self.inner = self.inner.with_decorations(decorations); + self + } + + fn always_on_bottom(mut self, always_on_bottom: bool) -> Self { + self.inner = self.inner.with_always_on_bottom(always_on_bottom); + self + } + + fn always_on_top(mut self, always_on_top: bool) -> Self { + self.inner = self.inner.with_always_on_top(always_on_top); + self + } + + fn visible_on_all_workspaces(mut self, visible_on_all_workspaces: bool) -> Self { + self.inner = self + .inner + .with_visible_on_all_workspaces(visible_on_all_workspaces); + self + } + + fn content_protected(mut self, protected: bool) -> Self { + self.inner = self.inner.with_content_protection(protected); + self + } + + fn shadow(#[allow(unused_mut)] mut self, _enable: bool) -> Self { + #[cfg(windows)] + { + self.inner = self.inner.with_undecorated_shadow(_enable); + } + #[cfg(target_os = "macos")] + { + self.inner = self.inner.with_has_shadow(_enable); + } + self + } + + #[cfg(windows)] + fn owner(mut self, owner: HWND) -> Self { + self.inner = self.inner.with_owner_window(owner.0 as _); + self + } + + #[cfg(windows)] + fn parent(mut self, parent: HWND) -> Self { + self.inner = self.inner.with_parent_window(parent.0 as _); + self + } + + #[cfg(target_os = "macos")] + fn parent(mut self, parent: *mut std::ffi::c_void) -> Self { + self.inner = self.inner.with_parent_window(parent); + self + } + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn transient_for(mut self, parent: &impl gtk::glib::IsA) -> Self { + self.inner = self.inner.with_transient_for(parent); + self + } + + #[cfg(windows)] + fn drag_and_drop(mut self, enabled: bool) -> Self { + self.inner = self.inner.with_drag_and_drop(enabled); + self + } + + #[cfg(target_os = "macos")] + fn title_bar_style(mut self, style: TitleBarStyle) -> Self { + match style { + TitleBarStyle::Visible => { + self.inner = self.inner.with_titlebar_transparent(false); + // Fixes rendering issue when resizing window with devtools open (https://github.com/tauri-apps/tauri/issues/3914) + self.inner = self.inner.with_fullsize_content_view(true); + } + TitleBarStyle::Transparent => { + self.inner = self.inner.with_titlebar_transparent(true); + self.inner = self.inner.with_fullsize_content_view(false); + } + TitleBarStyle::Overlay => { + self.inner = self.inner.with_titlebar_transparent(true); + self.inner = self.inner.with_fullsize_content_view(true); + } + unknown => { + #[cfg(feature = "tracing")] + tracing::warn!("unknown title bar style applied: {unknown}"); + + #[cfg(not(feature = "tracing"))] + eprintln!("unknown title bar style applied: {unknown}"); + } + } + self + } + + #[cfg(target_os = "macos")] + fn hidden_title(mut self, hidden: bool) -> Self { + self.inner = self.inner.with_title_hidden(hidden); + self + } + + #[cfg(target_os = "macos")] + fn tabbing_identifier(mut self, identifier: &str) -> Self { + self.inner = self.inner.with_tabbing_identifier(identifier); + self.tabbing_identifier.replace(identifier.into()); + self + } + + fn icon(mut self, icon: Icon) -> Result { + self.inner = self + .inner + .with_window_icon(Some(TaoIcon::try_from(icon)?.0)); + Ok(self) + } + + fn background_color(mut self, color: Color) -> Self { + self.inner = self.inner.with_background_color(color.into()); + self + } + + #[cfg(any(windows, target_os = "linux"))] + fn skip_taskbar(mut self, skip: bool) -> Self { + self.inner = self.inner.with_skip_taskbar(skip); + self + } + + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] + fn skip_taskbar(self, _skip: bool) -> Self { + self + } + + #[allow(unused_variables, unused_mut)] + fn theme(mut self, theme: Option) -> Self { + self.inner = self.inner.with_theme(if let Some(t) = theme { + match t { + Theme::Dark => Some(TaoTheme::Dark), + _ => Some(TaoTheme::Light), + } + } else { + None + }); + + self + } + + fn has_icon(&self) -> bool { + self.inner.window.window_icon.is_some() + } + + fn get_theme(&self) -> Option { + self.inner.window.preferred_theme.map(|theme| match theme { + TaoTheme::Dark => Theme::Dark, + _ => Theme::Light, + }) + } + + #[cfg(windows)] + fn window_classname>(mut self, window_classname: S) -> Self { + self.inner = self.inner.with_window_classname(window_classname); + self + } + #[cfg(not(windows))] + fn window_classname>(self, _window_classname: S) -> Self { + self + } +} + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +pub struct GtkWindow(pub gtk::ApplicationWindow); +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for GtkWindow {} + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +pub struct GtkBox(pub gtk::Box); +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Send for GtkBox {} + +pub struct SendRawWindowHandle(pub raw_window_handle::RawWindowHandle); +unsafe impl Send for SendRawWindowHandle {} + +#[cfg(target_os = "macos")] +#[derive(Debug, Clone)] +pub enum ApplicationMessage { + Show, + Hide, +} + +pub enum WindowMessage { + AddEventListener(WindowEventId, Box), + // Getters + ScaleFactor(Sender), + InnerPosition(Sender>>), + OuterPosition(Sender>>), + InnerSize(Sender>), + OuterSize(Sender>), + IsFullscreen(Sender), + IsMinimized(Sender), + IsMaximized(Sender), + IsFocused(Sender), + IsDecorated(Sender), + IsResizable(Sender), + IsMaximizable(Sender), + IsMinimizable(Sender), + IsClosable(Sender), + IsVisible(Sender), + Title(Sender), + CurrentMonitor(Sender>), + PrimaryMonitor(Sender>), + MonitorFromPoint(Sender>, (f64, f64)), + AvailableMonitors(Sender>), + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + GtkWindow(Sender), + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + GtkBox(Sender), + RawWindowHandle(Sender>), + Theme(Sender), + IsEnabled(Sender), + // Setters + Center, + RequestUserAttention(Option), + SetEnabled(bool), + SetResizable(bool), + SetMaximizable(bool), + SetMinimizable(bool), + SetClosable(bool), + SetTitle(String), + Maximize, + Unmaximize, + Minimize, + Unminimize, + Show, + Hide, + Close, + Destroy, + SetDecorations(bool), + SetShadow(bool), + SetAlwaysOnBottom(bool), + SetAlwaysOnTop(bool), + SetVisibleOnAllWorkspaces(bool), + SetContentProtected(bool), + SetSize(Size), + SetMinSize(Option), + SetMaxSize(Option), + SetSizeConstraints(WindowSizeConstraints), + SetPosition(Position), + SetFullscreen(bool), + SetFocus, + SetIcon(TaoWindowIcon), + SetSkipTaskbar(bool), + SetCursorGrab(bool), + SetCursorVisible(bool), + SetCursorIcon(CursorIcon), + SetCursorPosition(Position), + SetIgnoreCursorEvents(bool), + SetBadgeCount(Option, Option), + SetBadgeLabel(Option), + SetOverlayIcon(Option), + SetProgressBar(ProgressBarState), + SetTitleBarStyle(tauri_utils::TitleBarStyle), + SetTheme(Option), + SetBackgroundColor(Option), + DragWindow, + ResizeDragWindow(tauri_runtime::ResizeDirection), + RequestRedraw, +} + +#[derive(Debug, Clone)] +pub enum SynthesizedWindowEvent { + Focused(bool), + DragDrop(DragDropEvent), +} + +impl From for WindowEventWrapper { + fn from(event: SynthesizedWindowEvent) -> Self { + let event = match event { + SynthesizedWindowEvent::Focused(focused) => WindowEvent::Focused(focused), + SynthesizedWindowEvent::DragDrop(event) => WindowEvent::DragDrop(event), + }; + Self(Some(event)) + } +} + +pub enum WebviewMessage { + AddEventListener(WebviewEventId, Box), + #[cfg(not(all(feature = "tracing", not(target_os = "android"))))] + EvaluateScript(String), + #[cfg(all(feature = "tracing", not(target_os = "android")))] + EvaluateScript(String, Sender<()>, tracing::Span), + WebviewEvent(WebviewEvent), + SynthesizedWindowEvent(SynthesizedWindowEvent), + Navigate(Url), + Print, + Close, + Show, + Hide, + SetPosition(Position), + SetSize(Size), + SetBounds(tauri_runtime::Rect), + SetFocus, + Reparent(WindowId, Sender>), + SetAutoResize(bool), + SetZoom(f64), + SetBackgroundColor(Option), + ClearAllBrowsingData, + // Getters + Url(Sender>), + Bounds(Sender>), + Position(Sender>>), + Size(Sender>>), + WithWebview(Box), + // Devtools + #[cfg(any(debug_assertions, feature = "devtools"))] + OpenDevTools, + #[cfg(any(debug_assertions, feature = "devtools"))] + CloseDevTools, + #[cfg(any(debug_assertions, feature = "devtools"))] + IsDevToolsOpen(Sender), +} + +pub enum EventLoopWindowTargetMessage { + CursorPosition(Sender>>), +} + +pub type CreateWindowClosure = + Box>) -> Result + Send>; + +pub type CreateWebviewClosure = Box Result + Send>; + +pub enum Message { + Task(Box), + #[cfg(target_os = "macos")] + SetActivationPolicy(ActivationPolicy), + RequestExit(i32), + #[cfg(target_os = "macos")] + Application(ApplicationMessage), + Window(WindowId, WindowMessage), + Webview(WindowId, WebviewId, WebviewMessage), + EventLoopWindowTarget(EventLoopWindowTargetMessage), + CreateWebview(WindowId, CreateWebviewClosure), + CreateWindow(WindowId, CreateWindowClosure), + CreateRawWindow( + WindowId, + Box (String, TaoWindowBuilder) + Send>, + Sender>>, + ), + UserEvent(T), +} + +impl Clone for Message { + fn clone(&self) -> Self { + match self { + Self::UserEvent(t) => Self::UserEvent(t.clone()), + _ => unimplemented!(), + } + } +} + +/// The Tauri [`WebviewDispatch`] for [`Wry`]. +#[derive(Debug, Clone)] +pub struct WryWebviewDispatcher { + window_id: Arc>, + webview_id: WebviewId, + context: Context, +} + +impl WebviewDispatch for WryWebviewDispatcher { + type Runtime = Wry; + + fn run_on_main_thread(&self, f: F) -> Result<()> { + send_user_message(&self.context, Message::Task(Box::new(f))) + } + + fn on_webview_event(&self, f: F) -> WindowEventId { + let id = self.context.next_webview_event_id(); + let _ = self.context.proxy.send_event(Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::AddEventListener(id, Box::new(f)), + )); + id + } + + fn with_webview) + Send + 'static>(&self, f: F) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::WithWebview(Box::new(move |webview| f(Box::new(webview)))), + ), + ) + } + + #[cfg(any(debug_assertions, feature = "devtools"))] + fn open_devtools(&self) { + let _ = send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::OpenDevTools, + ), + ); + } + + #[cfg(any(debug_assertions, feature = "devtools"))] + fn close_devtools(&self) { + let _ = send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::CloseDevTools, + ), + ); + } + + /// Gets the devtools window's current open state. + #[cfg(any(debug_assertions, feature = "devtools"))] + fn is_devtools_open(&self) -> Result { + webview_getter!(self, WebviewMessage::IsDevToolsOpen) + } + + // Getters + + fn url(&self) -> Result { + webview_getter!(self, WebviewMessage::Url)? + } + + fn bounds(&self) -> Result { + webview_getter!(self, WebviewMessage::Bounds)? + } + + fn position(&self) -> Result> { + webview_getter!(self, WebviewMessage::Position)? + } + + fn size(&self) -> Result> { + webview_getter!(self, WebviewMessage::Size)? + } + + // Setters + + fn navigate(&self, url: Url) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::Navigate(url), + ), + ) + } + + fn print(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::Print, + ), + ) + } + + fn close(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::Close, + ), + ) + } + + fn set_bounds(&self, bounds: tauri_runtime::Rect) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetBounds(bounds), + ), + ) + } + + fn set_size(&self, size: Size) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetSize(size), + ), + ) + } + + fn set_position(&self, position: Position) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetPosition(position), + ), + ) + } + + fn set_focus(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetFocus, + ), + ) + } + + fn reparent(&self, window_id: WindowId) -> Result<()> { + let mut current_window_id = self.window_id.lock().unwrap(); + let (tx, rx) = channel(); + send_user_message( + &self.context, + Message::Webview( + *current_window_id, + self.webview_id, + WebviewMessage::Reparent(window_id, tx), + ), + )?; + + rx.recv().unwrap()?; + + *current_window_id = window_id; + Ok(()) + } + + fn set_auto_resize(&self, auto_resize: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetAutoResize(auto_resize), + ), + ) + } + + #[cfg(all(feature = "tracing", not(target_os = "android")))] + fn eval_script>(&self, script: S) -> Result<()> { + // use a channel so the EvaluateScript task uses the current span as parent + let (tx, rx) = channel(); + getter!( + self, + rx, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::EvaluateScript(script.into(), tx, tracing::Span::current()), + ) + ) + } + + #[cfg(not(all(feature = "tracing", not(target_os = "android"))))] + fn eval_script>(&self, script: S) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::EvaluateScript(script.into()), + ), + ) + } + + fn set_zoom(&self, scale_factor: f64) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetZoom(scale_factor), + ), + ) + } + + fn clear_all_browsing_data(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::ClearAllBrowsingData, + ), + ) + } + + fn hide(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::Hide, + ), + ) + } + + fn show(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::Show, + ), + ) + } + + fn set_background_color(&self, color: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Webview( + *self.window_id.lock().unwrap(), + self.webview_id, + WebviewMessage::SetBackgroundColor(color), + ), + ) + } +} + +/// The Tauri [`WindowDispatch`] for [`Wry`]. +#[derive(Debug, Clone)] +pub struct WryWindowDispatcher { + window_id: WindowId, + context: Context, +} + +// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for WryWindowDispatcher {} + +fn get_raw_window_handle( + dispatcher: &WryWindowDispatcher, +) -> Result> { + window_getter!(dispatcher, WindowMessage::RawWindowHandle) +} + +impl WindowDispatch for WryWindowDispatcher { + type Runtime = Wry; + type WindowBuilder = WindowBuilderWrapper; + + fn run_on_main_thread(&self, f: F) -> Result<()> { + send_user_message(&self.context, Message::Task(Box::new(f))) + } + + fn on_window_event(&self, f: F) -> WindowEventId { + let id = self.context.next_window_event_id(); + let _ = self.context.proxy.send_event(Message::Window( + self.window_id, + WindowMessage::AddEventListener(id, Box::new(f)), + )); + id + } + + // Getters + + fn scale_factor(&self) -> Result { + window_getter!(self, WindowMessage::ScaleFactor) + } + + fn inner_position(&self) -> Result> { + window_getter!(self, WindowMessage::InnerPosition)? + } + + fn outer_position(&self) -> Result> { + window_getter!(self, WindowMessage::OuterPosition)? + } + + fn inner_size(&self) -> Result> { + window_getter!(self, WindowMessage::InnerSize) + } + + fn outer_size(&self) -> Result> { + window_getter!(self, WindowMessage::OuterSize) + } + + fn is_fullscreen(&self) -> Result { + window_getter!(self, WindowMessage::IsFullscreen) + } + + fn is_minimized(&self) -> Result { + window_getter!(self, WindowMessage::IsMinimized) + } + + fn is_maximized(&self) -> Result { + window_getter!(self, WindowMessage::IsMaximized) + } + + fn is_focused(&self) -> Result { + window_getter!(self, WindowMessage::IsFocused) + } + + /// Gets the window's current decoration state. + fn is_decorated(&self) -> Result { + window_getter!(self, WindowMessage::IsDecorated) + } + + /// Gets the window's current resizable state. + fn is_resizable(&self) -> Result { + window_getter!(self, WindowMessage::IsResizable) + } + + /// Gets the current native window's maximize button state + fn is_maximizable(&self) -> Result { + window_getter!(self, WindowMessage::IsMaximizable) + } + + /// Gets the current native window's minimize button state + fn is_minimizable(&self) -> Result { + window_getter!(self, WindowMessage::IsMinimizable) + } + + /// Gets the current native window's close button state + fn is_closable(&self) -> Result { + window_getter!(self, WindowMessage::IsClosable) + } + + fn is_visible(&self) -> Result { + window_getter!(self, WindowMessage::IsVisible) + } + + fn title(&self) -> Result { + window_getter!(self, WindowMessage::Title) + } + + fn current_monitor(&self) -> Result> { + Ok(window_getter!(self, WindowMessage::CurrentMonitor)?.map(|m| MonitorHandleWrapper(m).into())) + } + + fn primary_monitor(&self) -> Result> { + Ok(window_getter!(self, WindowMessage::PrimaryMonitor)?.map(|m| MonitorHandleWrapper(m).into())) + } + + fn monitor_from_point(&self, x: f64, y: f64) -> Result> { + let (tx, rx) = channel(); + + let _ = send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::MonitorFromPoint(tx, (x, y))), + ); + + Ok( + rx.recv() + .map_err(|_| crate::Error::FailedToReceiveMessage)? + .map(|m| MonitorHandleWrapper(m).into()), + ) + } + + fn available_monitors(&self) -> Result> { + Ok( + window_getter!(self, WindowMessage::AvailableMonitors)? + .into_iter() + .map(|m| MonitorHandleWrapper(m).into()) + .collect(), + ) + } + + fn theme(&self) -> Result { + window_getter!(self, WindowMessage::Theme) + } + + fn is_enabled(&self) -> Result { + window_getter!(self, WindowMessage::IsEnabled) + } + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn gtk_window(&self) -> Result { + window_getter!(self, WindowMessage::GtkWindow).map(|w| w.0) + } + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn default_vbox(&self) -> Result { + window_getter!(self, WindowMessage::GtkBox).map(|w| w.0) + } + + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError> { + get_raw_window_handle(self) + .map_err(|_| raw_window_handle::HandleError::Unavailable) + .and_then(|r| r.map(|h| unsafe { raw_window_handle::WindowHandle::borrow_raw(h.0) })) + } + + // Setters + + fn center(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Center), + ) + } + + fn request_user_attention(&self, request_type: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::RequestUserAttention(request_type.map(Into::into)), + ), + ) + } + + // Creates a window by dispatching a message to the event loop. + // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. + fn create_window( + &mut self, + pending: PendingWindow, + after_window_creation: Option, + ) -> Result> { + self.context.create_window(pending, after_window_creation) + } + + // Creates a webview by dispatching a message to the event loop. + // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. + fn create_webview( + &mut self, + pending: PendingWebview, + ) -> Result> { + self.context.create_webview(self.window_id, pending) + } + + fn set_resizable(&self, resizable: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetResizable(resizable)), + ) + } + + fn set_enabled(&self, enabled: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetEnabled(enabled)), + ) + } + + fn set_maximizable(&self, maximizable: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetMaximizable(maximizable)), + ) + } + + fn set_minimizable(&self, minimizable: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetMinimizable(minimizable)), + ) + } + + fn set_closable(&self, closable: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetClosable(closable)), + ) + } + + fn set_title>(&self, title: S) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetTitle(title.into())), + ) + } + + fn maximize(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Maximize), + ) + } + + fn unmaximize(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Unmaximize), + ) + } + + fn minimize(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Minimize), + ) + } + + fn unminimize(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Unminimize), + ) + } + + fn show(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Show), + ) + } + + fn hide(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::Hide), + ) + } + + fn close(&self) -> Result<()> { + // NOTE: close cannot use the `send_user_message` function because it accesses the event loop callback + self + .context + .proxy + .send_event(Message::Window(self.window_id, WindowMessage::Close)) + .map_err(|_| Error::FailedToSendMessage) + } + + fn destroy(&self) -> Result<()> { + // NOTE: destroy cannot use the `send_user_message` function because it accesses the event loop callback + self + .context + .proxy + .send_event(Message::Window(self.window_id, WindowMessage::Destroy)) + .map_err(|_| Error::FailedToSendMessage) + } + + fn set_decorations(&self, decorations: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetDecorations(decorations)), + ) + } + + fn set_shadow(&self, enable: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetShadow(enable)), + ) + } + + fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetAlwaysOnBottom(always_on_bottom), + ), + ) + } + + fn set_always_on_top(&self, always_on_top: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetAlwaysOnTop(always_on_top)), + ) + } + + fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces), + ), + ) + } + + fn set_content_protected(&self, protected: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetContentProtected(protected), + ), + ) + } + + fn set_size(&self, size: Size) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetSize(size)), + ) + } + + fn set_min_size(&self, size: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetMinSize(size)), + ) + } + + fn set_max_size(&self, size: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetMaxSize(size)), + ) + } + + fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetSizeConstraints(constraints), + ), + ) + } + + fn set_position(&self, position: Position) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetPosition(position)), + ) + } + + fn set_fullscreen(&self, fullscreen: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetFullscreen(fullscreen)), + ) + } + + fn set_focus(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetFocus), + ) + } + + fn set_icon(&self, icon: Icon) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetIcon(TaoIcon::try_from(icon)?.0), + ), + ) + } + + fn set_skip_taskbar(&self, skip: bool) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetSkipTaskbar(skip)), + ) + } + + fn set_cursor_grab(&self, grab: bool) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetCursorGrab(grab)), + ) + } + + fn set_cursor_visible(&self, visible: bool) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetCursorVisible(visible)), + ) + } + + fn set_cursor_icon(&self, icon: CursorIcon) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetCursorIcon(icon)), + ) + } + + fn set_cursor_position>(&self, position: Pos) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetCursorPosition(position.into()), + ), + ) + } + + fn set_ignore_cursor_events(&self, ignore: bool) -> crate::Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetIgnoreCursorEvents(ignore)), + ) + } + + fn start_dragging(&self) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::DragWindow), + ) + } + + fn start_resize_dragging(&self, direction: tauri_runtime::ResizeDirection) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::ResizeDragWindow(direction)), + ) + } + + fn set_badge_count(&self, count: Option, desktop_filename: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetBadgeCount(count, desktop_filename), + ), + ) + } + + fn set_badge_label(&self, label: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetBadgeLabel(label)), + ) + } + + fn set_overlay_icon(&self, icon: Option) -> Result<()> { + let icon: Result> = icon.map_or(Ok(None), |x| Ok(Some(TaoIcon::try_from(x)?))); + + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetOverlayIcon(icon?)), + ) + } + + fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()> { + send_user_message( + &self.context, + Message::Window( + self.window_id, + WindowMessage::SetProgressBar(progress_state), + ), + ) + } + + fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetTitleBarStyle(style)), + ) + } + + fn set_theme(&self, theme: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetTheme(theme)), + ) + } + + fn set_background_color(&self, color: Option) -> Result<()> { + send_user_message( + &self.context, + Message::Window(self.window_id, WindowMessage::SetBackgroundColor(color)), + ) + } +} + +#[derive(Clone)] +pub struct WebviewWrapper { + label: String, + id: WebviewId, + inner: Rc, + context_store: WebContextStore, + webview_event_listeners: WebviewEventListeners, + // the key of the WebContext if it's not shared + context_key: Option, + bounds: Arc>>, +} + +impl Deref for WebviewWrapper { + type Target = WebView; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl Drop for WebviewWrapper { + fn drop(&mut self) { + if Rc::get_mut(&mut self.inner).is_some() { + let mut context_store = self.context_store.lock().unwrap(); + + if let Some(web_context) = context_store.get_mut(&self.context_key) { + web_context.referenced_by_webviews.remove(&self.label); + + if web_context.referenced_by_webviews.is_empty() { + context_store.remove(&self.context_key); + } + } + } + } +} + +pub struct WindowWrapper { + label: String, + inner: Option>, + // whether this window has child webviews + // or it's just a container for a single webview + has_children: AtomicBool, + webviews: Vec, + window_event_listeners: WindowEventListeners, + #[cfg(windows)] + background_color: Option, + #[cfg(windows)] + is_window_transparent: bool, + #[cfg(windows)] + surface: Option, Arc>>, +} + +impl fmt::Debug for WindowWrapper { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WindowWrapper") + .field("label", &self.label) + .field("inner", &self.inner) + .finish() + } +} + +#[derive(Debug, Clone)] +pub struct EventProxy(TaoEventLoopProxy>); + +#[cfg(target_os = "ios")] +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for EventProxy {} + +impl EventLoopProxy for EventProxy { + fn send_event(&self, event: T) -> Result<()> { + self + .0 + .send_event(Message::UserEvent(event)) + .map_err(|_| Error::EventLoopClosed) + } +} + +pub trait PluginBuilder { + type Plugin: Plugin; + fn build(self, context: Context) -> Self::Plugin; +} + +pub trait Plugin { + fn on_event( + &mut self, + event: &Event>, + event_loop: &EventLoopWindowTarget>, + proxy: &TaoEventLoopProxy>, + control_flow: &mut ControlFlow, + context: EventLoopIterationContext<'_, T>, + web_context: &WebContextStore, + ) -> bool; +} + +/// A Tauri [`Runtime`] wrapper around wry. +pub struct Wry { + context: Context, + event_loop: EventLoop>, +} + +impl fmt::Debug for Wry { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Wry") + .field("main_thread_id", &self.context.main_thread_id) + .field("event_loop", &self.event_loop) + .field("windows", &self.context.main_thread.windows) + .field("web_context", &self.context.main_thread.web_context) + .finish() + } +} + +/// A handle to the Wry runtime. +#[derive(Debug, Clone)] +pub struct WryHandle { + context: Context, +} + +// SAFETY: this is safe since the `Context` usage is guarded on `send_user_message`. +#[allow(clippy::non_send_fields_in_send_ty)] +unsafe impl Sync for WryHandle {} + +impl WryHandle { + /// Creates a new tao window using a callback, and returns its window id. + pub fn create_tao_window (String, TaoWindowBuilder) + Send + 'static>( + &self, + f: F, + ) -> Result> { + let id = self.context.next_window_id(); + let (tx, rx) = channel(); + send_user_message(&self.context, Message::CreateRawWindow(id, Box::new(f), tx))?; + rx.recv().unwrap() + } + + /// Gets the [`WebviewId'] associated with the given [`WindowId`]. + pub fn window_id(&self, window_id: TaoWindowId) -> WindowId { + *self + .context + .window_id_map + .0 + .lock() + .unwrap() + .get(&window_id) + .unwrap() + } + + /// Send a message to the event loop. + pub fn send_event(&self, message: Message) -> Result<()> { + self + .context + .proxy + .send_event(message) + .map_err(|_| Error::FailedToSendMessage)?; + Ok(()) + } + + pub fn plugin + 'static>(&mut self, plugin: P) + where +

>::Plugin: Send, + { + self + .context + .plugins + .lock() + .unwrap() + .push(Box::new(plugin.build(self.context.clone()))); + } +} + +impl RuntimeHandle for WryHandle { + type Runtime = Wry; + + fn create_proxy(&self) -> EventProxy { + EventProxy(self.context.proxy.clone()) + } + + #[cfg(target_os = "macos")] + fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()> { + send_user_message( + &self.context, + Message::SetActivationPolicy(activation_policy), + ) + } + + fn request_exit(&self, code: i32) -> Result<()> { + // NOTE: request_exit cannot use the `send_user_message` function because it accesses the event loop callback + self + .context + .proxy + .send_event(Message::RequestExit(code)) + .map_err(|_| Error::FailedToSendMessage) + } + + // Creates a window by dispatching a message to the event loop. + // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. + fn create_window( + &self, + pending: PendingWindow, + after_window_creation: Option, + ) -> Result> { + self.context.create_window(pending, after_window_creation) + } + + // Creates a webview by dispatching a message to the event loop. + // Note that this must be called from a separate thread, otherwise the channel will introduce a deadlock. + fn create_webview( + &self, + window_id: WindowId, + pending: PendingWebview, + ) -> Result> { + self.context.create_webview(window_id, pending) + } + + fn run_on_main_thread(&self, f: F) -> Result<()> { + send_user_message(&self.context, Message::Task(Box::new(f))) + } + + fn display_handle(&self) -> std::result::Result { + self.context.main_thread.window_target.display_handle() + } + + fn primary_monitor(&self) -> Option { + self + .context + .main_thread + .window_target + .primary_monitor() + .map(|m| MonitorHandleWrapper(m).into()) + } + + fn monitor_from_point(&self, x: f64, y: f64) -> Option { + self + .context + .main_thread + .window_target + .monitor_from_point(x, y) + .map(|m| MonitorHandleWrapper(m).into()) + } + + fn available_monitors(&self) -> Vec { + self + .context + .main_thread + .window_target + .available_monitors() + .map(|m| MonitorHandleWrapper(m).into()) + .collect() + } + + fn cursor_position(&self) -> Result> { + event_loop_window_getter!(self, EventLoopWindowTargetMessage::CursorPosition)? + .map(PhysicalPositionWrapper) + .map(Into::into) + .map_err(|_| Error::FailedToGetCursorPosition) + } + + fn set_theme(&self, theme: Option) { + self + .context + .main_thread + .window_target + .set_theme(match theme { + Some(Theme::Light) => Some(TaoTheme::Light), + Some(Theme::Dark) => Some(TaoTheme::Dark), + _ => None, + }); + } + + #[cfg(target_os = "macos")] + fn show(&self) -> tauri_runtime::Result<()> { + send_user_message( + &self.context, + Message::Application(ApplicationMessage::Show), + ) + } + + #[cfg(target_os = "macos")] + fn hide(&self) -> tauri_runtime::Result<()> { + send_user_message( + &self.context, + Message::Application(ApplicationMessage::Hide), + ) + } + + #[cfg(target_os = "android")] + fn find_class<'a>( + &self, + env: &mut jni::JNIEnv<'a>, + activity: &jni::objects::JObject<'_>, + name: impl Into, + ) -> std::result::Result, jni::errors::Error> { + find_class(env, activity, name.into()) + } + + #[cfg(target_os = "android")] + fn run_on_android_context(&self, f: F) + where + F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static, + { + dispatch(f) + } +} + +impl Wry { + fn init_with_builder( + mut event_loop_builder: EventLoopBuilder>, + #[allow(unused_variables)] args: RuntimeInitArgs, + ) -> Result { + #[cfg(windows)] + if let Some(hook) = args.msg_hook { + use tao::platform::windows::EventLoopBuilderExtWindows; + event_loop_builder.with_msg_hook(hook); + } + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + if let Some(app_id) = args.app_id { + use tao::platform::unix::EventLoopBuilderExtUnix; + event_loop_builder.with_app_id(app_id); + } + Self::init(event_loop_builder.build()) + } + + fn init(event_loop: EventLoop>) -> Result { + let main_thread_id = current_thread().id(); + let web_context = WebContextStore::default(); + + let windows = Arc::new(WindowsStore(RefCell::new(BTreeMap::default()))); + let window_id_map = WindowIdStore::default(); + + let context = Context { + window_id_map, + main_thread_id, + proxy: event_loop.create_proxy(), + main_thread: DispatcherMainThreadContext { + window_target: event_loop.deref().clone(), + web_context, + windows, + #[cfg(feature = "tracing")] + active_tracing_spans: Default::default(), + }, + plugins: Default::default(), + next_window_id: Default::default(), + next_webview_id: Default::default(), + next_window_event_id: Default::default(), + next_webview_event_id: Default::default(), + }; + + Ok(Self { + context, + event_loop, + }) + } +} + +impl Runtime for Wry { + type WindowDispatcher = WryWindowDispatcher; + type WebviewDispatcher = WryWebviewDispatcher; + type Handle = WryHandle; + + type EventLoopProxy = EventProxy; + + fn new(args: RuntimeInitArgs) -> Result { + Self::init_with_builder(EventLoopBuilder::>::with_user_event(), args) + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn new_any_thread(args: RuntimeInitArgs) -> Result { + use tao::platform::unix::EventLoopBuilderExtUnix; + let mut event_loop_builder = EventLoopBuilder::>::with_user_event(); + event_loop_builder.with_any_thread(true); + Self::init_with_builder(event_loop_builder, args) + } + + #[cfg(windows)] + fn new_any_thread(args: RuntimeInitArgs) -> Result { + use tao::platform::windows::EventLoopBuilderExtWindows; + let mut event_loop_builder = EventLoopBuilder::>::with_user_event(); + event_loop_builder.with_any_thread(true); + Self::init_with_builder(event_loop_builder, args) + } + + fn create_proxy(&self) -> EventProxy { + EventProxy(self.event_loop.create_proxy()) + } + + fn handle(&self) -> Self::Handle { + WryHandle { + context: self.context.clone(), + } + } + + fn create_window( + &self, + pending: PendingWindow, + after_window_creation: Option, + ) -> Result> { + let label = pending.label.clone(); + let window_id = self.context.next_window_id(); + let (webview_id, use_https_scheme) = pending + .webview + .as_ref() + .map(|w| { + ( + Some(self.context.next_webview_id()), + w.webview_attributes.use_https_scheme, + ) + }) + .unwrap_or((None, false)); + + let window = create_window( + window_id, + webview_id.unwrap_or_default(), + &self.event_loop, + &self.context, + pending, + after_window_creation, + )?; + + let dispatcher = WryWindowDispatcher { + window_id, + context: self.context.clone(), + }; + + self + .context + .main_thread + .windows + .0 + .borrow_mut() + .insert(window_id, window); + + let detached_webview = webview_id.map(|id| { + let webview = DetachedWebview { + label: label.clone(), + dispatcher: WryWebviewDispatcher { + window_id: Arc::new(Mutex::new(window_id)), + webview_id: id, + context: self.context.clone(), + }, + }; + DetachedWindowWebview { + webview, + use_https_scheme, + } + }); + + Ok(DetachedWindow { + id: window_id, + label, + dispatcher, + webview: detached_webview, + }) + } + + fn create_webview( + &self, + window_id: WindowId, + pending: PendingWebview, + ) -> Result> { + let label = pending.label.clone(); + + let window = self + .context + .main_thread + .windows + .0 + .borrow() + .get(&window_id) + .and_then(|w| w.inner.clone()); + if let Some(window) = window { + let window_id_wrapper = Arc::new(Mutex::new(window_id)); + + let webview_id = self.context.next_webview_id(); + + let webview = create_webview( + WebviewKind::WindowChild, + &window, + window_id_wrapper.clone(), + webview_id, + &self.context, + pending, + )?; + + #[allow(clippy::manual_inspect)] + self + .context + .main_thread + .windows + .0 + .borrow_mut() + .get_mut(&window_id) + .map(|w| { + w.webviews.push(webview); + w.has_children.store(true, Ordering::Relaxed); + w + }); + + let dispatcher = WryWebviewDispatcher { + window_id: window_id_wrapper, + webview_id, + context: self.context.clone(), + }; + + Ok(DetachedWebview { label, dispatcher }) + } else { + Err(Error::WindowNotFound) + } + } + + fn primary_monitor(&self) -> Option { + self + .context + .main_thread + .window_target + .primary_monitor() + .map(|m| MonitorHandleWrapper(m).into()) + } + + fn monitor_from_point(&self, x: f64, y: f64) -> Option { + self + .context + .main_thread + .window_target + .monitor_from_point(x, y) + .map(|m| MonitorHandleWrapper(m).into()) + } + + fn available_monitors(&self) -> Vec { + self + .context + .main_thread + .window_target + .available_monitors() + .map(|m| MonitorHandleWrapper(m).into()) + .collect() + } + + fn cursor_position(&self) -> Result> { + event_loop_window_getter!(self, EventLoopWindowTargetMessage::CursorPosition)? + .map(PhysicalPositionWrapper) + .map(Into::into) + .map_err(|_| Error::FailedToGetCursorPosition) + } + + fn set_theme(&self, theme: Option) { + self.event_loop.set_theme(match theme { + Some(Theme::Light) => Some(TaoTheme::Light), + Some(Theme::Dark) => Some(TaoTheme::Dark), + _ => None, + }); + } + + #[cfg(target_os = "macos")] + fn set_activation_policy(&mut self, activation_policy: ActivationPolicy) { + self + .event_loop + .set_activation_policy(tao_activation_policy(activation_policy)); + } + + #[cfg(target_os = "macos")] + fn show(&self) { + self.event_loop.show_application(); + } + + #[cfg(target_os = "macos")] + fn hide(&self) { + self.event_loop.hide_application(); + } + + fn set_device_event_filter(&mut self, filter: DeviceEventFilter) { + self + .event_loop + .set_device_event_filter(DeviceEventFilterWrapper::from(filter).0); + } + + #[cfg(desktop)] + fn run_iteration) + 'static>(&mut self, mut callback: F) { + use tao::platform::run_return::EventLoopExtRunReturn; + let windows = self.context.main_thread.windows.clone(); + let window_id_map = self.context.window_id_map.clone(); + let web_context = &self.context.main_thread.web_context; + let plugins = self.context.plugins.clone(); + + #[cfg(feature = "tracing")] + let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone(); + + let proxy = self.event_loop.create_proxy(); + + self + .event_loop + .run_return(|event, event_loop, control_flow| { + *control_flow = ControlFlow::Wait; + if let Event::MainEventsCleared = &event { + *control_flow = ControlFlow::Exit; + } + + for p in plugins.lock().unwrap().iter_mut() { + let prevent_default = p.on_event( + &event, + event_loop, + &proxy, + control_flow, + EventLoopIterationContext { + callback: &mut callback, + window_id_map: window_id_map.clone(), + windows: windows.clone(), + #[cfg(feature = "tracing")] + active_tracing_spans: active_tracing_spans.clone(), + }, + web_context, + ); + if prevent_default { + return; + } + } + + handle_event_loop( + event, + event_loop, + control_flow, + EventLoopIterationContext { + callback: &mut callback, + windows: windows.clone(), + window_id_map: window_id_map.clone(), + #[cfg(feature = "tracing")] + active_tracing_spans: active_tracing_spans.clone(), + }, + ); + }); + } + + fn run) + 'static>(self, mut callback: F) { + let windows = self.context.main_thread.windows.clone(); + let window_id_map = self.context.window_id_map.clone(); + let web_context = self.context.main_thread.web_context; + let plugins = self.context.plugins.clone(); + + #[cfg(feature = "tracing")] + let active_tracing_spans = self.context.main_thread.active_tracing_spans.clone(); + let proxy = self.event_loop.create_proxy(); + + self.event_loop.run(move |event, event_loop, control_flow| { + for p in plugins.lock().unwrap().iter_mut() { + let prevent_default = p.on_event( + &event, + event_loop, + &proxy, + control_flow, + EventLoopIterationContext { + callback: &mut callback, + window_id_map: window_id_map.clone(), + windows: windows.clone(), + #[cfg(feature = "tracing")] + active_tracing_spans: active_tracing_spans.clone(), + }, + &web_context, + ); + if prevent_default { + return; + } + } + handle_event_loop( + event, + event_loop, + control_flow, + EventLoopIterationContext { + callback: &mut callback, + window_id_map: window_id_map.clone(), + windows: windows.clone(), + #[cfg(feature = "tracing")] + active_tracing_spans: active_tracing_spans.clone(), + }, + ); + }) + } +} + +pub struct EventLoopIterationContext<'a, T: UserEvent> { + pub callback: &'a mut (dyn FnMut(RunEvent) + 'static), + pub window_id_map: WindowIdStore, + pub windows: Arc, + #[cfg(feature = "tracing")] + pub active_tracing_spans: ActiveTraceSpanStore, +} + +struct UserMessageContext { + windows: Arc, + window_id_map: WindowIdStore, +} + +fn handle_user_message( + event_loop: &EventLoopWindowTarget>, + message: Message, + context: UserMessageContext, +) { + let UserMessageContext { + window_id_map, + windows, + } = context; + match message { + Message::Task(task) => task(), + #[cfg(target_os = "macos")] + Message::SetActivationPolicy(activation_policy) => { + event_loop.set_activation_policy_at_runtime(tao_activation_policy(activation_policy)) + } + Message::RequestExit(_code) => panic!("cannot handle RequestExit on the main thread"), + #[cfg(target_os = "macos")] + Message::Application(application_message) => match application_message { + ApplicationMessage::Show => { + event_loop.show_application(); + } + ApplicationMessage::Hide => { + event_loop.hide_application(); + } + }, + Message::Window(id, window_message) => { + let w = windows.0.borrow().get(&id).map(|w| { + ( + w.inner.clone(), + w.webviews.clone(), + w.has_children.load(Ordering::Relaxed), + w.window_event_listeners.clone(), + ) + }); + if let Some((Some(window), webviews, has_children, window_event_listeners)) = w { + match window_message { + WindowMessage::AddEventListener(id, listener) => { + window_event_listeners.lock().unwrap().insert(id, listener); + } + + // Getters + WindowMessage::ScaleFactor(tx) => tx.send(window.scale_factor()).unwrap(), + WindowMessage::InnerPosition(tx) => tx + .send( + window + .inner_position() + .map(|p| PhysicalPositionWrapper(p).into()) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(), + WindowMessage::OuterPosition(tx) => tx + .send( + window + .outer_position() + .map(|p| PhysicalPositionWrapper(p).into()) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(), + WindowMessage::InnerSize(tx) => tx + .send(PhysicalSizeWrapper(inner_size(&window, &webviews, has_children)).into()) + .unwrap(), + WindowMessage::OuterSize(tx) => tx + .send(PhysicalSizeWrapper(window.outer_size()).into()) + .unwrap(), + WindowMessage::IsFullscreen(tx) => tx.send(window.fullscreen().is_some()).unwrap(), + WindowMessage::IsMinimized(tx) => tx.send(window.is_minimized()).unwrap(), + WindowMessage::IsMaximized(tx) => tx.send(window.is_maximized()).unwrap(), + WindowMessage::IsFocused(tx) => tx.send(window.is_focused()).unwrap(), + WindowMessage::IsDecorated(tx) => tx.send(window.is_decorated()).unwrap(), + WindowMessage::IsResizable(tx) => tx.send(window.is_resizable()).unwrap(), + WindowMessage::IsMaximizable(tx) => tx.send(window.is_maximizable()).unwrap(), + WindowMessage::IsMinimizable(tx) => tx.send(window.is_minimizable()).unwrap(), + WindowMessage::IsClosable(tx) => tx.send(window.is_closable()).unwrap(), + WindowMessage::IsVisible(tx) => tx.send(window.is_visible()).unwrap(), + WindowMessage::Title(tx) => tx.send(window.title()).unwrap(), + WindowMessage::CurrentMonitor(tx) => tx.send(window.current_monitor()).unwrap(), + WindowMessage::PrimaryMonitor(tx) => tx.send(window.primary_monitor()).unwrap(), + WindowMessage::MonitorFromPoint(tx, (x, y)) => { + tx.send(window.monitor_from_point(x, y)).unwrap() + } + WindowMessage::AvailableMonitors(tx) => { + tx.send(window.available_monitors().collect()).unwrap() + } + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + WindowMessage::GtkWindow(tx) => tx.send(GtkWindow(window.gtk_window().clone())).unwrap(), + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + WindowMessage::GtkBox(tx) => tx + .send(GtkBox(window.default_vbox().unwrap().clone())) + .unwrap(), + WindowMessage::RawWindowHandle(tx) => tx + .send( + window + .window_handle() + .map(|h| SendRawWindowHandle(h.as_raw())), + ) + .unwrap(), + WindowMessage::Theme(tx) => { + tx.send(map_theme(&window.theme())).unwrap(); + } + WindowMessage::IsEnabled(tx) => tx.send(window.is_enabled()).unwrap(), + + // Setters + WindowMessage::Center => window.center(), + WindowMessage::RequestUserAttention(request_type) => { + window.request_user_attention(request_type.map(|r| r.0)); + } + WindowMessage::SetResizable(resizable) => { + window.set_resizable(resizable); + #[cfg(windows)] + if !resizable { + undecorated_resizing::detach_resize_handler(window.hwnd()); + } else if !window.is_decorated() { + undecorated_resizing::attach_resize_handler(window.hwnd()); + } + } + WindowMessage::SetMaximizable(maximizable) => window.set_maximizable(maximizable), + WindowMessage::SetMinimizable(minimizable) => window.set_minimizable(minimizable), + WindowMessage::SetClosable(closable) => window.set_closable(closable), + WindowMessage::SetTitle(title) => window.set_title(&title), + WindowMessage::Maximize => window.set_maximized(true), + WindowMessage::Unmaximize => window.set_maximized(false), + WindowMessage::Minimize => window.set_minimized(true), + WindowMessage::Unminimize => window.set_minimized(false), + WindowMessage::SetEnabled(enabled) => window.set_enabled(enabled), + WindowMessage::Show => window.set_visible(true), + WindowMessage::Hide => window.set_visible(false), + WindowMessage::Close => { + panic!("cannot handle `WindowMessage::Close` on the main thread") + } + WindowMessage::Destroy => { + panic!("cannot handle `WindowMessage::Destroy` on the main thread") + } + WindowMessage::SetDecorations(decorations) => { + window.set_decorations(decorations); + #[cfg(windows)] + if decorations { + undecorated_resizing::detach_resize_handler(window.hwnd()); + } else if window.is_resizable() { + undecorated_resizing::attach_resize_handler(window.hwnd()); + } + } + WindowMessage::SetShadow(_enable) => { + #[cfg(windows)] + window.set_undecorated_shadow(_enable); + #[cfg(target_os = "macos")] + window.set_has_shadow(_enable); + } + WindowMessage::SetAlwaysOnBottom(always_on_bottom) => { + window.set_always_on_bottom(always_on_bottom) + } + WindowMessage::SetAlwaysOnTop(always_on_top) => window.set_always_on_top(always_on_top), + WindowMessage::SetVisibleOnAllWorkspaces(visible_on_all_workspaces) => { + window.set_visible_on_all_workspaces(visible_on_all_workspaces) + } + WindowMessage::SetContentProtected(protected) => window.set_content_protection(protected), + WindowMessage::SetSize(size) => { + window.set_inner_size(SizeWrapper::from(size).0); + } + WindowMessage::SetMinSize(size) => { + window.set_min_inner_size(size.map(|s| SizeWrapper::from(s).0)); + } + WindowMessage::SetMaxSize(size) => { + window.set_max_inner_size(size.map(|s| SizeWrapper::from(s).0)); + } + WindowMessage::SetSizeConstraints(constraints) => { + window.set_inner_size_constraints(tao::window::WindowSizeConstraints { + min_width: constraints.min_width, + min_height: constraints.min_height, + max_width: constraints.max_width, + max_height: constraints.max_height, + }); + } + WindowMessage::SetPosition(position) => { + window.set_outer_position(PositionWrapper::from(position).0) + } + WindowMessage::SetFullscreen(fullscreen) => { + if fullscreen { + window.set_fullscreen(Some(Fullscreen::Borderless(None))) + } else { + window.set_fullscreen(None) + } + } + WindowMessage::SetFocus => { + window.set_focus(); + } + WindowMessage::SetIcon(icon) => { + window.set_window_icon(Some(icon)); + } + #[allow(unused_variables)] + WindowMessage::SetSkipTaskbar(skip) => { + #[cfg(any(windows, target_os = "linux"))] + let _ = window.set_skip_taskbar(skip); + } + WindowMessage::SetCursorGrab(grab) => { + let _ = window.set_cursor_grab(grab); + } + WindowMessage::SetCursorVisible(visible) => { + window.set_cursor_visible(visible); + } + WindowMessage::SetCursorIcon(icon) => { + window.set_cursor_icon(CursorIconWrapper::from(icon).0); + } + WindowMessage::SetCursorPosition(position) => { + let _ = window.set_cursor_position(PositionWrapper::from(position).0); + } + WindowMessage::SetIgnoreCursorEvents(ignore) => { + let _ = window.set_ignore_cursor_events(ignore); + } + WindowMessage::DragWindow => { + let _ = window.drag_window(); + } + WindowMessage::ResizeDragWindow(direction) => { + let _ = window.drag_resize_window(match direction { + tauri_runtime::ResizeDirection::East => tao::window::ResizeDirection::East, + tauri_runtime::ResizeDirection::North => tao::window::ResizeDirection::North, + tauri_runtime::ResizeDirection::NorthEast => tao::window::ResizeDirection::NorthEast, + tauri_runtime::ResizeDirection::NorthWest => tao::window::ResizeDirection::NorthWest, + tauri_runtime::ResizeDirection::South => tao::window::ResizeDirection::South, + tauri_runtime::ResizeDirection::SouthEast => tao::window::ResizeDirection::SouthEast, + tauri_runtime::ResizeDirection::SouthWest => tao::window::ResizeDirection::SouthWest, + tauri_runtime::ResizeDirection::West => tao::window::ResizeDirection::West, + }); + } + WindowMessage::RequestRedraw => { + window.request_redraw(); + } + WindowMessage::SetBadgeCount(_count, _desktop_filename) => { + #[cfg(target_os = "ios")] + window.set_badge_count( + _count.map_or(0, |x| x.clamp(i32::MIN as i64, i32::MAX as i64) as i32), + ); + + #[cfg(target_os = "macos")] + window.set_badge_label(_count.map(|x| x.to_string())); + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + window.set_badge_count(_count, _desktop_filename); + } + WindowMessage::SetBadgeLabel(_label) => { + #[cfg(target_os = "macos")] + window.set_badge_label(_label); + } + WindowMessage::SetOverlayIcon(_icon) => { + #[cfg(windows)] + window.set_overlay_icon(_icon.map(|x| x.0).as_ref()); + } + WindowMessage::SetProgressBar(progress_state) => { + window.set_progress_bar(ProgressBarStateWrapper::from(progress_state).0); + } + WindowMessage::SetTitleBarStyle(_style) => { + #[cfg(target_os = "macos")] + match _style { + TitleBarStyle::Visible => { + window.set_titlebar_transparent(false); + window.set_fullsize_content_view(true); + } + TitleBarStyle::Transparent => { + window.set_titlebar_transparent(true); + window.set_fullsize_content_view(false); + } + TitleBarStyle::Overlay => { + window.set_titlebar_transparent(true); + window.set_fullsize_content_view(true); + } + unknown => { + #[cfg(feature = "tracing")] + tracing::warn!("unknown title bar style applied: {unknown}"); + + #[cfg(not(feature = "tracing"))] + eprintln!("unknown title bar style applied: {unknown}"); + } + }; + } + WindowMessage::SetTheme(theme) => { + window.set_theme(match theme { + Some(Theme::Light) => Some(TaoTheme::Light), + Some(Theme::Dark) => Some(TaoTheme::Dark), + _ => None, + }); + } + WindowMessage::SetBackgroundColor(color) => { + window.set_background_color(color.map(Into::into)) + } + } + } + } + Message::Webview(window_id, webview_id, webview_message) => { + #[cfg(any( + target_os = "macos", + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + if let WebviewMessage::Reparent(new_parent_window_id, tx) = webview_message { + let webview_handle = windows.0.borrow_mut().get_mut(&window_id).and_then(|w| { + w.webviews + .iter() + .position(|w| w.id == webview_id) + .map(|webview_index| w.webviews.remove(webview_index)) + }); + + if let Some(webview) = webview_handle { + if let Some((Some(new_parent_window), new_parent_window_webviews)) = windows + .0 + .borrow_mut() + .get_mut(&new_parent_window_id) + .map(|w| (w.inner.clone(), &mut w.webviews)) + { + #[cfg(target_os = "macos")] + let reparent_result = { + use wry::WebViewExtMacOS; + webview.inner.reparent(new_parent_window.ns_window() as _) + }; + #[cfg(windows)] + let reparent_result = { webview.inner.reparent(new_parent_window.hwnd()) }; + + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + let reparent_result = { + if let Some(container) = new_parent_window.default_vbox() { + webview.inner.reparent(container) + } else { + Err(wry::Error::MessageSender) + } + }; + + match reparent_result { + Ok(_) => { + new_parent_window_webviews.push(webview); + tx.send(Ok(())).unwrap(); + } + Err(e) => { + log::error!("failed to reparent webview: {e}"); + tx.send(Err(Error::FailedToSendMessage)).unwrap(); + } + } + } + } else { + tx.send(Err(Error::FailedToSendMessage)).unwrap(); + } + + return; + } + + let webview_handle = windows.0.borrow().get(&window_id).map(|w| { + ( + w.inner.clone(), + w.webviews.iter().find(|w| w.id == webview_id).cloned(), + ) + }); + if let Some((Some(window), Some(webview))) = webview_handle { + match webview_message { + WebviewMessage::WebviewEvent(_) => { /* already handled */ } + WebviewMessage::SynthesizedWindowEvent(_) => { /* already handled */ } + WebviewMessage::Reparent(_window_id, _tx) => { /* already handled */ } + WebviewMessage::AddEventListener(id, listener) => { + webview + .webview_event_listeners + .lock() + .unwrap() + .insert(id, listener); + } + + #[cfg(all(feature = "tracing", not(target_os = "android")))] + WebviewMessage::EvaluateScript(script, tx, span) => { + let _span = span.entered(); + if let Err(e) = webview.evaluate_script(&script) { + log::error!("{}", e); + } + tx.send(()).unwrap(); + } + #[cfg(not(all(feature = "tracing", not(target_os = "android"))))] + WebviewMessage::EvaluateScript(script) => { + if let Err(e) = webview.evaluate_script(&script) { + log::error!("{}", e); + } + } + WebviewMessage::Navigate(url) => { + if let Err(e) = webview.load_url(url.as_str()) { + log::error!("failed to navigate to url {}: {}", url, e); + } + } + WebviewMessage::Show => { + if let Err(e) = webview.set_visible(true) { + log::error!("failed to change webview visibility: {e}"); + } + } + WebviewMessage::Hide => { + if let Err(e) = webview.set_visible(false) { + log::error!("failed to change webview visibility: {e}"); + } + } + WebviewMessage::Print => { + let _ = webview.print(); + } + WebviewMessage::Close => { + #[allow(clippy::manual_inspect)] + windows.0.borrow_mut().get_mut(&window_id).map(|window| { + if let Some(i) = window.webviews.iter().position(|w| w.id == webview.id) { + window.webviews.remove(i); + } + window + }); + } + WebviewMessage::SetBounds(bounds) => { + let bounds: RectWrapper = bounds.into(); + let bounds = bounds.0; + + if let Some(b) = &mut *webview.bounds.lock().unwrap() { + let scale_factor = window.scale_factor(); + let size = bounds.size.to_logical::(scale_factor); + let position = bounds.position.to_logical::(scale_factor); + let window_size = window.inner_size().to_logical::(scale_factor); + b.width_rate = size.width / window_size.width; + b.height_rate = size.height / window_size.height; + b.x_rate = position.x / window_size.width; + b.y_rate = position.y / window_size.height; + } + + if let Err(e) = webview.set_bounds(bounds) { + log::error!("failed to set webview size: {e}"); + } + } + WebviewMessage::SetSize(size) => match webview.bounds() { + Ok(mut bounds) => { + bounds.size = size; + + let scale_factor = window.scale_factor(); + let size = size.to_logical::(scale_factor); + + if let Some(b) = &mut *webview.bounds.lock().unwrap() { + let window_size = window.inner_size().to_logical::(scale_factor); + b.width_rate = size.width / window_size.width; + b.height_rate = size.height / window_size.height; + } + + if let Err(e) = webview.set_bounds(bounds) { + log::error!("failed to set webview size: {e}"); + } + } + Err(e) => { + log::error!("failed to get webview bounds: {e}"); + } + }, + WebviewMessage::SetPosition(position) => match webview.bounds() { + Ok(mut bounds) => { + bounds.position = position; + + let scale_factor = window.scale_factor(); + let position = position.to_logical::(scale_factor); + + if let Some(b) = &mut *webview.bounds.lock().unwrap() { + let window_size = window.inner_size().to_logical::(scale_factor); + b.x_rate = position.x / window_size.width; + b.y_rate = position.y / window_size.height; + } + + if let Err(e) = webview.set_bounds(bounds) { + log::error!("failed to set webview position: {e}"); + } + } + Err(e) => { + log::error!("failed to get webview bounds: {e}"); + } + }, + WebviewMessage::SetZoom(scale_factor) => { + if let Err(e) = webview.zoom(scale_factor) { + log::error!("failed to set webview zoom: {e}"); + } + } + WebviewMessage::SetBackgroundColor(color) => { + if let Err(e) = + webview.set_background_color(color.map(Into::into).unwrap_or((255, 255, 255, 255))) + { + log::error!("failed to set webview background color: {e}"); + } + } + WebviewMessage::ClearAllBrowsingData => { + if let Err(e) = webview.clear_all_browsing_data() { + log::error!("failed to clear webview browsing data: {e}"); + } + } + // Getters + WebviewMessage::Url(tx) => { + tx.send( + webview + .url() + .map(|u| u.parse().expect("invalid webview URL")) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(); + } + WebviewMessage::Bounds(tx) => { + tx.send( + webview + .bounds() + .map(|bounds| tauri_runtime::Rect { + size: bounds.size, + position: bounds.position, + }) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(); + } + WebviewMessage::Position(tx) => { + tx.send( + webview + .bounds() + .map(|bounds| bounds.position.to_physical(window.scale_factor())) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(); + } + WebviewMessage::Size(tx) => { + tx.send( + webview + .bounds() + .map(|bounds| bounds.size.to_physical(window.scale_factor())) + .map_err(|_| Error::FailedToSendMessage), + ) + .unwrap(); + } + WebviewMessage::SetFocus => { + if let Err(e) = webview.focus() { + log::error!("failed to focus webview: {e}"); + } + } + WebviewMessage::SetAutoResize(auto_resize) => match webview.bounds() { + Ok(bounds) => { + let scale_factor = window.scale_factor(); + let window_size = window.inner_size().to_logical::(scale_factor); + *webview.bounds.lock().unwrap() = if auto_resize { + let size = bounds.size.to_logical::(scale_factor); + let position = bounds.position.to_logical::(scale_factor); + Some(WebviewBounds { + x_rate: position.x / window_size.width, + y_rate: position.y / window_size.height, + width_rate: size.width / window_size.width, + height_rate: size.height / window_size.height, + }) + } else { + None + }; + } + Err(e) => { + log::error!("failed to get webview bounds: {e}"); + } + }, + WebviewMessage::WithWebview(f) => { + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + f(webview.webview()); + } + #[cfg(target_os = "macos")] + { + use wry::WebViewExtMacOS; + f(Webview { + webview: Retained::into_raw(webview.webview()) as *mut objc2::runtime::AnyObject + as *mut std::ffi::c_void, + manager: Retained::into_raw(webview.manager()) as *mut objc2::runtime::AnyObject + as *mut std::ffi::c_void, + ns_window: Retained::into_raw(webview.ns_window()) as *mut objc2::runtime::AnyObject + as *mut std::ffi::c_void, + }); + } + #[cfg(target_os = "ios")] + { + use wry::WebViewExtIOS; + + f(Webview { + webview: Retained::into_raw(webview.inner.webview()) + as *mut objc2::runtime::AnyObject + as *mut std::ffi::c_void, + manager: Retained::into_raw(webview.inner.manager()) + as *mut objc2::runtime::AnyObject + as *mut std::ffi::c_void, + view_controller: window.ui_view_controller(), + }); + } + #[cfg(windows)] + { + f(Webview { + controller: webview.controller(), + }); + } + #[cfg(target_os = "android")] + { + f(webview.handle()) + } + } + #[cfg(any(debug_assertions, feature = "devtools"))] + WebviewMessage::OpenDevTools => { + webview.open_devtools(); + } + #[cfg(any(debug_assertions, feature = "devtools"))] + WebviewMessage::CloseDevTools => { + webview.close_devtools(); + } + #[cfg(any(debug_assertions, feature = "devtools"))] + WebviewMessage::IsDevToolsOpen(tx) => { + tx.send(webview.is_devtools_open()).unwrap(); + } + } + } + } + Message::CreateWebview(window_id, handler) => { + let window = windows + .0 + .borrow() + .get(&window_id) + .and_then(|w| w.inner.clone()); + if let Some(window) = window { + match handler(&window) { + Ok(webview) => { + #[allow(clippy::manual_inspect)] + windows.0.borrow_mut().get_mut(&window_id).map(|w| { + w.webviews.push(webview); + w.has_children.store(true, Ordering::Relaxed); + w + }); + } + Err(e) => { + log::error!("{}", e); + } + } + } + } + Message::CreateWindow(window_id, handler) => match handler(event_loop) { + Ok(webview) => { + windows.0.borrow_mut().insert(window_id, webview); + } + Err(e) => { + log::error!("{}", e); + } + }, + Message::CreateRawWindow(window_id, handler, sender) => { + let (label, builder) = handler(); + + #[cfg(windows)] + let background_color = builder.window.background_color; + #[cfg(windows)] + let is_window_transparent = builder.window.transparent; + + if let Ok(window) = builder.build(event_loop) { + window_id_map.insert(window.id(), window_id); + + let window = Arc::new(window); + + #[cfg(windows)] + let surface = if is_window_transparent { + if let Ok(context) = softbuffer::Context::new(window.clone()) { + if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) { + window.draw_surface(&mut surface, background_color); + Some(surface) + } else { + None + } + } else { + None + } + } else { + None + }; + + windows.0.borrow_mut().insert( + window_id, + WindowWrapper { + label, + has_children: AtomicBool::new(false), + inner: Some(window.clone()), + window_event_listeners: Default::default(), + webviews: Vec::new(), + #[cfg(windows)] + background_color, + #[cfg(windows)] + is_window_transparent, + #[cfg(windows)] + surface, + }, + ); + sender.send(Ok(Arc::downgrade(&window))).unwrap(); + } else { + sender.send(Err(Error::CreateWindow)).unwrap(); + } + } + + Message::UserEvent(_) => (), + Message::EventLoopWindowTarget(message) => match message { + EventLoopWindowTargetMessage::CursorPosition(sender) => { + let pos = event_loop + .cursor_position() + .map_err(|_| Error::FailedToSendMessage); + sender.send(pos).unwrap(); + } + }, + } +} + +fn handle_event_loop( + event: Event<'_, Message>, + event_loop: &EventLoopWindowTarget>, + control_flow: &mut ControlFlow, + context: EventLoopIterationContext<'_, T>, +) { + let EventLoopIterationContext { + callback, + window_id_map, + windows, + #[cfg(feature = "tracing")] + active_tracing_spans, + } = context; + if *control_flow != ControlFlow::Exit { + *control_flow = ControlFlow::Wait; + } + + match event { + Event::NewEvents(StartCause::Init) => { + callback(RunEvent::Ready); + } + + Event::NewEvents(StartCause::Poll) => { + callback(RunEvent::Resumed); + } + + Event::MainEventsCleared => { + callback(RunEvent::MainEventsCleared); + } + + Event::LoopDestroyed => { + callback(RunEvent::Exit); + } + + #[cfg(windows)] + Event::RedrawRequested(id) => { + if let Some(window_id) = window_id_map.get(&id) { + let mut windows_ref = windows.0.borrow_mut(); + if let Some(window) = windows_ref.get_mut(&window_id) { + if window.is_window_transparent { + let background_color = window.background_color; + if let Some(surface) = &mut window.surface { + if let Some(window) = &window.inner { + window.draw_surface(surface, background_color); + } + } + } + } + } + } + + #[cfg(feature = "tracing")] + Event::RedrawEventsCleared => { + active_tracing_spans.remove_window_draw(); + } + + Event::UserEvent(Message::Webview( + window_id, + webview_id, + WebviewMessage::WebviewEvent(event), + )) => { + let windows_ref = windows.0.borrow(); + if let Some(window) = windows_ref.get(&window_id) { + if let Some(webview) = window.webviews.iter().find(|w| w.id == webview_id) { + let label = webview.label.clone(); + let webview_event_listeners = webview.webview_event_listeners.clone(); + + drop(windows_ref); + + callback(RunEvent::WebviewEvent { + label, + event: event.clone(), + }); + let listeners = webview_event_listeners.lock().unwrap(); + let handlers = listeners.values(); + for handler in handlers { + handler(&event); + } + } + } + } + + Event::UserEvent(Message::Webview( + window_id, + _webview_id, + WebviewMessage::SynthesizedWindowEvent(event), + )) => { + if let Some(event) = WindowEventWrapper::from(event).0 { + let windows_ref = windows.0.borrow(); + let window = windows_ref.get(&window_id); + if let Some(window) = window { + let label = window.label.clone(); + let window_event_listeners = window.window_event_listeners.clone(); + + drop(windows_ref); + + callback(RunEvent::WindowEvent { + label, + event: event.clone(), + }); + + let listeners = window_event_listeners.lock().unwrap(); + let handlers = listeners.values(); + for handler in handlers { + handler(&event); + } + } + } + } + + Event::WindowEvent { + event, window_id, .. + } => { + if let Some(window_id) = window_id_map.get(&window_id) { + { + let windows_ref = windows.0.borrow(); + if let Some(window) = windows_ref.get(&window_id) { + if let Some(event) = WindowEventWrapper::parse(window, &event).0 { + let label = window.label.clone(); + let window_event_listeners = window.window_event_listeners.clone(); + + drop(windows_ref); + + callback(RunEvent::WindowEvent { + label, + event: event.clone(), + }); + let listeners = window_event_listeners.lock().unwrap(); + let handlers = listeners.values(); + for handler in handlers { + handler(&event); + } + } + } + } + + match event { + #[cfg(windows)] + TaoWindowEvent::ThemeChanged(theme) => { + if let Some(window) = windows.0.borrow().get(&window_id) { + for webview in &window.webviews { + let theme = match theme { + TaoTheme::Dark => wry::Theme::Dark, + TaoTheme::Light => wry::Theme::Light, + _ => wry::Theme::Light, + }; + if let Err(e) = webview.set_theme(theme) { + log::error!("failed to set theme: {e}"); + } + } + } + } + TaoWindowEvent::CloseRequested => { + on_close_requested(callback, window_id, windows); + } + TaoWindowEvent::Destroyed => { + let removed = windows.0.borrow_mut().remove(&window_id).is_some(); + if removed { + let is_empty = windows.0.borrow().is_empty(); + if is_empty { + let (tx, rx) = channel(); + callback(RunEvent::ExitRequested { code: None, tx }); + + let recv = rx.try_recv(); + let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent)); + + if !should_prevent { + *control_flow = ControlFlow::Exit; + } + } + } + } + TaoWindowEvent::Resized(size) => { + if let Some((Some(window), webviews)) = windows + .0 + .borrow() + .get(&window_id) + .map(|w| (w.inner.clone(), w.webviews.clone())) + { + let size = size.to_logical::(window.scale_factor()); + for webview in webviews { + if let Some(b) = &*webview.bounds.lock().unwrap() { + if let Err(e) = webview.set_bounds(wry::Rect { + position: LogicalPosition::new(size.width * b.x_rate, size.height * b.y_rate) + .into(), + size: LogicalSize::new(size.width * b.width_rate, size.height * b.height_rate) + .into(), + }) { + log::error!("failed to autoresize webview: {e}"); + } + } + } + } + } + _ => {} + } + } + } + Event::UserEvent(message) => match message { + Message::RequestExit(code) => { + let (tx, rx) = channel(); + callback(RunEvent::ExitRequested { + code: Some(code), + tx, + }); + + let recv = rx.try_recv(); + let should_prevent = matches!(recv, Ok(ExitRequestedEventAction::Prevent)); + + if !should_prevent { + *control_flow = ControlFlow::Exit; + } + } + Message::Window(id, WindowMessage::Close) => { + on_close_requested(callback, id, windows); + } + Message::Window(id, WindowMessage::Destroy) => { + on_window_close(id, windows); + } + Message::UserEvent(t) => callback(RunEvent::UserEvent(t)), + message => { + handle_user_message( + event_loop, + message, + UserMessageContext { + window_id_map, + windows, + }, + ); + } + }, + #[cfg(any(target_os = "macos", target_os = "ios"))] + Event::Opened { urls } => { + callback(RunEvent::Opened { urls }); + } + #[cfg(target_os = "macos")] + Event::Reopen { + has_visible_windows, + .. + } => callback(RunEvent::Reopen { + has_visible_windows, + }), + _ => (), + } +} + +fn on_close_requested<'a, T: UserEvent>( + callback: &'a mut (dyn FnMut(RunEvent) + 'static), + window_id: WindowId, + windows: Arc, +) { + let (tx, rx) = channel(); + let windows_ref = windows.0.borrow(); + if let Some(w) = windows_ref.get(&window_id) { + let label = w.label.clone(); + let window_event_listeners = w.window_event_listeners.clone(); + + drop(windows_ref); + + let listeners = window_event_listeners.lock().unwrap(); + let handlers = listeners.values(); + for handler in handlers { + handler(&WindowEvent::CloseRequested { + signal_tx: tx.clone(), + }); + } + callback(RunEvent::WindowEvent { + label, + event: WindowEvent::CloseRequested { signal_tx: tx }, + }); + if let Ok(true) = rx.try_recv() { + } else { + on_window_close(window_id, windows); + } + } +} + +fn on_window_close(window_id: WindowId, windows: Arc) { + if let Some(window_wrapper) = windows.0.borrow_mut().get_mut(&window_id) { + window_wrapper.inner = None; + #[cfg(windows)] + window_wrapper.surface.take(); + } +} + +fn parse_proxy_url(url: &Url) -> Result { + let host = url.host().map(|h| h.to_string()).unwrap_or_default(); + let port = url.port().map(|p| p.to_string()).unwrap_or_default(); + + if url.scheme() == "http" { + let config = ProxyConfig::Http(ProxyEndpoint { host, port }); + + Ok(config) + } else if url.scheme() == "socks5" { + let config = ProxyConfig::Socks5(ProxyEndpoint { host, port }); + + Ok(config) + } else { + Err(Error::InvalidProxyUrl) + } +} + +fn create_window( + window_id: WindowId, + webview_id: u32, + event_loop: &EventLoopWindowTarget>, + context: &Context, + pending: PendingWindow>, + after_window_creation: Option, +) -> Result { + #[allow(unused_mut)] + let PendingWindow { + mut window_builder, + label, + webview, + } = pending; + + #[cfg(feature = "tracing")] + let _webview_create_span = tracing::debug_span!("wry::webview::create").entered(); + #[cfg(feature = "tracing")] + let window_draw_span = tracing::debug_span!("wry::window::draw").entered(); + #[cfg(feature = "tracing")] + let window_create_span = + tracing::debug_span!(parent: &window_draw_span, "wry::window::create").entered(); + + let window_event_listeners = WindowEventListeners::default(); + + #[cfg(windows)] + let background_color = window_builder.inner.window.background_color; + #[cfg(windows)] + let is_window_transparent = window_builder.inner.window.transparent; + + #[cfg(target_os = "macos")] + { + if window_builder.tabbing_identifier.is_none() + || window_builder.inner.window.transparent + || !window_builder.inner.window.decorations + { + window_builder.inner = window_builder.inner.with_automatic_window_tabbing(false); + } + } + + #[cfg(desktop)] + if window_builder.center { + let monitor = if let Some(window_position) = &window_builder.inner.window.position { + event_loop.available_monitors().find(|m| { + let monitor_pos = m.position(); + let monitor_size = m.size(); + + // type annotations required for 32bit targets. + let window_position: LogicalPosition = window_position.to_logical(m.scale_factor()); + + monitor_pos.x <= window_position.x + && window_position.x <= monitor_pos.x + monitor_size.width as i32 + && monitor_pos.y <= window_position.y + && window_position.y <= monitor_pos.y + monitor_size.height as i32 + }) + } else { + event_loop.primary_monitor() + }; + + if let Some(monitor) = monitor { + let desired_size = window_builder + .inner + .window + .inner_size + .unwrap_or_else(|| TaoPhysicalSize::new(800, 600).into()); + let scale_factor = monitor.scale_factor(); + #[allow(unused_mut)] + let mut window_size = window_builder + .inner + .window + .inner_size_constraints + .clamp(desired_size, scale_factor) + .to_physical::(scale_factor); + #[cfg(windows)] + { + if window_builder.inner.window.decorations { + use windows::Win32::UI::WindowsAndMessaging::{AdjustWindowRect, WS_OVERLAPPEDWINDOW}; + let mut rect = windows::Win32::Foundation::RECT::default(); + let result = unsafe { AdjustWindowRect(&mut rect, WS_OVERLAPPEDWINDOW, false) }; + if result.is_ok() { + window_size.width += (rect.right - rect.left) as u32; + // rect.bottom is made out of shadow, and we don't care about it + window_size.height += -rect.top as u32; + } + } + } + let position = window::calculate_window_center_position(window_size, monitor); + let logical_position = position.to_logical::(scale_factor); + window_builder = window_builder.position(logical_position.x, logical_position.y); + } + } + + let window = window_builder.inner.build(event_loop).unwrap(); + + #[cfg(feature = "tracing")] + { + drop(window_create_span); + + context + .main_thread + .active_tracing_spans + .0 + .borrow_mut() + .push(ActiveTracingSpan::WindowDraw { + id: window.id(), + span: window_draw_span, + }); + } + + context.window_id_map.insert(window.id(), window_id); + + if let Some(handler) = after_window_creation { + let raw = RawWindow { + #[cfg(windows)] + hwnd: window.hwnd(), + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + gtk_window: window.gtk_window(), + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + default_vbox: window.default_vbox(), + _marker: &std::marker::PhantomData, + }; + handler(raw); + } + + let mut webviews = Vec::new(); + + if let Some(webview) = webview { + webviews.push(create_webview( + #[cfg(feature = "unstable")] + WebviewKind::WindowChild, + #[cfg(not(feature = "unstable"))] + WebviewKind::WindowContent, + &window, + Arc::new(Mutex::new(window_id)), + webview_id, + context, + webview, + )?); + } + + let window = Arc::new(window); + + #[cfg(windows)] + let surface = if is_window_transparent { + if let Ok(context) = softbuffer::Context::new(window.clone()) { + if let Ok(mut surface) = softbuffer::Surface::new(&context, window.clone()) { + window.draw_surface(&mut surface, background_color); + Some(surface) + } else { + None + } + } else { + None + } + } else { + None + }; + + Ok(WindowWrapper { + label, + has_children: AtomicBool::new(false), + inner: Some(window), + webviews, + window_event_listeners, + #[cfg(windows)] + background_color, + #[cfg(windows)] + is_window_transparent, + #[cfg(windows)] + surface, + }) +} + +/// the kind of the webview +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +enum WebviewKind { + // webview is the entire window content + WindowContent, + // webview is a child of the window, which can contain other webviews too + WindowChild, +} + +#[derive(Debug, Clone)] +struct WebviewBounds { + x_rate: f32, + y_rate: f32, + width_rate: f32, + height_rate: f32, +} + +fn create_webview( + kind: WebviewKind, + window: &Window, + window_id: Arc>, + id: WebviewId, + context: &Context, + pending: PendingWebview>, +) -> Result { + #[allow(unused_mut)] + let PendingWebview { + webview_attributes, + uri_scheme_protocols, + label, + ipc_handler, + url, + .. + } = pending; + + let mut web_context = context + .main_thread + .web_context + .lock() + .expect("poisoned WebContext store"); + let is_first_context = web_context.is_empty(); + // the context must be stored on the HashMap because it must outlive the WebView on macOS + let automation_enabled = std::env::var("TAURI_WEBVIEW_AUTOMATION").as_deref() == Ok("true"); + let web_context_key = webview_attributes.data_directory; + let entry = web_context.entry(web_context_key.clone()); + let web_context = match entry { + Occupied(occupied) => { + let occupied = occupied.into_mut(); + occupied.referenced_by_webviews.insert(label.clone()); + occupied + } + Vacant(vacant) => { + let mut web_context = WryWebContext::new(web_context_key.clone()); + web_context.set_allows_automation(if automation_enabled { + is_first_context + } else { + false + }); + vacant.insert(WebContext { + inner: web_context, + referenced_by_webviews: [label.clone()].into(), + registered_custom_protocols: HashSet::new(), + }) + } + }; + + let mut webview_builder = WebViewBuilder::with_web_context(&mut web_context.inner) + .with_id(&label) + .with_focused(webview_attributes.focus) + .with_url(&url) + .with_transparent(webview_attributes.transparent) + .with_accept_first_mouse(webview_attributes.accept_first_mouse) + .with_incognito(webview_attributes.incognito) + .with_clipboard(webview_attributes.clipboard) + .with_hotkeys_zoom(webview_attributes.zoom_hotkeys_enabled); + + #[cfg(any(target_os = "windows", target_os = "android"))] + { + webview_builder = webview_builder.with_https_scheme(webview_attributes.use_https_scheme); + } + + if let Some(color) = webview_attributes.background_color { + webview_builder = webview_builder.with_background_color(color.into()); + } + + if webview_attributes.drag_drop_handler_enabled { + let proxy = context.proxy.clone(); + let window_id_ = window_id.clone(); + webview_builder = webview_builder.with_drag_drop_handler(move |event| { + let event = match event { + WryDragDropEvent::Enter { + paths, + position: (x, y), + } => DragDropEvent::Enter { + paths, + position: PhysicalPosition::new(x as _, y as _), + }, + WryDragDropEvent::Over { position: (x, y) } => DragDropEvent::Over { + position: PhysicalPosition::new(x as _, y as _), + }, + WryDragDropEvent::Drop { + paths, + position: (x, y), + } => DragDropEvent::Drop { + paths, + position: PhysicalPosition::new(x as _, y as _), + }, + WryDragDropEvent::Leave => DragDropEvent::Leave, + _ => unimplemented!(), + }; + + let message = if kind == WebviewKind::WindowContent { + WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::DragDrop(event)) + } else { + WebviewMessage::WebviewEvent(WebviewEvent::DragDrop(event)) + }; + + let _ = proxy.send_event(Message::Webview(*window_id_.lock().unwrap(), id, message)); + true + }); + } + + if let Some(navigation_handler) = pending.navigation_handler { + webview_builder = webview_builder.with_navigation_handler(move |url| { + url + .parse() + .map(|url| navigation_handler(&url)) + .unwrap_or(true) + }); + } + + let webview_bounds = if let Some(bounds) = webview_attributes.bounds { + let bounds: RectWrapper = bounds.into(); + let bounds = bounds.0; + + let scale_factor = window.scale_factor(); + let position = bounds.position.to_logical::(scale_factor); + let size = bounds.size.to_logical::(scale_factor); + + webview_builder = webview_builder.with_bounds(bounds); + + let window_size = window.inner_size().to_logical::(scale_factor); + + if webview_attributes.auto_resize { + Some(WebviewBounds { + x_rate: position.x / window_size.width, + y_rate: position.y / window_size.height, + width_rate: size.width / window_size.width, + height_rate: size.height / window_size.height, + }) + } else { + None + } + } else { + #[cfg(feature = "unstable")] + { + webview_builder = webview_builder.with_bounds(wry::Rect { + position: LogicalPosition::new(0, 0).into(), + size: window.inner_size().into(), + }); + Some(WebviewBounds { + x_rate: 0., + y_rate: 0., + width_rate: 1., + height_rate: 1., + }) + } + #[cfg(not(feature = "unstable"))] + None + }; + + if let Some(download_handler) = pending.download_handler { + let download_handler_ = download_handler.clone(); + webview_builder = webview_builder.with_download_started_handler(move |url, path| { + if let Ok(url) = url.parse() { + download_handler_(DownloadEvent::Requested { + url, + destination: path, + }) + } else { + false + } + }); + webview_builder = webview_builder.with_download_completed_handler(move |url, path, success| { + if let Ok(url) = url.parse() { + download_handler(DownloadEvent::Finished { url, path, success }); + } + }); + } + + if let Some(page_load_handler) = pending.on_page_load_handler { + webview_builder = webview_builder.with_on_page_load_handler(move |event, url| { + let _ = url.parse().map(|url| { + page_load_handler( + url, + match event { + wry::PageLoadEvent::Started => tauri_runtime::webview::PageLoadEvent::Started, + wry::PageLoadEvent::Finished => tauri_runtime::webview::PageLoadEvent::Finished, + }, + ) + }); + }); + } + + if let Some(user_agent) = webview_attributes.user_agent { + webview_builder = webview_builder.with_user_agent(&user_agent); + } + + if let Some(proxy_url) = webview_attributes.proxy_url { + let config = parse_proxy_url(&proxy_url)?; + + webview_builder = webview_builder.with_proxy_config(config); + } + + #[cfg(windows)] + { + if let Some(additional_browser_args) = webview_attributes.additional_browser_args { + webview_builder = webview_builder.with_additional_browser_args(&additional_browser_args); + } + + webview_builder = webview_builder.with_theme(match window.theme() { + TaoTheme::Dark => wry::Theme::Dark, + TaoTheme::Light => wry::Theme::Light, + _ => wry::Theme::Light, + }); + } + + #[cfg(windows)] + { + webview_builder = webview_builder + .with_browser_extensions_enabled(webview_attributes.browser_extensions_enabled); + } + + #[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + if let Some(path) = &webview_attributes.extensions_path { + webview_builder = webview_builder.with_extension_path(path); + } + } + + #[cfg(any(target_os = "macos", target_os = "ios"))] + { + if let Some(data_store_identifier) = &webview_attributes.data_store_identifier { + webview_builder = webview_builder.with_data_store_identifier(*data_store_identifier); + } + } + + webview_builder = webview_builder.with_ipc_handler(create_ipc_handler( + kind, + window_id.clone(), + id, + context.clone(), + label.clone(), + ipc_handler, + )); + + for script in webview_attributes.initialization_scripts { + webview_builder = webview_builder.with_initialization_script(&script); + } + + for (scheme, protocol) in uri_scheme_protocols { + // on Linux the custom protocols are associated with the web context + // and you cannot register a scheme more than once + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + { + if web_context.registered_custom_protocols.contains(&scheme) { + continue; + } + + web_context + .registered_custom_protocols + .insert(scheme.clone()); + } + + webview_builder = webview_builder.with_asynchronous_custom_protocol( + scheme, + move |webview_id, request, responder| { + protocol( + webview_id, + request, + Box::new(move |response| responder.respond(response)), + ) + }, + ); + } + + #[cfg(any(debug_assertions, feature = "devtools"))] + { + webview_builder = webview_builder.with_devtools(webview_attributes.devtools.unwrap_or(true)); + } + + #[cfg(target_os = "android")] + { + if let Some(on_webview_created) = pending.on_webview_created { + webview_builder = webview_builder.on_webview_created(move |ctx| { + on_webview_created(tauri_runtime::webview::CreationContext { + env: ctx.env, + activity: ctx.activity, + webview: ctx.webview, + }) + }); + } + } + + let webview = match kind { + #[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "ios", + target_os = "android" + )))] + WebviewKind::WindowChild => { + // only way to account for menu bar height, and also works for multiwebviews :) + let vbox = window.default_vbox().unwrap(); + webview_builder.build_gtk(vbox) + } + #[cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "ios", + target_os = "android" + ))] + WebviewKind::WindowChild => webview_builder.build_as_child(&window), + WebviewKind::WindowContent => { + #[cfg(any( + target_os = "windows", + target_os = "macos", + target_os = "ios", + target_os = "android" + ))] + let builder = webview_builder.build(&window); + #[cfg(not(any( + target_os = "windows", + target_os = "macos", + target_os = "ios", + target_os = "android" + )))] + let builder = { + let vbox = window.default_vbox().unwrap(); + webview_builder.build_gtk(vbox) + }; + builder + } + } + .map_err(|e| Error::CreateWebview(Box::new(e)))?; + + if kind == WebviewKind::WindowContent { + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + undecorated_resizing::attach_resize_handler(&webview); + #[cfg(windows)] + if window.is_resizable() && !window.is_decorated() { + undecorated_resizing::attach_resize_handler(window.hwnd()); + } + } + + #[cfg(windows)] + if kind == WebviewKind::WindowContent { + let controller = webview.controller(); + let proxy = context.proxy.clone(); + let proxy_ = proxy.clone(); + let window_id_ = window_id.clone(); + let mut token = EventRegistrationToken::default(); + unsafe { + controller.add_GotFocus( + &FocusChangedEventHandler::create(Box::new(move |_, _| { + let _ = proxy.send_event(Message::Webview( + *window_id_.lock().unwrap(), + id, + WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::Focused(true)), + )); + Ok(()) + })), + &mut token, + ) + } + .unwrap(); + unsafe { + controller.add_LostFocus( + &FocusChangedEventHandler::create(Box::new(move |_, _| { + let _ = proxy_.send_event(Message::Webview( + *window_id.lock().unwrap(), + id, + WebviewMessage::SynthesizedWindowEvent(SynthesizedWindowEvent::Focused(false)), + )); + Ok(()) + })), + &mut token, + ) + } + .unwrap(); + } + + Ok(WebviewWrapper { + label, + id, + inner: Rc::new(webview), + context_store: context.main_thread.web_context.clone(), + webview_event_listeners: Default::default(), + context_key: if automation_enabled { + None + } else { + web_context_key + }, + bounds: Arc::new(Mutex::new(webview_bounds)), + }) +} + +/// Create a wry ipc handler from a tauri ipc handler. +fn create_ipc_handler( + _kind: WebviewKind, + window_id: Arc>, + webview_id: WebviewId, + context: Context, + label: String, + ipc_handler: Option>>, +) -> Box { + Box::new(move |request| { + if let Some(handler) = &ipc_handler { + handler( + DetachedWebview { + label: label.clone(), + dispatcher: WryWebviewDispatcher { + window_id: window_id.clone(), + webview_id, + context: context.clone(), + }, + }, + request, + ); + } + }) +} + +#[cfg(target_os = "macos")] +fn inner_size( + window: &Window, + webviews: &[WebviewWrapper], + has_children: bool, +) -> TaoPhysicalSize { + if !has_children && !webviews.is_empty() { + use wry::WebViewExtMacOS; + let webview = webviews.first().unwrap(); + let view = unsafe { Retained::cast::(webview.webview()) }; + let view_frame = view.frame(); + let logical: TaoLogicalSize = (view_frame.size.width, view_frame.size.height).into(); + return logical.to_physical(window.scale_factor()); + } + + window.inner_size() +} + +#[cfg(not(target_os = "macos"))] +#[allow(unused_variables)] +fn inner_size( + window: &Window, + webviews: &[WebviewWrapper], + has_children: bool, +) -> TaoPhysicalSize { + window.inner_size() +} diff --git a/crates/tauri-runtime-wry/src/undecorated_resizing.rs b/crates/tauri-runtime-wry/src/undecorated_resizing.rs new file mode 100644 index 000000000000..362d479dd8ae --- /dev/null +++ b/crates/tauri-runtime-wry/src/undecorated_resizing.rs @@ -0,0 +1,497 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] + +const CLIENT: isize = 0b0000; +const LEFT: isize = 0b0001; +const RIGHT: isize = 0b0010; +const TOP: isize = 0b0100; +const BOTTOM: isize = 0b1000; +const TOPLEFT: isize = TOP | LEFT; +const TOPRIGHT: isize = TOP | RIGHT; +const BOTTOMLEFT: isize = BOTTOM | LEFT; +const BOTTOMRIGHT: isize = BOTTOM | RIGHT; + +#[cfg(not(windows))] +pub use self::gtk::*; +#[cfg(windows)] +pub use self::windows::*; + +#[cfg(windows)] +type WindowPositions = i32; +#[cfg(not(windows))] +type WindowPositions = f64; + +#[derive(Debug, PartialEq, Eq, Clone, Copy)] +enum HitTestResult { + Client, + Left, + Right, + Top, + Bottom, + TopLeft, + TopRight, + BottomLeft, + BottomRight, + NoWhere, +} + +#[allow(clippy::too_many_arguments)] +fn hit_test( + left: WindowPositions, + top: WindowPositions, + right: WindowPositions, + bottom: WindowPositions, + cx: WindowPositions, + cy: WindowPositions, + border_x: WindowPositions, + border_y: WindowPositions, +) -> HitTestResult { + #[rustfmt::skip] + let result = (LEFT * (cx < left + border_x) as isize) + | (RIGHT * (cx >= right - border_x) as isize) + | (TOP * (cy < top + border_y) as isize) + | (BOTTOM * (cy >= bottom - border_y) as isize); + + match result { + CLIENT => HitTestResult::Client, + LEFT => HitTestResult::Left, + RIGHT => HitTestResult::Right, + TOP => HitTestResult::Top, + BOTTOM => HitTestResult::Bottom, + TOPLEFT => HitTestResult::TopLeft, + TOPRIGHT => HitTestResult::TopRight, + BOTTOMLEFT => HitTestResult::BottomLeft, + BOTTOMRIGHT => HitTestResult::BottomRight, + _ => HitTestResult::NoWhere, + } +} + +#[cfg(windows)] +mod windows { + use super::{hit_test, HitTestResult}; + + use windows::core::*; + use windows::Win32::System::LibraryLoader::*; + use windows::Win32::UI::WindowsAndMessaging::*; + use windows::Win32::{Foundation::*, UI::Shell::SetWindowSubclass}; + use windows::Win32::{Graphics::Gdi::*, UI::Shell::DefSubclassProc}; + + impl HitTestResult { + fn to_win32(self) -> i32 { + match self { + HitTestResult::Left => HTLEFT as _, + HitTestResult::Right => HTRIGHT as _, + HitTestResult::Top => HTTOP as _, + HitTestResult::Bottom => HTBOTTOM as _, + HitTestResult::TopLeft => HTTOPLEFT as _, + HitTestResult::TopRight => HTTOPRIGHT as _, + HitTestResult::BottomLeft => HTBOTTOMLEFT as _, + HitTestResult::BottomRight => HTBOTTOMRIGHT as _, + _ => HTTRANSPARENT, + } + } + } + + const CLASS_NAME: PCWSTR = w!("TAURI_DRAG_RESIZE_BORDERS"); + const WINDOW_NAME: PCWSTR = w!("TAURI_DRAG_RESIZE_WINDOW"); + + pub fn attach_resize_handler(hwnd: isize) { + let parent = HWND(hwnd as _); + + // return early if we already attached + if unsafe { FindWindowExW(parent, HWND::default(), CLASS_NAME, WINDOW_NAME) }.is_ok() { + return; + } + + let class = WNDCLASSEXW { + cbSize: std::mem::size_of::() as u32, + style: WNDCLASS_STYLES::default(), + lpfnWndProc: Some(drag_resize_window_proc), + cbClsExtra: 0, + cbWndExtra: 0, + hInstance: unsafe { HINSTANCE(GetModuleHandleW(PCWSTR::null()).unwrap_or_default().0) }, + hIcon: HICON::default(), + hCursor: HCURSOR::default(), + hbrBackground: HBRUSH::default(), + lpszMenuName: PCWSTR::null(), + lpszClassName: CLASS_NAME, + hIconSm: HICON::default(), + }; + + unsafe { RegisterClassExW(&class) }; + + let mut rect = RECT::default(); + unsafe { GetClientRect(parent, &mut rect).unwrap() }; + let width = rect.right - rect.left; + let height = rect.bottom - rect.top; + + let Ok(drag_window) = (unsafe { + CreateWindowExW( + WINDOW_EX_STYLE::default(), + CLASS_NAME, + WINDOW_NAME, + WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS, + 0, + 0, + width, + height, + parent, + HMENU::default(), + GetModuleHandleW(PCWSTR::null()).unwrap_or_default(), + None, + ) + }) else { + return; + }; + + unsafe { + set_drag_hwnd_rgn(drag_window, width, height); + + let _ = SetWindowPos( + drag_window, + HWND_TOP, + 0, + 0, + 0, + 0, + SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOSIZE, + ); + + let _ = SetWindowSubclass( + parent, + Some(subclass_parent), + (WM_USER + 1) as _, + drag_window.0 as _, + ); + } + } + + unsafe extern "system" fn subclass_parent( + parent: HWND, + msg: u32, + wparam: WPARAM, + lparam: LPARAM, + _: usize, + child: usize, + ) -> LRESULT { + if msg == WM_SIZE { + let child = HWND(child as _); + + if is_maximized(parent).unwrap_or(false) { + let _ = SetWindowPos( + child, + HWND_TOP, + 0, + 0, + 0, + 0, + SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE, + ); + } else { + let mut rect = RECT::default(); + if GetClientRect(parent, &mut rect).is_ok() { + let width = rect.right - rect.left; + let height = rect.bottom - rect.top; + + let _ = SetWindowPos( + child, + HWND_TOP, + 0, + 0, + width, + height, + SWP_ASYNCWINDOWPOS | SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOMOVE, + ); + + set_drag_hwnd_rgn(child, width, height); + } + } + } + + DefSubclassProc(parent, msg, wparam, lparam) + } + + unsafe extern "system" fn drag_resize_window_proc( + child: HWND, + msg: u32, + wparam: WPARAM, + lparam: LPARAM, + ) -> LRESULT { + match msg { + WM_NCHITTEST => { + let Ok(parent) = GetParent(child) else { + return DefWindowProcW(child, msg, wparam, lparam); + }; + let style = GetWindowLongPtrW(parent, GWL_STYLE); + let style = WINDOW_STYLE(style as u32); + + let is_resizable = (style & WS_SIZEBOX).0 != 0; + if !is_resizable { + return DefWindowProcW(child, msg, wparam, lparam); + } + + let mut rect = RECT::default(); + if GetWindowRect(child, &mut rect).is_err() { + return DefWindowProcW(child, msg, wparam, lparam); + } + + let (cx, cy) = (GET_X_LPARAM(lparam) as i32, GET_Y_LPARAM(lparam) as i32); + + let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER); + let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border; + let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border; + + let res = hit_test( + rect.left, + rect.top, + rect.right, + rect.bottom, + cx, + cy, + border_x, + border_y, + ); + + return LRESULT(res.to_win32() as _); + } + + WM_NCLBUTTONDOWN => { + let Ok(parent) = GetParent(child) else { + return DefWindowProcW(child, msg, wparam, lparam); + }; + let style = GetWindowLongPtrW(parent, GWL_STYLE); + let style = WINDOW_STYLE(style as u32); + + let is_resizable = (style & WS_SIZEBOX).0 != 0; + if !is_resizable { + return DefWindowProcW(child, msg, wparam, lparam); + } + + let mut rect = RECT::default(); + if GetWindowRect(child, &mut rect).is_err() { + return DefWindowProcW(child, msg, wparam, lparam); + } + + let (cx, cy) = (GET_X_LPARAM(lparam) as i32, GET_Y_LPARAM(lparam) as i32); + + let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER); + let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border; + let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border; + + let res = hit_test( + rect.left, + rect.top, + rect.right, + rect.bottom, + cx, + cy, + border_x, + border_y, + ); + + if res != HitTestResult::NoWhere { + let points = POINTS { + x: cx as i16, + y: cy as i16, + }; + + let _ = PostMessageW( + parent, + WM_NCLBUTTONDOWN, + WPARAM(res.to_win32() as _), + LPARAM(&points as *const _ as _), + ); + } + + return LRESULT(0); + } + + _ => {} + } + + DefWindowProcW(child, msg, wparam, lparam) + } + + pub fn detach_resize_handler(hwnd: isize) { + let hwnd = HWND(hwnd as _); + + let Ok(child) = (unsafe { FindWindowExW(hwnd, HWND::default(), CLASS_NAME, WINDOW_NAME) }) + else { + return; + }; + + let _ = unsafe { DestroyWindow(child) }; + } + + unsafe fn set_drag_hwnd_rgn(hwnd: HWND, width: i32, height: i32) { + let padded_border = GetSystemMetrics(SM_CXPADDEDBORDER); + let border_x = GetSystemMetrics(SM_CXFRAME) + padded_border; + let border_y = GetSystemMetrics(SM_CYFRAME) + padded_border; + + let hrgn1 = CreateRectRgn(0, 0, width, height); + let hrgn2 = CreateRectRgn(border_x, border_y, width - border_x, height - border_y); + CombineRgn(hrgn1, hrgn1, hrgn2, RGN_DIFF); + SetWindowRgn(hwnd, hrgn1, true); + } + + fn is_maximized(window: HWND) -> windows::core::Result { + let mut placement = WINDOWPLACEMENT { + length: std::mem::size_of::() as u32, + ..WINDOWPLACEMENT::default() + }; + unsafe { GetWindowPlacement(window, &mut placement)? }; + Ok(placement.showCmd == SW_MAXIMIZE.0 as u32) + } + + /// Implementation of the `GET_X_LPARAM` macro. + #[allow(non_snake_case)] + #[inline] + fn GET_X_LPARAM(lparam: LPARAM) -> i16 { + ((lparam.0 as usize) & 0xFFFF) as u16 as i16 + } + + /// Implementation of the `GET_Y_LPARAM` macro. + #[allow(non_snake_case)] + #[inline] + fn GET_Y_LPARAM(lparam: LPARAM) -> i16 { + (((lparam.0 as usize) & 0xFFFF_0000) >> 16) as u16 as i16 + } +} + +#[cfg(not(windows))] +mod gtk { + use super::{hit_test, HitTestResult}; + + const BORDERLESS_RESIZE_INSET: i32 = 5; + + impl HitTestResult { + fn to_gtk_edge(self) -> gtk::gdk::WindowEdge { + match self { + HitTestResult::Client | HitTestResult::NoWhere => gtk::gdk::WindowEdge::__Unknown(0), + HitTestResult::Left => gtk::gdk::WindowEdge::West, + HitTestResult::Right => gtk::gdk::WindowEdge::East, + HitTestResult::Top => gtk::gdk::WindowEdge::North, + HitTestResult::Bottom => gtk::gdk::WindowEdge::South, + HitTestResult::TopLeft => gtk::gdk::WindowEdge::NorthWest, + HitTestResult::TopRight => gtk::gdk::WindowEdge::NorthEast, + HitTestResult::BottomLeft => gtk::gdk::WindowEdge::SouthWest, + HitTestResult::BottomRight => gtk::gdk::WindowEdge::SouthEast, + } + } + } + + pub fn attach_resize_handler(webview: &wry::WebView) { + use gtk::{ + gdk::{prelude::*, WindowEdge}, + glib::Propagation, + prelude::*, + }; + use wry::WebViewExtUnix; + + let webview = webview.webview(); + + webview.add_events( + gtk::gdk::EventMask::BUTTON1_MOTION_MASK + | gtk::gdk::EventMask::BUTTON_PRESS_MASK + | gtk::gdk::EventMask::TOUCH_MASK, + ); + + webview.connect_button_press_event( + move |webview: &webkit2gtk::WebView, event: >k::gdk::EventButton| { + if event.button() == 1 { + // This one should be GtkBox + if let Some(window) = webview.parent().and_then(|w| w.parent()) { + // Safe to unwrap unless this is not from tao + let window: gtk::Window = window.downcast().unwrap(); + if !window.is_decorated() && window.is_resizable() && !window.is_maximized() { + if let Some(window) = window.window() { + let (root_x, root_y) = event.root(); + let (window_x, window_y) = window.position(); + let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64); + let border = window.scale_factor() * BORDERLESS_RESIZE_INSET; + let edge = hit_test( + 0.0, + 0.0, + window.width() as f64, + window.height() as f64, + client_x, + client_y, + border as _, + border as _, + ) + .to_gtk_edge(); + + // we ignore the `__Unknown` variant so the webview receives the click correctly if it is not on the edges. + match edge { + WindowEdge::__Unknown(_) => (), + _ => { + window.begin_resize_drag(edge, 1, root_x as i32, root_y as i32, event.time()) + } + } + } + } + } + } + + Propagation::Proceed + }, + ); + + webview.connect_touch_event( + move |webview: &webkit2gtk::WebView, event: >k::gdk::Event| { + // This one should be GtkBox + if let Some(window) = webview.parent().and_then(|w| w.parent()) { + // Safe to unwrap unless this is not from tao + let window: gtk::Window = window.downcast().unwrap(); + if !window.is_decorated() && window.is_resizable() && !window.is_maximized() { + if let Some(window) = window.window() { + if let Some((root_x, root_y)) = event.root_coords() { + if let Some(device) = event.device() { + let (window_x, window_y) = window.position(); + let (client_x, client_y) = (root_x - window_x as f64, root_y - window_y as f64); + let border = window.scale_factor() * BORDERLESS_RESIZE_INSET; + let edge = hit_test( + 0.0, + 0.0, + window.width() as f64, + window.height() as f64, + client_x, + client_y, + border as _, + border as _, + ) + .to_gtk_edge(); + + // we ignore the `__Unknown` variant so the window receives the click correctly if it is not on the edges. + match edge { + WindowEdge::__Unknown(_) => (), + _ => window.begin_resize_drag_for_device( + edge, + &device, + 0, + root_x as i32, + root_y as i32, + event.time(), + ), + } + } + } + } + } + } + + Propagation::Proceed + }, + ); + } +} diff --git a/crates/tauri-runtime-wry/src/webview.rs b/crates/tauri-runtime-wry/src/webview.rs new file mode 100644 index 000000000000..db15eb067117 --- /dev/null +++ b/crates/tauri-runtime-wry/src/webview.rs @@ -0,0 +1,44 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +mod imp { + pub type Webview = webkit2gtk::WebView; +} + +#[cfg(target_vendor = "apple")] +mod imp { + use std::ffi::c_void; + + pub struct Webview { + pub webview: *mut c_void, + pub manager: *mut c_void, + #[cfg(target_os = "macos")] + pub ns_window: *mut c_void, + #[cfg(target_os = "ios")] + pub view_controller: *mut c_void, + } +} + +#[cfg(windows)] +mod imp { + use webview2_com::Microsoft::Web::WebView2::Win32::ICoreWebView2Controller; + pub struct Webview { + pub controller: ICoreWebView2Controller, + } +} + +#[cfg(target_os = "android")] +mod imp { + use wry::JniHandle; + pub type Webview = JniHandle; +} + +pub use imp::*; diff --git a/crates/tauri-runtime-wry/src/window/linux.rs b/crates/tauri-runtime-wry/src/window/linux.rs new file mode 100644 index 000000000000..e7ee9276bd2a --- /dev/null +++ b/crates/tauri-runtime-wry/src/window/linux.rs @@ -0,0 +1,31 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use gtk::prelude::*; +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +use tao::platform::unix::WindowExtUnix; + +impl super::WindowExt for tao::window::Window { + fn set_enabled(&self, enabled: bool) { + self.gtk_window().set_sensitive(enabled); + } + + fn is_enabled(&self) -> bool { + self.gtk_window().is_sensitive() + } + + fn center(&self) { + if let Some(monitor) = self.current_monitor() { + let window_size = self.outer_size(); + let new_pos = super::calculate_window_center_position(window_size, monitor); + self.set_outer_position(new_pos); + } + } +} diff --git a/crates/tauri-runtime-wry/src/window/macos.rs b/crates/tauri-runtime-wry/src/window/macos.rs new file mode 100644 index 000000000000..737efb5831b8 --- /dev/null +++ b/crates/tauri-runtime-wry/src/window/macos.rs @@ -0,0 +1,43 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use objc2_app_kit::{NSBackingStoreType, NSWindow, NSWindowStyleMask}; +use objc2_foundation::MainThreadMarker; +use tao::platform::macos::WindowExtMacOS; + +impl super::WindowExt for tao::window::Window { + // based on electron implementation + // https://github.com/electron/electron/blob/15db63e26df3e3d59ce6281f030624f746518511/shell/browser/native_window_mac.mm#L474 + fn set_enabled(&self, enabled: bool) { + let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() }; + if !enabled { + let frame = ns_window.frame(); + let mtm = MainThreadMarker::new() + .expect("`Window::set_enabled` can only be called on the main thread"); + let sheet = unsafe { + NSWindow::initWithContentRect_styleMask_backing_defer( + mtm.alloc(), + frame, + NSWindowStyleMask::Titled, + NSBackingStoreType::NSBackingStoreBuffered, + false, + ) + }; + unsafe { sheet.setAlphaValue(0.5) }; + unsafe { ns_window.beginSheet_completionHandler(&sheet, None) }; + } else if let Some(attached) = unsafe { ns_window.attachedSheet() } { + unsafe { ns_window.endSheet(&attached) }; + } + } + + fn is_enabled(&self) -> bool { + let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() }; + unsafe { ns_window.attachedSheet() }.is_none() + } + + fn center(&self) { + let ns_window: &NSWindow = unsafe { &*self.ns_window().cast() }; + ns_window.center(); + } +} diff --git a/crates/tauri-runtime-wry/src/window/mod.rs b/crates/tauri-runtime-wry/src/window/mod.rs new file mode 100644 index 000000000000..c2b1b448686d --- /dev/null +++ b/crates/tauri-runtime-wry/src/window/mod.rs @@ -0,0 +1,89 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] +mod linux; +#[cfg(target_os = "macos")] +mod macos; +#[cfg(windows)] +mod windows; + +pub trait WindowExt { + /// Enable or disable the window + /// + /// ## Platform-specific: + /// + /// - **Android / iOS**: Unsupported. + fn set_enabled(&self, enabled: bool); + + /// Whether the window is enabled or disabled. + /// + /// ## Platform-specific: + /// + /// - **Android / iOS**: Unsupported, always returns `true`. + fn is_enabled(&self) -> bool; + + /// Center the window + /// + /// ## Platform-specific: + /// + /// - **Android / iOS**: Unsupported. + fn center(&self) {} + + /// Clears the window sufrace. i.e make it it transparent. + #[cfg(windows)] + fn draw_surface( + &self, + surface: &mut softbuffer::Surface< + std::sync::Arc, + std::sync::Arc, + >, + background_color: Option, + ); +} + +#[cfg(mobile)] +impl WindowExt for tao::window::Window { + fn set_enabled(&self, _: bool) {} + fn is_enabled(&self) -> bool { + true + } +} + +pub fn calculate_window_center_position( + window_size: tao::dpi::PhysicalSize, + target_monitor: tao::monitor::MonitorHandle, +) -> tao::dpi::PhysicalPosition { + #[cfg(windows)] + { + use ::windows::Win32::Graphics::Gdi::{GetMonitorInfoW, HMONITOR, MONITORINFO}; + use tao::platform::windows::MonitorHandleExtWindows; + + let mut monitor_info = MONITORINFO { + cbSize: std::mem::size_of::() as u32, + ..Default::default() + }; + let hmonitor = target_monitor.hmonitor(); + let status = unsafe { GetMonitorInfoW(HMONITOR(hmonitor as _), &mut monitor_info) }; + if status.into() { + let available_width = monitor_info.rcWork.right - monitor_info.rcWork.left; + let available_height = monitor_info.rcWork.bottom - monitor_info.rcWork.top; + let x = (available_width - window_size.width as i32) / 2 + monitor_info.rcWork.left; + let y = (available_height - window_size.height as i32) / 2 + monitor_info.rcWork.top; + return tao::dpi::PhysicalPosition::new(x, y); + } + } + + let screen_size = target_monitor.size(); + let monitor_pos = target_monitor.position(); + let x = (screen_size.width as i32 - window_size.width as i32) / 2 + monitor_pos.x; + let y = (screen_size.height as i32 - window_size.height as i32) / 2 + monitor_pos.y; + tao::dpi::PhysicalPosition::new(x, y) +} diff --git a/crates/tauri-runtime-wry/src/window/windows.rs b/crates/tauri-runtime-wry/src/window/windows.rs new file mode 100644 index 000000000000..6c032beabda8 --- /dev/null +++ b/crates/tauri-runtime-wry/src/window/windows.rs @@ -0,0 +1,68 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use windows::Win32::{ + Foundation::{HWND, RECT}, + Graphics::Dwm::{DwmGetWindowAttribute, DWMWA_EXTENDED_FRAME_BOUNDS}, + UI::Input::KeyboardAndMouse::{EnableWindow, IsWindowEnabled}, +}; + +use tao::platform::windows::WindowExtWindows; + +impl super::WindowExt for tao::window::Window { + fn set_enabled(&self, enabled: bool) { + let _ = unsafe { EnableWindow(HWND(self.hwnd() as _), enabled) }; + } + + fn is_enabled(&self) -> bool { + unsafe { IsWindowEnabled(HWND(self.hwnd() as _)) }.as_bool() + } + + fn center(&self) { + if let Some(monitor) = self.current_monitor() { + let mut window_size = self.outer_size(); + + if self.is_decorated() { + let mut rect = RECT::default(); + let result = unsafe { + DwmGetWindowAttribute( + HWND(self.hwnd() as _), + DWMWA_EXTENDED_FRAME_BOUNDS, + &mut rect as *mut _ as *mut _, + std::mem::size_of::() as u32, + ) + }; + if result.is_ok() { + window_size.height = (rect.bottom - rect.top) as u32; + } + } + + let new_pos = super::calculate_window_center_position(window_size, monitor); + self.set_outer_position(new_pos); + } + } + + fn draw_surface( + &self, + surface: &mut softbuffer::Surface< + std::sync::Arc, + std::sync::Arc, + >, + background_color: Option, + ) { + let size = self.inner_size(); + if let (Some(width), Some(height)) = ( + std::num::NonZeroU32::new(size.width), + std::num::NonZeroU32::new(size.height), + ) { + surface.resize(width, height).unwrap(); + let mut buffer = surface.buffer_mut().unwrap(); + let color = background_color + .map(|(r, g, b, _)| (b as u32) | ((g as u32) << 8) | ((r as u32) << 16)) + .unwrap_or(0); + buffer.fill(color); + let _ = buffer.present(); + } + } +} diff --git a/crates/tauri-runtime/CHANGELOG.md b/crates/tauri-runtime/CHANGELOG.md new file mode 100644 index 000000000000..8970d59f66fb --- /dev/null +++ b/crates/tauri-runtime/CHANGELOG.md @@ -0,0 +1,929 @@ +# Changelog + +## \[2.2.0] + +### New Features + +- [`4d545ab3c`](https://www.github.com/tauri-apps/tauri/commit/4d545ab3ca228c8a21b966b709f84a0da2864479) ([#11486](https://www.github.com/tauri-apps/tauri/pull/11486) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `Window::set_background_color` and `WindowBuilder::background_color`. +- [`f37e97d41`](https://www.github.com/tauri-apps/tauri/commit/f37e97d410c4a219e99f97692da05ca9d8e0ba3a) ([#11477](https://www.github.com/tauri-apps/tauri/pull/11477) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindowBuilder/WebviewBuilder::use_https_scheme` to choose whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost` on Windows and Android +- [`cbc095ec5`](https://www.github.com/tauri-apps/tauri/commit/cbc095ec5fe7de29b5c9265576d4e071ec159c1c) ([#11451](https://www.github.com/tauri-apps/tauri/pull/11451) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindowBuilder::devtools` and `WebviewBuilder::devtools` to enable or disable devtools for a specific webview. +- [`2a75c64b5`](https://www.github.com/tauri-apps/tauri/commit/2a75c64b5431284e7340e8743d4ea56a62c75466) ([#11469](https://www.github.com/tauri-apps/tauri/pull/11469) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `WindowBuilder/WebviewWindowBuilder::window_classname` method to specify the name of the window class on Windows. + +### Bug Fixes + +- [`129414faa`](https://www.github.com/tauri-apps/tauri/commit/129414faa4e027c9035d56614682cacc0335a6a0) ([#11569](https://www.github.com/tauri-apps/tauri/pull/11569) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix webview not focused by default. + +### Dependencies + +- Upgraded to `tauri-utils@2.1.0` + +## \[2.1.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.2` + +## \[2.1.0] + +### Bug Fixes + +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix commands, that use `Webview` or `WebviewWindow` as an argument, receiving an incorrect webview when using multi webviews. +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix events only emitted to first webview only when using multi webviews. +- [`2d087ee4b`](https://www.github.com/tauri-apps/tauri/commit/2d087ee4b7d3e8849933f81284e4f5ed1aaa6455) ([#11268](https://www.github.com/tauri-apps/tauri/pull/11268) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) On Linux, fix custom protocols receiving an incorrect webview label when using multi webviews + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.1` + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0` + +## \[2.0.0-rc.13] + +### New Features + +- [`a247170e1`](https://www.github.com/tauri-apps/tauri/commit/a247170e1f620a9b012274b11cfe51e90327d6e9) ([#11056](https://www.github.com/tauri-apps/tauri/pull/11056) by [@SpikeHD](https://www.github.com/tauri-apps/tauri/../../SpikeHD)) Expose the ability to enabled browser extensions in WebView2 on Windows. +- [`9014a3f17`](https://www.github.com/tauri-apps/tauri/commit/9014a3f1765ca406ea5c3e5224267a79c52cd53d) ([#11066](https://www.github.com/tauri-apps/tauri/pull/11066) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewWindow::clear_all_browsing_data` and `Webview::clear_all_browsing_data` to clear the webview browsing data. +- [`95df53a2e`](https://www.github.com/tauri-apps/tauri/commit/95df53a2ed96873cd35a4b14a5e312d07e4e3004) ([#11143](https://www.github.com/tauri-apps/tauri/pull/11143) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Add the ability to set theme dynamically using `Window::set_theme`, `App::set_theme` +- [`d9d2502b4`](https://www.github.com/tauri-apps/tauri/commit/d9d2502b41e39efde679e30c8955006e2ba9ea64) ([#11140](https://www.github.com/tauri-apps/tauri/pull/11140) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `WebviewDispatch::hide` and `WebviewDispatch::show` methods. +- [`de7414aab`](https://www.github.com/tauri-apps/tauri/commit/de7414aab935e45540594ea930eb60bae4dbc979) ([#11154](https://www.github.com/tauri-apps/tauri/pull/11154) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `Window::set_enabled` and `Window::is_enabled` methods + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.13` + +## \[2.0.0-rc.12] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.12` + +## \[2.0.0-rc.11] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.11` + +## \[2.0.0-rc.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.10` + +## \[2.0.0-rc.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.9` + +## \[2.0.0-rc.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.8` + +## \[2.0.0-rc.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.7` + +## \[2.0.0-rc.6] + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.6` + +## \[2.0.0-rc.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.5` + +## \[2.0.0-rc.4] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.4` + +## \[2.0.0-rc.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.3` +- [`d39c392b7`](https://www.github.com/tauri-apps/tauri/commit/d39c392b7cec746da423211f9c74632abe4b6af5) ([#10655](https://www.github.com/tauri-apps/tauri/pull/10655) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Update `tao` to 0.29 and `wry` to 0.42. + +## \[2.0.0-rc.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.2` + +## \[2.0.0-rc.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.1` + +## \[2.0.0-rc.0] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-rc.0` + +## \[2.0.0-beta.21] + +### What's Changed + +- [`da25f7353`](https://www.github.com/tauri-apps/tauri/commit/da25f7353070477ba969851e974379d7666d6806) ([#10242](https://www.github.com/tauri-apps/tauri/pull/10242) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `inner_size_constraints` method on `WindowBuilder` trait and `set_size_constraints` method on `WindowDispatch` trait. + +## \[2.0.0-beta.20] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.19` + +## \[2.0.0-beta.19] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.18` +- [`d4c908cfb`](https://www.github.com/tauri-apps/tauri/commit/d4c908cfb8c567abdaf99b85f65f482ea81967e5) ([#10048](https://www.github.com/tauri-apps/tauri/pull/10048)) Update `windows` crate to version `0.57` and `webview2-com` crate to version `0.31` + +## \[2.0.0-beta.18] + +### Enhancements + +- [`276c4b143`](https://www.github.com/tauri-apps/tauri/commit/276c4b14385e17cff15a2e5b57fd2a7cddef9f08)([#9832](https://www.github.com/tauri-apps/tauri/pull/9832)) Added `WindowBuilder::get_theme`. + +### What's Changed + +- [`9ac930380`](https://www.github.com/tauri-apps/tauri/commit/9ac930380a5df3fe700e68e75df8684d261ca292)([#9850](https://www.github.com/tauri-apps/tauri/pull/9850)) Emit `cargo:rustc-check-cfg` instruction so Cargo validates custom cfg attributes on Rust 1.80 (or nightly-2024-05-05). + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.17` + +## \[2.0.0-beta.17] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.16` + +## \[2.0.0-beta.16] + +### New Features + +- [`78839b6d2`](https://www.github.com/tauri-apps/tauri/commit/78839b6d2f1005a5e6e1a54b0305136bae0c3a7c)([#4865](https://www.github.com/tauri-apps/tauri/pull/4865)) Add `RunEvent::Reopen` for handle click on dock icon on macOS. + +### What's Changed + +- [`783ef0f2d`](https://www.github.com/tauri-apps/tauri/commit/783ef0f2d331f520fa827c3112f36c0b519b9292)([#9647](https://www.github.com/tauri-apps/tauri/pull/9647)) Changed `WebviewDispatch::url` getter to return a result. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.15` + +## \[2.0.0-beta.15] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.14` + +## \[2.0.0-beta.14] + +### New Features + +- [`477bb8cd4`](https://www.github.com/tauri-apps/tauri/commit/477bb8cd4ea88ade3f6c1f268ad1701a68150161)([#9297](https://www.github.com/tauri-apps/tauri/pull/9297)) Add `App/AppHandle/Window/Webview/WebviewWindow::cursor_position` getter to get the current cursor position. + +## \[2.0.0-beta.13] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.13` + +## \[2.0.0-beta.12] + +### New Features + +- [`58a7a552d`](https://www.github.com/tauri-apps/tauri/commit/58a7a552d739b77b71d61af11c53f7f2dc7a6e7e)([#9378](https://www.github.com/tauri-apps/tauri/pull/9378)) Added the `set_zoom` function to the webview API. +- [`58a7a552d`](https://www.github.com/tauri-apps/tauri/commit/58a7a552d739b77b71d61af11c53f7f2dc7a6e7e)([#9378](https://www.github.com/tauri-apps/tauri/pull/9378)) Add `zoom_hotkeys_enabled` to enable browser native zoom controls on creating webviews. +- [`4973d73a2`](https://www.github.com/tauri-apps/tauri/commit/4973d73a237dc5c60618c1011e202278e7a29b5c)([#9386](https://www.github.com/tauri-apps/tauri/pull/9386)) Provide a basic zoom hotkey polyfill for non-Windows platforms + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.12` + +## \[2.0.0-beta.11] + +### What's Changed + +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Updated `http` crate to `1.1` + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.11` + +### Breaking Changes + +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) The IPC handler closure now receives a `http::Request` instead of a String representing the request body. +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Rename `FileDrop` to `DragDrop` on structs, enums and enum variants. Also renamed `file_drop` to `drag_drop` on fields and function names. +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Moved `window::dpi` module to the root of the crate. + +## \[2.0.0-beta.10] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.10` + +## \[2.0.0-beta.9] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.9` + +## \[2.0.0-beta.8] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.8` + +## \[2.0.0-beta.7] + +### New Features + +- [`46de49aaa`](https://www.github.com/tauri-apps/tauri/commit/46de49aaad4a148fafc31d591be0e2ed12256507)([#9059](https://www.github.com/tauri-apps/tauri/pull/9059)) Added `set_auto_resize` method for the webview. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.7` + +### Breaking Changes + +- [`d1e77acd8`](https://www.github.com/tauri-apps/tauri/commit/d1e77acd8dfdf554b90b542513a58a2de1ef2360)([#9011](https://www.github.com/tauri-apps/tauri/pull/9011)) Add a lifetime parameter for `Icon` type. Also changed `rgba` field to be `Cow<'a, [u8]>` + +## \[2.0.0-beta.6] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.6` + +## \[2.0.0-beta.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.5` + +## \[2.0.0-beta.4] + +### New Features + +- [`fdcaf935`](https://www.github.com/tauri-apps/tauri/commit/fdcaf935fa75ecfa2806939c4faad4fe9e880386)([#8939](https://www.github.com/tauri-apps/tauri/pull/8939)) Added the `reparent` function to the webview API. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.4` + +## \[2.0.0-beta.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.3` + +## \[2.0.0-beta.2] + +### What's Changed + +- [`16e550ec`](https://www.github.com/tauri-apps/tauri/commit/16e550ec1503765158cdc3bb2a20e70ec710e981)([#8844](https://www.github.com/tauri-apps/tauri/pull/8844)) Add `WebviewEvent`, `RunEvent::WebviewEvent` and `WebviewDispatch::on_webview_event`. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.2` + +### Breaking Changes + +- [`2f55bfec`](https://www.github.com/tauri-apps/tauri/commit/2f55bfecbf0244f3b5aa1ad7622182fca3fcdcbb)([#8795](https://www.github.com/tauri-apps/tauri/pull/8795)) Update raw-window-handle to 0.6. + +## \[2.0.0-beta.1] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.1` + +## \[2.0.0-beta.0] + +### New Features + +- [`af610232`](https://www.github.com/tauri-apps/tauri/commit/af6102327376884364b2075b468bdf08ee0d02aa)([#8710](https://www.github.com/tauri-apps/tauri/pull/8710)) Added `Window::destroy` to force close a window. +- [`c77b4032`](https://www.github.com/tauri-apps/tauri/commit/c77b40324ea9bf580871fc11aed69ba0c9b6b8cf)([#8280](https://www.github.com/tauri-apps/tauri/pull/8280)) Add multiwebview support behind the `unstable` feature flag. See `WindowBuilder` and `WebviewBuilder` for more information. +- [`00e15675`](https://www.github.com/tauri-apps/tauri/commit/00e1567584721644797b587205187f9cbe4e5cd1)([#8708](https://www.github.com/tauri-apps/tauri/pull/8708)) Added `RuntimeHandle::request_exit` function. + +### Bug Fixes + +- [`95da1a27`](https://www.github.com/tauri-apps/tauri/commit/95da1a27476e01e06f6ce0335df8535b662dd9c4)([#8713](https://www.github.com/tauri-apps/tauri/pull/8713)) Fix calling `set_activation_policy` when the event loop is running. + +### What's Changed + +- [`9eaeb5a8`](https://www.github.com/tauri-apps/tauri/commit/9eaeb5a8cd95ae24b5e66205bdc2763cb7f965ce)([#8622](https://www.github.com/tauri-apps/tauri/pull/8622)) Added `WindowBuilder::transient_for` and Renamed `WindowBuilder::owner_window` to `WindowBuilder::owner` and `WindowBuilder::parent_window` to `WindowBuilder::parent`. +- [`7f033f6d`](https://www.github.com/tauri-apps/tauri/commit/7f033f6dcd54c69a4193765a5c1584755ba92c61)([#8537](https://www.github.com/tauri-apps/tauri/pull/8537)) Add `Window::start_resize_dragging` and `ResizeDirection` enum. +- [`6639a579`](https://www.github.com/tauri-apps/tauri/commit/6639a579c76d45210f33a72d37e21d4c5a9d334b)([#8441](https://www.github.com/tauri-apps/tauri/pull/8441)) Added the `WindowConfig::proxy_url` `WebviewBuilder::proxy_url() / WebviewWindowBuilder::proxy_url()` options when creating a webview. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-beta.0` + +### Breaking Changes + +- [`9eaeb5a8`](https://www.github.com/tauri-apps/tauri/commit/9eaeb5a8cd95ae24b5e66205bdc2763cb7f965ce)([#8622](https://www.github.com/tauri-apps/tauri/pull/8622)) Changed `WindowBuilder::with_config` to take a reference to a `WindowConfig` instead of an owned value. + +## \[1.0.0-alpha.8] + +### New Features + +- [`29ced5ce`](https://www.github.com/tauri-apps/tauri/commit/29ced5ceec40b2934094ade2db9a8855f294e1d1)([#8159](https://www.github.com/tauri-apps/tauri/pull/8159)) Added download event closure via `PendingWindow::download_handler`. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.13` + +## \[1.0.0-alpha.7] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.12` + +## \[1.0.0-alpha.6] + +### Dependencies + +- [\`\`](https://www.github.com/tauri-apps/tauri/commit/undefined) Update dependencies. + +## \[1.0.0-alpha.5] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.11` + +## \[1.0.0-alpha.4] + +### New Features + +- [`74d2464d`](https://www.github.com/tauri-apps/tauri/commit/74d2464d0e490fae341ad73bdf2964cf215fe6c5)([#8116](https://www.github.com/tauri-apps/tauri/pull/8116)) Added `on_page_load` hook for `PendingWindow`. + +### Enhancements + +- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.10` +- [`9580df1d`](https://www.github.com/tauri-apps/tauri/commit/9580df1d7b027befb9e5f025ea2cbaf2dcc82c8e)([#8084](https://www.github.com/tauri-apps/tauri/pull/8084)) Upgrade `gtk` to 0.18. +- [`c7c2507d`](https://www.github.com/tauri-apps/tauri/commit/c7c2507da16a9beb71bf06745fe7ac1325ab7c2a)([#8035](https://www.github.com/tauri-apps/tauri/pull/8035)) Update `windows` to version `0.51` and `webview2-com` to version `0.27` + +## \[1.0.0-alpha.3] + +### New Features + +- [`c085adda`](https://www.github.com/tauri-apps/tauri/commit/c085addab58ba851398373c6fd13f9cb026d71e8)([#8009](https://www.github.com/tauri-apps/tauri/pull/8009)) Added `set_progress_bar` to `Window`. +- [`c1ec0f15`](https://www.github.com/tauri-apps/tauri/commit/c1ec0f155118527361dd5645d920becbc8afd569)([#7933](https://www.github.com/tauri-apps/tauri/pull/7933)) Added `Window::set_always_on_bottom` and the `always_on_bottom` option when creating a window. +- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70. + +### Enhancements + +- [`46dcb941`](https://www.github.com/tauri-apps/tauri/commit/46dcb94110ac16d0d4328fa149bb86975b658f59)([#8006](https://www.github.com/tauri-apps/tauri/pull/8006)) Include mobile on docs.rs targets. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.9` + +### Breaking Changes + +- [`2558fab8`](https://www.github.com/tauri-apps/tauri/commit/2558fab861006936296e8511e43ccd69a38f61b0)([#7939](https://www.github.com/tauri-apps/tauri/pull/7939)) Added `WindowEventId` type and Changed `Dispatch::on_window_event` return type from `Uuid` to `WindowEventId` + +## \[1.0.0-alpha.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.8` + +## \[1.0.0-alpha.1] + +### Enhancements + +- [`0d63732b`](https://www.github.com/tauri-apps/tauri/commit/0d63732b962e71b98430f8d7b34ea5b59a2e8bb4)([#7754](https://www.github.com/tauri-apps/tauri/pull/7754)) Changed custom protocol closure type to enable asynchronous usage. + +### What's Changed + +- [`6177150b`](https://www.github.com/tauri-apps/tauri/commit/6177150b6f83b52ca359d6e20f7e540f7554e4eb)([#7601](https://www.github.com/tauri-apps/tauri/pull/7601)) Changed `FileDropEvent` to include drop and hover position. + +### Breaking Changes + +- [`0d63732b`](https://www.github.com/tauri-apps/tauri/commit/0d63732b962e71b98430f8d7b34ea5b59a2e8bb4)([#7754](https://www.github.com/tauri-apps/tauri/pull/7754)) `tauri-runtime` no longer implements its own HTTP types and relies on the `http` crate instead. + +## \[1.0.0-alpha.0] + +### New Features + +- [`4db363a0`](https://www.github.com/tauri-apps/tauri/commit/4db363a03c182349f8491f46ced258d84723b11f)([#6589](https://www.github.com/tauri-apps/tauri/pull/6589)) Added `visible_on_all_workspaces` configuration option to `WindowBuilder`, `Window`, and `WindowConfig`. +- [`84c41597`](https://www.github.com/tauri-apps/tauri/commit/84c4159754b2e59244211ed9e1fc702d851a0562)([#6394](https://www.github.com/tauri-apps/tauri/pull/6394)) Added `primary_monitor` and `available_monitors` to `Runtime` and `RuntimeHandle`. +- [`2a000e15`](https://www.github.com/tauri-apps/tauri/commit/2a000e150d02dff28c8b20ad097b29e209160045)([#7235](https://www.github.com/tauri-apps/tauri/pull/7235)) Added `navigate` function to `Dispatch` trait. +- [`3b98141a`](https://www.github.com/tauri-apps/tauri/commit/3b98141aa26f74c641a4090874247b97079bd58a)([#3736](https://www.github.com/tauri-apps/tauri/pull/3736)) Added the `Opened` variant to `RunEvent`. + +### Dependencies + +- Upgraded to `tauri-utils@2.0.0-alpha.7` + +### Breaking Changes + +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) `Dispatch::create_window`, `Runtime::create_window` and `RuntimeHandle::create_window` has been changed to accept a 3rd parameter which is a closure that takes `RawWindow` and to be executed right after the window is created and before the webview is added to the window. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) System tray and menu related APIs and structs have all been removed and are now implemented in tauri outside of the runtime-space. +- [`3a2c3e74`](https://www.github.com/tauri-apps/tauri/commit/3a2c3e74710bef9a14932dce74c351cca6215429)([#7306](https://www.github.com/tauri-apps/tauri/pull/7306)) The `PendingWindow#navigation_handler` closure now receives a `&Url` argument instead of `Url`. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) `Runtime::new` and `Runtime::new_any_thread` now accept a `RuntimeInitArgs`. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) Removed `system-tray` feature flag + +## \[0.13.0-alpha.6] + +### New Features + +- [`e0f0dce2`](https://www.github.com/tauri-apps/tauri/commit/e0f0dce220730e2822fc202463aedf0166145de7)([#6442](https://www.github.com/tauri-apps/tauri/pull/6442)) Added the `window_effects` option when creating a window and `Window::set_effects` to change it at runtime. + +## \[0.13.0-alpha.5] + +- [`39f1b04f`](https://www.github.com/tauri-apps/tauri/commit/39f1b04f7be4966488484829cd54c8ce72a04200)([#6943](https://www.github.com/tauri-apps/tauri/pull/6943)) Moved the `event` JS APIs to a plugin. +- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65. +- [`cebd7526`](https://www.github.com/tauri-apps/tauri/commit/cebd75261ac71b98976314a450cb292eeeec1515)([#6728](https://www.github.com/tauri-apps/tauri/pull/6728)) Moved the `clipboard` feature to its own plugin in the plugins-workspace repository. +- [`3f17ee82`](https://www.github.com/tauri-apps/tauri/commit/3f17ee82f6ff21108806edb7b00500b8512b8dc7)([#6737](https://www.github.com/tauri-apps/tauri/pull/6737)) Moved the `global-shortcut` feature to its own plugin in the plugins-workspace repository. + +## \[0.13.0-alpha.4] + +- Added `android` configuration object under `tauri > bundle`. + - Bumped due to a bump in tauri-utils. + - [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07 + +## \[0.13.0-alpha.3] + +- Pull changes from Tauri 1.3 release. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[0.13.0-alpha.2] + +- Add `find_class`, `run_on_android_context` on `RuntimeHandle`. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 +- Added the `shadow` option when creating a window and `Window::set_shadow`. + - [a81750d7](https://www.github.com/tauri-apps/tauri/commit/a81750d779bc72f0fdb7de90b7fbddfd8049b328) feat(core): add shadow APIs ([#6206](https://www.github.com/tauri-apps/tauri/pull/6206)) on 2023-02-08 +- Implemented `with_webview` on Android and iOS. + - [05dad087](https://www.github.com/tauri-apps/tauri/commit/05dad0876842e2a7334431247d49365cee835d3e) feat: initial work for iOS plugins ([#6205](https://www.github.com/tauri-apps/tauri/pull/6205)) on 2023-02-11 + +## \[0.13.0-alpha.1] + +- Update gtk to 0.16. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Bump the MSRV to 1.64. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 + +## \[0.13.0-alpha.0] + +- Parse `android` and `ios` Tauri configuration files. + - Bumped due to a bump in tauri-utils. + - [b3a3afc7](https://www.github.com/tauri-apps/tauri/commit/b3a3afc7de8de4021d73559288f5192732a706cf) feat(core): detect android and ios platform configuration files ([#4997](https://www.github.com/tauri-apps/tauri/pull/4997)) on 2022-08-22 +- First mobile alpha release! + - Bumped due to a bump in tauri-utils. + - [fa3a1098](https://www.github.com/tauri-apps/tauri/commit/fa3a10988a03aed1b66fb17d893b1a9adb90f7cd) feat(ci): prepare 2.0.0-alpha.0 ([#5786](https://www.github.com/tauri-apps/tauri/pull/5786)) on 2022-12-08 + +## \[0.14.2] + +### Dependencies + +- Upgraded to `tauri-utils@1.5.2` + +## \[0.14.1] + +### Enhancements + +- [`9aa34ada`](https://www.github.com/tauri-apps/tauri/commit/9aa34ada5769dbefa7dfe5f7a6288b3d20b294e4)([#7645](https://www.github.com/tauri-apps/tauri/pull/7645)) Add setting to switch to `http://.localhost/` for custom protocols on Windows. + +### Dependencies + +- Upgraded to `tauri-utils@1.5.0` + +## \[0.14.0] + +### New Features + +- [`c4d6fb4b`](https://www.github.com/tauri-apps/tauri/commit/c4d6fb4b1ea8acf02707a9fe5dcab47c1c5bae7b)([#2353](https://www.github.com/tauri-apps/tauri/pull/2353)) Added the `maximizable`, `minimizable` and `closable` methods to `WindowBuilder`. +- [`c4d6fb4b`](https://www.github.com/tauri-apps/tauri/commit/c4d6fb4b1ea8acf02707a9fe5dcab47c1c5bae7b)([#2353](https://www.github.com/tauri-apps/tauri/pull/2353)) Added `set_maximizable`, `set_minimizable`, `set_closable`, `is_maximizable`, `is_minimizable` and `is_closable` methods to the `Dispatch` trait. +- [`000104bc`](https://www.github.com/tauri-apps/tauri/commit/000104bc3bc0c9ff3d20558ab9cf2080f126e9e0)([#6472](https://www.github.com/tauri-apps/tauri/pull/6472)) Add `Window::is_focused` getter. + +### Enhancements + +- [`d2710e9d`](https://www.github.com/tauri-apps/tauri/commit/d2710e9d2e8fd93975ef6494512370faa8cb3b7e)([#6944](https://www.github.com/tauri-apps/tauri/pull/6944)) Unpin `time`, `ignore`, and `winnow` crate versions. Developers now have to pin crates if needed themselves. A list of crates that need pinning to adhere to Tauri's MSRV will be visible in Tauri's GitHub workflow: https://github.com/tauri-apps/tauri/blob/dev/.github/workflows/test-core.yml#L85. + +### Bug Fixes + +- [`2b487c94`](https://www.github.com/tauri-apps/tauri/commit/2b487c946737352187d7e042dd6142873e62a4ca)([#7012](https://www.github.com/tauri-apps/tauri/pull/7012)) Fixes typo in `CursorIcon` deserialization of the `ZoomIn` variant. + +### What's Changed + +- [`076e1a81`](https://www.github.com/tauri-apps/tauri/commit/076e1a81a50468e3dfb34ae9ca7e77c5e1758daa)([#7119](https://www.github.com/tauri-apps/tauri/pull/7119)) Use `u32` instead of `u64` for js event listener ids +- [`ff5e4dbb`](https://www.github.com/tauri-apps/tauri/commit/ff5e4dbbb01bf3fc9c5143df732c75eef6fd98cb)([#6794](https://www.github.com/tauri-apps/tauri/pull/6794)) impl `From<&WindowConfig>` for `WebviewAttributes`. + +## \[0.13.0] + +- Added the `additional_browser_args` option when creating a window. + - [3dc38b15](https://www.github.com/tauri-apps/tauri/commit/3dc38b150ea8c59c8ba67fd586f921016928f47c) feat(core): expose additional_browser_args to window config (fix: [#5757](https://www.github.com/tauri-apps/tauri/pull/5757)) ([#5799](https://www.github.com/tauri-apps/tauri/pull/5799)) on 2022-12-14 +- Added the `content_protected` option when creating a window and `Window::set_content_protected` to change it at runtime. + - [4ab5545b](https://www.github.com/tauri-apps/tauri/commit/4ab5545b7a831c549f3c65e74de487ede3ab7ce5) feat: add content protection api, closes [#5132](https://www.github.com/tauri-apps/tauri/pull/5132) ([#5513](https://www.github.com/tauri-apps/tauri/pull/5513)) on 2022-12-13 +- Added `Builder::device_event_filter` and `App::set_device_event_filter` methods. + - [73fd60ee](https://www.github.com/tauri-apps/tauri/commit/73fd60eef2b60f5dc84525ef9c315f4d80c4414f) expose set_device_event_filter in tauri ([#5562](https://www.github.com/tauri-apps/tauri/pull/5562)) on 2022-12-13 +- Add `is_minimized()` window method. + - [62144ef3](https://www.github.com/tauri-apps/tauri/commit/62144ef3be63b237869e511826edfb938e2c7174) feat: add is_minimized (fix [#3878](https://www.github.com/tauri-apps/tauri/pull/3878)) ([#5618](https://www.github.com/tauri-apps/tauri/pull/5618)) on 2022-12-13 +- Bump minimum supported Rust version to 1.60. + - [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31 +- Pin raw-window-handle to 0.5.0 to keep MSRV. + - [c46c09f3](https://www.github.com/tauri-apps/tauri/commit/c46c09f31d9f5169ca8a7e62406a9ea170e3a5c5) fix(deps): pin raw-window-handle to 0.5.0 ([#6480](https://www.github.com/tauri-apps/tauri/pull/6480)) on 2023-03-17 +- Added `navigation_handler` field on `PendingWindow`. + - [3f35b452](https://www.github.com/tauri-apps/tauri/commit/3f35b452637ef1c794a423f1eda62a15d2ddaf42) Expose wry navigation_handler via WindowBuilder closes [#4080](https://www.github.com/tauri-apps/tauri/pull/4080) ([#5686](https://www.github.com/tauri-apps/tauri/pull/5686)) on 2022-12-27 +- Add `title` getter on window. + - [233e43b0](https://www.github.com/tauri-apps/tauri/commit/233e43b0c34fada1ca025378533a0b76931a6540) feat: add `title` getter on window, closes [#5023](https://www.github.com/tauri-apps/tauri/pull/5023) ([#5515](https://www.github.com/tauri-apps/tauri/pull/5515)) on 2022-12-13 +- Added `TrayHandle::set_tooltip` and `SystemTray::with_tooltip`. + - [2265e097](https://www.github.com/tauri-apps/tauri/commit/2265e09718f6ebfeb1d200f11e1e1e069075af6e) feat(windows): implement `with_tooltip` ([#5938](https://www.github.com/tauri-apps/tauri/pull/5938)) on 2023-01-01 +- Added window's `url()` getter. + - [d17027e1](https://www.github.com/tauri-apps/tauri/commit/d17027e1a0db3e8c5ae81fc4f472c5918fbce611) feat: expose url method ([#5914](https://www.github.com/tauri-apps/tauri/pull/5914)) on 2022-12-26 +- On Windows, change webview theme based on Window theme for more accurate `prefers-color-scheme` support. + - [7a8d570d](https://www.github.com/tauri-apps/tauri/commit/7a8d570db72667367eb24b75ddc5dd07a968f7c0) fix: sync webview theme with window theme on Windows, closes [#5802](https://www.github.com/tauri-apps/tauri/pull/5802) ([#5874](https://www.github.com/tauri-apps/tauri/pull/5874)) on 2022-12-27 + +## \[0.12.2] + +- Block remote URLs from accessing the IPC. + - [9c0593c33](https://www.github.com/tauri-apps/tauri/commit/9c0593c33af52cd9e00ec784d15f63efebdf039c) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.12.1] + +- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`. + - Bumped due to a bump in tauri-utils. + - [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18 + +## \[0.12.0] + +- Readd the option to create an unfocused window via the `focused` method. The `focus` function has been deprecated. + - [4036e15f](https://www.github.com/tauri-apps/tauri/commit/4036e15f5af933bdc0d0913508b5103958afc143) feat(core): reimplement window initial focus flag, closes [#5120](https://www.github.com/tauri-apps/tauri/pull/5120) ([#5338](https://www.github.com/tauri-apps/tauri/pull/5338)) on 2022-10-08 +- Added `Runtime::show()`, `RuntimeHandle::show()`, `Runtime::hide()`, `RuntimeHandle::hide()` for hiding/showing the entire application on macOS. + - [39bf895b](https://www.github.com/tauri-apps/tauri/commit/39bf895b73ec6b53f5758815396ba85dda6b9c67) feat(macOS): Add application `show` and `hide` methods ([#3689](https://www.github.com/tauri-apps/tauri/pull/3689)) on 2022-10-03 +- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28 +- Added `tabbing_identifier` to the window builder on macOS. + - [4137ab44](https://www.github.com/tauri-apps/tauri/commit/4137ab44a81d739556cbc7583485887e78952bf1) feat(macos): add `tabbing_identifier` option, closes [#2804](https://www.github.com/tauri-apps/tauri/pull/2804), [#3912](https://www.github.com/tauri-apps/tauri/pull/3912) ([#5399](https://www.github.com/tauri-apps/tauri/pull/5399)) on 2022-10-19 +- Added methods to set the system tray title on macOS. + - [8f1ace77](https://www.github.com/tauri-apps/tauri/commit/8f1ace77956ac3477826ceb059a191e55b3fff93) feat: expose `set_title` for MacOS tray ([#5182](https://www.github.com/tauri-apps/tauri/pull/5182)) on 2022-09-30 +- Added the `user_agent` option when creating a window. + - [a6c94119](https://www.github.com/tauri-apps/tauri/commit/a6c94119d8545d509723b147c273ca5edfe3729f) feat(core): expose user_agent to window config ([#5317](https://www.github.com/tauri-apps/tauri/pull/5317)) on 2022-10-02 + +## \[0.11.2] + +- Block remote URLs from accessing the IPC. + - [58ea0b452](https://www.github.com/tauri-apps/tauri/commit/58ea0b45268dbd46cbac0ebb0887353d057ca767) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.11.1] + +- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs. + - Bumped due to a bump in tauri-utils. + - [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16 + +## \[0.11.0] + +- Added APIs to create a system tray at runtime. + - [4d063ae9](https://www.github.com/tauri-apps/tauri/commit/4d063ae9ee9538cd6fa5e01b80070c6edf8eaeb9) feat(core): create system tray at runtime, closes [#2278](https://www.github.com/tauri-apps/tauri/pull/2278) ([#4862](https://www.github.com/tauri-apps/tauri/pull/4862)) on 2022-08-09 +- Update windows to 0.39.0 and webview2-com to 0.19.1. + - [e6d9b670](https://www.github.com/tauri-apps/tauri/commit/e6d9b670b0b314ed667b0e164f2c8d27048e678f) refactor: remove unneeded focus code ([#5065](https://www.github.com/tauri-apps/tauri/pull/5065)) on 2022-09-03 + +## \[0.10.3] + +- Block remote URLs from accessing the IPC. + - [fa90214b0](https://www.github.com/tauri-apps/tauri/commit/fa90214b052b1a5d38d54fbf1ca422b4c37cfd1f) feat(core): block remote URLs from accessing the IPC on 2023-04-12 + +## \[0.10.2] + +- Added option to disable tray menu on left click on macOS. + - [f8a3becb](https://www.github.com/tauri-apps/tauri/commit/f8a3becb287942db7f7b551b5db6aeb5a2e939ee) feat(core): add option to disable tray menu on left click, closes [#4584](https://www.github.com/tauri-apps/tauri/pull/4584) ([#4587](https://www.github.com/tauri-apps/tauri/pull/4587)) on 2022-07-05 + +## \[0.10.1] + +- Expose `platform::windows_version` function. + - Bumped due to a bump in tauri-utils. + - [bf764e83](https://www.github.com/tauri-apps/tauri/commit/bf764e83e01e7443e6cc54572001e1c98c357465) feat(utils): expose `windows_version` function ([#4534](https://www.github.com/tauri-apps/tauri/pull/4534)) on 2022-06-30 + +## \[0.10.0] + +- Added `fn new` constructors for `PhysicalSize`, `LogicalSize`, `PhysicalPosition` and `LogicalPosition` and missing conversion methods. + - [c7d13a1c](https://www.github.com/tauri-apps/tauri/commit/c7d13a1c60cdbe0c42834ea059321d7a3a7f01a0) feat(core): add missing methods to the dpi module ([#4393](https://www.github.com/tauri-apps/tauri/pull/4393)) on 2022-06-19 +- Implement `raw_window_handle::HasRawWindowHandle` on Linux. + - [3efbc67f](https://www.github.com/tauri-apps/tauri/commit/3efbc67f7469ce65a2d9ea4ff2b60b51d2a36aa5) feat: implement `raw_window_handle` on Linux ([#4469](https://www.github.com/tauri-apps/tauri/pull/4469)) on 2022-06-26 +- Removed the `hwnd` and `ns_window` functions from `Dispatch` in favor of `raw_window_handle`. + - [3efbc67f](https://www.github.com/tauri-apps/tauri/commit/3efbc67f7469ce65a2d9ea4ff2b60b51d2a36aa5) feat: implement `raw_window_handle` on Linux ([#4469](https://www.github.com/tauri-apps/tauri/pull/4469)) on 2022-06-26 +- The theme API is now implemented on macOS 10.14+. + - [6d94ce42](https://www.github.com/tauri-apps/tauri/commit/6d94ce42353204a02fe9c82ed397d349439f75ef) feat(core): theme is now implemented on macOS ([#4380](https://www.github.com/tauri-apps/tauri/pull/4380)) on 2022-06-17 + +## \[0.9.0] + +- Upgrade to `stable`! + - Bumped due to a bump in tauri-utils. + - [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15 + +## \[0.8.1] + +- Add `Menu::os_default` which will create a menu filled with default menu items and submenus. + - [4c4acc30](https://www.github.com/tauri-apps/tauri/commit/4c4acc3094218dd9cee0f1ad61810c979e0b41fa) feat: implement `Default` for `Menu`, closes [#2398](https://www.github.com/tauri-apps/tauri/pull/2398) ([#4291](https://www.github.com/tauri-apps/tauri/pull/4291)) on 2022-06-15 + +## \[0.8.0] + +- Removed `TrayIcon` and renamed `WindowIcon` to `Icon`, a shared type for both icons. + - [4ce8e228](https://www.github.com/tauri-apps/tauri/commit/4ce8e228134cd3f22973b74ef26ca0d165fbbbd9) refactor(core): use `Icon` for tray icons ([#4342](https://www.github.com/tauri-apps/tauri/pull/4342)) on 2022-06-14 + +## \[0.7.0] + +- Added a config flag to bundle the media framework used by webkit2gtk `tauri.conf.json > tauri > bundle > appimage > bundleMediaFramework`. + - Bumped due to a bump in tauri-utils. + - [d335fae9](https://www.github.com/tauri-apps/tauri/commit/d335fae92cdcbb0ee18aad4e54558914afa3e778) feat(bundler): bundle additional gstreamer files, closes [#4092](https://www.github.com/tauri-apps/tauri/pull/4092) ([#4271](https://www.github.com/tauri-apps/tauri/pull/4271)) on 2022-06-10 + +## \[0.6.0] + +- Update `windows-rs` to `0.37.0`, which requires Rust 1.61.0+. + - [2326be39](https://www.github.com/tauri-apps/tauri/commit/2326be39821890cdd4de76e7029a531424dcb26f) feat(core): update windows-rs to 0.37.0 ([#4199](https://www.github.com/tauri-apps/tauri/pull/4199)) on 2022-05-24 + +## \[0.5.1] + +- Fix `.mjs` not being recognised as a file extension for JavaScript files (`text/javascript`). + - [45c45253](https://www.github.com/tauri-apps/tauri/commit/45c45253866ce0de317a6a547af3ea0434d4bcac) fix: add mjs mime type (fix: [#4098](https://www.github.com/tauri-apps/tauri/pull/4098)) ([#4108](https://www.github.com/tauri-apps/tauri/pull/4108)) on 2022-05-13 + +## \[0.5.0] + +- Expose methods to access the underlying native handles of the webview. + - [c82b4761](https://www.github.com/tauri-apps/tauri/commit/c82b4761e1660592472dc55308ad69d9efc5855b) feat(core): expose `with_webview` API to access the platform webview ([#4058](https://www.github.com/tauri-apps/tauri/pull/4058)) on 2022-05-04 + +## \[0.4.0] + +- The `AboutMetadata` string setters now take `impl Into`. + - [b14aa896](https://www.github.com/tauri-apps/tauri/commit/b14aa89673c3563522e5c04baf9630fa1c4739b0) feat(core): improve `AboutMetadata` setters on 2022-03-29 +- \**Breaking change::* Added the `clipboard` Cargo feature. + - [24e4ff20](https://www.github.com/tauri-apps/tauri/commit/24e4ff208ee0fe1a4cc5b10667ea0922ac63dfb5) refactor(core): add clipboard Cargo feature, enhancing binary size ([#3957](https://www.github.com/tauri-apps/tauri/pull/3957)) on 2022-04-24 +- Expose Window cursor APIs `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position`. + - [c54ddfe9](https://www.github.com/tauri-apps/tauri/commit/c54ddfe9338e7eb90b4d5b02dfde687d432d5bc1) feat: expose window cursor APIs, closes [#3888](https://www.github.com/tauri-apps/tauri/pull/3888) [#3890](https://www.github.com/tauri-apps/tauri/pull/3890) ([#3935](https://www.github.com/tauri-apps/tauri/pull/3935)) on 2022-04-21 +- \**Breaking change::* Added the `global-shortcut` Cargo feature. + - [e11878bc](https://www.github.com/tauri-apps/tauri/commit/e11878bcf7174b261a1fa146fc7d564d12e6312a) refactor(core): add global-shortcut Cargo feature, enhancing binary size ([#3956](https://www.github.com/tauri-apps/tauri/pull/3956)) on 2022-04-24 +- Added `WindowEvent::ThemeChanged(theme)`. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 +- Added `theme` getter on `Window`. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 +- Added `theme` setter to the WindowBuilder. + - [4cebcf6d](https://www.github.com/tauri-apps/tauri/commit/4cebcf6da7cad1953e0f01b426afac3b5ef1f81e) feat: expose theme APIs, closes [#3903](https://www.github.com/tauri-apps/tauri/pull/3903) ([#3937](https://www.github.com/tauri-apps/tauri/pull/3937)) on 2022-04-21 + +## \[0.3.4] + +- Added `close_devtools` and `is_devtools_open` APIs to the `Dispatch` trait. + - [e05d718a](https://www.github.com/tauri-apps/tauri/commit/e05d718a7b46476d1fe4817c169008080e84f959) feat(core): add hotkey to toggle devtools, closes [#3776](https://www.github.com/tauri-apps/tauri/pull/3776) ([#3791](https://www.github.com/tauri-apps/tauri/pull/3791)) on 2022-03-28 +- **Breaking change:** The `MenuItem::About` variant is now associated with a tuple value `(String, AboutMetadata)`. + - [5fb74332](https://www.github.com/tauri-apps/tauri/commit/5fb74332ab9210ac062d96b0e9afd1c942ee2911) chore(deps): update wry to 0.14, tao to 0.7 ([#3790](https://www.github.com/tauri-apps/tauri/pull/3790)) on 2022-03-28 +- Support window parenting on macOS + - [4e807a53](https://www.github.com/tauri-apps/tauri/commit/4e807a53e2d6d3f3cd5293d90013d5cdded5454e) Support window parenting on macOS, closes [#3751](https://www.github.com/tauri-apps/tauri/pull/3751) ([#3754](https://www.github.com/tauri-apps/tauri/pull/3754)) on 2022-03-23 +- The file drop event is now part of the `WindowEvent` enum instead of a having a dedicated handler. + - [07d1584c](https://www.github.com/tauri-apps/tauri/commit/07d1584cf06ea326aa45d8044bee1b77ecba5006) feat(core): add `WindowEvent::FileDrop`, closes [#3664](https://www.github.com/tauri-apps/tauri/pull/3664) ([#3686](https://www.github.com/tauri-apps/tauri/pull/3686)) on 2022-03-13 +- **Breaking change:** Use the dedicated `WindowEvent` enum on `RunEvent`. + - [edad9f4f](https://www.github.com/tauri-apps/tauri/commit/edad9f4f55dcc69a06cd9d6d5a5068c94ecb77dd) refactor(core): add `RunEvent::WindowEvent` ([#3793](https://www.github.com/tauri-apps/tauri/pull/3793)) on 2022-03-28 +- Added `create_proxy` to the `Runtime` and `RuntimeHandle` traits. + - [5d538ec2](https://www.github.com/tauri-apps/tauri/commit/5d538ec27c246274df4ff5b8057ff78b6364a43f) refactor(core): use the event loop proxy to send updater events ([#3687](https://www.github.com/tauri-apps/tauri/pull/3687)) on 2022-03-15 +- Force `Error` boxed errors to be `Sync`. + - [da1e8793](https://www.github.com/tauri-apps/tauri/commit/da1e879358895f7b190b1c1b20d23da23666a74b) feat(core): improve and cleanup the `Error` enum ([#3748](https://www.github.com/tauri-apps/tauri/pull/3748)) on 2022-03-22 +- **Breaking change:** Move the `FileDropEvent` struct to the `window` module. + - [07d1584c](https://www.github.com/tauri-apps/tauri/commit/07d1584cf06ea326aa45d8044bee1b77ecba5006) feat(core): add `WindowEvent::FileDrop`, closes [#3664](https://www.github.com/tauri-apps/tauri/pull/3664) ([#3686](https://www.github.com/tauri-apps/tauri/pull/3686)) on 2022-03-13 +- Allow specifying a user event type for the event loop message. + - [5d538ec2](https://www.github.com/tauri-apps/tauri/commit/5d538ec27c246274df4ff5b8057ff78b6364a43f) refactor(core): use the event loop proxy to send updater events ([#3687](https://www.github.com/tauri-apps/tauri/pull/3687)) on 2022-03-15 +- Added the `WindowEvent::FileDrop` variant. + - [07d1584c](https://www.github.com/tauri-apps/tauri/commit/07d1584cf06ea326aa45d8044bee1b77ecba5006) feat(core): add `WindowEvent::FileDrop`, closes [#3664](https://www.github.com/tauri-apps/tauri/pull/3664) ([#3686](https://www.github.com/tauri-apps/tauri/pull/3686)) on 2022-03-13 + +## \[0.3.3] + +- **Breaking change:** Move `ico` and `png` parsing behind `icon-ico` and `icon-png` Cargo features. + - [8c935872](https://www.github.com/tauri-apps/tauri/commit/8c9358725a17dcc2acaf4d10c3f654afdff586b0) refactor(core): move `png` and `ico` behind Cargo features ([#3588](https://www.github.com/tauri-apps/tauri/pull/3588)) on 2022-03-05 +- The `PendingWindow::new` and `PendingWindow::with_config` functions now return `Result` validating the window label. + - [64e00542](https://www.github.com/tauri-apps/tauri/commit/64e0054299c95f10ef5a1a9d3f914bbaeff3d73f) refactor(core): do not panic on invalid window labels,[#3544](https://www.github.com/tauri-apps/tauri/pull/3544) ([#3596](https://www.github.com/tauri-apps/tauri/pull/3596)) on 2022-03-03 + +## \[0.3.2] + +- Fix requirements for `RuntimeHandle`, `ClipboardManager`, `GlobalShortcutHandle` and `TrayHandle`. + - [84895a9c](https://www.github.com/tauri-apps/tauri/commit/84895a9cd270fc743e236d0f4d4cd6210b24a30f) fix(runtime): trait requirements ([#3489](https://www.github.com/tauri-apps/tauri/pull/3489)) on 2022-02-17 + +## \[0.3.1] + +- Change default value for the `freezePrototype` configuration to `false`. + - Bumped due to a bump in tauri-utils. + - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 + +## \[0.3.0] + +- Replace `WindowBuilder`'s `has_menu` with `get_menu`. + - [ac37b56e](https://www.github.com/tauri-apps/tauri/commit/ac37b56ef43c9e97039967a5fd99f0d2dccb5b5a) fix(core): menu id map not reflecting the current window menu ([#2726](https://www.github.com/tauri-apps/tauri/pull/2726)) on 2021-10-08 +- The `run_return` API is now available on Linux. + - [8483fde9](https://www.github.com/tauri-apps/tauri/commit/8483fde975aac8833d2ce426e42fb40aeaeecba9) feat(core): expose `run_return` on Linux ([#3352](https://www.github.com/tauri-apps/tauri/pull/3352)) on 2022-02-07 +- Add `Menu::with_items` constructor, taking an iterator of `MenuEntry`. + - [7cc95e10](https://www.github.com/tauri-apps/tauri/commit/7cc95e10ec66d8b155e9bb7f89cf73df56d1f107) feat(core): add `Menu::with_items`, closes [#2807](https://www.github.com/tauri-apps/tauri/pull/2807) ([#2966](https://www.github.com/tauri-apps/tauri/pull/2966)) on 2021-12-27 +- Change event loop callbacks definition to allow callers to move in mutable values. + - [bdbf905e](https://www.github.com/tauri-apps/tauri/commit/bdbf905e5d802b58693d2bd27582ce4269faf79c) Transformed event-loop callback to FnMut to allow mutable values ([#2667](https://www.github.com/tauri-apps/tauri/pull/2667)) on 2021-09-27 +- Added `any_thread` constructor on the `Runtime` trait (only possible on Linux and Windows). + - [af44bf81](https://www.github.com/tauri-apps/tauri/commit/af44bf8168310cf77fbe102a53e7c433f11641a3) feat(core): allow app run on any thread on Linux & Windows, closes [#3172](https://www.github.com/tauri-apps/tauri/pull/3172) ([#3353](https://www.github.com/tauri-apps/tauri/pull/3353)) on 2022-02-07 +- Added `run_on_main_thread` API on `RuntimeHandle`. + - [53fdfe52](https://www.github.com/tauri-apps/tauri/commit/53fdfe52bb30d52653c72ca9f42506c3863dcf4a) feat(core): expose `run_on_main_thread` API ([#2711](https://www.github.com/tauri-apps/tauri/pull/2711)) on 2021-10-04 +- **Breaking change:** Renamed the `RPC` interface to `IPC`. + - [3420aa50](https://www.github.com/tauri-apps/tauri/commit/3420aa5031b3274a95c6c5fa0f8683ca13213396) refactor: IPC handler \[TRI-019] ([#9](https://www.github.com/tauri-apps/tauri/pull/9)) on 2022-01-09 +- Added `open_devtools` to the `Dispatcher` trait. + - [55aa22de](https://www.github.com/tauri-apps/tauri/commit/55aa22de80c3de873e29bcffcb5b2fe236a637a6) feat(core): add `Window#open_devtools` API, closes [#1213](https://www.github.com/tauri-apps/tauri/pull/1213) ([#3350](https://www.github.com/tauri-apps/tauri/pull/3350)) on 2022-02-07 +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 +- The window label is now validated and must be alphanumeric, resulting in a panic if it isn't. + - [680554de](https://www.github.com/tauri-apps/tauri/commit/680554de3ef6b7fccf87c441ad355cfef7aab6fe) feat: validate window label \[TRI-021] ([#13](https://www.github.com/tauri-apps/tauri/pull/13)) on 2021-10-23 +- Added `clipboard` field on the `WebviewAttributes` struct, which must be set to `true` to enable clipboard access on the webview. + - [d42ccfb3](https://www.github.com/tauri-apps/tauri/commit/d42ccfb34f71851dfeb22fe74c83a8bdbddb5550) feat: add `clipboard` flag to `WebviewAttributes` \[TRI-032] ([#12](https://www.github.com/tauri-apps/tauri/pull/12)) on 2021-10-23 +- Replace all of the `winapi` crate references with the `windows` crate, and replace `webview2` and `webview2-sys` with `webview2-com` and `webview2-com-sys` built with the `windows` crate. This goes along with updates to the TAO and WRY `next` branches. + - [bb00d5bd](https://www.github.com/tauri-apps/tauri/commit/bb00d5bd6c9dfcb6bdd0d308dadb70e6c6aafe5c) Replace winapi with windows crate and use webview2-com instead of webview2 ([#2615](https://www.github.com/tauri-apps/tauri/pull/2615)) on 2021-09-24 +- Update the `windows` crate to 0.25.0, which comes with pre-built libraries. WRY and Tao can both reference the same types directly from the `windows` crate instead of sharing bindings in `webview2-com-sys`. + - [34be6cf3](https://www.github.com/tauri-apps/tauri/commit/34be6cf37a98ee7cbd66623ebddae08e5a6520fd) Update webview2-com and windows crates ([#2875](https://www.github.com/tauri-apps/tauri/pull/2875)) on 2021-11-11 + +## \[0.2.1] + +- **Breaking change:** Removed `register_uri_scheme_protocol` from the `WebviewAttributes` struct and renamed `register_global_uri_scheme_protocol` to `register_uri_scheme_protocol` on the `Builder` struct, which now takes a `Fn(&AppHandle, &http::Request) -> http::Response` closure. + - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 +- Migrate to latest custom protocol allowing `Partial content` streaming and Header parsing. + - [539e4489](https://www.github.com/tauri-apps/tauri/commit/539e4489e0bac7029d86917e9982ea49e02fe489) refactor: custom protocol ([#2503](https://www.github.com/tauri-apps/tauri/pull/2503)) on 2021-08-23 + +## \[0.2.0] + +- Fix blur/focus events being incorrect on Windows. + - [d832d575](https://www.github.com/tauri-apps/tauri/commit/d832d575d9b03a0ff78accabe4631cc638c08c3b) fix(windows): use webview events on windows ([#2277](https://www.github.com/tauri-apps/tauri/pull/2277)) on 2021-07-23 + +- Add `ExitRequested` event that allows preventing the app from exiting when all windows are closed, and an `AppHandle.exit()` function to exit the app manually. + - [892c63a0](https://www.github.com/tauri-apps/tauri/commit/892c63a0538f8d62680dce5848657128ad6b7af3) feat([#2287](https://www.github.com/tauri-apps/tauri/pull/2287)): Add `ExitRequested` event to let users prevent app from exiting ([#2293](https://www.github.com/tauri-apps/tauri/pull/2293)) on 2021-08-09 + +- Fixes minimum window height being used as maximum height. + - [e3f99165](https://www.github.com/tauri-apps/tauri/commit/e3f9916526b226866137cb663e5cafab2b6a0e01) fix(core) minHeight being used as maxHeight ([#2247](https://www.github.com/tauri-apps/tauri/pull/2247)) on 2021-07-19 + +- Update gtk and its related libraries to v0.14. This also remove requirements of `clang` as build dependency. + - [63ad3039](https://www.github.com/tauri-apps/tauri/commit/63ad303903bbee7c9a7382413b342e2a05d3ea75) chore(linux): bump gtk to v0.14 ([#2361](https://www.github.com/tauri-apps/tauri/pull/2361)) on 2021-08-07 + +- Implement `Debug` on public API structs and enums. + - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 + +- Panic when a dispatcher getter method (`Window`, `GlobalShortcutHandle`, `ClipboardManager` and `MenuHandle` APIs) is called on the main thread. + - [50ffdc06](https://www.github.com/tauri-apps/tauri/commit/50ffdc06fbde56aba32b4291fd130104935d1408) feat(core): panic when a dispatcher getter is used on the main thread ([#2455](https://www.github.com/tauri-apps/tauri/pull/2455)) on 2021-08-16 + +- Remove menu feature flag since there's no package dependency need to be installed on any platform anymore. + - [f81ebddf](https://www.github.com/tauri-apps/tauri/commit/f81ebddfcc1aea0d4989706aef43538e8ea98bea) feat: remove menu feature flag ([#2415](https://www.github.com/tauri-apps/tauri/pull/2415)) on 2021-08-13 + +- Adds `Resumed` and `MainEventsCleared` variants to the `RunEvent` enum. + - [6be3f433](https://www.github.com/tauri-apps/tauri/commit/6be3f4339168651fe4e003b09f7d181fd12cd5a8) feat(core): add `Resumed` and `MainEventsCleared` events, closes [#2127](https://www.github.com/tauri-apps/tauri/pull/2127) ([#2439](https://www.github.com/tauri-apps/tauri/pull/2439)) on 2021-08-15 + +- Adds `set_activation_policy` API to the `Runtime` trait (macOS only). + - [4a031add](https://www.github.com/tauri-apps/tauri/commit/4a031add69014a1f3823f4ea19b172a2557f6794) feat(core): expose `set_activation_policy`, closes [#2258](https://www.github.com/tauri-apps/tauri/pull/2258) ([#2420](https://www.github.com/tauri-apps/tauri/pull/2420)) on 2021-08-13 + +- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. + - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 + - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 + +- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. + +- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. + +- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 + +- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. + - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 + +## \[0.1.4] + +- Allow preventing window close when the user requests it. + - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 +- Expose `gtk_window` getter. + - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 +- `Params` has been removed, along with all the associated types on it. Functions that previously accepted those + associated types now accept strings instead. Type that used a generic parameter `Params` now use `Runtime` instead. If + you use the `wry` feature, then types with a `Runtime` generic parameter should default to `Wry`, letting you omit the + explicit type and let the compiler infer it instead. + +`tauri`: + +- See `Params` note +- If you were using `Params` inside a function parameter or definition, all references to it have been replaced with a + simple runtime that defaults to `Wry`. If you are not using a custom runtime, just remove `Params` from the definition + of functions/items that previously took it. If you are using a custom runtime, you *may* need to pass the runtime type + to these functions. +- If you were using custom types for `Params` (uncommon and if you don't understand you probably were not using it), all + methods that were previously taking the custom type now takes an `Into` or a `&str`. The types were already + required to be string-able, so just make sure to convert it into a string before passing it in if this breaking change + affects you. + +`tauri-macros`: + +- (internal) Added private `default_runtime` proc macro to allow us to give item definitions a custom runtime only when + the specified feature is enabled. + +`tauri-runtime`: + +- See `Params` note +- Removed `Params`, `MenuId`, `Tag`, `TagRef`. +- Added `menu::{MenuHash, MenuId, MenuIdRef}` as type aliases for the internal type that menu types now use. + - All previous menu items that had a `MenuId` generic now use the underlying `MenuId` type without a generic. +- `Runtime`, `RuntimeHandle`, and `Dispatch` have no more generic parameter on `create_window(...)` and instead use the + `Runtime` type directly +- `Runtime::system_tray` has no more `MenuId` generic and uses the string based `SystemTray` type directly. +- (internal) `CustomMenuItem::id_value()` is now hashed on creation and exposed as the `id` field with type `MenuHash`. + +`tauri-runtime-wry`: + +- See `Params` note +- update menu and runtime related types to the ones changed in `tauri-runtime`. + +`tauri-utils`: + +- `Assets::get` signature has changed to take a `&AssetKey` instead of `impl Into` to become trait object + safe. +- [fd8fab50](https://www.github.com/tauri-apps/tauri/commit/fd8fab507c8fa1b113b841af14c6693eb3955f6b) refactor(core): remove `Params` and replace with strings ([#2191](https://www.github.com/tauri-apps/tauri/pull/2191)) on 2021-07-15 + +## \[0.1.3] + +- `Window` is now `Send + Sync` on Windows. + - [fe32afcc](https://www.github.com/tauri-apps/tauri/commit/fe32afcc933920d6282ae1d63b041b182278a031) fix(core): `Window` must be `Send + Sync` on Windows, closes [#2078](https://www.github.com/tauri-apps/tauri/pull/2078) ([#2093](https://www.github.com/tauri-apps/tauri/pull/2093)) on 2021-06-27 + +## \[0.1.2] + +- Adds `clipboard` APIs (write and read text). + - [285bf64b](https://www.github.com/tauri-apps/tauri/commit/285bf64bf9569efb2df904c69c6df405ff0d62e2) feat(core): add clipboard writeText and readText APIs ([#2035](https://www.github.com/tauri-apps/tauri/pull/2035)) on 2021-06-21 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `focus` API to the WindowBuilder. + - [5f351622](https://www.github.com/tauri-apps/tauri/commit/5f351622c7812ad1bb56ddb37364ccaa4124c24b) feat(core): add focus API to the WindowBuilder and WindowOptions, [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `is_decorated` getter on Window. + - [f58a2114](https://www.github.com/tauri-apps/tauri/commit/f58a2114fbfd5307c349f05c88f2e08fd8baa8aa) feat(core): add `is_decorated` Window getter on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `is_resizable` getter on Window. + - [1e8af280](https://www.github.com/tauri-apps/tauri/commit/1e8af280c27f381828d6209722b10e889082fa00) feat(core): add `is_resizable` Window getter on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `is_visible` getter on Window. + - [36506c96](https://www.github.com/tauri-apps/tauri/commit/36506c967de82bc7ff453d11e6104ecf66d7a588) feat(core): add `is_visible` API on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `accelerator` method to the `CustomMenuItem` struct to define a keyboard shortcut for the menu item. + - [034c2601](https://www.github.com/tauri-apps/tauri/commit/034c26013bce0c7bbe6db067ea7fd24a53a5c998) feat(core): add `accelerator` method to `CustomMenuItem` ([#2043](https://www.github.com/tauri-apps/tauri/pull/2043)) on 2021-06-22 +- Adds global shortcut interfaces. + - [3280c4aa](https://www.github.com/tauri-apps/tauri/commit/3280c4aa91e50a8ccdd561a8b48a12a4a13ea8d5) refactor(core): global shortcut is now provided by `tao` ([#2031](https://www.github.com/tauri-apps/tauri/pull/2031)) on 2021-06-21 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `request_user_attention` API to the `Dispatcher` trait. + - [7dcca6e9](https://www.github.com/tauri-apps/tauri/commit/7dcca6e9281182b11ad3d4a79871f09b30b9b419) feat(core): add `request_user_attention` API, closes [#2023](https://www.github.com/tauri-apps/tauri/pull/2023) ([#2026](https://www.github.com/tauri-apps/tauri/pull/2026)) on 2021-06-20 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `fn run_iteration` (macOS and Windows only) to the Runtime trait. + - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 +- Adds `show_menu`, `hide_menu` and `is_menu_visible` APIs to the `Dispatcher` trait. + - [954460c5](https://www.github.com/tauri-apps/tauri/commit/954460c5205d57444ef4b1412051fbedf3e38676) feat(core): MenuHandle `show`, `hide`, `is_visible` and `toggle` APIs ([#1958](https://www.github.com/tauri-apps/tauri/pull/1958)) on 2021-06-15 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `set_focus` API on Window. + - [bb6992f8](https://www.github.com/tauri-apps/tauri/commit/bb6992f888196ca7c87bb2fe74ad2bd8bf393e05) feat(core): add `set_focus` window API, fixes [#1737](https://www.github.com/tauri-apps/tauri/pull/1737) on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `set_skip_taskbar` API on Window. + - [e06aa277](https://www.github.com/tauri-apps/tauri/commit/e06aa277384450cfef617c0e57b0d5d403bb1e7f) feat(core): add `set_skip_taskbar` API on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `skip_taskbar` API to the WindowBuilder. + - [5525b03a](https://www.github.com/tauri-apps/tauri/commit/5525b03a78a2232c650043fbd9894ce1553cad41) feat(core): add `skip_taskbar` API to the WindowBuilder/WindowOptions on 2021-05-30 + - [dee71ad5](https://www.github.com/tauri-apps/tauri/commit/dee71ad58349f699995cc9077b79032bacc6afcb) fix(workflows): update docs workflow syntax ([#2054](https://www.github.com/tauri-apps/tauri/pull/2054)) on 2021-06-23 +- Adds `Window#center` and `WindowBuilder#center` APIs. + - [5cba6eb4](https://www.github.com/tauri-apps/tauri/commit/5cba6eb4d28d53f06855d60d4d0eae6b95233ccf) feat(core): add window `center` API, closes [#1822](https://www.github.com/tauri-apps/tauri/pull/1822) ([#1954](https://www.github.com/tauri-apps/tauri/pull/1954)) on 2021-06-05 +- Adds `parent_window` and `owner_window` setters to the `WindowBuilder` (Windows only). + - [8c0d0739](https://www.github.com/tauri-apps/tauri/commit/8c0d0739eebf7286b64a5380e922746411eb52c6) feat(core): add `run_iteration`, `parent_window` and `owner_window` APIs, closes [#1872](https://www.github.com/tauri-apps/tauri/pull/1872) ([#1874](https://www.github.com/tauri-apps/tauri/pull/1874)) on 2021-05-21 +- Adds window native handle getter (HWND on Windows). + - [abf78c58](https://www.github.com/tauri-apps/tauri/commit/abf78c5860cdc52fbfd2bc5dbca29a864e2da8f9) fix(core): set parent window handle on dialogs, closes [#1876](https://www.github.com/tauri-apps/tauri/pull/1876) ([#1889](https://www.github.com/tauri-apps/tauri/pull/1889)) on 2021-05-21 + +## \[0.1.1] + +- Fixes `system-tray` feature usage. + - [1ab8dd9](https://www.github.com/tauri-apps/tauri/commit/1ab8dd93e670d2a2d070c7a6ec48308a0ab32f1a) fix(core): `system-tray` cargo feature usage, fixes [#1798](https://www.github.com/tauri-apps/tauri/pull/1798) ([#1801](https://www.github.com/tauri-apps/tauri/pull/1801)) on 2021-05-12 + +## \[0.1.0] + +- **Breaking:** `Context` fields are now private, and is expected to be created through `Context::new(...)`. + All fields previously available through `Context` are now public methods. + - [5542359](https://www.github.com/tauri-apps/tauri/commit/55423590ddbf560684dab6a0214acf95aadfa8d2) refactor(core): Context fields now private, Icon used on all platforms ([#1774](https://www.github.com/tauri-apps/tauri/pull/1774)) on 2021-05-11 +- `tauri-runtime` crate initial release. + - [665ec1d](https://www.github.com/tauri-apps/tauri/commit/665ec1d4a199ad06e369221da187dc838da71cbf) refactor: move runtime to `tauri-runtime` crate ([#1751](https://www.github.com/tauri-apps/tauri/pull/1751)) on 2021-05-09 + - [45a7a11](https://www.github.com/tauri-apps/tauri/commit/45a7a111e0cf9d9956d713cc9a99fa7a5313eec7) feat(core): add `tauri-wry` crate ([#1756](https://www.github.com/tauri-apps/tauri/pull/1756)) on 2021-05-09 diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml new file mode 100644 index 000000000000..6a2110af08a0 --- /dev/null +++ b/crates/tauri-runtime/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "tauri-runtime" +version = "2.2.0" +description = "Runtime for Tauri applications" +exclude = ["CHANGELOG.md", "/target"] +readme = "README.md" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +categories.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true + +[package.metadata.docs.rs] +all-features = true +rustc-args = ["--cfg", "docsrs"] +rustdoc-args = ["--cfg", "docsrs"] +default-target = "x86_64-unknown-linux-gnu" +targets = [ + "x86_64-pc-windows-msvc", + "x86_64-unknown-linux-gnu", + "x86_64-apple-darwin", + "x86_64-linux-android", + "x86_64-apple-ios", +] + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +thiserror = "2" +tauri-utils = { version = "2.1.0", path = "../tauri-utils" } +http = "1.1" +raw-window-handle = "0.6" +url = { version = "2" } +dpi = { version = "0.1", features = ["serde"] } + +[target."cfg(windows)".dependencies.windows] +version = "0.58" +features = ["Win32_Foundation"] + +[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] +gtk = { version = "0.18", features = ["v3_24"] } + +[target."cfg(target_os = \"android\")".dependencies] +jni = "0.21" + +[target."cfg(target_os = \"macos\")".dependencies] +url = "2" + +[features] +devtools = [] +macos-private-api = [] diff --git a/core/tauri-utils/LICENSE_APACHE-2.0 b/crates/tauri-runtime/LICENSE_APACHE-2.0 similarity index 100% rename from core/tauri-utils/LICENSE_APACHE-2.0 rename to crates/tauri-runtime/LICENSE_APACHE-2.0 diff --git a/core/tauri-utils/LICENSE_MIT b/crates/tauri-runtime/LICENSE_MIT similarity index 100% rename from core/tauri-utils/LICENSE_MIT rename to crates/tauri-runtime/LICENSE_MIT diff --git a/crates/tauri-runtime/README.md b/crates/tauri-runtime/README.md new file mode 100644 index 000000000000..450fbd90ca6d --- /dev/null +++ b/crates/tauri-runtime/README.md @@ -0,0 +1,44 @@ +# tauri-runtime + + + +[![status](https://img.shields.io/badge/Status-Beta-green.svg)](https://github.com/tauri-apps/tauri) +[![Chat Server](https://img.shields.io/badge/chat-on%20discord-7289da.svg)](https://discord.gg/SpmNs4S) + +[![test core](https://img.shields.io/github/actions/workflow/status/tauri-apps/tauri/test-core.yml?label=test%20core&logo=github)](https://github.com/tauri-apps/tauri/actions/workflows/test-core.yml) +[![website](https://img.shields.io/badge/website-tauri.app-purple.svg)](https://tauri.app) + +[![https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg](https://good-labs.github.io/greater-good-affirmation/assets/images/badge.svg)](https://good-labs.github.io/greater-good-affirmation) +[![support](https://img.shields.io/badge/sponsor-Opencollective-blue.svg)](https://opencollective.com/tauri) + +| Component | Version | +| ------------- | -------------------------------------------------------------------------------------------------------------- | +| tauri-runtime | [![](https://img.shields.io/crates/v/tauri-runtime?style=flat-square)](https://crates.io/crates/tauri-runtime) | + +## About Tauri + +Tauri is a polyglot and generic system that is very composable and allows engineers to make a wide variety of applications. It is used for building applications for Desktop Computers using a combination of Rust tools and HTML rendered in a Webview. Apps built with Tauri can ship with any number of pieces of an optional JS API / Rust API so that webviews can control the system via message passing. In fact, developers can extend the default API with their own functionality and bridge the Webview and Rust-based backend easily. + +Tauri apps can have custom menus and have tray-type interfaces. They can be updated, and are managed by the user's operating system as expected. They are very small, because they use the system's webview. They do not ship a runtime, since the final binary is compiled from rust. This makes the reversing of Tauri apps not a trivial task. + +## This module + +This is the glue layer between tauri itself and lower level webview libraries. +None of the exposed API of this crate is stable, and it may break semver +compatibility in the future. The major version only signifies the intended Tauri version. + +To learn more about the details of how all of these pieces fit together, please consult this [ARCHITECTURE.md](https://github.com/tauri-apps/tauri/blob/dev/ARCHITECTURE.md) document. + +## Semver + +**tauri** is following [Semantic Versioning 2.0](https://semver.org/). + +## Licenses + +Code: (c) 2021 - The Tauri Programme within The Commons Conservancy. + +MIT or MIT/Apache 2.0 where applicable. + +Logo: CC-BY-NC-ND + +- Original Tauri Logo Designs by [Daniel Thompson-Yvetot](https://github.com/nothingismagick) and [Guillaume Chau](https://github.com/akryum) diff --git a/crates/tauri-runtime/build.rs b/crates/tauri-runtime/build.rs new file mode 100644 index 000000000000..9974c5040b19 --- /dev/null +++ b/crates/tauri-runtime/build.rs @@ -0,0 +1,19 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +// creates a cfg alias if `has_feature` is true. +// `alias` must be a snake case string. +fn alias(alias: &str, has_feature: bool) { + println!("cargo:rustc-check-cfg=cfg({alias})"); + if has_feature { + println!("cargo:rustc-cfg={alias}"); + } +} + +fn main() { + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + let mobile = target_os == "ios" || target_os == "android"; + alias("desktop", !mobile); + alias("mobile", mobile); +} diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs new file mode 100644 index 000000000000..8c93a19a0907 --- /dev/null +++ b/crates/tauri-runtime/src/lib.rs @@ -0,0 +1,857 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Internal runtime between Tauri and the underlying webview runtime. +//! +//! None of the exposed API of this crate is stable, and it may break semver +//! compatibility in the future. The major version only signifies the intended Tauri version. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] +#![cfg_attr(docsrs, feature(doc_cfg))] + +use raw_window_handle::DisplayHandle; +use serde::{Deserialize, Serialize}; +use std::{borrow::Cow, fmt::Debug, sync::mpsc::Sender}; +use tauri_utils::config::Color; +use tauri_utils::Theme; +use url::Url; +use webview::{DetachedWebview, PendingWebview}; + +/// Types useful for interacting with a user's monitors. +pub mod monitor; +pub mod webview; +pub mod window; + +use dpi::{PhysicalPosition, PhysicalSize, Position, Size}; +use monitor::Monitor; +use window::{ + CursorIcon, DetachedWindow, PendingWindow, RawWindow, WebviewEvent, WindowEvent, + WindowSizeConstraints, +}; +use window::{WindowBuilder, WindowId}; + +use http::{ + header::{InvalidHeaderName, InvalidHeaderValue}, + method::InvalidMethod, + status::InvalidStatusCode, +}; + +/// UI scaling utilities. +pub use dpi; + +pub type WindowEventId = u32; +pub type WebviewEventId = u32; + +/// A rectangular region. +#[derive(Clone, Copy, Debug, Serialize)] +pub struct Rect { + /// Rect position. + pub position: dpi::Position, + /// Rect size. + pub size: dpi::Size, +} + +impl Default for Rect { + fn default() -> Self { + Self { + position: Position::Logical((0, 0).into()), + size: Size::Logical((0, 0).into()), + } + } +} + +/// Progress bar status. +#[derive(Debug, Clone, Copy, Deserialize)] +#[serde(rename_all = "camelCase")] +pub enum ProgressBarStatus { + /// Hide progress bar. + None, + /// Normal state. + Normal, + /// Indeterminate state. **Treated as Normal on Linux and macOS** + Indeterminate, + /// Paused state. **Treated as Normal on Linux** + Paused, + /// Error state. **Treated as Normal on Linux** + Error, +} + +/// Progress Bar State +#[derive(Debug, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct ProgressBarState { + /// The progress bar status. + pub status: Option, + /// The progress bar progress. This can be a value ranging from `0` to `100` + pub progress: Option, + /// The `.desktop` filename with the Unity desktop window manager, for example `myapp.desktop` **Linux Only** + pub desktop_filename: Option, +} + +/// Type of user attention requested on a window. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[serde(tag = "type")] +pub enum UserAttentionType { + /// ## Platform-specific + /// - **macOS:** Bounces the dock icon until the application is in focus. + /// - **Windows:** Flashes both the window and the taskbar button until the application is in focus. + Critical, + /// ## Platform-specific + /// - **macOS:** Bounces the dock icon once. + /// - **Windows:** Flashes the taskbar button until the application is in focus. + Informational, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[serde(tag = "type")] +pub enum DeviceEventFilter { + /// Always filter out device events. + Always, + /// Filter out device events while the window is not focused. + Unfocused, + /// Report all device events regardless of window focus. + Never, +} + +impl Default for DeviceEventFilter { + fn default() -> Self { + Self::Unfocused + } +} + +/// Defines the orientation that a window resize will be performed. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +pub enum ResizeDirection { + East, + North, + NorthEast, + NorthWest, + South, + SouthEast, + SouthWest, + West, +} + +#[derive(Debug, thiserror::Error)] +#[non_exhaustive] +pub enum Error { + /// Failed to create webview. + #[error("failed to create webview: {0}")] + CreateWebview(Box), + /// Failed to create window. + #[error("failed to create window")] + CreateWindow, + /// The given window label is invalid. + #[error("Window labels must only include alphanumeric characters, `-`, `/`, `:` and `_`.")] + InvalidWindowLabel, + /// Failed to send message to webview. + #[error("failed to send message to the webview")] + FailedToSendMessage, + /// Failed to receive message from webview. + #[error("failed to receive message from webview")] + FailedToReceiveMessage, + /// Failed to serialize/deserialize. + #[error("JSON error: {0}")] + Json(#[from] serde_json::Error), + /// Failed to load window icon. + #[error("invalid icon: {0}")] + InvalidIcon(Box), + /// Failed to get monitor on window operation. + #[error("failed to get monitor")] + FailedToGetMonitor, + /// Failed to get cursor position. + #[error("failed to get cursor position")] + FailedToGetCursorPosition, + #[error("Invalid header name: {0}")] + InvalidHeaderName(#[from] InvalidHeaderName), + #[error("Invalid header value: {0}")] + InvalidHeaderValue(#[from] InvalidHeaderValue), + #[error("Invalid status code: {0}")] + InvalidStatusCode(#[from] InvalidStatusCode), + #[error("Invalid method: {0}")] + InvalidMethod(#[from] InvalidMethod), + #[error("Infallible error, something went really wrong: {0}")] + Infallible(#[from] std::convert::Infallible), + #[error("the event loop has been closed")] + EventLoopClosed, + #[error("Invalid proxy url")] + InvalidProxyUrl, + #[error("window not found")] + WindowNotFound, +} + +/// Result type. +pub type Result = std::result::Result; + +/// Window icon. +#[derive(Debug, Clone)] +pub struct Icon<'a> { + /// RGBA bytes of the icon. + pub rgba: Cow<'a, [u8]>, + /// Icon width. + pub width: u32, + /// Icon height. + pub height: u32, +} + +/// A type that can be used as an user event. +pub trait UserEvent: Debug + Clone + Send + 'static {} + +impl UserEvent for T {} + +/// Event triggered on the event loop run. +#[derive(Debug)] +#[non_exhaustive] +pub enum RunEvent { + /// Event loop is exiting. + Exit, + /// Event loop is about to exit + ExitRequested { + /// The exit code. + code: Option, + tx: Sender, + }, + /// An event associated with a window. + WindowEvent { + /// The window label. + label: String, + /// The detailed event. + event: WindowEvent, + }, + /// An event associated with a webview. + WebviewEvent { + /// The webview label. + label: String, + /// The detailed event. + event: WebviewEvent, + }, + /// Application ready. + Ready, + /// Sent if the event loop is being resumed. + Resumed, + /// Emitted when all of the event loop's input events have been processed and redraw processing is about to begin. + /// + /// This event is useful as a place to put your code that should be run after all state-changing events have been handled and you want to do stuff (updating state, performing calculations, etc) that happens as the “main body” of your event loop. + MainEventsCleared, + /// Emitted when the user wants to open the specified resource with the app. + #[cfg(any(target_os = "macos", target_os = "ios"))] + Opened { urls: Vec }, + /// Emitted when the NSApplicationDelegate's applicationShouldHandleReopen gets called + #[cfg(target_os = "macos")] + Reopen { + /// Indicates whether the NSApplication object found any visible windows in your application. + has_visible_windows: bool, + }, + /// A custom event defined by the user. + UserEvent(T), +} + +/// Action to take when the event loop is about to exit +#[derive(Debug)] +pub enum ExitRequestedEventAction { + /// Prevent the event loop from exiting + Prevent, +} + +/// Application's activation policy. Corresponds to NSApplicationActivationPolicy. +#[cfg(target_os = "macos")] +#[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] +#[non_exhaustive] +pub enum ActivationPolicy { + /// Corresponds to NSApplicationActivationPolicyRegular. + Regular, + /// Corresponds to NSApplicationActivationPolicyAccessory. + Accessory, + /// Corresponds to NSApplicationActivationPolicyProhibited. + Prohibited, +} + +/// A [`Send`] handle to the runtime. +pub trait RuntimeHandle: Debug + Clone + Send + Sync + Sized + 'static { + type Runtime: Runtime; + + /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop. + fn create_proxy(&self) -> >::EventLoopProxy; + + /// Sets the activation policy for the application. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn set_activation_policy(&self, activation_policy: ActivationPolicy) -> Result<()>; + + /// Requests an exit of the event loop. + fn request_exit(&self, code: i32) -> Result<()>; + + /// Create a new window. + fn create_window( + &self, + pending: PendingWindow, + before_window_creation: Option, + ) -> Result>; + + /// Create a new webview. + fn create_webview( + &self, + window_id: WindowId, + pending: PendingWebview, + ) -> Result>; + + /// Run a task on the main thread. + fn run_on_main_thread(&self, f: F) -> Result<()>; + + fn display_handle(&self) -> std::result::Result; + + fn primary_monitor(&self) -> Option; + fn monitor_from_point(&self, x: f64, y: f64) -> Option; + fn available_monitors(&self) -> Vec; + + fn cursor_position(&self) -> Result>; + + fn set_theme(&self, theme: Option); + + /// Shows the application, but does not automatically focus it. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn show(&self) -> Result<()>; + + /// Hides the application. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn hide(&self) -> Result<()>; + + /// Finds an Android class in the project scope. + #[cfg(target_os = "android")] + fn find_class<'a>( + &self, + env: &mut jni::JNIEnv<'a>, + activity: &jni::objects::JObject<'_>, + name: impl Into, + ) -> std::result::Result, jni::errors::Error>; + + /// Dispatch a closure to run on the Android context. + /// + /// The closure takes the JNI env, the Android activity instance and the possibly null webview. + #[cfg(target_os = "android")] + fn run_on_android_context(&self, f: F) + where + F: FnOnce(&mut jni::JNIEnv, &jni::objects::JObject, &jni::objects::JObject) + Send + 'static; +} + +pub trait EventLoopProxy: Debug + Clone + Send + Sync { + fn send_event(&self, event: T) -> Result<()>; +} + +#[derive(Default)] +pub struct RuntimeInitArgs { + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub app_id: Option, + #[cfg(windows)] + pub msg_hook: Option bool + 'static>>, +} + +/// The webview runtime interface. +pub trait Runtime: Debug + Sized + 'static { + /// The window message dispatcher. + type WindowDispatcher: WindowDispatch; + /// The webview message dispatcher. + type WebviewDispatcher: WebviewDispatch; + /// The runtime handle type. + type Handle: RuntimeHandle; + /// The proxy type. + type EventLoopProxy: EventLoopProxy; + + /// Creates a new webview runtime. Must be used on the main thread. + fn new(args: RuntimeInitArgs) -> Result; + + /// Creates a new webview runtime on any thread. + #[cfg(any(windows, target_os = "linux"))] + #[cfg_attr(docsrs, doc(cfg(any(windows, target_os = "linux"))))] + fn new_any_thread(args: RuntimeInitArgs) -> Result; + + /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop. + fn create_proxy(&self) -> Self::EventLoopProxy; + + /// Gets a runtime handle. + fn handle(&self) -> Self::Handle; + + /// Create a new window. + fn create_window( + &self, + pending: PendingWindow, + after_window_creation: Option, + ) -> Result>; + + /// Create a new webview. + fn create_webview( + &self, + window_id: WindowId, + pending: PendingWebview, + ) -> Result>; + + fn primary_monitor(&self) -> Option; + fn monitor_from_point(&self, x: f64, y: f64) -> Option; + fn available_monitors(&self) -> Vec; + + fn cursor_position(&self) -> Result>; + + fn set_theme(&self, theme: Option); + + /// Sets the activation policy for the application. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn set_activation_policy(&mut self, activation_policy: ActivationPolicy); + + /// Shows the application, but does not automatically focus it. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn show(&self); + + /// Hides the application. + #[cfg(target_os = "macos")] + #[cfg_attr(docsrs, doc(cfg(target_os = "macos")))] + fn hide(&self); + + /// Change the device event filter mode. + /// + /// Since the DeviceEvent capture can lead to high CPU usage for unfocused windows, [`tao`] + /// will ignore them by default for unfocused windows on Windows. This method allows changing + /// the filter to explicitly capture them again. + /// + /// ## Platform-specific + /// + /// - ** Linux / macOS / iOS / Android**: Unsupported. + /// + /// [`tao`]: https://crates.io/crates/tao + fn set_device_event_filter(&mut self, filter: DeviceEventFilter); + + /// Runs an iteration of the runtime event loop and returns control flow to the caller. + #[cfg(desktop)] + fn run_iteration) + 'static>(&mut self, callback: F); + + /// Run the webview runtime. + fn run) + 'static>(self, callback: F); +} + +/// Webview dispatcher. A thread-safe handle to the webview APIs. +pub trait WebviewDispatch: Debug + Clone + Send + Sync + Sized + 'static { + /// The runtime this [`WebviewDispatch`] runs under. + type Runtime: Runtime; + + /// Run a task on the main thread. + fn run_on_main_thread(&self, f: F) -> Result<()>; + + /// Registers a webview event handler. + fn on_webview_event(&self, f: F) -> WebviewEventId; + + /// Runs a closure with the platform webview object as argument. + fn with_webview) + Send + 'static>(&self, f: F) -> Result<()>; + + /// Open the web inspector which is usually called devtools. + #[cfg(any(debug_assertions, feature = "devtools"))] + fn open_devtools(&self); + + /// Close the web inspector which is usually called devtools. + #[cfg(any(debug_assertions, feature = "devtools"))] + fn close_devtools(&self); + + /// Gets the devtools window's current open state. + #[cfg(any(debug_assertions, feature = "devtools"))] + fn is_devtools_open(&self) -> Result; + + // GETTERS + + /// Returns the webview's current URL. + fn url(&self) -> Result; + + /// Returns the webview's bounds. + fn bounds(&self) -> Result; + + /// Returns the position of the top-left hand corner of the webviews's client area relative to the top-left hand corner of the window. + fn position(&self) -> Result>; + + /// Returns the physical size of the webviews's client area. + fn size(&self) -> Result>; + + // SETTER + + /// Navigate to the given URL. + fn navigate(&self, url: Url) -> Result<()>; + + /// Opens the dialog to prints the contents of the webview. + fn print(&self) -> Result<()>; + + /// Closes the webview. + fn close(&self) -> Result<()>; + + /// Sets the webview's bounds. + fn set_bounds(&self, bounds: Rect) -> Result<()>; + + /// Resizes the webview. + fn set_size(&self, size: Size) -> Result<()>; + + /// Updates the webview position. + fn set_position(&self, position: Position) -> Result<()>; + + /// Bring the window to front and focus the webview. + fn set_focus(&self) -> Result<()>; + + /// Hide the webview + fn hide(&self) -> Result<()>; + + /// Show the webview + fn show(&self) -> Result<()>; + + /// Executes javascript on the window this [`WindowDispatch`] represents. + fn eval_script>(&self, script: S) -> Result<()>; + + /// Moves the webview to the given window. + fn reparent(&self, window_id: WindowId) -> Result<()>; + + /// Sets whether the webview should automatically grow and shrink its size and position when the parent window resizes. + fn set_auto_resize(&self, auto_resize: bool) -> Result<()>; + + /// Set the webview zoom level + fn set_zoom(&self, scale_factor: f64) -> Result<()>; + + /// Set the webview background. + fn set_background_color(&self, color: Option) -> Result<()>; + + /// Clear all browsing data for this webview. + fn clear_all_browsing_data(&self) -> Result<()>; +} + +/// Window dispatcher. A thread-safe handle to the window APIs. +pub trait WindowDispatch: Debug + Clone + Send + Sync + Sized + 'static { + /// The runtime this [`WindowDispatch`] runs under. + type Runtime: Runtime; + + /// The window builder type. + type WindowBuilder: WindowBuilder; + + /// Run a task on the main thread. + fn run_on_main_thread(&self, f: F) -> Result<()>; + + /// Registers a window event handler. + fn on_window_event(&self, f: F) -> WindowEventId; + + // GETTERS + + /// Returns the scale factor that can be used to map logical pixels to physical pixels, and vice versa. + fn scale_factor(&self) -> Result; + + /// Returns the position of the top-left hand corner of the window's client area relative to the top-left hand corner of the desktop. + fn inner_position(&self) -> Result>; + + /// Returns the position of the top-left hand corner of the window relative to the top-left hand corner of the desktop. + fn outer_position(&self) -> Result>; + + /// Returns the physical size of the window's client area. + /// + /// The client area is the content of the window, excluding the title bar and borders. + fn inner_size(&self) -> Result>; + + /// Returns the physical size of the entire window. + /// + /// These dimensions include the title bar and borders. If you don't want that (and you usually don't), use inner_size instead. + fn outer_size(&self) -> Result>; + + /// Gets the window's current fullscreen state. + fn is_fullscreen(&self) -> Result; + + /// Gets the window's current minimized state. + fn is_minimized(&self) -> Result; + + /// Gets the window's current maximized state. + fn is_maximized(&self) -> Result; + + /// Gets the window's current focus state. + fn is_focused(&self) -> Result; + + /// Gets the window's current decoration state. + fn is_decorated(&self) -> Result; + + /// Gets the window's current resizable state. + fn is_resizable(&self) -> Result; + + /// Gets the window's native maximize button state. + /// + /// ## Platform-specific + /// + /// - **Linux / iOS / Android:** Unsupported. + fn is_maximizable(&self) -> Result; + + /// Gets the window's native minimize button state. + /// + /// ## Platform-specific + /// + /// - **Linux / iOS / Android:** Unsupported. + fn is_minimizable(&self) -> Result; + + /// Gets the window's native close button state. + /// + /// ## Platform-specific + /// + /// - **iOS / Android:** Unsupported. + fn is_closable(&self) -> Result; + + /// Gets the window's current visibility state. + fn is_visible(&self) -> Result; + + /// Whether the window is enabled or disable. + fn is_enabled(&self) -> Result; + + /// Gets the window's current title. + fn title(&self) -> Result; + + /// Returns the monitor on which the window currently resides. + /// + /// Returns None if current monitor can't be detected. + fn current_monitor(&self) -> Result>; + + /// Returns the primary monitor of the system. + /// + /// Returns None if it can't identify any monitor as a primary one. + fn primary_monitor(&self) -> Result>; + + /// Returns the monitor that contains the given point. + fn monitor_from_point(&self, x: f64, y: f64) -> Result>; + + /// Returns the list of all the monitors available on the system. + fn available_monitors(&self) -> Result>; + + /// Returns the `ApplicationWindow` from gtk crate that is used by this window. + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn gtk_window(&self) -> Result; + + /// Returns the vertical [`gtk::Box`] that is added by default as the sole child of this window. + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn default_vbox(&self) -> Result; + + /// Raw window handle. + fn window_handle( + &self, + ) -> std::result::Result, raw_window_handle::HandleError>; + + /// Returns the current window theme. + fn theme(&self) -> Result; + + // SETTERS + + /// Centers the window. + fn center(&self) -> Result<()>; + + /// Requests user attention to the window. + /// + /// Providing `None` will unset the request for user attention. + fn request_user_attention(&self, request_type: Option) -> Result<()>; + + /// Create a new window. + fn create_window( + &mut self, + pending: PendingWindow, + after_window_creation: Option, + ) -> Result>; + + /// Create a new webview. + fn create_webview( + &mut self, + pending: PendingWebview, + ) -> Result>; + + /// Updates the window resizable flag. + fn set_resizable(&self, resizable: bool) -> Result<()>; + + /// Enable or disable the window. + /// + /// ## Platform-specific + /// + /// - **Android / iOS**: Unsupported. + fn set_enabled(&self, enabled: bool) -> Result<()>; + + /// Updates the window's native maximize button state. + /// + /// ## Platform-specific + /// + /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode. + /// - **Linux / iOS / Android:** Unsupported. + fn set_maximizable(&self, maximizable: bool) -> Result<()>; + + /// Updates the window's native minimize button state. + /// + /// ## Platform-specific + /// + /// - **Linux / iOS / Android:** Unsupported. + fn set_minimizable(&self, minimizable: bool) -> Result<()>; + + /// Updates the window's native close button state. + /// + /// ## Platform-specific + /// + /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button. + /// Depending on the system, this function may not have any effect when called on a window that is already visible" + /// - **iOS / Android:** Unsupported. + fn set_closable(&self, closable: bool) -> Result<()>; + + /// Updates the window title. + fn set_title>(&self, title: S) -> Result<()>; + + /// Maximizes the window. + fn maximize(&self) -> Result<()>; + + /// Unmaximizes the window. + fn unmaximize(&self) -> Result<()>; + + /// Minimizes the window. + fn minimize(&self) -> Result<()>; + + /// Unminimizes the window. + fn unminimize(&self) -> Result<()>; + + /// Shows the window. + fn show(&self) -> Result<()>; + + /// Hides the window. + fn hide(&self) -> Result<()>; + + /// Closes the window. + fn close(&self) -> Result<()>; + + /// Destroys the window. + fn destroy(&self) -> Result<()>; + + /// Updates the decorations flag. + fn set_decorations(&self, decorations: bool) -> Result<()>; + + /// Updates the shadow flag. + fn set_shadow(&self, enable: bool) -> Result<()>; + + /// Updates the window alwaysOnBottom flag. + fn set_always_on_bottom(&self, always_on_bottom: bool) -> Result<()>; + + /// Updates the window alwaysOnTop flag. + fn set_always_on_top(&self, always_on_top: bool) -> Result<()>; + + /// Updates the window visibleOnAllWorkspaces flag. + fn set_visible_on_all_workspaces(&self, visible_on_all_workspaces: bool) -> Result<()>; + + /// Set the window background. + fn set_background_color(&self, color: Option) -> Result<()>; + + /// Prevents the window contents from being captured by other apps. + fn set_content_protected(&self, protected: bool) -> Result<()>; + + /// Resizes the window. + fn set_size(&self, size: Size) -> Result<()>; + + /// Updates the window min inner size. + fn set_min_size(&self, size: Option) -> Result<()>; + + /// Updates the window max inner size. + fn set_max_size(&self, size: Option) -> Result<()>; + + /// Sets this window's minimum inner width. + fn set_size_constraints(&self, constraints: WindowSizeConstraints) -> Result<()>; + + /// Updates the window position. + fn set_position(&self, position: Position) -> Result<()>; + + /// Updates the window fullscreen state. + fn set_fullscreen(&self, fullscreen: bool) -> Result<()>; + + /// Bring the window to front and focus. + fn set_focus(&self) -> Result<()>; + + /// Updates the window icon. + fn set_icon(&self, icon: Icon) -> Result<()>; + + /// Whether to hide the window icon from the taskbar or not. + fn set_skip_taskbar(&self, skip: bool) -> Result<()>; + + /// Grabs the cursor, preventing it from leaving the window. + /// + /// There's no guarantee that the cursor will be hidden. You should + /// hide it by yourself if you want so. + fn set_cursor_grab(&self, grab: bool) -> Result<()>; + + /// Modifies the cursor's visibility. + /// + /// If `false`, this will hide the cursor. If `true`, this will show the cursor. + fn set_cursor_visible(&self, visible: bool) -> Result<()>; + + // Modifies the cursor icon of the window. + fn set_cursor_icon(&self, icon: CursorIcon) -> Result<()>; + + /// Changes the position of the cursor in window coordinates. + fn set_cursor_position>(&self, position: Pos) -> Result<()>; + + /// Ignores the window cursor events. + fn set_ignore_cursor_events(&self, ignore: bool) -> Result<()>; + + /// Starts dragging the window. + fn start_dragging(&self) -> Result<()>; + + /// Starts resize-dragging the window. + fn start_resize_dragging(&self, direction: ResizeDirection) -> Result<()>; + + /// Sets the badge count on the taskbar + /// The badge count appears as a whole for the application + /// Using `0` or using `None` will remove the badge + /// + /// ## Platform-specific + /// - **Windows:** Unsupported, use [`WindowDispatch::set_overlay_icon`] instead. + /// - **Android:** Unsupported. + /// - **iOS:** iOS expects i32, if the value is larger than i32::MAX, it will be clamped to i32::MAX. + fn set_badge_count(&self, count: Option, desktop_filename: Option) -> Result<()>; + + /// Sets the badge count on the taskbar **macOS only**. Using `None` will remove the badge + fn set_badge_label(&self, label: Option) -> Result<()>; + + /// Sets the overlay icon on the taskbar **Windows only**. Using `None` will remove the icon + /// + /// The overlay icon can be unique for each window. + fn set_overlay_icon(&self, icon: Option) -> Result<()>; + + /// Sets the taskbar progress state. + /// + /// ## Platform-specific + /// + /// - **Linux / macOS**: Progress bar is app-wide and not specific to this window. Only supported desktop environments with `libunity` (e.g. GNOME). + /// - **iOS / Android:** Unsupported. + fn set_progress_bar(&self, progress_state: ProgressBarState) -> Result<()>; + + /// Sets the title bar style. Available on macOS only. + /// + /// ## Platform-specific + /// + /// - **Linux / Windows / iOS / Android:** Unsupported. + fn set_title_bar_style(&self, style: tauri_utils::TitleBarStyle) -> Result<()>; + + /// Sets the theme for this window. + /// + /// ## Platform-specific + /// + /// - **Linux / macOS**: Theme is app-wide and not specific to this window. + /// - **iOS / Android:** Unsupported. + fn set_theme(&self, theme: Option) -> Result<()>; +} diff --git a/core/tauri-runtime/src/monitor.rs b/crates/tauri-runtime/src/monitor.rs similarity index 83% rename from core/tauri-runtime/src/monitor.rs rename to crates/tauri-runtime/src/monitor.rs index d14125a845a4..0bedbbf4f5cd 100644 --- a/core/tauri-runtime/src/monitor.rs +++ b/crates/tauri-runtime/src/monitor.rs @@ -1,8 +1,8 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use super::window::dpi::{PhysicalPosition, PhysicalSize}; +use crate::dpi::{PhysicalPosition, PhysicalSize}; /// Monitor descriptor. #[derive(Debug, Clone)] diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs new file mode 100644 index 000000000000..f317a5857638 --- /dev/null +++ b/crates/tauri-runtime/src/webview.rs @@ -0,0 +1,450 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! A layer between raw [`Runtime`] webviews and Tauri. +//! +use crate::{window::is_label_valid, Rect, Runtime, UserEvent}; + +use http::Request; +use tauri_utils::config::{Color, WebviewUrl, WindowConfig, WindowEffectsConfig}; +use url::Url; + +use std::{ + borrow::Cow, + collections::HashMap, + hash::{Hash, Hasher}, + path::PathBuf, + sync::Arc, +}; + +type UriSchemeProtocol = dyn Fn(&str, http::Request>, Box>) + Send>) + + Send + + Sync + + 'static; + +type WebResourceRequestHandler = + dyn Fn(http::Request>, &mut http::Response>) + Send + Sync; + +type NavigationHandler = dyn Fn(&Url) -> bool + Send; + +type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send; + +type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync; + +/// Download event. +pub enum DownloadEvent<'a> { + /// Download requested. + Requested { + /// The url being downloaded. + url: Url, + /// Represents where the file will be downloaded to. + /// Can be used to set the download location by assigning a new path to it. + /// The assigned path _must_ be absolute. + destination: &'a mut PathBuf, + }, + /// Download finished. + Finished { + /// The URL of the original download request. + url: Url, + /// Potentially representing the filesystem path the file was downloaded to. + path: Option, + /// Indicates if the download succeeded or not. + success: bool, + }, +} + +#[cfg(target_os = "android")] +pub struct CreationContext<'a, 'b> { + pub env: &'a mut jni::JNIEnv<'b>, + pub activity: &'a jni::objects::JObject<'b>, + pub webview: &'a jni::objects::JObject<'b>, +} + +/// Kind of event for the page load handler. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum PageLoadEvent { + /// Page started to load. + Started, + /// Page finished loading. + Finished, +} + +/// A webview that has yet to be built. +pub struct PendingWebview> { + /// The label that the webview will be named. + pub label: String, + + /// The [`WebviewAttributes`] that the webview will be created with. + pub webview_attributes: WebviewAttributes, + + pub uri_scheme_protocols: HashMap>, + + /// How to handle IPC calls on the webview. + pub ipc_handler: Option>, + + /// A handler to decide if incoming url is allowed to navigate. + pub navigation_handler: Option>, + + /// The resolved URL to load on the webview. + pub url: String, + + #[cfg(target_os = "android")] + #[allow(clippy::type_complexity)] + pub on_webview_created: + Option) -> Result<(), jni::errors::Error> + Send>>, + + pub web_resource_request_handler: Option>, + + pub on_page_load_handler: Option>, + + pub download_handler: Option>, +} + +impl> PendingWebview { + /// Create a new [`PendingWebview`] with a label from the given [`WebviewAttributes`]. + pub fn new( + webview_attributes: WebviewAttributes, + label: impl Into, + ) -> crate::Result { + let label = label.into(); + if !is_label_valid(&label) { + Err(crate::Error::InvalidWindowLabel) + } else { + Ok(Self { + webview_attributes, + uri_scheme_protocols: Default::default(), + label, + ipc_handler: None, + navigation_handler: None, + url: "tauri://localhost".to_string(), + #[cfg(target_os = "android")] + on_webview_created: None, + web_resource_request_handler: None, + on_page_load_handler: None, + download_handler: None, + }) + } + } + + pub fn register_uri_scheme_protocol< + N: Into, + H: Fn(&str, http::Request>, Box>) + Send>) + + Send + + Sync + + 'static, + >( + &mut self, + uri_scheme: N, + protocol: H, + ) { + let uri_scheme = uri_scheme.into(); + self + .uri_scheme_protocols + .insert(uri_scheme, Box::new(protocol)); + } + + #[cfg(target_os = "android")] + pub fn on_webview_created< + F: Fn(CreationContext<'_, '_>) -> Result<(), jni::errors::Error> + Send + 'static, + >( + mut self, + f: F, + ) -> Self { + self.on_webview_created.replace(Box::new(f)); + self + } +} + +/// A webview that is not yet managed by Tauri. +#[derive(Debug)] +pub struct DetachedWebview> { + /// Name of the window + pub label: String, + + /// The [`crate::WebviewDispatch`] associated with the window. + pub dispatcher: R::WebviewDispatcher, +} + +impl> Clone for DetachedWebview { + fn clone(&self) -> Self { + Self { + label: self.label.clone(), + dispatcher: self.dispatcher.clone(), + } + } +} + +impl> Hash for DetachedWebview { + /// Only use the [`DetachedWebview`]'s label to represent its hash. + fn hash(&self, state: &mut H) { + self.label.hash(state) + } +} + +impl> Eq for DetachedWebview {} +impl> PartialEq for DetachedWebview { + /// Only use the [`DetachedWebview`]'s label to compare equality. + fn eq(&self, other: &Self) -> bool { + self.label.eq(&other.label) + } +} + +/// The attributes used to create an webview. +#[derive(Debug, Clone)] +pub struct WebviewAttributes { + pub url: WebviewUrl, + pub user_agent: Option, + pub initialization_scripts: Vec, + pub data_directory: Option, + pub drag_drop_handler_enabled: bool, + pub clipboard: bool, + pub accept_first_mouse: bool, + pub additional_browser_args: Option, + pub window_effects: Option, + pub incognito: bool, + pub transparent: bool, + pub focus: bool, + pub bounds: Option, + pub auto_resize: bool, + pub proxy_url: Option, + pub zoom_hotkeys_enabled: bool, + pub browser_extensions_enabled: bool, + pub extensions_path: Option, + pub data_store_identifier: Option<[u8; 16]>, + pub use_https_scheme: bool, + pub devtools: Option, + pub background_color: Option, +} + +impl From<&WindowConfig> for WebviewAttributes { + fn from(config: &WindowConfig) -> Self { + let mut builder = Self::new(config.url.clone()) + .incognito(config.incognito) + .focused(config.focus) + .zoom_hotkeys_enabled(config.zoom_hotkeys_enabled) + .use_https_scheme(config.use_https_scheme) + .browser_extensions_enabled(config.browser_extensions_enabled) + .devtools(config.devtools); + #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] + { + builder = builder.transparent(config.transparent); + } + builder = builder.accept_first_mouse(config.accept_first_mouse); + if !config.drag_drop_enabled { + builder = builder.disable_drag_drop_handler(); + } + if let Some(user_agent) = &config.user_agent { + builder = builder.user_agent(user_agent); + } + if let Some(additional_browser_args) = &config.additional_browser_args { + builder = builder.additional_browser_args(additional_browser_args); + } + if let Some(effects) = &config.window_effects { + builder = builder.window_effects(effects.clone()); + } + if let Some(url) = &config.proxy_url { + builder = builder.proxy_url(url.to_owned()); + } + if let Some(color) = config.background_color { + builder = builder.background_color(color); + } + builder + } +} + +impl WebviewAttributes { + /// Initializes the default attributes for a webview. + pub fn new(url: WebviewUrl) -> Self { + Self { + url, + user_agent: None, + initialization_scripts: Vec::new(), + data_directory: None, + drag_drop_handler_enabled: true, + clipboard: false, + accept_first_mouse: false, + additional_browser_args: None, + window_effects: None, + incognito: false, + transparent: false, + focus: true, + bounds: None, + auto_resize: false, + proxy_url: None, + zoom_hotkeys_enabled: false, + browser_extensions_enabled: false, + data_store_identifier: None, + extensions_path: None, + use_https_scheme: false, + devtools: None, + background_color: None, + } + } + + /// Sets the user agent + #[must_use] + pub fn user_agent(mut self, user_agent: &str) -> Self { + self.user_agent = Some(user_agent.to_string()); + self + } + + /// Sets the init script. + #[must_use] + pub fn initialization_script(mut self, script: &str) -> Self { + self.initialization_scripts.push(script.to_string()); + self + } + + /// Data directory for the webview. + #[must_use] + pub fn data_directory(mut self, data_directory: PathBuf) -> Self { + self.data_directory.replace(data_directory); + self + } + + /// Disables the drag and drop handler. This is required to use HTML5 drag and drop APIs on the frontend on Windows. + #[must_use] + pub fn disable_drag_drop_handler(mut self) -> Self { + self.drag_drop_handler_enabled = false; + self + } + + /// Enables clipboard access for the page rendered on **Linux** and **Windows**. + /// + /// **macOS** doesn't provide such method and is always enabled by default, + /// but you still need to add menu item accelerators to use shortcuts. + #[must_use] + pub fn enable_clipboard_access(mut self) -> Self { + self.clipboard = true; + self + } + + /// Sets whether clicking an inactive window also clicks through to the webview. + #[must_use] + pub fn accept_first_mouse(mut self, accept: bool) -> Self { + self.accept_first_mouse = accept; + self + } + + /// Sets additional browser arguments. **Windows Only** + #[must_use] + pub fn additional_browser_args(mut self, additional_args: &str) -> Self { + self.additional_browser_args = Some(additional_args.to_string()); + self + } + + /// Sets window effects + #[must_use] + pub fn window_effects(mut self, effects: WindowEffectsConfig) -> Self { + self.window_effects = Some(effects); + self + } + + /// Enable or disable incognito mode for the WebView. + #[must_use] + pub fn incognito(mut self, incognito: bool) -> Self { + self.incognito = incognito; + self + } + + /// Enable or disable transparency for the WebView. + #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] + #[must_use] + pub fn transparent(mut self, transparent: bool) -> Self { + self.transparent = transparent; + self + } + + /// Whether the webview should be focused or not. + #[must_use] + pub fn focused(mut self, focus: bool) -> Self { + self.focus = focus; + self + } + + /// Sets the webview to automatically grow and shrink its size and position when the parent window resizes. + #[must_use] + pub fn auto_resize(mut self) -> Self { + self.auto_resize = true; + self + } + + /// Enable proxy for the WebView + #[must_use] + pub fn proxy_url(mut self, url: Url) -> Self { + self.proxy_url = Some(url); + self + } + + /// Whether page zooming by hotkeys is enabled + /// + /// ## Platform-specific: + /// + /// - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting. + /// - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`, + /// 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission + /// + /// - **Android / iOS**: Unsupported. + #[must_use] + pub fn zoom_hotkeys_enabled(mut self, enabled: bool) -> Self { + self.zoom_hotkeys_enabled = enabled; + self + } + + /// Whether browser extensions can be installed for the webview process + /// + /// ## Platform-specific: + /// + /// - **Windows**: Enables the WebView2 environment's [`AreBrowserExtensionsEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2environmentoptions?view=webview2-winrt-1.0.2739.15#arebrowserextensionsenabled) + /// - **MacOS / Linux / iOS / Android** - Unsupported. + #[must_use] + pub fn browser_extensions_enabled(mut self, enabled: bool) -> Self { + self.browser_extensions_enabled = enabled; + self + } + + /// Sets whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost` on Windows and Android. Defaults to `false`. + /// + /// ## Note + /// + /// Using a `https` scheme will NOT allow mixed content when trying to fetch `http` endpoints and therefore will not match the behavior of the `://localhost` protocols used on macOS and Linux. + /// + /// ## Warning + /// + /// Changing this value between releases will change the IndexedDB, cookies and localstorage location and your app will not be able to access the old data. + #[must_use] + pub fn use_https_scheme(mut self, enabled: bool) -> Self { + self.use_https_scheme = enabled; + self + } + + /// Whether web inspector, which is usually called browser devtools, is enabled or not. Enabled by default. + /// + /// This API works in **debug** builds, but requires `devtools` feature flag to enable it in **release** builds. + /// + /// ## Platform-specific + /// + /// - macOS: This will call private functions on **macOS**. + /// - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android. + /// - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window. + #[must_use] + pub fn devtools(mut self, enabled: Option) -> Self { + self.devtools = enabled; + self + } + + /// Set the window and webview background color. + /// ## Platform-specific: + /// + /// - **Windows**: On Windows 7, alpha channel is ignored for the webview layer. + /// - **Windows**: On Windows 8 and newer, if alpha channel is not `0`, it will be ignored. + #[must_use] + pub fn background_color(mut self, color: Color) -> Self { + self.background_color = Some(color); + self + } +} + +/// IPC handler. +pub type WebviewIpcHandler = Box, Request) + Send>; diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs new file mode 100644 index 000000000000..dc843100da98 --- /dev/null +++ b/crates/tauri-runtime/src/window.rs @@ -0,0 +1,594 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! A layer between raw [`Runtime`] windows and Tauri. + +use crate::{ + webview::{DetachedWebview, PendingWebview}, + Icon, Runtime, UserEvent, WindowDispatch, +}; + +use dpi::PixelUnit; +use serde::{Deserialize, Deserializer, Serialize}; +use tauri_utils::{ + config::{Color, WindowConfig}, + Theme, +}; +#[cfg(windows)] +use windows::Win32::Foundation::HWND; + +use std::{ + hash::{Hash, Hasher}, + marker::PhantomData, + path::PathBuf, + sync::mpsc::Sender, +}; + +/// An event from a window. +#[derive(Debug, Clone)] +pub enum WindowEvent { + /// The size of the window has changed. Contains the client area's new dimensions. + Resized(dpi::PhysicalSize), + /// The position of the window has changed. Contains the window's new position. + Moved(dpi::PhysicalPosition), + /// The window has been requested to close. + CloseRequested { + /// A signal sender. If a `true` value is emitted, the window won't be closed. + signal_tx: Sender, + }, + /// The window has been destroyed. + Destroyed, + /// The window gained or lost focus. + /// + /// The parameter is true if the window has gained focus, and false if it has lost focus. + Focused(bool), + /// The window's scale factor has changed. + /// + /// The following user actions can cause DPI changes: + /// + /// - Changing the display's resolution. + /// - Changing the display's scale factor (e.g. in Control Panel on Windows). + /// - Moving the window to a display with a different scale factor. + ScaleFactorChanged { + /// The new scale factor. + scale_factor: f64, + /// The window inner size. + new_inner_size: dpi::PhysicalSize, + }, + /// An event associated with the drag and drop action. + DragDrop(DragDropEvent), + /// The system window theme has changed. + /// + /// Applications might wish to react to this to change the theme of the content of the window when the system changes the window theme. + ThemeChanged(Theme), +} + +/// An event from a window. +#[derive(Debug, Clone)] +pub enum WebviewEvent { + /// An event associated with the drag and drop action. + DragDrop(DragDropEvent), +} + +/// The drag drop event payload. +#[derive(Debug, Clone)] +#[non_exhaustive] +pub enum DragDropEvent { + /// A drag operation has entered the webview. + Enter { + /// List of paths that are being dragged onto the webview. + paths: Vec, + /// The position of the mouse cursor. + position: dpi::PhysicalPosition, + }, + /// A drag operation is moving over the webview. + Over { + /// The position of the mouse cursor. + position: dpi::PhysicalPosition, + }, + /// The file(s) have been dropped onto the webview. + Drop { + /// List of paths that are being dropped onto the window. + paths: Vec, + /// The position of the mouse cursor. + position: dpi::PhysicalPosition, + }, + /// The drag operation has been cancelled or left the window. + Leave, +} + +/// Describes the appearance of the mouse cursor. +#[non_exhaustive] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, Hash)] +pub enum CursorIcon { + /// The platform-dependent default cursor. + #[default] + Default, + /// A simple crosshair. + Crosshair, + /// A hand (often used to indicate links in web browsers). + Hand, + /// Self explanatory. + Arrow, + /// Indicates something is to be moved. + Move, + /// Indicates text that may be selected or edited. + Text, + /// Program busy indicator. + Wait, + /// Help indicator (often rendered as a "?") + Help, + /// Progress indicator. Shows that processing is being done. But in contrast + /// with "Wait" the user may still interact with the program. Often rendered + /// as a spinning beach ball, or an arrow with a watch or hourglass. + Progress, + + /// Cursor showing that something cannot be done. + NotAllowed, + ContextMenu, + Cell, + VerticalText, + Alias, + Copy, + NoDrop, + /// Indicates something can be grabbed. + Grab, + /// Indicates something is grabbed. + Grabbing, + AllScroll, + ZoomIn, + ZoomOut, + + /// Indicate that some edge is to be moved. For example, the 'SeResize' cursor + /// is used when the movement starts from the south-east corner of the box. + EResize, + NResize, + NeResize, + NwResize, + SResize, + SeResize, + SwResize, + WResize, + EwResize, + NsResize, + NeswResize, + NwseResize, + ColResize, + RowResize, +} + +impl<'de> Deserialize<'de> for CursorIcon { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + Ok(match s.to_lowercase().as_str() { + "default" => CursorIcon::Default, + "crosshair" => CursorIcon::Crosshair, + "hand" => CursorIcon::Hand, + "arrow" => CursorIcon::Arrow, + "move" => CursorIcon::Move, + "text" => CursorIcon::Text, + "wait" => CursorIcon::Wait, + "help" => CursorIcon::Help, + "progress" => CursorIcon::Progress, + "notallowed" => CursorIcon::NotAllowed, + "contextmenu" => CursorIcon::ContextMenu, + "cell" => CursorIcon::Cell, + "verticaltext" => CursorIcon::VerticalText, + "alias" => CursorIcon::Alias, + "copy" => CursorIcon::Copy, + "nodrop" => CursorIcon::NoDrop, + "grab" => CursorIcon::Grab, + "grabbing" => CursorIcon::Grabbing, + "allscroll" => CursorIcon::AllScroll, + "zoomin" => CursorIcon::ZoomIn, + "zoomout" => CursorIcon::ZoomOut, + "eresize" => CursorIcon::EResize, + "nresize" => CursorIcon::NResize, + "neresize" => CursorIcon::NeResize, + "nwresize" => CursorIcon::NwResize, + "sresize" => CursorIcon::SResize, + "seresize" => CursorIcon::SeResize, + "swresize" => CursorIcon::SwResize, + "wresize" => CursorIcon::WResize, + "ewresize" => CursorIcon::EwResize, + "nsresize" => CursorIcon::NsResize, + "neswresize" => CursorIcon::NeswResize, + "nwseresize" => CursorIcon::NwseResize, + "colresize" => CursorIcon::ColResize, + "rowresize" => CursorIcon::RowResize, + _ => CursorIcon::Default, + }) + } +} + +/// Window size constraints +#[derive(Clone, Copy, PartialEq, Debug, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct WindowSizeConstraints { + /// The minimum width a window can be, If this is `None`, the window will have no minimum width. + /// + /// The default is `None`. + pub min_width: Option, + /// The minimum height a window can be, If this is `None`, the window will have no minimum height. + /// + /// The default is `None`. + pub min_height: Option, + /// The maximum width a window can be, If this is `None`, the window will have no maximum width. + /// + /// The default is `None`. + pub max_width: Option, + /// The maximum height a window can be, If this is `None`, the window will have no maximum height. + /// + /// The default is `None`. + pub max_height: Option, +} + +/// Do **NOT** implement this trait except for use in a custom [`Runtime`] +/// +/// This trait is separate from [`WindowBuilder`] to prevent "accidental" implementation. +pub trait WindowBuilderBase: std::fmt::Debug + Clone + Sized {} + +/// A builder for all attributes related to a single window. +/// +/// This trait is only meant to be implemented by a custom [`Runtime`] +/// and not by applications. +pub trait WindowBuilder: WindowBuilderBase { + /// Initializes a new window attributes builder. + fn new() -> Self; + + /// Initializes a new window builder from a [`WindowConfig`] + fn with_config(config: &WindowConfig) -> Self; + + /// Show window in the center of the screen. + #[must_use] + fn center(self) -> Self; + + /// The initial position of the window's. + #[must_use] + fn position(self, x: f64, y: f64) -> Self; + + /// Window size. + #[must_use] + fn inner_size(self, width: f64, height: f64) -> Self; + + /// Window min inner size. + #[must_use] + fn min_inner_size(self, min_width: f64, min_height: f64) -> Self; + + /// Window max inner size. + #[must_use] + fn max_inner_size(self, max_width: f64, max_height: f64) -> Self; + + /// Window inner size constraints. + #[must_use] + fn inner_size_constraints(self, constraints: WindowSizeConstraints) -> Self; + + /// Whether the window is resizable or not. + /// When resizable is set to false, native window's maximize button is automatically disabled. + #[must_use] + fn resizable(self, resizable: bool) -> Self; + + /// Whether the window's native maximize button is enabled or not. + /// If resizable is set to false, this setting is ignored. + /// + /// ## Platform-specific + /// + /// - **macOS:** Disables the "zoom" button in the window titlebar, which is also used to enter fullscreen mode. + /// - **Linux / iOS / Android:** Unsupported. + #[must_use] + fn maximizable(self, maximizable: bool) -> Self; + + /// Whether the window's native minimize button is enabled or not. + /// + /// ## Platform-specific + /// + /// - **Linux / iOS / Android:** Unsupported. + #[must_use] + fn minimizable(self, minimizable: bool) -> Self; + + /// Whether the window's native close button is enabled or not. + /// + /// ## Platform-specific + /// + /// - **Linux:** "GTK+ will do its best to convince the window manager not to show a close button. + /// Depending on the system, this function may not have any effect when called on a window that is already visible" + /// - **iOS / Android:** Unsupported. + #[must_use] + fn closable(self, closable: bool) -> Self; + + /// The title of the window in the title bar. + #[must_use] + fn title>(self, title: S) -> Self; + + /// Whether to start the window in fullscreen or not. + #[must_use] + fn fullscreen(self, fullscreen: bool) -> Self; + + /// Whether the window will be initially focused or not. + #[must_use] + fn focused(self, focused: bool) -> Self; + + /// Whether the window should be maximized upon creation. + #[must_use] + fn maximized(self, maximized: bool) -> Self; + + /// Whether the window should be immediately visible upon creation. + #[must_use] + fn visible(self, visible: bool) -> Self; + + /// Whether the window should be transparent. If this is true, writing colors + /// with alpha values different than `1.0` will produce a transparent window. + #[cfg(any(not(target_os = "macos"), feature = "macos-private-api"))] + #[cfg_attr( + docsrs, + doc(cfg(any(not(target_os = "macos"), feature = "macos-private-api"))) + )] + #[must_use] + fn transparent(self, transparent: bool) -> Self; + + /// Whether the window should have borders and bars. + #[must_use] + fn decorations(self, decorations: bool) -> Self; + + /// Whether the window should always be below other windows. + #[must_use] + fn always_on_bottom(self, always_on_bottom: bool) -> Self; + + /// Whether the window should always be on top of other windows. + #[must_use] + fn always_on_top(self, always_on_top: bool) -> Self; + + /// Whether the window should be visible on all workspaces or virtual desktops. + #[must_use] + fn visible_on_all_workspaces(self, visible_on_all_workspaces: bool) -> Self; + + /// Prevents the window contents from being captured by other apps. + #[must_use] + fn content_protected(self, protected: bool) -> Self; + + /// Sets the window icon. + fn icon(self, icon: Icon) -> crate::Result; + + /// Sets whether or not the window icon should be added to the taskbar. + #[must_use] + fn skip_taskbar(self, skip: bool) -> Self; + + /// Set the window background color. + #[must_use] + fn background_color(self, color: Color) -> Self; + + /// Sets whether or not the window has shadow. + /// + /// ## Platform-specific + /// + /// - **Windows:** + /// - `false` has no effect on decorated window, shadows are always ON. + /// - `true` will make undecorated window have a 1px white border, + /// and on Windows 11, it will have a rounded corners. + /// - **Linux:** Unsupported. + #[must_use] + fn shadow(self, enable: bool) -> Self; + + /// Set an owner to the window to be created. + /// + /// From MSDN: + /// - An owned window is always above its owner in the z-order. + /// - The system automatically destroys an owned window when its owner is destroyed. + /// - An owned window is hidden when its owner is minimized. + /// + /// For more information, see + #[cfg(windows)] + #[must_use] + fn owner(self, owner: HWND) -> Self; + + /// Sets a parent to the window to be created. + /// + /// A child window has the WS_CHILD style and is confined to the client area of its parent window. + /// + /// For more information, see + #[cfg(windows)] + #[must_use] + fn parent(self, parent: HWND) -> Self; + + /// Sets a parent to the window to be created. + /// + /// See + #[cfg(target_os = "macos")] + #[must_use] + fn parent(self, parent: *mut std::ffi::c_void) -> Self; + + /// Sets the window to be created transient for parent. + /// + /// See + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + fn transient_for(self, parent: &impl gtk::glib::IsA) -> Self; + + /// Enables or disables drag and drop support. + #[cfg(windows)] + #[must_use] + fn drag_and_drop(self, enabled: bool) -> Self; + + /// Hide the titlebar. Titlebar buttons will still be visible. + #[cfg(target_os = "macos")] + #[must_use] + fn title_bar_style(self, style: tauri_utils::TitleBarStyle) -> Self; + + /// Hide the window title. + #[cfg(target_os = "macos")] + #[must_use] + fn hidden_title(self, hidden: bool) -> Self; + + /// Defines the window [tabbing identifier] for macOS. + /// + /// Windows with matching tabbing identifiers will be grouped together. + /// If the tabbing identifier is not set, automatic tabbing will be disabled. + /// + /// [tabbing identifier]: + #[cfg(target_os = "macos")] + #[must_use] + fn tabbing_identifier(self, identifier: &str) -> Self; + + /// Forces a theme or uses the system settings if None was provided. + fn theme(self, theme: Option) -> Self; + + /// Whether the icon was set or not. + fn has_icon(&self) -> bool; + + fn get_theme(&self) -> Option; + + /// Sets custom name for Windows' window class. **Windows only**. + #[must_use] + fn window_classname>(self, window_classname: S) -> Self; +} + +/// A window that has yet to be built. +pub struct PendingWindow> { + /// The label that the window will be named. + pub label: String, + + /// The [`WindowBuilder`] that the window will be created with. + pub window_builder: >::WindowBuilder, + + /// The webview that gets added to the window. Optional in case you want to use child webviews or other window content instead. + pub webview: Option>, +} + +pub fn is_label_valid(label: &str) -> bool { + label + .chars() + .all(|c| char::is_alphanumeric(c) || c == '-' || c == '/' || c == ':' || c == '_') +} + +pub fn assert_label_is_valid(label: &str) { + assert!( + is_label_valid(label), + "Window label must include only alphanumeric characters, `-`, `/`, `:` and `_`." + ); +} + +impl> PendingWindow { + /// Create a new [`PendingWindow`] with a label from the given [`WindowBuilder`]. + pub fn new( + window_builder: >::WindowBuilder, + label: impl Into, + ) -> crate::Result { + let label = label.into(); + if !is_label_valid(&label) { + Err(crate::Error::InvalidWindowLabel) + } else { + Ok(Self { + window_builder, + label, + webview: None, + }) + } + } + + /// Sets a webview to be created on the window. + pub fn set_webview(&mut self, webview: PendingWebview) -> &mut Self { + self.webview.replace(webview); + self + } +} + +/// Identifier of a window. +#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Ord, PartialOrd)] +pub struct WindowId(u32); + +impl From for WindowId { + fn from(value: u32) -> Self { + Self(value) + } +} + +/// A window that is not yet managed by Tauri. +#[derive(Debug)] +pub struct DetachedWindow> { + /// The identifier of the window. + pub id: WindowId, + /// Name of the window + pub label: String, + + /// The [`WindowDispatch`] associated with the window. + pub dispatcher: R::WindowDispatcher, + + /// The webview dispatcher in case this window has an attached webview. + pub webview: Option>, +} + +/// A detached webview associated with a window. +#[derive(Debug)] +pub struct DetachedWindowWebview> { + pub webview: DetachedWebview, + pub use_https_scheme: bool, +} + +impl> Clone for DetachedWindowWebview { + fn clone(&self) -> Self { + Self { + webview: self.webview.clone(), + use_https_scheme: self.use_https_scheme, + } + } +} + +impl> Clone for DetachedWindow { + fn clone(&self) -> Self { + Self { + id: self.id, + label: self.label.clone(), + dispatcher: self.dispatcher.clone(), + webview: self.webview.clone(), + } + } +} + +impl> Hash for DetachedWindow { + /// Only use the [`DetachedWindow`]'s label to represent its hash. + fn hash(&self, state: &mut H) { + self.label.hash(state) + } +} + +impl> Eq for DetachedWindow {} +impl> PartialEq for DetachedWindow { + /// Only use the [`DetachedWindow`]'s label to compare equality. + fn eq(&self, other: &Self) -> bool { + self.label.eq(&other.label) + } +} + +/// A raw window type that contains fields to access +/// the HWND on Windows, gtk::ApplicationWindow on Linux and +/// NSView on macOS. +pub struct RawWindow<'a> { + #[cfg(windows)] + pub hwnd: isize, + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub gtk_window: &'a gtk::ApplicationWindow, + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + pub default_vbox: Option<&'a gtk::Box>, + pub _marker: &'a PhantomData<()>, +} diff --git a/crates/tauri-schema-generator/Cargo.toml b/crates/tauri-schema-generator/Cargo.toml new file mode 100644 index 000000000000..a2b42c3c27f0 --- /dev/null +++ b/crates/tauri-schema-generator/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "tauri-schema-generator" +version = "0.0.0" +edition = "2021" +publish = false + +[build-dependencies] +tauri-utils = { features = ["schema"], path = "../tauri-utils" } +schemars = { version = "0.8", features = ["url", "preserve_order"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +url = { version = "2.3", features = ["serde"] } diff --git a/crates/tauri-schema-generator/README.md b/crates/tauri-schema-generator/README.md new file mode 100644 index 000000000000..af1c3fbd176d --- /dev/null +++ b/crates/tauri-schema-generator/README.md @@ -0,0 +1,3 @@ +# tauri-schema-generator + +This crate is part of the tauri monorepo workspace and its sole purpose is to generate JSON schema for various tauri config files. diff --git a/crates/tauri-schema-generator/build.rs b/crates/tauri-schema-generator/build.rs new file mode 100644 index 000000000000..f029c6d50299 --- /dev/null +++ b/crates/tauri-schema-generator/build.rs @@ -0,0 +1,58 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::{error::Error, path::PathBuf}; + +use serde::Deserialize; +use tauri_utils::{ + acl::{capability::Capability, Permission, Scopes}, + config::Config, + write_if_changed, +}; + +macro_rules! schema { + ($name:literal, $path:ty) => { + (concat!($name, ".schema.json"), schemars::schema_for!($path)) + }; +} + +#[derive(Deserialize)] +pub struct VersionMetadata { + tauri: String, +} + +pub fn main() -> Result<(), Box> { + let schemas = [ + schema!("capability", Capability), + schema!("permission", Permission), + schema!("scope", Scopes), + ]; + + let out = PathBuf::from(std::env::var("CARGO_MANIFEST_DIR")?); + + let schemas_dir = out.join("schemas"); + std::fs::create_dir_all(&schemas_dir)?; + + 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::(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!("https://schema.tauri.app/config/{tauri_ver}")); + + 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(()) +} diff --git a/crates/tauri-schema-generator/schemas/capability.schema.json b/crates/tauri-schema-generator/schemas/capability.schema.json new file mode 100644 index 000000000000..0c9462c500aa --- /dev/null +++ b/crates/tauri-schema-generator/schemas/capability.schema.json @@ -0,0 +1,234 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Capability", + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n ## Example\n\n `main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\n It should contain a description of what the grouped permissions should allow.\n\n ## Example\n\n This capability allows the `main` window access to `filesystem` write related\n commands and `dialog` commands to enable programatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\n This setting is optional and defaults to not being set, as our\n default use case is that the content is served from our local application.\n\n :::caution\n Make sure you understand the security implications of providing remote\n sources with local system access.\n :::\n\n ## Example\n\n ```json\n {\n \"urls\": [\"https://*.mydomain.dev\"]\n }\n ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\n On multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n ## Example\n\n `[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\n This is only required when using on multiwebview contexts, by default\n all child webviews of a window that matches [`Self::windows`] are linked.\n\n ## Example\n\n `[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ]\n ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\n By default all platforms are targeted.\n\n ## Example\n\n `[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + }, + "definitions": { + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n ## Examples\n\n - \"https://*.mydomain.dev\": allows subdomains of mydomain.dev\n - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`]\n or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ] + }, + "Identifier": { + "type": "string" + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json new file mode 100644 index 000000000000..1c25517eacc7 --- /dev/null +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -0,0 +1,3453 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://schema.tauri.app/config/2.1.1", + "title": "Config", + "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"../dist\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "$schema": { + "description": "The JSON schema for the Tauri config.", + "type": [ + "string", + "null" + ] + }, + "productName": { + "description": "App name.", + "type": [ + "string", + "null" + ], + "pattern": "^[^/\\:*?\"<>|]+$" + }, + "mainBinaryName": { + "description": "App main binary filename. Defaults to the name of your cargo crate.", + "type": [ + "string", + "null" + ] + }, + "version": { + "description": "App version. It is a semver version number or a path to a `package.json` file containing the `version` field. If removed the version number from `Cargo.toml` is used.\n\n By default version 1.0 is used on Android.", + "type": [ + "string", + "null" + ] + }, + "identifier": { + "description": "The application identifier in reverse domain name notation (e.g. `com.tauri.example`).\n This string must be unique across applications since it is used in system configurations like\n the bundle ID and path to the webview data directory.\n This string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-),\n and periods (.).", + "type": "string" + }, + "app": { + "description": "The App configuration.", + "default": { + "enableGTKAppId": false, + "macOSPrivateApi": false, + "security": { + "assetProtocol": { + "enable": false, + "scope": [] + }, + "capabilities": [], + "dangerousDisableAssetCspModification": false, + "freezePrototype": false, + "pattern": { + "use": "brownfield" + } + }, + "windows": [], + "withGlobalTauri": false + }, + "allOf": [ + { + "$ref": "#/definitions/AppConfig" + } + ] + }, + "build": { + "description": "The build configuration.", + "default": {}, + "allOf": [ + { + "$ref": "#/definitions/BuildConfig" + } + ] + }, + "bundle": { + "description": "The bundler configuration.", + "default": { + "active": false, + "android": { + "minSdkVersion": 24 + }, + "createUpdaterArtifacts": false, + "iOS": { + "minimumSystemVersion": "13.0" + }, + "icon": [], + "linux": { + "appimage": { + "bundleMediaFramework": false, + "files": {} + }, + "deb": { + "files": {} + }, + "rpm": { + "epoch": 0, + "files": {}, + "release": "1" + } + }, + "macOS": { + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "files": {}, + "hardenedRuntime": true, + "minimumSystemVersion": "10.13" + }, + "targets": "all", + "useLocalToolsDir": false, + "windows": { + "allowDowngrades": true, + "certificateThumbprint": null, + "digestAlgorithm": null, + "nsis": null, + "signCommand": null, + "timestampUrl": null, + "tsp": false, + "webviewInstallMode": { + "silent": true, + "type": "downloadBootstrapper" + }, + "wix": null + } + }, + "allOf": [ + { + "$ref": "#/definitions/BundleConfig" + } + ] + }, + "plugins": { + "description": "The plugins config.", + "default": {}, + "allOf": [ + { + "$ref": "#/definitions/PluginConfig" + } + ] + } + }, + "additionalProperties": false, + "definitions": { + "AppConfig": { + "description": "The App configuration object.\n\n See more: ", + "type": "object", + "properties": { + "windows": { + "description": "The app windows configuration.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/WindowConfig" + } + }, + "security": { + "description": "Security configuration.", + "default": { + "assetProtocol": { + "enable": false, + "scope": [] + }, + "capabilities": [], + "dangerousDisableAssetCspModification": false, + "freezePrototype": false, + "pattern": { + "use": "brownfield" + } + }, + "allOf": [ + { + "$ref": "#/definitions/SecurityConfig" + } + ] + }, + "trayIcon": { + "description": "Configuration for app tray icon.", + "anyOf": [ + { + "$ref": "#/definitions/TrayIconConfig" + }, + { + "type": "null" + } + ] + }, + "macOSPrivateApi": { + "description": "MacOS private API configuration. Enables the transparent background API and sets the `fullScreenEnabled` preference to `true`.", + "default": false, + "type": "boolean" + }, + "withGlobalTauri": { + "description": "Whether we should inject the Tauri API on `window.__TAURI__` or not.", + "default": false, + "type": "boolean" + }, + "enableGTKAppId": { + "description": "If set to true \"identifier\" will be set as GTK app ID (on systems that use GTK).", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "WindowConfig": { + "description": "The window configuration object.\n\n See more: ", + "type": "object", + "properties": { + "label": { + "description": "The window identifier. It must be alphanumeric.", + "default": "main", + "type": "string" + }, + "create": { + "description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2.0.0-rc/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).", + "default": true, + "type": "boolean" + }, + "url": { + "description": "The window webview URL.", + "default": "index.html", + "allOf": [ + { + "$ref": "#/definitions/WebviewUrl" + } + ] + }, + "userAgent": { + "description": "The user agent for the webview", + "type": [ + "string", + "null" + ] + }, + "dragDropEnabled": { + "description": "Whether the drag and drop is enabled or not on the webview. By default it is enabled.\n\n Disabling it is required to use HTML5 drag and drop on the frontend on Windows.", + "default": true, + "type": "boolean" + }, + "center": { + "description": "Whether or not the window starts centered or not.", + "default": false, + "type": "boolean" + }, + "x": { + "description": "The horizontal position of the window's top left corner", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "y": { + "description": "The vertical position of the window's top left corner", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "width": { + "description": "The window width.", + "default": 800.0, + "type": "number", + "format": "double" + }, + "height": { + "description": "The window height.", + "default": 600.0, + "type": "number", + "format": "double" + }, + "minWidth": { + "description": "The min window width.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "minHeight": { + "description": "The min window height.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "maxWidth": { + "description": "The max window width.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "maxHeight": { + "description": "The max window height.", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "resizable": { + "description": "Whether the window is resizable or not. When resizable is set to false, native window's maximize button is automatically disabled.", + "default": true, + "type": "boolean" + }, + "maximizable": { + "description": "Whether the window's native maximize button is enabled or not.\n If resizable is set to false, this setting is ignored.\n\n ## Platform-specific\n\n - **macOS:** Disables the \"zoom\" button in the window titlebar, which is also used to enter fullscreen mode.\n - **Linux / iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "minimizable": { + "description": "Whether the window's native minimize button is enabled or not.\n\n ## Platform-specific\n\n - **Linux / iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "closable": { + "description": "Whether the window's native close button is enabled or not.\n\n ## Platform-specific\n\n - **Linux:** \"GTK+ will do its best to convince the window manager not to show a close button.\n Depending on the system, this function may not have any effect when called on a window that is already visible\"\n - **iOS / Android:** Unsupported.", + "default": true, + "type": "boolean" + }, + "title": { + "description": "The window title.", + "default": "Tauri App", + "type": "string" + }, + "fullscreen": { + "description": "Whether the window starts as fullscreen or not.", + "default": false, + "type": "boolean" + }, + "focus": { + "description": "Whether the window will be initially focused or not.", + "default": true, + "type": "boolean" + }, + "transparent": { + "description": "Whether the window is transparent or not.\n\n Note that on `macOS` this requires the `macos-private-api` feature flag, enabled under `tauri > macOSPrivateApi`.\n WARNING: Using private APIs on `macOS` prevents your application from being accepted to the `App Store`.", + "default": false, + "type": "boolean" + }, + "maximized": { + "description": "Whether the window is maximized or not.", + "default": false, + "type": "boolean" + }, + "visible": { + "description": "Whether the window is visible or not.", + "default": true, + "type": "boolean" + }, + "decorations": { + "description": "Whether the window should have borders and bars.", + "default": true, + "type": "boolean" + }, + "alwaysOnBottom": { + "description": "Whether the window should always be below other windows.", + "default": false, + "type": "boolean" + }, + "alwaysOnTop": { + "description": "Whether the window should always be on top of other windows.", + "default": false, + "type": "boolean" + }, + "visibleOnAllWorkspaces": { + "description": "Whether the window should be visible on all workspaces or virtual desktops.\n\n ## Platform-specific\n\n - **Windows / iOS / Android:** Unsupported.", + "default": false, + "type": "boolean" + }, + "contentProtected": { + "description": "Prevents the window contents from being captured by other apps.", + "default": false, + "type": "boolean" + }, + "skipTaskbar": { + "description": "If `true`, hides the window icon from the taskbar on Windows and Linux.", + "default": false, + "type": "boolean" + }, + "windowClassname": { + "description": "The name of the window class created on Windows to create the window. **Windows only**.", + "type": [ + "string", + "null" + ] + }, + "theme": { + "description": "The initial window theme. Defaults to the system theme. Only implemented on Windows and macOS 10.14+.", + "anyOf": [ + { + "$ref": "#/definitions/Theme" + }, + { + "type": "null" + } + ] + }, + "titleBarStyle": { + "description": "The style of the macOS title bar.", + "default": "Visible", + "allOf": [ + { + "$ref": "#/definitions/TitleBarStyle" + } + ] + }, + "hiddenTitle": { + "description": "If `true`, sets the window title to be hidden on macOS.", + "default": false, + "type": "boolean" + }, + "acceptFirstMouse": { + "description": "Whether clicking an inactive window also clicks through to the webview on macOS.", + "default": false, + "type": "boolean" + }, + "tabbingIdentifier": { + "description": "Defines the window [tabbing identifier] for macOS.\n\n Windows with matching tabbing identifiers will be grouped together.\n If the tabbing identifier is not set, automatic tabbing will be disabled.\n\n [tabbing identifier]: ", + "type": [ + "string", + "null" + ] + }, + "additionalBrowserArgs": { + "description": "Defines additional browser arguments on Windows. By default wry passes `--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection`\n so if you use this method, you also need to disable these components by yourself if you want.", + "type": [ + "string", + "null" + ] + }, + "shadow": { + "description": "Whether or not the window has shadow.\n\n ## Platform-specific\n\n - **Windows:**\n - `false` has no effect on decorated window, shadow are always ON.\n - `true` will make undecorated window have a 1px white border,\n and on Windows 11, it will have a rounded corners.\n - **Linux:** Unsupported.", + "default": true, + "type": "boolean" + }, + "windowEffects": { + "description": "Window effects.\n\n Requires the window to be transparent.\n\n ## Platform-specific:\n\n - **Windows**: If using decorations or shadows, you may want to try this workaround \n - **Linux**: Unsupported", + "anyOf": [ + { + "$ref": "#/definitions/WindowEffectsConfig" + }, + { + "type": "null" + } + ] + }, + "incognito": { + "description": "Whether or not the webview should be launched in incognito mode.\n\n ## Platform-specific:\n\n - **Android**: Unsupported.", + "default": false, + "type": "boolean" + }, + "parent": { + "description": "Sets the window associated with this label to be the parent of the window to be created.\n\n ## Platform-specific\n\n - **Windows**: This sets the passed parent as an owner window to the window to be created.\n From [MSDN owned windows docs](https://docs.microsoft.com/en-us/windows/win32/winmsg/window-features#owned-windows):\n - An owned window is always above its owner in the z-order.\n - The system automatically destroys an owned window when its owner is destroyed.\n - An owned window is hidden when its owner is minimized.\n - **Linux**: This makes the new window transient for parent, see \n - **macOS**: This adds the window as a child of parent, see ", + "type": [ + "string", + "null" + ] + }, + "proxyUrl": { + "description": "The proxy URL for the WebView for all network requests.\n\n Must be either a `http://` or a `socks5://` URL.\n\n ## Platform-specific\n\n - **macOS**: Requires the `macos-proxy` feature flag and only compiles for macOS 14+.", + "type": [ + "string", + "null" + ], + "format": "uri" + }, + "zoomHotkeysEnabled": { + "description": "Whether page zooming by hotkeys is enabled\n\n ## Platform-specific:\n\n - **Windows**: Controls WebView2's [`IsZoomControlEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2settings?view=webview2-winrt-1.0.2420.47#iszoomcontrolenabled) setting.\n - **MacOS / Linux**: Injects a polyfill that zooms in and out with `ctrl/command` + `-/=`,\n 20% in each step, ranging from 20% to 1000%. Requires `webview:allow-set-webview-zoom` permission\n\n - **Android / iOS**: Unsupported.", + "default": false, + "type": "boolean" + }, + "browserExtensionsEnabled": { + "description": "Whether browser extensions can be installed for the webview process\n\n ## Platform-specific:\n\n - **Windows**: Enables the WebView2 environment's [`AreBrowserExtensionsEnabled`](https://learn.microsoft.com/en-us/microsoft-edge/webview2/reference/winrt/microsoft_web_webview2_core/corewebview2environmentoptions?view=webview2-winrt-1.0.2739.15#arebrowserextensionsenabled)\n - **MacOS / Linux / iOS / Android** - Unsupported.", + "default": false, + "type": "boolean" + }, + "useHttpsScheme": { + "description": "Sets whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost` on Windows and Android. Defaults to `false`.\n\n ## Note\n\n Using a `https` scheme will NOT allow mixed content when trying to fetch `http` endpoints and therefore will not match the behavior of the `://localhost` protocols used on macOS and Linux.\n\n ## Warning\n\n Changing this value between releases will change the IndexedDB, cookies and localstorage location and your app will not be able to access the old data.", + "default": false, + "type": "boolean" + }, + "devtools": { + "description": "Enable web inspector which is usually called browser devtools. Enabled by default.\n\n This API works in **debug** builds, but requires `devtools` feature flag to enable it in **release** builds.\n\n ## Platform-specific\n\n - macOS: This will call private functions on **macOS**.\n - Android: Open `chrome://inspect/#devices` in Chrome to get the devtools window. Wry's `WebView` devtools API isn't supported on Android.\n - iOS: Open Safari > Develop > [Your Device Name] > [Your WebView] to get the devtools window.", + "type": [ + "boolean", + "null" + ] + }, + "backgroundColor": { + "description": "Set the window and webview background color.\n\n ## Platform-specific:\n\n - **Windows**: alpha channel is ignored for the window layer.\n - **Windows**: On Windows 7, alpha channel is ignored for the webview layer.\n - **Windows**: On Windows 8 and newer, if alpha channel is not `0`, it will be ignored for the webview layer.", + "anyOf": [ + { + "$ref": "#/definitions/Color" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "WebviewUrl": { + "description": "An URL to open on a Tauri webview window.", + "anyOf": [ + { + "description": "An external URL. Must use either the `http` or `https` schemes.", + "type": "string", + "format": "uri" + }, + { + "description": "The path portion of an app URL.\n For instance, to load `tauri://localhost/users/john`,\n you can simply provide `users/john` in this configuration.", + "type": "string" + }, + { + "description": "A custom protocol url, for example, `doom://index.html`", + "type": "string", + "format": "uri" + } + ] + }, + "Theme": { + "description": "System theme.", + "oneOf": [ + { + "description": "Light theme.", + "type": "string", + "enum": [ + "Light" + ] + }, + { + "description": "Dark theme.", + "type": "string", + "enum": [ + "Dark" + ] + } + ] + }, + "TitleBarStyle": { + "description": "How the window title bar should be displayed on macOS.", + "oneOf": [ + { + "description": "A normal title bar.", + "type": "string", + "enum": [ + "Visible" + ] + }, + { + "description": "Makes the title bar transparent, so the window background color is shown instead.\n\n Useful if you don't need to have actual HTML under the title bar. This lets you avoid the caveats of using `TitleBarStyle::Overlay`. Will be more useful when Tauri lets you set a custom window background color.", + "type": "string", + "enum": [ + "Transparent" + ] + }, + { + "description": "Shows the title bar as a transparent overlay over the window's content.\n\n Keep in mind:\n - The height of the title bar is different on different OS versions, which can lead to window the controls and title not being where you don't expect.\n - You need to define a custom drag region to make your window draggable, however due to a limitation you can't drag the window when it's not in focus .\n - The color of the window title depends on the system theme.", + "type": "string", + "enum": [ + "Overlay" + ] + } + ] + }, + "WindowEffectsConfig": { + "description": "The window effects configuration object", + "type": "object", + "required": [ + "effects" + ], + "properties": { + "effects": { + "description": "List of Window effects to apply to the Window.\n Conflicting effects will apply the first one and ignore the rest.", + "type": "array", + "items": { + "$ref": "#/definitions/WindowEffect" + } + }, + "state": { + "description": "Window effect state **macOS Only**", + "anyOf": [ + { + "$ref": "#/definitions/WindowEffectState" + }, + { + "type": "null" + } + ] + }, + "radius": { + "description": "Window effect corner radius **macOS Only**", + "type": [ + "number", + "null" + ], + "format": "double" + }, + "color": { + "description": "Window effect color. Affects [`WindowEffect::Blur`] and [`WindowEffect::Acrylic`] only\n on Windows 10 v1903+. Doesn't have any effect on Windows 7 or Windows 11.", + "anyOf": [ + { + "$ref": "#/definitions/Color" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "WindowEffect": { + "description": "Platform-specific window effects", + "oneOf": [ + { + "description": "A default material appropriate for the view's effectiveAppearance. **macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "appearanceBased" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "light" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "dark" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "mediumLight" + ] + }, + { + "description": "**macOS 10.14-**", + "deprecated": true, + "type": "string", + "enum": [ + "ultraDark" + ] + }, + { + "description": "**macOS 10.10+**", + "type": "string", + "enum": [ + "titlebar" + ] + }, + { + "description": "**macOS 10.10+**", + "type": "string", + "enum": [ + "selection" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "menu" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "popover" + ] + }, + { + "description": "**macOS 10.11+**", + "type": "string", + "enum": [ + "sidebar" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "headerView" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "sheet" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "windowBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "hudWindow" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "fullScreenUI" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "tooltip" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "contentBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "underWindowBackground" + ] + }, + { + "description": "**macOS 10.14+**", + "type": "string", + "enum": [ + "underPageBackground" + ] + }, + { + "description": "Mica effect that matches the system dark perefence **Windows 11 Only**", + "type": "string", + "enum": [ + "mica" + ] + }, + { + "description": "Mica effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**", + "type": "string", + "enum": [ + "micaDark" + ] + }, + { + "description": "Mica effect with light mode **Windows 11 Only**", + "type": "string", + "enum": [ + "micaLight" + ] + }, + { + "description": "Tabbed effect that matches the system dark perefence **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbed" + ] + }, + { + "description": "Tabbed effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbedDark" + ] + }, + { + "description": "Tabbed effect with light mode **Windows 11 Only**", + "type": "string", + "enum": [ + "tabbedLight" + ] + }, + { + "description": "**Windows 7/10/11(22H1) Only**\n\n ## Notes\n\n This effect has bad performance when resizing/dragging the window on Windows 11 build 22621.", + "type": "string", + "enum": [ + "blur" + ] + }, + { + "description": "**Windows 10/11 Only**\n\n ## Notes\n\n This effect has bad performance when resizing/dragging the window on Windows 10 v1903+ and Windows 11 build 22000.", + "type": "string", + "enum": [ + "acrylic" + ] + } + ] + }, + "WindowEffectState": { + "description": "Window effect state **macOS only**\n\n ", + "oneOf": [ + { + "description": "Make window effect state follow the window's active state", + "type": "string", + "enum": [ + "followsWindowActiveState" + ] + }, + { + "description": "Make window effect state always active", + "type": "string", + "enum": [ + "active" + ] + }, + { + "description": "Make window effect state always inactive", + "type": "string", + "enum": [ + "inactive" + ] + } + ] + }, + "Color": { + "anyOf": [ + { + "description": "Color hex string, for example: #fff, #ffffff, or #ffffffff.", + "type": "string", + "pattern": "^#?([A-Fa-f0-9]{3}|[A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})$" + }, + { + "description": "Array of RGB colors. Each value has minimum of 0 and maximum of 255.", + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + ], + "maxItems": 3, + "minItems": 3 + }, + { + "description": "Array of RGBA colors. Each value has minimum of 0 and maximum of 255.", + "type": "array", + "items": [ + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + ], + "maxItems": 4, + "minItems": 4 + }, + { + "description": "Object of red, green, blue, alpha color values. Each value has minimum of 0 and maximum of 255.", + "type": "object", + "required": [ + "blue", + "green", + "red" + ], + "properties": { + "red": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "green": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "blue": { + "type": "integer", + "format": "uint8", + "minimum": 0.0 + }, + "alpha": { + "default": 255, + "type": "integer", + "format": "uint8", + "minimum": 0.0 + } + } + } + ] + }, + "SecurityConfig": { + "description": "Security configuration.\n\n See more: ", + "type": "object", + "properties": { + "csp": { + "description": "The Content Security Policy that will be injected on all HTML files on the built application.\n If [`dev_csp`](#SecurityConfig.devCsp) is not specified, this value is also injected on dev.\n\n This is a really important part of the configuration since it helps you ensure your WebView is secured.\n See .", + "anyOf": [ + { + "$ref": "#/definitions/Csp" + }, + { + "type": "null" + } + ] + }, + "devCsp": { + "description": "The Content Security Policy that will be injected on all HTML files on development.\n\n This is a really important part of the configuration since it helps you ensure your WebView is secured.\n See .", + "anyOf": [ + { + "$ref": "#/definitions/Csp" + }, + { + "type": "null" + } + ] + }, + "freezePrototype": { + "description": "Freeze the `Object.prototype` when using the custom protocol.", + "default": false, + "type": "boolean" + }, + "dangerousDisableAssetCspModification": { + "description": "Disables the Tauri-injected CSP sources.\n\n At compile time, Tauri parses all the frontend assets and changes the Content-Security-Policy\n to only allow loading of your own scripts and styles by injecting nonce and hash sources.\n This stricts your CSP, which may introduce issues when using along with other flexing sources.\n\n This configuration option allows both a boolean and a list of strings as value.\n A boolean instructs Tauri to disable the injection for all CSP injections,\n and a list of strings indicates the CSP directives that Tauri cannot inject.\n\n **WARNING:** Only disable this if you know what you are doing and have properly configured the CSP.\n Your application might be vulnerable to XSS attacks without this Tauri protection.", + "default": false, + "allOf": [ + { + "$ref": "#/definitions/DisabledCspModificationKind" + } + ] + }, + "assetProtocol": { + "description": "Custom protocol config.", + "default": { + "enable": false, + "scope": [] + }, + "allOf": [ + { + "$ref": "#/definitions/AssetProtocolConfig" + } + ] + }, + "pattern": { + "description": "The pattern to use.", + "default": { + "use": "brownfield" + }, + "allOf": [ + { + "$ref": "#/definitions/PatternKind" + } + ] + }, + "capabilities": { + "description": "List of capabilities that are enabled on the application.\n\n If the list is empty, all capabilities are included.", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/CapabilityEntry" + } + }, + "headers": { + "description": "The headers, which are added to every http response from tauri to the web view\n This doesn't include IPC Messages and error responses", + "anyOf": [ + { + "$ref": "#/definitions/HeaderConfig" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "Csp": { + "description": "A Content-Security-Policy definition.\n See .", + "anyOf": [ + { + "description": "The entire CSP policy in a single text string.", + "type": "string" + }, + { + "description": "An object mapping a directive with its sources values as a list of strings.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/CspDirectiveSources" + } + } + ] + }, + "CspDirectiveSources": { + "description": "A Content-Security-Policy directive source list.\n See .", + "anyOf": [ + { + "description": "An inline list of CSP sources. Same as [`Self::List`], but concatenated with a space separator.", + "type": "string" + }, + { + "description": "A list of CSP sources. The collection will be concatenated with a space separator for the CSP string.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "DisabledCspModificationKind": { + "description": "The possible values for the `dangerous_disable_asset_csp_modification` config option.", + "anyOf": [ + { + "description": "If `true`, disables all CSP modification.\n `false` is the default value and it configures Tauri to control the CSP.", + "type": "boolean" + }, + { + "description": "Disables the given list of CSP directives modifications.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "AssetProtocolConfig": { + "description": "Config for the asset custom protocol.\n\n See more: ", + "type": "object", + "properties": { + "scope": { + "description": "The access scope for the asset protocol.", + "default": [], + "allOf": [ + { + "$ref": "#/definitions/FsScope" + } + ] + }, + "enable": { + "description": "Enables the asset protocol.", + "default": false, + "type": "boolean" + } + }, + "additionalProperties": false + }, + "FsScope": { + "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,\n `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "anyOf": [ + { + "description": "A list of paths that are allowed by this scope.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A complete scope configuration.", + "type": "object", + "properties": { + "allow": { + "description": "A list of paths that are allowed by this scope.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "A list of paths that are not allowed by this scope.\n This gets precedence over the [`Self::Scope::allow`] list.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "requireLiteralLeadingDot": { + "description": "Whether or not paths that contain components that start with a `.`\n will require that `.` appears literally in the pattern; `*`, `?`, `**`,\n or `[...]` will not match. This is useful because such files are\n conventionally considered hidden on Unix systems and it might be\n desirable to skip them when listing files.\n\n Defaults to `true` on Unix systems and `false` on Windows", + "type": [ + "boolean", + "null" + ] + } + } + } + ] + }, + "PatternKind": { + "description": "The application pattern.", + "oneOf": [ + { + "description": "Brownfield pattern.", + "type": "object", + "required": [ + "use" + ], + "properties": { + "use": { + "type": "string", + "enum": [ + "brownfield" + ] + } + } + }, + { + "description": "Isolation pattern. Recommended for security purposes.", + "type": "object", + "required": [ + "options", + "use" + ], + "properties": { + "use": { + "type": "string", + "enum": [ + "isolation" + ] + }, + "options": { + "type": "object", + "required": [ + "dir" + ], + "properties": { + "dir": { + "description": "The dir containing the index.html file that contains the secure isolation application.", + "type": "string" + } + } + } + } + } + ] + }, + "CapabilityEntry": { + "description": "A capability entry which can be either an inlined capability or a reference to a capability defined on its own file.", + "anyOf": [ + { + "description": "An inlined capability.", + "allOf": [ + { + "$ref": "#/definitions/Capability" + } + ] + }, + { + "description": "Reference to a capability identifier.", + "type": "string" + } + ] + }, + "Capability": { + "description": "A grouping and boundary mechanism developers can use to isolate access to the IPC layer.\n\n It controls application windows fine grained access to the Tauri core, application, or plugin commands.\n If a window is not matching any capability then it has no access to the IPC layer at all.\n\n This can be done to create groups of windows, based on their required system access, which can reduce\n impact of frontend vulnerabilities in less privileged windows.\n Windows can be added to a capability by exact name (e.g. `main-window`) or glob patterns like `*` or `admin-*`.\n A Window can have none, one, or multiple associated capabilities.\n\n ## Example\n\n ```json\n {\n \"identifier\": \"main-user-files-write\",\n \"description\": \"This capability allows the `main` window on macOS and Windows access to `filesystem` write related commands and `dialog` commands to enable programatic access to files selected by the user.\",\n \"windows\": [\n \"main\"\n ],\n \"permissions\": [\n \"core:default\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n },\n ],\n \"platforms\": [\"macOS\",\"windows\"]\n }\n ```", + "type": "object", + "required": [ + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "Identifier of the capability.\n\n ## Example\n\n `main-user-files-write`", + "type": "string" + }, + "description": { + "description": "Description of what the capability is intended to allow on associated windows.\n\n It should contain a description of what the grouped permissions should allow.\n\n ## Example\n\n This capability allows the `main` window access to `filesystem` write related\n commands and `dialog` commands to enable programatic access to files selected by the user.", + "default": "", + "type": "string" + }, + "remote": { + "description": "Configure remote URLs that can use the capability permissions.\n\n This setting is optional and defaults to not being set, as our\n default use case is that the content is served from our local application.\n\n :::caution\n Make sure you understand the security implications of providing remote\n sources with local system access.\n :::\n\n ## Example\n\n ```json\n {\n \"urls\": [\"https://*.mydomain.dev\"]\n }\n ```", + "anyOf": [ + { + "$ref": "#/definitions/CapabilityRemote" + }, + { + "type": "null" + } + ] + }, + "local": { + "description": "Whether this capability is enabled for local app URLs or not. Defaults to `true`.", + "default": true, + "type": "boolean" + }, + "windows": { + "description": "List of windows that are affected by this capability. Can be a glob pattern.\n\n On multiwebview windows, prefer [`Self::webviews`] for a fine grained access control.\n\n ## Example\n\n `[\"main\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "webviews": { + "description": "List of webviews that are affected by this capability. Can be a glob pattern.\n\n This is only required when using on multiwebview contexts, by default\n all child webviews of a window that matches [`Self::windows`] are linked.\n\n ## Example\n\n `[\"sub-webview-one\", \"sub-webview-two\"]`", + "type": "array", + "items": { + "type": "string" + } + }, + "permissions": { + "description": "List of permissions attached to this capability.\n\n Must include the plugin name as prefix in the form of `${plugin-name}:${permission-name}`.\n For commands directly implemented in the application itself only `${permission-name}`\n is required.\n\n ## Example\n\n ```json\n [\n \"core:default\",\n \"shell:allow-open\",\n \"dialog:open\",\n {\n \"identifier\": \"fs:allow-write-text-file\",\n \"allow\": [{ \"path\": \"$HOME/test.txt\" }]\n }\n ]\n ```", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionEntry" + }, + "uniqueItems": true + }, + "platforms": { + "description": "Limit which target platforms this capability applies to.\n\n By default all platforms are targeted.\n\n ## Example\n\n `[\"macOS\",\"windows\"]`", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "CapabilityRemote": { + "description": "Configuration for remote URLs that are associated with the capability.", + "type": "object", + "required": [ + "urls" + ], + "properties": { + "urls": { + "description": "Remote domains this capability refers to using the [URLPattern standard](https://urlpattern.spec.whatwg.org/).\n\n ## Examples\n\n - \"https://*.mydomain.dev\": allows subdomains of mydomain.dev\n - \"https://mydomain.dev/api/*\": allows any subpath of mydomain.dev/api", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionEntry": { + "description": "An entry for a permission value in a [`Capability`] can be either a raw permission [`Identifier`]\n or an object that references a permission and extends its scope.", + "anyOf": [ + { + "description": "Reference a permission or permission set by identifier.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + { + "description": "Reference a permission or permission set by identifier and extends its scope.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "identifier": { + "description": "Identifier of the permission or permission set.", + "allOf": [ + { + "$ref": "#/definitions/Identifier" + } + ] + }, + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + } + ] + }, + "Identifier": { + "type": "string" + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "HeaderConfig": { + "description": "A struct, where the keys are some specific http header names.\n If the values to those keys are defined, then they will be send as part of a response message.\n This does not include error messages and ipc messages\n\n ## Example configuration\n ```javascript\n {\n //..\n app:{\n //..\n security: {\n headers: {\n \"Cross-Origin-Opener-Policy\": \"same-origin\",\n \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n \"Timing-Allow-Origin\": [\n \"https://developer.mozilla.org\",\n \"https://example.com\",\n ],\n \"Access-Control-Expose-Headers\": \"Tauri-Custom-Header\",\n \"Tauri-Custom-Header\": {\n \"key1\": \"'value1' 'value2'\",\n \"key2\": \"'value3'\"\n }\n },\n csp: \"default-src 'self'; connect-src ipc: http://ipc.localhost\",\n }\n //..\n }\n //..\n }\n ```\n In this example `Cross-Origin-Opener-Policy` and `Cross-Origin-Embedder-Policy` are set to allow for the use of [`SharedArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer).\n The result is, that those headers are then set on every response sent via the `get_response` function in crates/tauri/src/protocol/tauri.rs.\n The Content-Security-Policy header is defined separately, because it is also handled separately.\n\n For the helloworld example, this config translates into those response headers:\n ```http\n access-control-allow-origin: http://tauri.localhost\n access-control-expose-headers: Tauri-Custom-Header\n content-security-policy: default-src 'self'; connect-src ipc: http://ipc.localhost; script-src 'self' 'sha256-Wjjrs6qinmnr+tOry8x8PPwI77eGpUFR3EEGZktjJNs='\n content-type: text/html\n cross-origin-embedder-policy: require-corp\n cross-origin-opener-policy: same-origin\n tauri-custom-header: key1 'value1' 'value2'; key2 'value3'\n timing-allow-origin: https://developer.mozilla.org, https://example.com\n ```\n Since the resulting header values are always 'string-like'. So depending on the what data type the HeaderSource is, they need to be converted.\n - `String`(JS/Rust): stay the same for the resulting header value\n - `Array`(JS)/`Vec\\`(Rust): Item are joined by \", \" for the resulting header value\n - `Object`(JS)/ `Hashmap\\`(Rust): Items are composed from: key + space + value. Item are then joined by \"; \" for the resulting header value", + "type": "object", + "properties": { + "Access-Control-Allow-Credentials": { + "description": "The Access-Control-Allow-Credentials response header tells browsers whether the\n server allows cross-origin HTTP requests to include credentials.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Access-Control-Allow-Headers": { + "description": "The Access-Control-Allow-Headers response header is used in response\n to a preflight request which includes the Access-Control-Request-Headers\n to indicate which HTTP headers can be used during the actual request.\n\n This header is required if the request has an Access-Control-Request-Headers header.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Access-Control-Allow-Methods": { + "description": "The Access-Control-Allow-Methods response header specifies one or more methods\n allowed when accessing a resource in response to a preflight request.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Access-Control-Expose-Headers": { + "description": "The Access-Control-Expose-Headers response header allows a server to indicate\n which response headers should be made available to scripts running in the browser,\n in response to a cross-origin request.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Access-Control-Max-Age": { + "description": "The Access-Control-Max-Age response header indicates how long the results of a\n preflight request (that is the information contained in the\n Access-Control-Allow-Methods and Access-Control-Allow-Headers headers) can\n be cached.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Cross-Origin-Embedder-Policy": { + "description": "The HTTP Cross-Origin-Embedder-Policy (COEP) response header configures embedding\n cross-origin resources into the document.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Cross-Origin-Opener-Policy": { + "description": "The HTTP Cross-Origin-Opener-Policy (COOP) response header allows you to ensure a\n top-level document does not share a browsing context group with cross-origin documents.\n COOP will process-isolate your document and potential attackers can't access your global\n object if they were to open it in a popup, preventing a set of cross-origin attacks dubbed XS-Leaks.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Cross-Origin-Resource-Policy": { + "description": "The HTTP Cross-Origin-Resource-Policy response header conveys a desire that the\n browser blocks no-cors cross-origin/cross-site requests to the given resource.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Permissions-Policy": { + "description": "The HTTP Permissions-Policy header provides a mechanism to allow and deny the\n use of browser features in a document or within any \\ elements in the document.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Timing-Allow-Origin": { + "description": "The Timing-Allow-Origin response header specifies origins that are allowed to see values\n of attributes retrieved via features of the Resource Timing API, which would otherwise be\n reported as zero due to cross-origin restrictions.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "X-Content-Type-Options": { + "description": "The X-Content-Type-Options response HTTP header is a marker used by the server to indicate\n that the MIME types advertised in the Content-Type headers should be followed and not be\n changed. The header allows you to avoid MIME type sniffing by saying that the MIME types\n are deliberately configured.\n\n See ", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + }, + "Tauri-Custom-Header": { + "description": "A custom header field Tauri-Custom-Header, don't use it.\n Remember to set Access-Control-Expose-Headers accordingly\n\n **NOT INTENDED FOR PRODUCTION USE**", + "anyOf": [ + { + "$ref": "#/definitions/HeaderSource" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "HeaderSource": { + "description": "definition of a header source\n\n The header value to a header name", + "anyOf": [ + { + "description": "string version of the header Value", + "type": "string" + }, + { + "description": "list version of the header value. Item are joined by \",\" for the real header value", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "(Rust struct | Json | JavaScript Object) equivalent of the header value. Items are composed from: key + space + value. Item are then joined by \";\" for the real header value", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + ] + }, + "TrayIconConfig": { + "description": "Configuration for application tray icon.\n\n See more: ", + "type": "object", + "required": [ + "iconPath" + ], + "properties": { + "id": { + "description": "Set an id for this tray icon so you can reference it later, defaults to `main`.", + "type": [ + "string", + "null" + ] + }, + "iconPath": { + "description": "Path to the default icon to use for the tray icon.\n\n Note: this stores the image in raw pixels to the final binary,\n so keep the icon size (width and height) small\n or else it's going to bloat your final executable", + "type": "string" + }, + "iconAsTemplate": { + "description": "A Boolean value that determines whether the image represents a [template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) image on macOS.", + "default": false, + "type": "boolean" + }, + "menuOnLeftClick": { + "description": "A Boolean value that determines whether the menu should appear when the tray icon receives a left click.\n\n ## Platform-specific:\n\n - **Linux**: Unsupported.", + "default": true, + "deprecated": true, + "type": "boolean" + }, + "showMenuOnLeftClick": { + "description": "A Boolean value that determines whether the menu should appear when the tray icon receives a left click.\n\n ## Platform-specific:\n\n - **Linux**: Unsupported.", + "default": true, + "type": "boolean" + }, + "title": { + "description": "Title for MacOS tray", + "type": [ + "string", + "null" + ] + }, + "tooltip": { + "description": "Tray icon tooltip on Windows and macOS", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "BuildConfig": { + "description": "The Build configuration object.\n\n See more: ", + "type": "object", + "properties": { + "runner": { + "description": "The binary used to build and run the application.", + "type": [ + "string", + "null" + ] + }, + "devUrl": { + "description": "The URL to load in development.\n\n This is usually an URL to a dev server, which serves your application assets with hot-reload and HMR.\n Most modern JavaScript bundlers like [vite](https://vitejs.dev/guide/) provides a way to start a dev server by default.\n\n If you don't have a dev server or don't want to use one, ignore this option and use [`frontendDist`](BuildConfig::frontend_dist)\n and point to a web assets directory, and Tauri CLI will run its built-in dev server and provide a simple hot-reload experience.", + "type": [ + "string", + "null" + ], + "format": "uri" + }, + "frontendDist": { + "description": "The path to the application assets (usually the `dist` folder of your javascript bundler)\n or a URL that could be either a custom protocol registered in the tauri app (for example: `myprotocol://`)\n or a remote URL (for example: `https://site.com/app`).\n\n When a path relative to the configuration file is provided,\n it is read recursively and all files are embedded in the application binary.\n Tauri then looks for an `index.html` and serves it as the default entry point for your application.\n\n You can also provide a list of paths to be embedded, which allows granular control over what files are added to the binary.\n In this case, all files are added to the root and you must reference it that way in your HTML files.\n\n When a URL is provided, the application won't have bundled assets\n and the application will load that URL by default.", + "anyOf": [ + { + "$ref": "#/definitions/FrontendDist" + }, + { + "type": "null" + } + ] + }, + "beforeDevCommand": { + "description": "A shell command to run before `tauri dev` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/BeforeDevCommand" + }, + { + "type": "null" + } + ] + }, + "beforeBuildCommand": { + "description": "A shell command to run before `tauri build` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/HookCommand" + }, + { + "type": "null" + } + ] + }, + "beforeBundleCommand": { + "description": "A shell command to run before the bundling phase in `tauri build` kicks in.\n\n The TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG environment variables are set if you perform conditional compilation.", + "anyOf": [ + { + "$ref": "#/definitions/HookCommand" + }, + { + "type": "null" + } + ] + }, + "features": { + "description": "Features passed to `cargo` commands.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "FrontendDist": { + "description": "Defines the URL or assets to embed in the application.", + "anyOf": [ + { + "description": "An external URL that should be used as the default application URL.", + "type": "string", + "format": "uri" + }, + { + "description": "Path to a directory containing the frontend dist assets.", + "type": "string" + }, + { + "description": "An array of files to embed on the app.", + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "BeforeDevCommand": { + "description": "Describes the shell command to run before `tauri dev`.", + "anyOf": [ + { + "description": "Run the given script with the default options.", + "type": "string" + }, + { + "description": "Run the given script with custom options.", + "type": "object", + "required": [ + "script" + ], + "properties": { + "script": { + "description": "The script to execute.", + "type": "string" + }, + "cwd": { + "description": "The current working directory.", + "type": [ + "string", + "null" + ] + }, + "wait": { + "description": "Whether `tauri dev` should wait for the command to finish or not. Defaults to `false`.", + "default": false, + "type": "boolean" + } + } + } + ] + }, + "HookCommand": { + "description": "Describes a shell command to be executed when a CLI hook is triggered.", + "anyOf": [ + { + "description": "Run the given script with the default options.", + "type": "string" + }, + { + "description": "Run the given script with custom options.", + "type": "object", + "required": [ + "script" + ], + "properties": { + "script": { + "description": "The script to execute.", + "type": "string" + }, + "cwd": { + "description": "The current working directory.", + "type": [ + "string", + "null" + ] + } + } + } + ] + }, + "BundleConfig": { + "description": "Configuration for tauri-bundler.\n\n See more: ", + "type": "object", + "properties": { + "active": { + "description": "Whether Tauri should bundle your application or just output the executable.", + "default": false, + "type": "boolean" + }, + "targets": { + "description": "The bundle targets, currently supports [\"deb\", \"rpm\", \"appimage\", \"nsis\", \"msi\", \"app\", \"dmg\"] or \"all\".", + "default": "all", + "allOf": [ + { + "$ref": "#/definitions/BundleTarget" + } + ] + }, + "createUpdaterArtifacts": { + "description": "Produce updaters and their signatures or not", + "default": false, + "allOf": [ + { + "$ref": "#/definitions/Updater" + } + ] + }, + "publisher": { + "description": "The application's publisher. Defaults to the second element in the identifier string.\n\n Currently maps to the Manufacturer property of the Windows Installer\n and the Maintainer field of debian packages if the Cargo.toml does not have the authors field.", + "type": [ + "string", + "null" + ] + }, + "homepage": { + "description": "A url to the home page of your application. If unset, will\n fallback to `homepage` defined in `Cargo.toml`.\n\n Supported bundle targets: `deb`, `rpm`, `nsis` and `msi`.", + "type": [ + "string", + "null" + ] + }, + "icon": { + "description": "The app's icons", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "resources": { + "description": "App resources to bundle.\n Each resource is a path to a file or directory.\n Glob patterns are supported.", + "anyOf": [ + { + "$ref": "#/definitions/BundleResources" + }, + { + "type": "null" + } + ] + }, + "copyright": { + "description": "A copyright string associated with your application.", + "type": [ + "string", + "null" + ] + }, + "license": { + "description": "The package's license identifier to be included in the appropriate bundles.\n If not set, defaults to the license from the Cargo.toml file.", + "type": [ + "string", + "null" + ] + }, + "licenseFile": { + "description": "The path to the license file to be included in the appropriate bundles.", + "type": [ + "string", + "null" + ] + }, + "category": { + "description": "The application kind.\n\n Should be one of the following:\n Business, DeveloperTool, Education, Entertainment, Finance, Game, ActionGame, AdventureGame, ArcadeGame, BoardGame, CardGame, CasinoGame, DiceGame, EducationalGame, FamilyGame, KidsGame, MusicGame, PuzzleGame, RacingGame, RolePlayingGame, SimulationGame, SportsGame, StrategyGame, TriviaGame, WordGame, GraphicsAndDesign, HealthcareAndFitness, Lifestyle, Medical, Music, News, Photography, Productivity, Reference, SocialNetworking, Sports, Travel, Utility, Video, Weather.", + "type": [ + "string", + "null" + ] + }, + "fileAssociations": { + "description": "File associations to application.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/FileAssociation" + } + }, + "shortDescription": { + "description": "A short description of your application.", + "type": [ + "string", + "null" + ] + }, + "longDescription": { + "description": "A longer, multi-line description of the application.", + "type": [ + "string", + "null" + ] + }, + "useLocalToolsDir": { + "description": "Whether to use the project's `target` directory, for caching build tools (e.g., Wix and NSIS) when building this application. Defaults to `false`.\n\n If true, tools will be cached in `target\\.tauri-tools`.\n If false, tools will be cached in the current user's platform-specific cache directory.\n\n An example where it can be appropriate to set this to `true` is when building this application as a Windows System user (e.g., AWS EC2 workloads),\n because the Window system's app data directory is restricted.", + "default": false, + "type": "boolean" + }, + "externalBin": { + "description": "A list of—either absolute or relative—paths to binaries to embed with your application.\n\n Note that Tauri will look for system-specific binaries following the pattern \"binary-name{-target-triple}{.system-extension}\".\n\n E.g. for the external binary \"my-binary\", Tauri looks for:\n\n - \"my-binary-x86_64-pc-windows-msvc.exe\" for Windows\n - \"my-binary-x86_64-apple-darwin\" for macOS\n - \"my-binary-x86_64-unknown-linux-gnu\" for Linux\n\n so don't forget to provide binaries for all targeted platforms.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "windows": { + "description": "Configuration for the Windows bundles.", + "default": { + "allowDowngrades": true, + "certificateThumbprint": null, + "digestAlgorithm": null, + "nsis": null, + "signCommand": null, + "timestampUrl": null, + "tsp": false, + "webviewInstallMode": { + "silent": true, + "type": "downloadBootstrapper" + }, + "wix": null + }, + "allOf": [ + { + "$ref": "#/definitions/WindowsConfig" + } + ] + }, + "linux": { + "description": "Configuration for the Linux bundles.", + "default": { + "appimage": { + "bundleMediaFramework": false, + "files": {} + }, + "deb": { + "files": {} + }, + "rpm": { + "epoch": 0, + "files": {}, + "release": "1" + } + }, + "allOf": [ + { + "$ref": "#/definitions/LinuxConfig" + } + ] + }, + "macOS": { + "description": "Configuration for the macOS bundles.", + "default": { + "dmg": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "files": {}, + "hardenedRuntime": true, + "minimumSystemVersion": "10.13" + }, + "allOf": [ + { + "$ref": "#/definitions/MacConfig" + } + ] + }, + "iOS": { + "description": "iOS configuration.", + "default": { + "minimumSystemVersion": "13.0" + }, + "allOf": [ + { + "$ref": "#/definitions/IosConfig" + } + ] + }, + "android": { + "description": "Android configuration.", + "default": { + "minSdkVersion": 24 + }, + "allOf": [ + { + "$ref": "#/definitions/AndroidConfig" + } + ] + } + }, + "additionalProperties": false + }, + "BundleTarget": { + "description": "Targets to bundle. Each value is case insensitive.", + "anyOf": [ + { + "description": "Bundle all targets.", + "const": "all" + }, + { + "description": "A list of bundle targets.", + "type": "array", + "items": { + "$ref": "#/definitions/BundleType" + } + }, + { + "description": "A single bundle target.", + "allOf": [ + { + "$ref": "#/definitions/BundleType" + } + ] + } + ] + }, + "BundleType": { + "description": "A bundle referenced by tauri-bundler.", + "oneOf": [ + { + "description": "The debian bundle (.deb).", + "type": "string", + "enum": [ + "deb" + ] + }, + { + "description": "The RPM bundle (.rpm).", + "type": "string", + "enum": [ + "rpm" + ] + }, + { + "description": "The AppImage bundle (.appimage).", + "type": "string", + "enum": [ + "appimage" + ] + }, + { + "description": "The Microsoft Installer bundle (.msi).", + "type": "string", + "enum": [ + "msi" + ] + }, + { + "description": "The NSIS bundle (.exe).", + "type": "string", + "enum": [ + "nsis" + ] + }, + { + "description": "The macOS application bundle (.app).", + "type": "string", + "enum": [ + "app" + ] + }, + { + "description": "The Apple Disk Image bundle (.dmg).", + "type": "string", + "enum": [ + "dmg" + ] + } + ] + }, + "Updater": { + "description": "Updater type", + "anyOf": [ + { + "description": "Generates lagacy zipped v1 compatible updaters", + "allOf": [ + { + "$ref": "#/definitions/V1Compatible" + } + ] + }, + { + "description": "Produce updaters and their signatures or not", + "type": "boolean" + } + ] + }, + "V1Compatible": { + "description": "Generates lagacy zipped v1 compatible updaters", + "oneOf": [ + { + "description": "Generates lagacy zipped v1 compatible updaters", + "type": "string", + "enum": [ + "v1Compatible" + ] + } + ] + }, + "BundleResources": { + "description": "Definition for bundle resources.\n Can be either a list of paths to include or a map of source to target paths.", + "anyOf": [ + { + "description": "A list of paths to include.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A map of source to target paths.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + ] + }, + "FileAssociation": { + "description": "File association", + "type": "object", + "required": [ + "ext" + ], + "properties": { + "ext": { + "description": "File extensions to associate with this app. e.g. 'png'", + "type": "array", + "items": { + "$ref": "#/definitions/AssociationExt" + } + }, + "name": { + "description": "The name. Maps to `CFBundleTypeName` on macOS. Default to `ext[0]`", + "type": [ + "string", + "null" + ] + }, + "description": { + "description": "The association description. Windows-only. It is displayed on the `Type` column on Windows Explorer.", + "type": [ + "string", + "null" + ] + }, + "role": { + "description": "The app's role with respect to the type. Maps to `CFBundleTypeRole` on macOS.", + "default": "Editor", + "allOf": [ + { + "$ref": "#/definitions/BundleTypeRole" + } + ] + }, + "mimeType": { + "description": "The mime-type e.g. 'image/png' or 'text/plain'. Linux-only.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "AssociationExt": { + "description": "An extension for a [`FileAssociation`].\n\n A leading `.` is automatically stripped.", + "type": "string" + }, + "BundleTypeRole": { + "description": "macOS-only. Corresponds to CFBundleTypeRole", + "oneOf": [ + { + "description": "CFBundleTypeRole.Editor. Files can be read and edited.", + "type": "string", + "enum": [ + "Editor" + ] + }, + { + "description": "CFBundleTypeRole.Viewer. Files can be read.", + "type": "string", + "enum": [ + "Viewer" + ] + }, + { + "description": "CFBundleTypeRole.Shell", + "type": "string", + "enum": [ + "Shell" + ] + }, + { + "description": "CFBundleTypeRole.QLGenerator", + "type": "string", + "enum": [ + "QLGenerator" + ] + }, + { + "description": "CFBundleTypeRole.None", + "type": "string", + "enum": [ + "None" + ] + } + ] + }, + "WindowsConfig": { + "description": "Windows bundler configuration.\n\n See more: ", + "type": "object", + "properties": { + "digestAlgorithm": { + "description": "Specifies the file digest algorithm to use for creating file signatures.\n Required for code signing. SHA-256 is recommended.", + "type": [ + "string", + "null" + ] + }, + "certificateThumbprint": { + "description": "Specifies the SHA1 hash of the signing certificate.", + "type": [ + "string", + "null" + ] + }, + "timestampUrl": { + "description": "Server to use during timestamping.", + "type": [ + "string", + "null" + ] + }, + "tsp": { + "description": "Whether to use Time-Stamp Protocol (TSP, a.k.a. RFC 3161) for the timestamp server. Your code signing provider may\n use a TSP timestamp server, like e.g. SSL.com does. If so, enable TSP by setting to true.", + "default": false, + "type": "boolean" + }, + "webviewInstallMode": { + "description": "The installation mode for the Webview2 runtime.", + "default": { + "silent": true, + "type": "downloadBootstrapper" + }, + "allOf": [ + { + "$ref": "#/definitions/WebviewInstallMode" + } + ] + }, + "allowDowngrades": { + "description": "Validates a second app installation, blocking the user from installing an older version if set to `false`.\n\n For instance, if `1.2.1` is installed, the user won't be able to install app version `1.2.0` or `1.1.5`.\n\n The default value of this flag is `true`.", + "default": true, + "type": "boolean" + }, + "wix": { + "description": "Configuration for the MSI generated with WiX.", + "anyOf": [ + { + "$ref": "#/definitions/WixConfig" + }, + { + "type": "null" + } + ] + }, + "nsis": { + "description": "Configuration for the installer generated with NSIS.", + "anyOf": [ + { + "$ref": "#/definitions/NsisConfig" + }, + { + "type": "null" + } + ] + }, + "signCommand": { + "description": "Specify a custom command to sign the binaries.\n This command needs to have a `%1` in args which is just a placeholder for the binary path,\n which we will detect and replace before calling the command.\n\n By Default we use `signtool.exe` which can be found only on Windows so\n if you are on another platform and want to cross-compile and sign you will\n need to use another tool like `osslsigncode`.", + "anyOf": [ + { + "$ref": "#/definitions/CustomSignCommandConfig" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "WebviewInstallMode": { + "description": "Install modes for the Webview2 runtime.\n Note that for the updater bundle [`Self::DownloadBootstrapper`] is used.\n\n For more information see .", + "oneOf": [ + { + "description": "Do not install the Webview2 as part of the Windows Installer.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "skip" + ] + } + }, + "additionalProperties": false + }, + { + "description": "Download the bootstrapper and run it.\n Requires an internet connection.\n Results in a smaller installer size, but is not recommended on Windows 7.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "downloadBootstrapper" + ] + }, + "silent": { + "description": "Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed the bootstrapper and run it.\n Requires an internet connection.\n Increases the installer size by around 1.8MB, but offers better support on Windows 7.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "embedBootstrapper" + ] + }, + "silent": { + "description": "Instructs the installer to run the bootstrapper in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed the offline installer and run it.\n Does not require an internet connection.\n Increases the installer size by around 127MB.", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "offlineInstaller" + ] + }, + "silent": { + "description": "Instructs the installer to run the installer in silent mode. Defaults to `true`.", + "default": true, + "type": "boolean" + } + }, + "additionalProperties": false + }, + { + "description": "Embed a fixed webview2 version and use it at runtime.\n Increases the installer size by around 180MB.", + "type": "object", + "required": [ + "path", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "fixedRuntime" + ] + }, + "path": { + "description": "The path to the fixed runtime to use.\n\n The fixed version can be downloaded [on the official website](https://developer.microsoft.com/en-us/microsoft-edge/webview2/#download-section).\n The `.cab` file must be extracted to a folder and this folder path must be defined on this field.", + "type": "string" + } + }, + "additionalProperties": false + } + ] + }, + "WixConfig": { + "description": "Configuration for the MSI bundle using WiX.\n\n See more: ", + "type": "object", + "properties": { + "version": { + "description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and foruth fields have a maximum value of 65,535.\n\n See for more info.", + "type": [ + "string", + "null" + ] + }, + "upgradeCode": { + "description": "A GUID upgrade code for MSI installer. This code **_must stay the same across all of your updates_**,\n otherwise, Windows will treat your update as a different app and your users will have duplicate versions of your app.\n\n By default, tauri generates this code by generating a Uuid v5 using the string `.exe.app.x64` in the DNS namespace.\n You can use Tauri's CLI to generate and print this code for you, run `tauri inspect wix-upgrade-code`.\n\n It is recommended that you set this value in your tauri config file to avoid accidental changes in your upgrade code\n whenever you want to change your product name.", + "type": [ + "string", + "null" + ], + "format": "uuid" + }, + "language": { + "description": "The installer languages to build. See .", + "default": "en-US", + "allOf": [ + { + "$ref": "#/definitions/WixLanguage" + } + ] + }, + "template": { + "description": "A custom .wxs template to use.", + "type": [ + "string", + "null" + ] + }, + "fragmentPaths": { + "description": "A list of paths to .wxs files with WiX fragments to use.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "componentGroupRefs": { + "description": "The ComponentGroup element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "componentRefs": { + "description": "The Component element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "featureGroupRefs": { + "description": "The FeatureGroup element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "featureRefs": { + "description": "The Feature element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "mergeRefs": { + "description": "The Merge element ids you want to reference from the fragments.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "enableElevatedUpdateTask": { + "description": "Create an elevated update task within Windows Task Scheduler.", + "default": false, + "type": "boolean" + }, + "bannerPath": { + "description": "Path to a bitmap file to use as the installation user interface banner.\n This bitmap will appear at the top of all but the first page of the installer.\n\n The required dimensions are 493px × 58px.", + "type": [ + "string", + "null" + ] + }, + "dialogImagePath": { + "description": "Path to a bitmap file to use on the installation user interface dialogs.\n It is used on the welcome and completion dialogs.\n\n The required dimensions are 493px × 312px.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "WixLanguage": { + "description": "The languages to build using WiX.", + "anyOf": [ + { + "description": "A single language to build, without configuration.", + "type": "string" + }, + { + "description": "A list of languages to build, without configuration.", + "type": "array", + "items": { + "type": "string" + } + }, + { + "description": "A map of languages and its configuration.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/WixLanguageConfig" + } + } + ] + }, + "WixLanguageConfig": { + "description": "Configuration for a target language for the WiX build.\n\n See more: ", + "type": "object", + "properties": { + "localePath": { + "description": "The path to a locale (`.wxl`) file. See .", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "NsisConfig": { + "description": "Configuration for the Installer bundle using NSIS.", + "type": "object", + "properties": { + "template": { + "description": "A custom .nsi template to use.", + "type": [ + "string", + "null" + ] + }, + "headerImage": { + "description": "The path to a bitmap file to display on the header of installers pages.\n\n The recommended dimensions are 150px x 57px.", + "type": [ + "string", + "null" + ] + }, + "sidebarImage": { + "description": "The path to a bitmap file for the Welcome page and the Finish page.\n\n The recommended dimensions are 164px x 314px.", + "type": [ + "string", + "null" + ] + }, + "installerIcon": { + "description": "The path to an icon file used as the installer icon.", + "type": [ + "string", + "null" + ] + }, + "installMode": { + "description": "Whether the installation will be for all users or just the current user.", + "default": "currentUser", + "allOf": [ + { + "$ref": "#/definitions/NSISInstallerMode" + } + ] + }, + "languages": { + "description": "A list of installer languages.\n By default the OS language is used. If the OS language is not in the list of languages, the first language will be used.\n To allow the user to select the language, set `display_language_selector` to `true`.\n\n See for the complete list of languages.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "customLanguageFiles": { + "description": "A key-value pair where the key is the language and the\n value is the path to a custom `.nsh` file that holds the translated text for tauri's custom messages.\n\n See for an example `.nsh` file.\n\n **Note**: the key must be a valid NSIS language and it must be added to [`NsisConfig`] languages array,", + "type": [ + "object", + "null" + ], + "additionalProperties": { + "type": "string" + } + }, + "displayLanguageSelector": { + "description": "Whether to display a language selector dialog before the installer and uninstaller windows are rendered or not.\n By default the OS language is selected, with a fallback to the first language in the `languages` array.", + "default": false, + "type": "boolean" + }, + "compression": { + "description": "Set the compression algorithm used to compress files in the installer.\n\n See ", + "default": "lzma", + "allOf": [ + { + "$ref": "#/definitions/NsisCompression" + } + ] + }, + "startMenuFolder": { + "description": "Set the folder name for the start menu shortcut.\n\n Use this option if you have multiple apps and wish to group their shortcuts under one folder\n or if you generally prefer to set your shortcut inside a folder.\n\n Examples:\n - `AwesomePublisher`, shortcut will be placed in `%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\AwesomePublisher\\.lnk`\n - If unset, shortcut will be placed in `%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\.lnk`", + "type": [ + "string", + "null" + ] + }, + "installerHooks": { + "description": "A path to a `.nsh` file that contains special NSIS macros to be hooked into the\n main installer.nsi script.\n\n Supported hooks are:\n - `NSIS_HOOK_PREINSTALL`: This hook runs before copying files, setting registry key values and creating shortcuts.\n - `NSIS_HOOK_POSTINSTALL`: This hook runs after the installer has finished copying all files, setting the registry keys and created shortcuts.\n - `NSIS_HOOK_PREUNINSTALL`: This hook runs before removing any files, registry keys and shortcuts.\n - `NSIS_HOOK_POSTUNINSTALL`: This hook runs after files, registry keys and shortcuts have been removed.\n\n\n ### Example\n\n ```nsh\n !macro NSIS_HOOK_PREINSTALL\n MessageBox MB_OK \"PreInstall\"\n !macroend\n\n !macro NSIS_HOOK_POSTINSTALL\n MessageBox MB_OK \"PostInstall\"\n !macroend\n\n !macro NSIS_HOOK_PREUNINSTALL\n MessageBox MB_OK \"PreUnInstall\"\n !macroend\n\n !macro NSIS_HOOK_POSTUNINSTALL\n MessageBox MB_OK \"PostUninstall\"\n !macroend\n\n ```", + "type": [ + "string", + "null" + ] + }, + "minimumWebview2Version": { + "description": "Try to ensure that the WebView2 version is equal to or newer than this version,\n if the user's WebView2 is older than this version,\n the installer will try to trigger a WebView2 update.", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "NSISInstallerMode": { + "description": "Install Modes for the NSIS installer.", + "oneOf": [ + { + "description": "Default mode for the installer.\n\n Install the app by default in a directory that doesn't require Administrator access.\n\n Installer metadata will be saved under the `HKCU` registry path.", + "type": "string", + "enum": [ + "currentUser" + ] + }, + { + "description": "Install the app by default in the `Program Files` folder directory requires Administrator\n access for the installation.\n\n Installer metadata will be saved under the `HKLM` registry path.", + "type": "string", + "enum": [ + "perMachine" + ] + }, + { + "description": "Combines both modes and allows the user to choose at install time\n whether to install for the current user or per machine. Note that this mode\n will require Administrator access even if the user wants to install it for the current user only.\n\n Installer metadata will be saved under the `HKLM` or `HKCU` registry path based on the user's choice.", + "type": "string", + "enum": [ + "both" + ] + } + ] + }, + "NsisCompression": { + "description": "Compression algorithms used in the NSIS installer.\n\n See ", + "oneOf": [ + { + "description": "ZLIB uses the deflate algorithm, it is a quick and simple method. With the default compression level it uses about 300 KB of memory.", + "type": "string", + "enum": [ + "zlib" + ] + }, + { + "description": "BZIP2 usually gives better compression ratios than ZLIB, but it is a bit slower and uses more memory. With the default compression level it uses about 4 MB of memory.", + "type": "string", + "enum": [ + "bzip2" + ] + }, + { + "description": "LZMA (default) is a new compression method that gives very good compression ratios. The decompression speed is high (10-20 MB/s on a 2 GHz CPU), the compression speed is lower. The memory size that will be used for decompression is the dictionary size plus a few KBs, the default is 8 MB.", + "type": "string", + "enum": [ + "lzma" + ] + }, + { + "description": "Disable compression", + "type": "string", + "enum": [ + "none" + ] + } + ] + }, + "CustomSignCommandConfig": { + "description": "Custom Signing Command configuration.", + "anyOf": [ + { + "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].", + "type": "string" + }, + { + "description": "An object notation of the command.\n\n This is more complex notation for the command but\n this allows you to use whitespace in the command and arguments.", + "type": "object", + "required": [ + "args", + "cmd" + ], + "properties": { + "cmd": { + "description": "The command to run to sign the binary.", + "type": "string" + }, + "args": { + "description": "The arguments to pass to the command.\n\n \"%1\" will be replaced with the path to the binary to be signed.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + ] + }, + "LinuxConfig": { + "description": "Configuration for Linux bundles.\n\n See more: ", + "type": "object", + "properties": { + "appimage": { + "description": "Configuration for the AppImage bundle.", + "default": { + "bundleMediaFramework": false, + "files": {} + }, + "allOf": [ + { + "$ref": "#/definitions/AppImageConfig" + } + ] + }, + "deb": { + "description": "Configuration for the Debian bundle.", + "default": { + "files": {} + }, + "allOf": [ + { + "$ref": "#/definitions/DebConfig" + } + ] + }, + "rpm": { + "description": "Configuration for the RPM bundle.", + "default": { + "epoch": 0, + "files": {}, + "release": "1" + }, + "allOf": [ + { + "$ref": "#/definitions/RpmConfig" + } + ] + } + }, + "additionalProperties": false + }, + "AppImageConfig": { + "description": "Configuration for AppImage bundles.\n\n See more: ", + "type": "object", + "properties": { + "bundleMediaFramework": { + "description": "Include additional gstreamer dependencies needed for audio and video playback.\n This increases the bundle size by ~15-35MB depending on your build system.", + "default": false, + "type": "boolean" + }, + "files": { + "description": "The files to include in the Appimage Binary.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "additionalProperties": false + }, + "DebConfig": { + "description": "Configuration for Debian (.deb) bundles.\n\n See more: ", + "type": "object", + "properties": { + "depends": { + "description": "The list of deb dependencies your application relies on.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "recommends": { + "description": "The list of deb dependencies your application recommends.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "provides": { + "description": "The list of dependencies the package provides.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "conflicts": { + "description": "The list of package conflicts.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "replaces": { + "description": "The list of package replaces.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "files": { + "description": "The files to include on the package.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "section": { + "description": "Define the section in Debian Control file. See : https://www.debian.org/doc/debian-policy/ch-archive.html#s-subsections", + "type": [ + "string", + "null" + ] + }, + "priority": { + "description": "Change the priority of the Debian Package. By default, it is set to `optional`.\n Recognized Priorities as of now are : `required`, `important`, `standard`, `optional`, `extra`", + "type": [ + "string", + "null" + ] + }, + "changelog": { + "description": "Path of the uncompressed Changelog file, to be stored at /usr/share/doc/package-name/changelog.gz. See\n ", + "type": [ + "string", + "null" + ] + }, + "desktopTemplate": { + "description": "Path to a custom desktop file Handlebars template.\n\n Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.", + "type": [ + "string", + "null" + ] + }, + "preInstallScript": { + "description": "Path to script that will be executed before the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "postInstallScript": { + "description": "Path to script that will be executed after the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "preRemoveScript": { + "description": "Path to script that will be executed before the package is removed. See\n ", + "type": [ + "string", + "null" + ] + }, + "postRemoveScript": { + "description": "Path to script that will be executed after the package is removed. See\n ", + "type": [ + "string", + "null" + ] + } + }, + "additionalProperties": false + }, + "RpmConfig": { + "description": "Configuration for RPM bundles.", + "type": "object", + "properties": { + "depends": { + "description": "The list of RPM dependencies your application relies on.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "recommends": { + "description": "The list of RPM dependencies your application recommends.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "provides": { + "description": "The list of RPM dependencies your application provides.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "conflicts": { + "description": "The list of RPM dependencies your application conflicts with. They must not be present\n in order for the package to be installed.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "obsoletes": { + "description": "The list of RPM dependencies your application supersedes - if this package is installed,\n packages listed as \"obsoletes\" will be automatically removed (if they are present).", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "release": { + "description": "The RPM release tag.", + "default": "1", + "type": "string" + }, + "epoch": { + "description": "The RPM epoch.", + "default": 0, + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "files": { + "description": "The files to include on the package.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "desktopTemplate": { + "description": "Path to a custom desktop file Handlebars template.\n\n Available variables: `categories`, `comment` (optional), `exec`, `icon` and `name`.", + "type": [ + "string", + "null" + ] + }, + "preInstallScript": { + "description": "Path to script that will be executed before the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "postInstallScript": { + "description": "Path to script that will be executed after the package is unpacked. See\n ", + "type": [ + "string", + "null" + ] + }, + "preRemoveScript": { + "description": "Path to script that will be executed before the package is removed. See\n ", + "type": [ + "string", + "null" + ] + }, + "postRemoveScript": { + "description": "Path to script that will be executed after the package is removed. See\n ", + "type": [ + "string", + "null" + ] + }, + "compression": { + "description": "Compression algorithm and level. Defaults to `Gzip` with level 6.", + "anyOf": [ + { + "$ref": "#/definitions/RpmCompression" + }, + { + "type": "null" + } + ] + } + }, + "additionalProperties": false + }, + "RpmCompression": { + "description": "Compression algorithms used when bundling RPM packages.", + "oneOf": [ + { + "description": "Gzip compression", + "type": "object", + "required": [ + "level", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "gzip" + ] + }, + "level": { + "description": "Gzip compression level", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Zstd compression", + "type": "object", + "required": [ + "level", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "zstd" + ] + }, + "level": { + "description": "Zstd compression level", + "type": "integer", + "format": "int32" + } + }, + "additionalProperties": false + }, + { + "description": "Xz compression", + "type": "object", + "required": [ + "level", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "xz" + ] + }, + "level": { + "description": "Xz compression level", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Bzip2 compression", + "type": "object", + "required": [ + "level", + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "bzip2" + ] + }, + "level": { + "description": "Bzip2 compression level", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + { + "description": "Disable compression", + "type": "object", + "required": [ + "type" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "none" + ] + } + }, + "additionalProperties": false + } + ] + }, + "MacConfig": { + "description": "Configuration for the macOS bundles.\n\n See more: ", + "type": "object", + "properties": { + "frameworks": { + "description": "A list of strings indicating any macOS X frameworks that need to be bundled with the application.\n\n If a name is used, \".framework\" must be omitted and it will look for standard install locations. You may also use a path to a specific framework.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "files": { + "description": "The files to include in the application relative to the Contents directory.", + "default": {}, + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "minimumSystemVersion": { + "description": "A version string indicating the minimum macOS X version that the bundled application supports. Defaults to `10.13`.\n\n Setting it to `null` completely removes the `LSMinimumSystemVersion` field on the bundle's `Info.plist`\n and the `MACOSX_DEPLOYMENT_TARGET` environment variable.\n\n An empty string is considered an invalid value so the default value is used.", + "default": "10.13", + "type": [ + "string", + "null" + ] + }, + "exceptionDomain": { + "description": "Allows your application to communicate with the outside world.\n It should be a lowercase, without port and protocol domain name.", + "type": [ + "string", + "null" + ] + }, + "signingIdentity": { + "description": "Identity to use for code signing.", + "type": [ + "string", + "null" + ] + }, + "hardenedRuntime": { + "description": "Whether the codesign should enable [hardened runtime] (for executables) or not.\n\n [hardened runtime]: ", + "default": true, + "type": "boolean" + }, + "providerShortName": { + "description": "Provider short name for notarization.", + "type": [ + "string", + "null" + ] + }, + "entitlements": { + "description": "Path to the entitlements file.", + "type": [ + "string", + "null" + ] + }, + "dmg": { + "description": "DMG-specific settings.", + "default": { + "appPosition": { + "x": 180, + "y": 170 + }, + "applicationFolderPosition": { + "x": 480, + "y": 170 + }, + "windowSize": { + "height": 400, + "width": 660 + } + }, + "allOf": [ + { + "$ref": "#/definitions/DmgConfig" + } + ] + } + }, + "additionalProperties": false + }, + "DmgConfig": { + "description": "Configuration for Apple Disk Image (.dmg) bundles.\n\n See more: ", + "type": "object", + "properties": { + "background": { + "description": "Image to use as the background in dmg file. Accepted formats: `png`/`jpg`/`gif`.", + "type": [ + "string", + "null" + ] + }, + "windowPosition": { + "description": "Position of volume window on screen.", + "anyOf": [ + { + "$ref": "#/definitions/Position" + }, + { + "type": "null" + } + ] + }, + "windowSize": { + "description": "Size of volume window.", + "default": { + "height": 400, + "width": 660 + }, + "allOf": [ + { + "$ref": "#/definitions/Size" + } + ] + }, + "appPosition": { + "description": "Position of app file on window.", + "default": { + "x": 180, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + }, + "applicationFolderPosition": { + "description": "Position of application folder on window.", + "default": { + "x": 480, + "y": 170 + }, + "allOf": [ + { + "$ref": "#/definitions/Position" + } + ] + } + }, + "additionalProperties": false + }, + "Position": { + "description": "Position coordinates struct.", + "type": "object", + "required": [ + "x", + "y" + ], + "properties": { + "x": { + "description": "X coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "y": { + "description": "Y coordinate.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "Size": { + "description": "Size of the window.", + "type": "object", + "required": [ + "height", + "width" + ], + "properties": { + "width": { + "description": "Width of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "height": { + "description": "Height of the window.", + "type": "integer", + "format": "uint32", + "minimum": 0.0 + } + }, + "additionalProperties": false + }, + "IosConfig": { + "description": "General configuration for the iOS target.", + "type": "object", + "properties": { + "template": { + "description": "A custom [XcodeGen] project.yml template to use.\n\n [XcodeGen]: ", + "type": [ + "string", + "null" + ] + }, + "frameworks": { + "description": "A list of strings indicating any iOS frameworks that need to be bundled with the application.\n\n Note that you need to recreate the iOS project for the changes to be applied.", + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + } + }, + "developmentTeam": { + "description": "The development team. This value is required for iOS development because code signing is enforced.\n The `APPLE_DEVELOPMENT_TEAM` environment variable can be set to overwrite it.", + "type": [ + "string", + "null" + ] + }, + "minimumSystemVersion": { + "description": "A version string indicating the minimum iOS version that the bundled application supports. Defaults to `13.0`.\n\n Maps to the IPHONEOS_DEPLOYMENT_TARGET value.", + "default": "13.0", + "type": "string" + } + }, + "additionalProperties": false + }, + "AndroidConfig": { + "description": "General configuration for the iOS target.", + "type": "object", + "properties": { + "minSdkVersion": { + "description": "The minimum API level required for the application to run.\n The Android system will prevent the user from installing the application if the system's API level is lower than the value specified.", + "default": 24, + "type": "integer", + "format": "uint32", + "minimum": 0.0 + }, + "versionCode": { + "description": "The version code of the application.\n It is limited to 2,100,000,000 as per Google Play Store requirements.\n\n By default we use your configured version and perform the following math:\n versionCode = version.major * 1000000 + version.minor * 1000 + version.patch", + "type": [ + "integer", + "null" + ], + "format": "uint32", + "maximum": 2100000000.0, + "minimum": 1.0 + } + }, + "additionalProperties": false + }, + "PluginConfig": { + "description": "The plugin configs holds a HashMap mapping a plugin name to its configuration object.\n\n See more: ", + "type": "object", + "additionalProperties": true + } + } +} \ No newline at end of file diff --git a/crates/tauri-schema-generator/schemas/permission.schema.json b/crates/tauri-schema-generator/schemas/permission.schema.json new file mode 100644 index 000000000000..59aefcfe95f2 --- /dev/null +++ b/crates/tauri-schema-generator/schemas/permission.schema.json @@ -0,0 +1,205 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Permission", + "description": "Descriptions of explicit privileges of commands.\n\n It can enable commands to be accessible in the frontend of the application.\n\n If the scope is defined it can be used to fine grain control the access of individual or multiple commands.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does.\n Tauri internal convention is to use

headings in markdown content\n for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "commands": { + "description": "Allowed or denied commands when using this permission.", + "default": { + "allow": [], + "deny": [] + }, + "allOf": [ + { + "$ref": "#/definitions/Commands" + } + ] + }, + "scope": { + "description": "Allowed or denied scoped when using this permission.", + "allOf": [ + { + "$ref": "#/definitions/Scopes" + } + ] + }, + "platforms": { + "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + }, + "definitions": { + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\n If two commands clash inside of `allow` and `deny`, it should be denied by default.", + "type": "object", + "properties": { + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "An argument for fine grained behavior control of Tauri commands.\n\n It can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\n The configured scope is passed to the command and will be enforced by the command implementation.\n\n ## Example\n\n ```json\n {\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n }\n ```", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + } + } +} \ No newline at end of file diff --git a/crates/tauri-schema-generator/schemas/scope.schema.json b/crates/tauri-schema-generator/schemas/scope.schema.json new file mode 100644 index 000000000000..cedbf22d6b23 --- /dev/null +++ b/crates/tauri-schema-generator/schemas/scope.schema.json @@ -0,0 +1,84 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Scopes", + "description": "An argument for fine grained behavior control of Tauri commands.\n\n It can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\n The configured scope is passed to the command and will be enforced by the command implementation.\n\n ## Example\n\n ```json\n {\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n }\n ```", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + }, + "definitions": { + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + } + } +} \ No newline at end of file diff --git a/crates/tauri-schema-generator/src/main.rs b/crates/tauri-schema-generator/src/main.rs new file mode 100644 index 000000000000..b7f6eeb5fcea --- /dev/null +++ b/crates/tauri-schema-generator/src/main.rs @@ -0,0 +1,12 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +//! Hosts the schema for the Tauri configuration file. + +#![doc( + html_logo_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png", + html_favicon_url = "https://github.com/tauri-apps/tauri/raw/dev/.github/icon.png" +)] + +fn main() {} diff --git a/crates/tauri-schema-worker/.gitignore b/crates/tauri-schema-worker/.gitignore new file mode 100644 index 000000000000..b9515a5be520 --- /dev/null +++ b/crates/tauri-schema-worker/.gitignore @@ -0,0 +1,4 @@ +/target +/node_modules +/.wrangler +/build diff --git a/crates/tauri-schema-worker/Cargo.toml b/crates/tauri-schema-worker/Cargo.toml new file mode 100644 index 000000000000..3af5a33e7ac8 --- /dev/null +++ b/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" diff --git a/crates/tauri-schema-worker/README.md b/crates/tauri-schema-worker/README.md new file mode 100644 index 000000000000..288b74ce9600 --- /dev/null +++ b/crates/tauri-schema-worker/README.md @@ -0,0 +1,3 @@ +# schema.tauri.app worker + +Source code for `https://schema.tauri.app` cloudflare worker. diff --git a/crates/tauri-schema-worker/package.json b/crates/tauri-schema-worker/package.json new file mode 100644 index 000000000000..63fa7b0fd007 --- /dev/null +++ b/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.95.0" + } +} diff --git a/crates/tauri-schema-worker/src/config.rs b/crates/tauri-schema-worker/src/config.rs new file mode 100644 index 000000000000..b4c818b910bf --- /dev/null +++ b/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, +} + +#[derive(Debug, Deserialize)] +pub struct CrateRelease { + #[serde(alias = "num")] + pub version: Version, + pub yanked: Option, +} + +#[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) -> Result { + 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 { + try_stable_schema() + .await + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())) + .map_err(Into::into) +} + +async fn next_schema() -> Result { + 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 { + let version = version.parse::()?; + + 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 { + let max = stable_version("tauri").await?; + schema_file_for_version(max).await +} + +#[worker::send] +async fn try_next_schema() -> anyhow::Result { + 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 { + let cache = Cache::open("schema".to_string()).await; + let cache_key = format!("https://schema.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> { + 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 { + 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 { + 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) +} diff --git a/crates/tauri-schema-worker/src/lib.rs b/crates/tauri-schema-worker/src/lib.rs new file mode 100644 index 000000000000..368d98892834 --- /dev/null +++ b/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> { + 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" +} diff --git a/crates/tauri-schema-worker/wrangler.toml b/crates/tauri-schema-worker/wrangler.toml new file mode 100644 index 000000000000..0df7ef3bbf1b --- /dev/null +++ b/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" diff --git a/crates/tauri-utils/CHANGELOG.md b/crates/tauri-utils/CHANGELOG.md new file mode 100644 index 000000000000..319527f97ece --- /dev/null +++ b/crates/tauri-utils/CHANGELOG.md @@ -0,0 +1,879 @@ +# Changelog + +## \[2.1.0] + +### New Features + +- [`fabc2f283`](https://www.github.com/tauri-apps/tauri/commit/fabc2f283e38b62c721326e44645d47138418cbc) ([#11485](https://www.github.com/tauri-apps/tauri/pull/11485) by [@39zde](https://www.github.com/tauri-apps/tauri/../../39zde)) Adds a new configuration option `app > security > headers` to define headers that will be added to every http response from tauri to the web view. This doesn't include IPC messages and error responses. +- [`4d545ab3c`](https://www.github.com/tauri-apps/tauri/commit/4d545ab3ca228c8a21b966b709f84a0da2864479) ([#11486](https://www.github.com/tauri-apps/tauri/pull/11486) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `Window::set_background_color` and `WindowBuilder::background_color`. +- [`cbc095ec5`](https://www.github.com/tauri-apps/tauri/commit/cbc095ec5fe7de29b5c9265576d4e071ec159c1c) ([#11451](https://www.github.com/tauri-apps/tauri/pull/11451) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `app > windows > devtools` config option and when creating the webview from JS, to enable or disable devtools for a specific webview. +- [`058c0db72`](https://www.github.com/tauri-apps/tauri/commit/058c0db72f43fbe1574d0db654560e693755cd7e) ([#11584](https://www.github.com/tauri-apps/tauri/pull/11584) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `bundle > linux > rpm > compression` config option to control RPM bundle compression type and level. +- [`f37e97d41`](https://www.github.com/tauri-apps/tauri/commit/f37e97d410c4a219e99f97692da05ca9d8e0ba3a) ([#11477](https://www.github.com/tauri-apps/tauri/pull/11477) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `app > windows > useHttpsScheme` config option to choose whether the custom protocols should use `https://.localhost` instead of the default `http://.localhost` on Windows and Android +- [`2a75c64b5`](https://www.github.com/tauri-apps/tauri/commit/2a75c64b5431284e7340e8743d4ea56a62c75466) ([#11469](https://www.github.com/tauri-apps/tauri/pull/11469) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Added `app > windows > windowClassname` config option to specify the name of the window class on Windows. + +### Enhancements + +- [`c33bbf457`](https://www.github.com/tauri-apps/tauri/commit/c33bbf45740274b6918ea6c647f366fb6008e459) ([#11575](https://www.github.com/tauri-apps/tauri/pull/11575) by [@kornelski](https://www.github.com/tauri-apps/tauri/../../kornelski)) Include the path in ACL I/O errors. + +### Bug Fixes + +- [`378142914`](https://www.github.com/tauri-apps/tauri/commit/37814291475814b4a24cc77b6fa457ec9ba7a779) ([#11429](https://www.github.com/tauri-apps/tauri/pull/11429) by [@griffi-gh](https://www.github.com/tauri-apps/tauri/../../griffi-gh)) Enhance resource directory resolution to support running on distros like NixOS. + +## \[2.0.2] + +### New Features + +- Add `bundler > windows > wix > version` to manually specify a wix-compatible version. + +## \[2.0.1] + +### What's Changed + +- [`0ab2b3306`](https://www.github.com/tauri-apps/tauri/commit/0ab2b330644b6419f6cee1d5377bfb5cdda2ccf9) ([#11205](https://www.github.com/tauri-apps/tauri/pull/11205) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. + +## \[2.0.0] + +### What's Changed + +- [`382ed482b`](https://www.github.com/tauri-apps/tauri/commit/382ed482bd08157c39e62f9a0aaad8802f1092cb) Bump MSRV to 1.78. +- [`637285790`](https://www.github.com/tauri-apps/tauri/commit/6372857905ae9c0aedb7f482ddf6cf9f9836c9f2) Promote to v2 stable! + +## \[2.0.0-rc.13] + +### New Features + +- [`a247170e1`](https://www.github.com/tauri-apps/tauri/commit/a247170e1f620a9b012274b11cfe51e90327d6e9) ([#11056](https://www.github.com/tauri-apps/tauri/pull/11056) by [@SpikeHD](https://www.github.com/tauri-apps/tauri/../../SpikeHD)) Expose the ability to enabled browser extensions in WebView2 on Windows. +- [`f57a729cd`](https://www.github.com/tauri-apps/tauri/commit/f57a729cd8f7e10d8daf0b9d5b85f9c7ad530496) ([#11039](https://www.github.com/tauri-apps/tauri/pull/11039) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `upgradeCode` in `wix` configuration to set an upgrade code for your MSI installer. This is recommended to be set if you plan to change your `productName`. + +### Bug Fixes + +- [`1efa5e718`](https://www.github.com/tauri-apps/tauri/commit/1efa5e7184009537b688a395596c696173ae0231) ([#11099](https://www.github.com/tauri-apps/tauri/pull/11099) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Rerun build script if the platform-specific configuration file changes. + +## \[2.0.0-rc.12] + +### New Features + +- [`ad294d274`](https://www.github.com/tauri-apps/tauri/commit/ad294d274dd81d2ef91ed73af9163b6e9b8eb964) ([#11032](https://www.github.com/tauri-apps/tauri/pull/11032) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `app > windows > create` option to choose whether to create this window at app startup or not. + +## \[2.0.0-rc.11] + +### New Features + +- [`35bd9dd3d`](https://www.github.com/tauri-apps/tauri/commit/35bd9dd3dc3d8972bbc4aa5f4a6c6fa14354e9bf) ([#10977](https://www.github.com/tauri-apps/tauri/pull/10977) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `mainBinaryName` config option to set the file name for the main binary. + +## \[2.0.0-rc.10] + +### Bug Fixes + +- [`0a47bf043`](https://www.github.com/tauri-apps/tauri/commit/0a47bf04302ca8502d3da21b3bc27818720fe34a) ([#10946](https://www.github.com/tauri-apps/tauri/pull/10946) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that made the `identifier` in `tauri.conf.json` optional while it was actually required. + +## \[2.0.0-rc.9] + +### Dependencies + +- [`d9c8d3cc8`](https://www.github.com/tauri-apps/tauri/commit/d9c8d3cc8d5ca67cd767ffc7a521f801b41ce201) ([#10902](https://www.github.com/tauri-apps/tauri/pull/10902) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Update infer to 0.16, tray icon to 0.17, urlpattern to 0.3, image to 0.25 + +### Breaking Changes + +- [`faa259bac`](https://www.github.com/tauri-apps/tauri/commit/faa259bacf1ace670af763982c6903190faf163a) ([#10907](https://www.github.com/tauri-apps/tauri/pull/10907) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) The `Assets::iter` function now must return a iterator with `Item = (Cow<'_, str>, Cow<'_, [u8]>)` to be more flexible on contexts where the assets are not `'static`. + +## \[2.0.0-rc.8] + +### Enhancements + +- [`f0acf504a`](https://www.github.com/tauri-apps/tauri/commit/f0acf504a2a972c063188a00143d8bf2b887691d) ([#10858](https://www.github.com/tauri-apps/tauri/pull/10858) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Validate duplicate capability identifier. + +## \[2.0.0-rc.7] + +### New Features + +- [`58dda44a5`](https://www.github.com/tauri-apps/tauri/commit/58dda44a59b915f091602cdfc53385a148469793) ([#10339](https://www.github.com/tauri-apps/tauri/pull/10339) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Add a new option `minimumWebview2Version` for Windows NSIS installer to trigger a webview2 update if the user's webview2 is older than this version + +### Bug Fixes + +- [`03f2a5098`](https://www.github.com/tauri-apps/tauri/commit/03f2a50981b8c01b1c196811fce9d93f1bf0820d) ([#10718](https://www.github.com/tauri-apps/tauri/pull/10718) by [@rdlabo](https://www.github.com/tauri-apps/tauri/../../rdlabo)) Update swift-rs fixing a plugin build when native dependencies are used. + +### Breaking Changes + +- [`073bb4f45`](https://www.github.com/tauri-apps/tauri/commit/073bb4f459a923541b94970dfa7e087bccaa2cfd) ([#10772](https://www.github.com/tauri-apps/tauri/pull/10772) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Removed the deprecated `webview_fixed_runtime_path` config option, use the `webview_install_mode` instead. + +## \[2.0.0-rc.6] + +### Bug Fixes + +- [`9bcff3cd7`](https://www.github.com/tauri-apps/tauri/commit/9bcff3cd7997fe13425a21b577f93317831f77fa) ([#10703](https://www.github.com/tauri-apps/tauri/pull/10703) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Properly remove isolation script on Android. + +### What's Changed + +- [`f4d5241b3`](https://www.github.com/tauri-apps/tauri/commit/f4d5241b377d0f7a1b58100ee19f7843384634ac) ([#10731](https://www.github.com/tauri-apps/tauri/pull/10731) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Update documentation icon path. + +## \[2.0.0-rc.5] + +### Bug Fixes + +- [`da381e07f`](https://www.github.com/tauri-apps/tauri/commit/da381e07f3770988fe6d0859a02331b87cc6723f) ([#10696](https://www.github.com/tauri-apps/tauri/pull/10696) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Implemented `resource_dir` on Android, which returns a URI that needs to be resolved using [AssetManager::open](https://developer.android.com/reference/android/content/res/AssetManager#open\(java.lang.String,%20int\)). This will be handled by the file system plugin. +- [`da381e07f`](https://www.github.com/tauri-apps/tauri/commit/da381e07f3770988fe6d0859a02331b87cc6723f) ([#10696](https://www.github.com/tauri-apps/tauri/pull/10696) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix `resource_dir` on iOS. + +## \[2.0.0-rc.4] + +### New Features + +- [`8d148a9e2`](https://www.github.com/tauri-apps/tauri/commit/8d148a9e2566edebfea2d75f32df7c9396d765a4) ([#10634](https://www.github.com/tauri-apps/tauri/pull/10634) by [@anatawa12](https://www.github.com/tauri-apps/tauri/../../anatawa12)) Custom sign command with object notation for whitespaces in the command path and arguments. + +### Bug Fixes + +- [`5c335ae9a`](https://www.github.com/tauri-apps/tauri/commit/5c335ae9ad88e46c2135a557390f6e808c9a6088) ([#10648](https://www.github.com/tauri-apps/tauri/pull/10648) by [@Flakebi](https://www.github.com/tauri-apps/tauri/../../Flakebi)) Prevent build script from rerunning unnecessarily by only writing files when the content changes. + +## \[2.0.0-rc.3] + +### Enhancements + +- [`0bb7b0f35`](https://www.github.com/tauri-apps/tauri/commit/0bb7b0f352960fb5111a40157c0953d19e76f1fd) ([#10559](https://www.github.com/tauri-apps/tauri/pull/10559) by [@Norbiros](https://www.github.com/tauri-apps/tauri/../../Norbiros)) Return autogenerated permissions from `autogenerate_command_permissions`. + +### Bug Fixes + +- [`9e891933d`](https://www.github.com/tauri-apps/tauri/commit/9e891933d8ac7a67e37770a149d0a5dd385ee625) ([#10293](https://www.github.com/tauri-apps/tauri/pull/10293) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Fix `ResourcePaths` iterator returning an unexpected result for mapped resources, for example `"../resources/user.json": "resources/user.json"` generates this resource `resources/user.json/user.json` where it should generate just `resources/user.json`. +- [`9fe846615`](https://www.github.com/tauri-apps/tauri/commit/9fe846615b7c4f310f07897ded881c239e3df30a) ([#10547](https://www.github.com/tauri-apps/tauri/pull/10547) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix plugin permissions documentation heading for permissions table. + +### Dependencies + +- [`0afee5ed8`](https://www.github.com/tauri-apps/tauri/commit/0afee5ed80265c95c4581e173c4886677cfed593) ([#10436](https://www.github.com/tauri-apps/tauri/pull/10436) by [@nyurik](https://www.github.com/tauri-apps/tauri/../../nyurik)) Updated brotli to v6. + +## \[2.0.0-rc.2] + +### Bug Fixes + +- [`f5dfc0280`](https://www.github.com/tauri-apps/tauri/commit/f5dfc02800dbd3bdee671b032454c49ac7102fb4) ([#10533](https://www.github.com/tauri-apps/tauri/pull/10533) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue causing `tauri ios init` to fail if `iOS.minimumSystemVersion` was not configured explicitly. + +## \[2.0.0-rc.1] + +### New Features + +- [`8dc81b6cc`](https://www.github.com/tauri-apps/tauri/commit/8dc81b6cc2b8235b11f74a971d6aa3a5df5e9f68) ([#10496](https://www.github.com/tauri-apps/tauri/pull/10496) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Added `bundle > ios > template` configuration option for custom Xcode project YML Handlebars template using XcodeGen. +- [`02c00abc6`](https://www.github.com/tauri-apps/tauri/commit/02c00abc63cf86e9bf9179cbb143d5145a9397b6) ([#10495](https://www.github.com/tauri-apps/tauri/pull/10495) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Added `bundle > ios > minimumSystemVersion` configuration option. + +### Bug Fixes + +- [`7e810cb2a`](https://www.github.com/tauri-apps/tauri/commit/7e810cb2a3fd934017ae973e737864dfa4bdf64e) ([#10485](https://www.github.com/tauri-apps/tauri/pull/10485) by [@anatawa12](https://www.github.com/tauri-apps/tauri/../../anatawa12)) Fixed an issue where permission files will be generated with ':' in the file path. + +## \[2.0.0-rc.0] + +### New Features + +- [`a5bfbaa62`](https://www.github.com/tauri-apps/tauri/commit/a5bfbaa62b8cd0aacbb33f730d4e30b43c461fe1)([#9962](https://www.github.com/tauri-apps/tauri/pull/9962)) Added `bundle > iOS > frameworks` configuration to define a list of frameworks that are linked to the Xcode project when it is generated. + +### Enhancements + +- [`7aeac39e7`](https://www.github.com/tauri-apps/tauri/commit/7aeac39e7fb97dc57ca278f1c097058275c20aa2) ([#10397](https://www.github.com/tauri-apps/tauri/pull/10397)) Make the set of gtk application id optional, to allow more then one instance of the app running at the same time. + +### Bug Fixes + +- [`498f405ca`](https://www.github.com/tauri-apps/tauri/commit/498f405ca80440447823dd3c9cd53c0f79d655b5) ([#10404](https://www.github.com/tauri-apps/tauri/pull/10404)) Fixed an issue where configuration parsing errors always displayed 'tauri.conf.json' as the file path, even when using 'Tauri.toml' or 'tauri.conf.json5'. + + The error messages now correctly shows the actual config file being used. + +### Security fixes + +- [`426d14bb4`](https://www.github.com/tauri-apps/tauri/commit/426d14bb4164290d93b5a0f61e925cb2dfc4aafa) ([#10423](https://www.github.com/tauri-apps/tauri/pull/10423)) Explicitly check that the main frame's origin is the sender of Isolation Payloads + +## \[2.0.0-beta.19] + +### New Features + +- [`4c239729c`](https://www.github.com/tauri-apps/tauri/commit/4c239729c3e1b899ecbc6793c3682848e8de1729) ([#10167](https://www.github.com/tauri-apps/tauri/pull/10167) by [@amrbashir](https://www.github.com/tauri-apps/tauri/../../amrbashir)) Add `RawIsolationPayload::content_type` method. + +## \[2.0.0-beta.18] + +### New Features + +- [`fafc238f7`](https://www.github.com/tauri-apps/tauri/commit/fafc238f7288548975ca7d3e5207b925c0295c91) ([#9977](https://www.github.com/tauri-apps/tauri/pull/9977)) Add `bundle > homepage` option, if unset, it will fallback to `homepage` defined in `Cargo.toml`. +- [`656a64974`](https://www.github.com/tauri-apps/tauri/commit/656a64974468bc207bf39537e02ae179bdee9b83) ([#9318](https://www.github.com/tauri-apps/tauri/pull/9318)) Added a configuration option to disable hardened runtime on macOS codesign. +- [`5b769948a`](https://www.github.com/tauri-apps/tauri/commit/5b769948a81cac333f64c870a470ba6525bd5cd3) ([#9959](https://www.github.com/tauri-apps/tauri/pull/9959)) Add `include_image` macro to help embedding instances of `Image` struct at compile-time in rust to be used with window, menu or tray icons. +- [`3ab170917`](https://www.github.com/tauri-apps/tauri/commit/3ab170917ed535fc9013f0a9255631fb34493e18) ([#9932](https://www.github.com/tauri-apps/tauri/pull/9932)) Add an option to disable NSIS compression `bundle > nsis > compression: "none"` +- [`f21029b1b`](https://www.github.com/tauri-apps/tauri/commit/f21029b1bc25f5cb987e1a25de94c2d364e3e462) ([#9994](https://www.github.com/tauri-apps/tauri/pull/9994)) Add `bundle > nsis > startMenuFolder` option to customize start menu folder for NSIS installer + +### Enhancements + +- [`878198777`](https://www.github.com/tauri-apps/tauri/commit/878198777ef693efdbd394cb4be4b234e8a7ed3d) ([#9999](https://www.github.com/tauri-apps/tauri/pull/9999)) Mark ACL `permissions` array with unique items + +### Breaking Changes + +- [`3ab170917`](https://www.github.com/tauri-apps/tauri/commit/3ab170917ed535fc9013f0a9255631fb34493e18) ([#9932](https://www.github.com/tauri-apps/tauri/pull/9932)) Changed `NsisSettings::compression` field from `Option` to just `NsisCompression` +- [`911242f09`](https://www.github.com/tauri-apps/tauri/commit/911242f0928e0a2add3595fa9de27850fb875fa6) ([#9883](https://www.github.com/tauri-apps/tauri/pull/9883)) Move updater target from `bundle > targets` to a separate field `bundle > createUpdaterArtifacts` +- [`3ab170917`](https://www.github.com/tauri-apps/tauri/commit/3ab170917ed535fc9013f0a9255631fb34493e18) ([#9932](https://www.github.com/tauri-apps/tauri/pull/9932)) Changed `NsisConfig::compression` field from `Option` to just `NsisCompression` + +## \[2.0.0-beta.17] + +### New Features + +- [`8a1ae2dea`](https://www.github.com/tauri-apps/tauri/commit/8a1ae2deaf3086e531ada25b1627f900e2e421fb)([#9843](https://www.github.com/tauri-apps/tauri/pull/9843)) Added an option to use a Xcode project for the iOS plugin instead of a plain SwiftPM project. +- [`5462e5cad`](https://www.github.com/tauri-apps/tauri/commit/5462e5cadc73c1b9083d852061d7c7f982cfbe53)([#9731](https://www.github.com/tauri-apps/tauri/pull/9731)) Add `installer_hooks` NSIS configuration field +- [`d6d3efbd1`](https://www.github.com/tauri-apps/tauri/commit/d6d3efbd125489cb46642b6d013cdc1eb7fc1a66)([#9865](https://www.github.com/tauri-apps/tauri/pull/9865)) Add `sign_command` in `WindowsConfig` + +### Breaking Changes + +- [`fc1543c65`](https://www.github.com/tauri-apps/tauri/commit/fc1543c65e736622bed93543dcc6504c43e200bb)([#9864](https://www.github.com/tauri-apps/tauri/pull/9864)) Removed `skip_webview_install` (`skipWebviewInstall`) option from config, which has been deprecated for a while now and planned to be removed in v2. Use `webview_install_mode` (`webviewInstallMode`) instead. +- [`265c23886`](https://www.github.com/tauri-apps/tauri/commit/265c23886ee5efbcc6d7188ff5c84cb32fa82aea)([#9375](https://www.github.com/tauri-apps/tauri/pull/9375)) Removed `Config::binary_name` and `PackageInfo::package_name` + +## \[2.0.0-beta.16] + +### Bug Fixes + +- [`be95d8d37`](https://www.github.com/tauri-apps/tauri/commit/be95d8d37c4b1a420c0d28a83b7efa40ab0b0ab5)([#9782](https://www.github.com/tauri-apps/tauri/pull/9782)) Fixes the `ToTokens` implementation for `Capability`. + +## \[2.0.0-beta.15] + +### Bug Fixes + +- [`a5205f179`](https://www.github.com/tauri-apps/tauri/commit/a5205f179e577cce5c05b710b597da8f4e1d0780)([#9691](https://www.github.com/tauri-apps/tauri/pull/9691)) Fixes the ToTokens implementation of the window configuration `proxy_url` field. + +## \[2.0.0-beta.14] + +### Bug Fixes + +- [`3fbc1703f`](https://www.github.com/tauri-apps/tauri/commit/3fbc1703f107dfb2c5a75e848805dcf60d449eb1)([#9676](https://www.github.com/tauri-apps/tauri/pull/9676)) Fixes `schemars` compilation issue. + +## \[2.0.0-beta.13] + +### Bug Fixes + +- [`a1e0e268f`](https://www.github.com/tauri-apps/tauri/commit/a1e0e268f02f7e2934bec48de4cac0dc00529a2b)([#9477](https://www.github.com/tauri-apps/tauri/pull/9477)) Replace `tauri:` prefix with `tauri-` for temporary permission file names + +## \[2.0.0-beta.12] + +### New Features + +- [`36b4c1249`](https://www.github.com/tauri-apps/tauri/commit/36b4c12497fbe636066f4848c6877b3ab6cc892e)([#9331](https://www.github.com/tauri-apps/tauri/pull/9331)) Added support for `provides`, `conflicts` and `replaces` (`obsoletes` for RPM) options for `bundler > deb` and `bundler > rpm` configs. + +## \[2.0.0-beta.11] + +### New Features + +- [`259d84529`](https://www.github.com/tauri-apps/tauri/commit/259d845290dde40639537258b2810567910f47f3)([#9209](https://www.github.com/tauri-apps/tauri/pull/9209)) Added `preInstallScript`, `postInstallScript`, `preRemoveScript` and `postRemoveScript` options for `bundler > deb` and `bundler > rpm` configs. + +### Enhancements + +- [`7c334cb18`](https://www.github.com/tauri-apps/tauri/commit/7c334cb1851ab034a3cfb472dd99dfc61ad3ca7f)([#9327](https://www.github.com/tauri-apps/tauri/pull/9327)) Make the isolation pattern encrypt key unextractable. +- [`a804a70a7`](https://www.github.com/tauri-apps/tauri/commit/a804a70a7aa1dc40fa9043206ad2265c6a5a437b)([#9328](https://www.github.com/tauri-apps/tauri/pull/9328)) The isolation iframe script now removes itself after execution. + +### Breaking Changes + +- [`06833f4fa`](https://www.github.com/tauri-apps/tauri/commit/06833f4fa8e63ecc55fe3fc874a9e397e77a5709)([#9100](https://www.github.com/tauri-apps/tauri/pull/9100)) Rename `FileDrop` to `DragDrop` on structs, enums and enum variants. Also renamed `file_drop` to `drag_drop` on fields and function names. + +## \[2.0.0-beta.10] + +### New Features + +- [`e227fe02f`](https://www.github.com/tauri-apps/tauri/commit/e227fe02f986e145c0731a64693e1c830a9eb5b0)([#9156](https://www.github.com/tauri-apps/tauri/pull/9156)) Added the `plugin` module. + +### Enhancements + +- [`7213b9e47`](https://www.github.com/tauri-apps/tauri/commit/7213b9e47242bef814aa7257e0bf84631bf5fe7e)([#9124](https://www.github.com/tauri-apps/tauri/pull/9124)) Fallback to an empty permission set if the plugin did not define its `default` permissions. + +## \[2.0.0-beta.9] + +### Breaking Changes + +- [`490a6b424`](https://www.github.com/tauri-apps/tauri/commit/490a6b424e81714524150aef96fbf6cf7004b940)([#9147](https://www.github.com/tauri-apps/tauri/pull/9147)) Removed the `assets::Assets` trait which is now part of the `tauri` crate. + +## \[2.0.0-beta.8] + +### Enhancements + +- [`3e472d0af`](https://www.github.com/tauri-apps/tauri/commit/3e472d0afcd67545dd6d9f18d304580a3b2759a8)([#9115](https://www.github.com/tauri-apps/tauri/pull/9115)) Changed the permission and capability platforms to be optional. + +### Breaking Changes + +- [`4ef17d083`](https://www.github.com/tauri-apps/tauri/commit/4ef17d08336a2e0df4a7ef9adea746d7419710b6)([#9116](https://www.github.com/tauri-apps/tauri/pull/9116)) The ACL configuration for remote URLs now uses the URLPattern standard instead of glob patterns. + +## \[2.0.0-beta.7] + +### Bug Fixes + +- [`86fa339de`](https://www.github.com/tauri-apps/tauri/commit/86fa339de7b176efafa9b3e89f94dcad5fcd03da)([#9071](https://www.github.com/tauri-apps/tauri/pull/9071)) Fix compile time error in context generation when using `app.windows.windowEffects.color` +- [`6c0683224`](https://www.github.com/tauri-apps/tauri/commit/6c068322460300e9d56a4fac5b018d4c437daa9e)([#9068](https://www.github.com/tauri-apps/tauri/pull/9068)) Fixes scope resolution grouping scopes for all windows. +- [`c68218b36`](https://www.github.com/tauri-apps/tauri/commit/c68218b362c417b62e56c7a2b5b32c13fe035a83)([#8990](https://www.github.com/tauri-apps/tauri/pull/8990)) Fix `BundleTarget::to_vec` returning an empty vec for `BundleTarget::All` variant. +- [`c68218b36`](https://www.github.com/tauri-apps/tauri/commit/c68218b362c417b62e56c7a2b5b32c13fe035a83)([#8990](https://www.github.com/tauri-apps/tauri/pull/8990)) Add `BundleType::all` method to return all possible `BundleType` variants. + +### Breaking Changes + +- [`9aa0d6e95`](https://www.github.com/tauri-apps/tauri/commit/9aa0d6e959269a9d99ff474e7f12bd397ea75fcd)([#9069](https://www.github.com/tauri-apps/tauri/pull/9069)) Removed `debug_eprintln!` and `consume_unused_variable` macros. +- [`bb23511ea`](https://www.github.com/tauri-apps/tauri/commit/bb23511ea80bcaffbdebf057301e463fff268c90)([#9079](https://www.github.com/tauri-apps/tauri/pull/9079)) Changed `CapabiltyFile::List` enum variant to be a tuple-struct and added `CapabiltyFile::NamedList`. This allows more flexibility when parsing capabilties from JSON files. + +## \[2.0.0-beta.6] + +### New Features + +- [`d7f56fef`](https://www.github.com/tauri-apps/tauri/commit/d7f56fef85cac3af4e2dbac1eac40e5567b1f160)([#9014](https://www.github.com/tauri-apps/tauri/pull/9014)) Allow defining a permission that only applies to a set of target platforms via the `platforms` configuration option. + +### Enhancements + +- [`04440edc`](https://www.github.com/tauri-apps/tauri/commit/04440edce870f9d06055616034941d79443d5a87)([#9019](https://www.github.com/tauri-apps/tauri/pull/9019)) Changed plugin markdown docs generation to table format. + +### Breaking Changes + +- [`3657ad82`](https://www.github.com/tauri-apps/tauri/commit/3657ad82f88ce528551d032d521c52eed3f396b4)([#9008](https://www.github.com/tauri-apps/tauri/pull/9008)) Allow defining permissions for the application commands via `tauri_build::Attributes::app_manifest`. + +## \[2.0.0-beta.5] + +### Enhancements + +- [`bc5b5e67`](https://www.github.com/tauri-apps/tauri/commit/bc5b5e671a546512f823f1c157421b4c3311dfc0)([#8984](https://www.github.com/tauri-apps/tauri/pull/8984)) Do not include a CSP tag in the application HTML and rely on the custom protocol response header instead. + +## \[2.0.0-beta.4] + +### Breaking Changes + +- [`a76fb118`](https://www.github.com/tauri-apps/tauri/commit/a76fb118ce2de22e1bdb4216bf0ac01dfc3e5799)([#8950](https://www.github.com/tauri-apps/tauri/pull/8950)) Changed the capability format to allow configuring both `remote: { urls: Vec }` and `local: bool (default: true)` instead of choosing one on the `context` field. + +## \[2.0.0-beta.3] + +### Breaking Changes + +- [`361ec37f`](https://www.github.com/tauri-apps/tauri/commit/361ec37fd4a5caa5b6630b9563ef079f53c6c336)([#8932](https://www.github.com/tauri-apps/tauri/pull/8932)) Moved `ProgressBarState` from `tauri-utils` to the `tauri::window` module and removed the `unity_uri` field. + +## \[2.0.0-beta.2] + +### Enhancements + +- [`0cb0a15c`](https://www.github.com/tauri-apps/tauri/commit/0cb0a15ce22af3d649cf219ac04188c14c5f4905)([#8789](https://www.github.com/tauri-apps/tauri/pull/8789)) Add `webviews` array on the capability for usage on multiwebview contexts. +- [`83a68deb`](https://www.github.com/tauri-apps/tauri/commit/83a68deb5676d39cd4728d2e140f6b46d5f787ed)([#8797](https://www.github.com/tauri-apps/tauri/pull/8797)) Added a new configuration option `tauri.conf.json > app > security > capabilities` to reference existing capabilities and inline new ones. If it is empty, all capabilities are still included preserving the current behavior. +- [`8d16a80d`](https://www.github.com/tauri-apps/tauri/commit/8d16a80d2fb2468667e7987d0cc99dbc7e3b9d0a)([#8802](https://www.github.com/tauri-apps/tauri/pull/8802)) The `Context` struct now includes the runtime authority instead of the resolved ACL. This does not impact most applications. +- [`28fb036c`](https://www.github.com/tauri-apps/tauri/commit/28fb036ce476c6f22815c35385f923135212c6f3)([#8852](https://www.github.com/tauri-apps/tauri/pull/8852)) Enhance resource directory resolution on development. +- [`dd7571a7`](https://www.github.com/tauri-apps/tauri/commit/dd7571a7808676c8063a4983b9c6687dfaf03a09)([#8815](https://www.github.com/tauri-apps/tauri/pull/8815)) Do not generate JSON schema and markdown reference file if the plugin does not define any permissions and delete those files if they exist. +- [`5618f6d2`](https://www.github.com/tauri-apps/tauri/commit/5618f6d2ffc9ebf40710145538b06bebfa55f878)([#8856](https://www.github.com/tauri-apps/tauri/pull/8856)) Relax requirements on plugin's identifiers to be alphanumeric and `-` instead of only lower alpha and `-`. +- [`8d16a80d`](https://www.github.com/tauri-apps/tauri/commit/8d16a80d2fb2468667e7987d0cc99dbc7e3b9d0a)([#8802](https://www.github.com/tauri-apps/tauri/pull/8802)) Refactored the capability types and resolution algorithm. + +### Bug Fixes + +- [`ae0fe47c`](https://www.github.com/tauri-apps/tauri/commit/ae0fe47c4c35fa87c77acf42af32ef3f0615cb08)([#8774](https://www.github.com/tauri-apps/tauri/pull/8774)) Fix compile error when `tauri.conf.json` had `bundle > license` set. + +### Breaking Changes + +- [`f284f9c5`](https://www.github.com/tauri-apps/tauri/commit/f284f9c545deeb77d15b6e8b1d0d05f49c40634c)([#8898](https://www.github.com/tauri-apps/tauri/pull/8898)) Changed the capability `remote` configuration to take a list of `urls` instead of `domains` for more flexibility. + +## \[2.0.0-beta.1] + +### Enhancements + +- [`4e101f80`](https://www.github.com/tauri-apps/tauri/commit/4e101f801657e7d01ce8c22f9c6468067d0caab2)([#8756](https://www.github.com/tauri-apps/tauri/pull/8756)) Moved the capability JSON schema to the `src-tauri/gen` folder so it's easier to track changes on the `capabilities` folder. + +### Bug Fixes + +- [`4e101f80`](https://www.github.com/tauri-apps/tauri/commit/4e101f801657e7d01ce8c22f9c6468067d0caab2)([#8756](https://www.github.com/tauri-apps/tauri/pull/8756)) Rerun build script when a new permission is added. + +## \[2.0.0-beta.0] + +### New Features + +- [`74a2a603`](https://www.github.com/tauri-apps/tauri/commit/74a2a6036a5e57462f161d728cbd8a6f121028ca)([#8661](https://www.github.com/tauri-apps/tauri/pull/8661)) Implement access control list for IPC usage. +- [`9eaeb5a8`](https://www.github.com/tauri-apps/tauri/commit/9eaeb5a8cd95ae24b5e66205bdc2763cb7f965ce)([#8622](https://www.github.com/tauri-apps/tauri/pull/8622)) Add `parent` option for window config. +- [`58fe2e81`](https://www.github.com/tauri-apps/tauri/commit/58fe2e812a85b9f4eba105286a63f271ea637836)([#8670](https://www.github.com/tauri-apps/tauri/pull/8670)) Add `WebviewUrl::CustomProtocol` enum variant. + +### What's Changed + +- [`6639a579`](https://www.github.com/tauri-apps/tauri/commit/6639a579c76d45210f33a72d37e21d4c5a9d334b)([#8441](https://www.github.com/tauri-apps/tauri/pull/8441)) Added the `WindowConfig::proxy_url` `WebviewBuilder::proxy_url() / WebviewWindowBuilder::proxy_url()` options when creating a webview. + +### Breaking Changes + +- [`8de308d1`](https://www.github.com/tauri-apps/tauri/commit/8de308d1bf6a855d7a26af58bd0e744938ba47d8)([#8723](https://www.github.com/tauri-apps/tauri/pull/8723)) Restructured Tauri config per [RFC#5](https://github.com/tauri-apps/rfcs/blob/f3e82a6b0c5390401e855850d47dc7b7d9afd684/texts/0005-tauri-config-restructure.md): + + - Moved `package.productName`, `package.version` and `tauri.bundle.identifier` fields to the top-level. + - Removed `package` object. + - Renamed `tauri` object to `app`. + - Moved `tauri.bundle` object to the top-level. + - Renamed `build.distDir` field to `frontendDist`. + - Renamed `build.devPath` field to `devUrl` and will no longer accepts paths, it will only accept URLs. + - Moved `tauri.pattern` to `app.security.pattern`. + - Removed `tauri.bundle.updater` object, and its fields have been moved to the updater plugin under `plugins.updater` object. + - Moved `build.withGlobalTauri` to `app.withGlobalTauri`. + - Moved `tauri.bundle.dmg` object to `bundle.macOS.dmg`. + - Moved `tauri.bundle.deb` object to `bundle.linux.deb`. + - Moved `tauri.bundle.appimage` object to `bundle.linux.appimage`. + - Removed all license fields from each bundle configuration object and instead added `bundle.license` and `bundle.licenseFile`. + - Renamed `AppUrl` to `FrontendDist` and refactored its variants to be more explicit. +- [`c77b4032`](https://www.github.com/tauri-apps/tauri/commit/c77b40324ea9bf580871fc11aed69ba0c9b6b8cf)([#8280](https://www.github.com/tauri-apps/tauri/pull/8280)) Renamed `config::WindowUrl` to `config::WebviewUrl`. +- [`a093682d`](https://www.github.com/tauri-apps/tauri/commit/a093682d2df7169b024bb4f736c7f1fd2ea8b327)([#8621](https://www.github.com/tauri-apps/tauri/pull/8621)) Changed `error` field in `ConfigError::FormatToml` to be boxed `Box` to reduce the enum `ConfigError` size in memory. +- [`58fe2e81`](https://www.github.com/tauri-apps/tauri/commit/58fe2e812a85b9f4eba105286a63f271ea637836)([#8670](https://www.github.com/tauri-apps/tauri/pull/8670)) Changed `dist_dir` and `dev_path` config options to be optional. + +## \[2.0.0-alpha.13] + +### Bug Fixes + +- [`9b230de7`](https://www.github.com/tauri-apps/tauri/commit/9b230de7bc6690c2733f5324d50b999af1f7a6ef)([#8407](https://www.github.com/tauri-apps/tauri/pull/8407)) Fix compile error when parsing config that includes float values. + +## \[2.0.0-alpha.12] + +### New Features + +- [\`\`](https://www.github.com/tauri-apps/tauri/commit/undefined) Add bundle DMG configuration options. + +## \[2.0.0-alpha.11] + +### Breaking Changes + +- [`5e84e92e`](https://www.github.com/tauri-apps/tauri/commit/5e84e92e99376f24b730f8eba002239379b593e1)([#8243](https://www.github.com/tauri-apps/tauri/pull/8243)) Changed `platform::windows_version` to return a `(u32, u32, u32)` instead of `Option<(u32, u32, u32)>` + +## \[2.0.0-alpha.10] + +### Enhancements + +- [`c6c59cf2`](https://www.github.com/tauri-apps/tauri/commit/c6c59cf2373258b626b00a26f4de4331765dd487) Pull changes from Tauri 1.5 release. + +### Dependencies + +- [`c7c2507d`](https://www.github.com/tauri-apps/tauri/commit/c7c2507da16a9beb71bf06745fe7ac1325ab7c2a)([#8035](https://www.github.com/tauri-apps/tauri/pull/8035)) Update `windows` to version `0.51` and `webview2-com` to version `0.27` + +## \[2.0.0-alpha.9] + +### New Features + +- [`c085adda`](https://www.github.com/tauri-apps/tauri/commit/c085addab58ba851398373c6fd13f9cb026d71e8)([#8009](https://www.github.com/tauri-apps/tauri/pull/8009)) Added `set_progress_bar` to `Window`. +- [`c1ec0f15`](https://www.github.com/tauri-apps/tauri/commit/c1ec0f155118527361dd5645d920becbc8afd569)([#7933](https://www.github.com/tauri-apps/tauri/pull/7933)) Added the `always_on_bottom` option to the window configuration. +- [`880266a7`](https://www.github.com/tauri-apps/tauri/commit/880266a7f697e1fe58d685de3bb6836ce5251e92)([#8031](https://www.github.com/tauri-apps/tauri/pull/8031)) Bump the MSRV to 1.70. +- [`ed32257d`](https://www.github.com/tauri-apps/tauri/commit/ed32257d044f90b5eb15053efd1667125def2d2b)([#7794](https://www.github.com/tauri-apps/tauri/pull/7794)) On Windows, add `WindowEffect::Tabbed`,`WindowEffect::TabbedDark` and `WindowEffect::TabbedLight` + +### Breaking Changes + +- [`ebcc21e4`](https://www.github.com/tauri-apps/tauri/commit/ebcc21e4b95f4e8c27639fb1bca545b432f52d5e)([#8057](https://www.github.com/tauri-apps/tauri/pull/8057)) Renamed the beforeDevCommand, beforeBuildCommand and beforeBundleCommand hooks environment variables from `TAURI_PLATFORM, TAURI_ARCH, TAURI_FAMILY, TAURI_PLATFORM_VERSION, TAURI_PLATFORM_TYPE and TAURI_DEBUG` to `TAURI_ENV_PLATFORM, TAURI_ENV_ARCH, TAURI_ENV_FAMILY, TAURI_ENV_PLATFORM_VERSION, TAURI_ENV_PLATFORM_TYPE and TAURI_ENV_DEBUG` to differentiate the prefix with other CLI environment variables. + +## \[2.0.0-alpha.8] + +### Enhancements + +- Add an option to specify `id` for the tray icon in the tauri configuration file. + +### Breaking Changes + +- [`100d9ede`](https://www.github.com/tauri-apps/tauri/commit/100d9ede35995d9db21d2087dd5606adfafb89a5)([#7802](https://www.github.com/tauri-apps/tauri/pull/7802)) Follow file name conventions set by desktop for mobile Tauri configuration files. Added `target` argument on most `config::parse` methods. + +## \[2.0.0-alpha.7] + +### New Features + +- [`4db363a0`](https://www.github.com/tauri-apps/tauri/commit/4db363a03c182349f8491f46ced258d84723b11f)([#6589](https://www.github.com/tauri-apps/tauri/pull/6589)) Added `visible_on_all_workspaces` configuration option to `WindowBuilder`, `Window`, and `WindowConfig`. +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) Add option to specify a tooltip text for the tray icon in the config. +- [`74b1f4fc`](https://www.github.com/tauri-apps/tauri/commit/74b1f4fc6625d5b4f9b86f70e4eebd6551c61809)([#7384](https://www.github.com/tauri-apps/tauri/pull/7384)) Add `WindowEffect::MicaDark` and `WindowEffect::MicaLight` +- [`3b98141a`](https://www.github.com/tauri-apps/tauri/commit/3b98141aa26f74c641a4090874247b97079bd58a)([#3736](https://www.github.com/tauri-apps/tauri/pull/3736)) Add a configuration object for file associations under `BundleConfig`. + +### Enhancements + +- [`fbeb5b91`](https://www.github.com/tauri-apps/tauri/commit/fbeb5b9185baeda19e865228179e3e44c165f1d9)([#7170](https://www.github.com/tauri-apps/tauri/pull/7170)) Use custom protocols on the IPC implementation to enhance performance. + +### Security fixes + +- [`43c6285e`](https://www.github.com/tauri-apps/tauri/commit/43c6285e9006fb84066461d57fe09ea8db76d636)([#7359](https://www.github.com/tauri-apps/tauri/pull/7359)) Changed HTML implementation from unmaintained `kuchiki` to `kuchikiki`. + +### Breaking Changes + +- [`7fb419c3`](https://www.github.com/tauri-apps/tauri/commit/7fb419c326aaf72ecd556d8404377444ebb200e7)([#7535](https://www.github.com/tauri-apps/tauri/pull/7535)) `systemTray` config option has been renamed to `trayIcon`. + +## \[2.0.0-alpha.6] + +### New Features + +- [`e0f0dce2`](https://www.github.com/tauri-apps/tauri/commit/e0f0dce220730e2822fc202463aedf0166145de7)([#6442](https://www.github.com/tauri-apps/tauri/pull/6442)) Added the `window_effects` option to the window configuration. + +## \[2.0.0-alpha.5] + +- [`9a79dc08`](https://www.github.com/tauri-apps/tauri/commit/9a79dc085870e0c1a5df13481ff271b8c6cc3b78)([#6947](https://www.github.com/tauri-apps/tauri/pull/6947)) Remove `enable_tauri_api` from the IPC scope. +- [`09376af5`](https://www.github.com/tauri-apps/tauri/commit/09376af59424cc27803fa2820d2ac0d4cdc90a6d)([#6704](https://www.github.com/tauri-apps/tauri/pull/6704)) Moved the `cli` feature to its own plugin in the plugins-workspace repository. +- [`e1e85dc2`](https://www.github.com/tauri-apps/tauri/commit/e1e85dc2a5f656fc37867e278cae8042037740ac)([#6925](https://www.github.com/tauri-apps/tauri/pull/6925)) Moved the `protocol` scope configuration to the `asset_protocol` field in `SecurityConfig`. +- [`e1e85dc2`](https://www.github.com/tauri-apps/tauri/commit/e1e85dc2a5f656fc37867e278cae8042037740ac)([#6925](https://www.github.com/tauri-apps/tauri/pull/6925)) Moved the updater configuration to the `BundleConfig`. +- [`b072daa3`](https://www.github.com/tauri-apps/tauri/commit/b072daa3bd3e38b808466666619ddb885052c5b2)([#6919](https://www.github.com/tauri-apps/tauri/pull/6919)) Moved the `updater` feature to its own plugin in the plugins-workspace repository. +- [`3188f376`](https://www.github.com/tauri-apps/tauri/commit/3188f3764978c6d1452ee31d5a91469691e95094)([#6883](https://www.github.com/tauri-apps/tauri/pull/6883)) Bump the MSRV to 1.65. +- [`e1e85dc2`](https://www.github.com/tauri-apps/tauri/commit/e1e85dc2a5f656fc37867e278cae8042037740ac)([#6925](https://www.github.com/tauri-apps/tauri/pull/6925)) Removed the allowlist configuration. +- [`2d5378bf`](https://www.github.com/tauri-apps/tauri/commit/2d5378bfc1ba817ee2f331b41738a90e5997e5e8)([#6717](https://www.github.com/tauri-apps/tauri/pull/6717)) Remove the updater's dialog option. + +## \[2.0.0-alpha.4] + +- Added `android` configuration object under `tauri > bundle`. + - [db4c9dc6](https://www.github.com/tauri-apps/tauri/commit/db4c9dc655e07ee2184fe04571f500f7910890cd) feat(core): add option to configure Android's minimum SDK version ([#6651](https://www.github.com/tauri-apps/tauri/pull/6651)) on 2023-04-07 + +## \[2.0.0-alpha.3] + +- Pull changes from Tauri 1.3 release. + - [](https://www.github.com/tauri-apps/tauri/commit/undefined) on undefined + +## \[2.0.0-alpha.2] + +- Added the `shadow` option to the window configuration and `set_shadow` option to the `window` allow list. + - [a81750d7](https://www.github.com/tauri-apps/tauri/commit/a81750d779bc72f0fdb7de90b7fbddfd8049b328) feat(core): add shadow APIs ([#6206](https://www.github.com/tauri-apps/tauri/pull/6206)) on 2023-02-08 + +## \[2.0.0-alpha.1] + +- Bump the MSRV to 1.64. + - [7eb9aa75](https://www.github.com/tauri-apps/tauri/commit/7eb9aa75cfd6a3176d3f566fdda02d88aa529b0f) Update gtk to 0.16 ([#6155](https://www.github.com/tauri-apps/tauri/pull/6155)) on 2023-01-30 +- Added `crate_name` field on `PackageInfo`. + - [630a7f4b](https://www.github.com/tauri-apps/tauri/commit/630a7f4b18cef169bfd48673609306fec434e397) refactor: remove mobile log initialization, ref [#6049](https://www.github.com/tauri-apps/tauri/pull/6049) ([#6081](https://www.github.com/tauri-apps/tauri/pull/6081)) on 2023-01-17 + +## \[2.0.0-alpha.0] + +- Parse `android` and `ios` Tauri configuration files. + - [b3a3afc7](https://www.github.com/tauri-apps/tauri/commit/b3a3afc7de8de4021d73559288f5192732a706cf) feat(core): detect android and ios platform configuration files ([#4997](https://www.github.com/tauri-apps/tauri/pull/4997)) on 2022-08-22 +- First mobile alpha release! + - [fa3a1098](https://www.github.com/tauri-apps/tauri/commit/fa3a10988a03aed1b66fb17d893b1a9adb90f7cd) feat(ci): prepare 2.0.0-alpha.0 ([#5786](https://www.github.com/tauri-apps/tauri/pull/5786)) on 2022-12-08 + +## \[1.5.3] + +### New features + +- [`7aa30dec`](https://www.github.com/tauri-apps/tauri/commit/7aa30dec85a17c3d3faaf3841b93e10991b991b0)([#8620](https://www.github.com/tauri-apps/tauri/pull/8620)) Add `priority`, `section` and `changelog` options in Debian config. + +## \[1.5.2] + +### Bug Fixes + +- [`9b230de7`](https://www.github.com/tauri-apps/tauri/commit/9b230de7bc6690c2733f5324d50b999af1f7a6ef)([#8407](https://www.github.com/tauri-apps/tauri/pull/8407)) Fix compile error when parsing config that includes float values. + +## \[1.5.3] + +### New Features + +- [`b3e53e72`](https://www.github.com/tauri-apps/tauri/commit/b3e53e7243311a2659b7569dddc20c56ac9f9d8e)([#8288](https://www.github.com/tauri-apps/tauri/pull/8288)) Added `Assets::iter` to iterate on all embedded assets. + +## \[1.5.0] + +### New Features + +- [`4dd4893d`](https://www.github.com/tauri-apps/tauri/commit/4dd4893d7d166ac3a3b6dc2e3bd2540326352a78)([#5950](https://www.github.com/tauri-apps/tauri/pull/5950)) Allow specifying resources as a map specifying source and target paths. + +### Enhancements + +- [`9aa34ada`](https://www.github.com/tauri-apps/tauri/commit/9aa34ada5769dbefa7dfe5f7a6288b3d20b294e4)([#7645](https://www.github.com/tauri-apps/tauri/pull/7645)) Add setting to switch to `http://.localhost/` for custom protocols on Windows. + +### Bug Fixes + +- [`a6b52e44`](https://www.github.com/tauri-apps/tauri/commit/a6b52e44f22844009e273fb0250368d7a463f095)([#6519](https://www.github.com/tauri-apps/tauri/pull/6519)) Fix `io::read_line` not including the new line character `\n`. + +### Security fixes + +- [`eeff1784`](https://www.github.com/tauri-apps/tauri/commit/eeff1784e1ffa568e4ba024e17dd611f8e086784)([#7367](https://www.github.com/tauri-apps/tauri/pull/7367)) Changed HTML implementation from unmaintained `kuchiki` to `kuchikiki`. + +## \[1.4.0] + +### New Features + +- [`acc36fe1`](https://www.github.com/tauri-apps/tauri/commit/acc36fe1176cc8aa9063bde932abeb94796c5c72)([#6158](https://www.github.com/tauri-apps/tauri/pull/6158)) Add option to configure `require_literal_leading_dot` on `fs` and `asset` protocol scopes. +- [`35cd751a`](https://www.github.com/tauri-apps/tauri/commit/35cd751adc6fef1f792696fa0cfb471b0bf99374)([#5176](https://www.github.com/tauri-apps/tauri/pull/5176)) Added the `desktop_template` option on `tauri.conf.json > tauri > bundle > deb`. +- [`c4d6fb4b`](https://www.github.com/tauri-apps/tauri/commit/c4d6fb4b1ea8acf02707a9fe5dcab47c1c5bae7b)([#2353](https://www.github.com/tauri-apps/tauri/pull/2353)) Added the `maximizable`, `minimizable` and `closable` options to the window configuration. +- [`3cb7a3e6`](https://www.github.com/tauri-apps/tauri/commit/3cb7a3e642bb10ee90dc1d24daa48b8c8c15c9ce)([#6997](https://www.github.com/tauri-apps/tauri/pull/6997)) Add `MimeType::parse_with_fallback` and `MimeType::parse_from_uri_with_fallback` +- [`29488205`](https://www.github.com/tauri-apps/tauri/commit/2948820579d20dfaa0861c2f0a58bd7737a7ffd1)([#6867](https://www.github.com/tauri-apps/tauri/pull/6867)) Allow specifying custom language files of Tauri's custom messages for the NSIS installer +- [`e092f799`](https://www.github.com/tauri-apps/tauri/commit/e092f799469ff32c7d1595d0f07d06fd2dab5c29)([#6887](https://www.github.com/tauri-apps/tauri/pull/6887)) Add `nsis > template` option to specify custom NSIS installer template. +- [`cd3846c8`](https://www.github.com/tauri-apps/tauri/commit/cd3846c8ce61ab2879b3911e831525e6242aaab2)([#6955](https://www.github.com/tauri-apps/tauri/pull/6955)) Add `WindowsUpdateInstallMode::nsis_args` +- [`85e77fb7`](https://www.github.com/tauri-apps/tauri/commit/85e77fb797ec17882f55d0944578d929fc6c9c1f)([#6762](https://www.github.com/tauri-apps/tauri/pull/6762)) Correctly determine MIME type of `.txt` files. + +## \[1.3.0] + +- Added the `additional_browser_args` option to the window configuration. + - [3dc38b15](https://www.github.com/tauri-apps/tauri/commit/3dc38b150ea8c59c8ba67fd586f921016928f47c) feat(core): expose additional_browser_args to window config (fix: [#5757](https://www.github.com/tauri-apps/tauri/pull/5757)) ([#5799](https://www.github.com/tauri-apps/tauri/pull/5799)) on 2022-12-14 +- Added the `content_protected` option to the window configuration. + - [4ab5545b](https://www.github.com/tauri-apps/tauri/commit/4ab5545b7a831c549f3c65e74de487ede3ab7ce5) feat: add content protection api, closes [#5132](https://www.github.com/tauri-apps/tauri/pull/5132) ([#5513](https://www.github.com/tauri-apps/tauri/pull/5513)) on 2022-12-13 +- Correctly determine mime type of `.less`, `.sass` and `.styl` files. + - [5fdf8dcb](https://www.github.com/tauri-apps/tauri/commit/5fdf8dcb8ed171d06121dceb32078a7e4f86cc64) fix(core): mime type of .less, .sass and .styl files ([#6316](https://www.github.com/tauri-apps/tauri/pull/6316)) on 2023-02-19 +- Bump minimum supported Rust version to 1.60. + - [5fdc616d](https://www.github.com/tauri-apps/tauri/commit/5fdc616df9bea633810dcb814ac615911d77222c) feat: Use the zbus-backed of notify-rust ([#6332](https://www.github.com/tauri-apps/tauri/pull/6332)) on 2023-03-31 +- Add initial support for building `nsis` bundles on non-Windows platforms. + - [60e6f6c3](https://www.github.com/tauri-apps/tauri/commit/60e6f6c3f1605f3064b5bb177992530ff788ccf0) feat(bundler): Add support for creating NSIS bundles on unix hosts ([#5788](https://www.github.com/tauri-apps/tauri/pull/5788)) on 2023-01-19 +- Add `nsis` bundle target + - [c94e1326](https://www.github.com/tauri-apps/tauri/commit/c94e1326a7c0767a13128a8b1d327a00156ece12) feat(bundler): add `nsis`, closes [#4450](https://www.github.com/tauri-apps/tauri/pull/4450), closes [#2319](https://www.github.com/tauri-apps/tauri/pull/2319) ([#4674](https://www.github.com/tauri-apps/tauri/pull/4674)) on 2023-01-03 +- Added configuration to specify remote URLs allowed to access the IPC. + - [ee71c31f](https://www.github.com/tauri-apps/tauri/commit/ee71c31fd09cc5427da6d29d37c003a914547696) feat(core): allow configuring remote domains with IPC access, closes [#5088](https://www.github.com/tauri-apps/tauri/pull/5088) ([#5918](https://www.github.com/tauri-apps/tauri/pull/5918)) on 2023-04-11 + +## \[1.2.1] + +- Fix `allowlist > app > show/hide` always disabled when `allowlist > app > all: false`. + - [bb251087](https://www.github.com/tauri-apps/tauri/commit/bb2510876d0bdff736d36bf3a465cdbe4ad2b90c) fix(core): extend allowlist with `app`'s allowlist, closes [#5650](https://www.github.com/tauri-apps/tauri/pull/5650) ([#5652](https://www.github.com/tauri-apps/tauri/pull/5652)) on 2022-11-18 + +## \[1.2.0] + +- Validate `package > productName` in the tauri config and produce errors if it contains one of the following characters `/\:*?\"<>|` + - [b9316a64](https://www.github.com/tauri-apps/tauri/commit/b9316a64eaa9348c79efafb8b94960d9b4d5b27a) fix(cli): validate `productName` in config, closes [#5233](https://www.github.com/tauri-apps/tauri/pull/5233) ([#5262](https://www.github.com/tauri-apps/tauri/pull/5262)) on 2022-09-28 +- Properly serialize HTML template tags. + - [aec5537d](https://www.github.com/tauri-apps/tauri/commit/aec5537de0205f62b2ae5c89da04d21930a6fc2e) fix(codegen): serialize template tags, closes [#4410](https://www.github.com/tauri-apps/tauri/pull/4410) ([#5247](https://www.github.com/tauri-apps/tauri/pull/5247)) on 2022-09-28 +- `PatternKind::Isolation` is now defined even without the `isolation` feature. + - [a178f95d](https://www.github.com/tauri-apps/tauri/commit/a178f95d68b773779b40235a3a22115a5e36aa6a) feat: config schema generator ([#5193](https://www.github.com/tauri-apps/tauri/pull/5193)) on 2022-10-28 +- Added the `app` allowlist module. + - [39bf895b](https://www.github.com/tauri-apps/tauri/commit/39bf895b73ec6b53f5758815396ba85dda6b9c67) feat(macOS): Add application `show` and `hide` methods ([#3689](https://www.github.com/tauri-apps/tauri/pull/3689)) on 2022-10-03 +- - [7d9aa398](https://www.github.com/tauri-apps/tauri/commit/7d9aa3987efce2d697179ffc33646d086c68030c) feat: bump MSRV to 1.59 ([#5296](https://www.github.com/tauri-apps/tauri/pull/5296)) on 2022-09-28 +- Add `tauri.conf.json > bundle > publisher` field to specify the app publisher. + - [628285c1](https://www.github.com/tauri-apps/tauri/commit/628285c1cf43f03ed62378f3b6cc0c991317526f) feat(bundler): add `publisher` field, closes [#5273](https://www.github.com/tauri-apps/tauri/pull/5273) ([#5283](https://www.github.com/tauri-apps/tauri/pull/5283)) on 2022-09-28 +- Canonicalize the return value of `platform::resource_dir`. + - [a06dc699](https://www.github.com/tauri-apps/tauri/commit/a06dc6993148f10ff7623c9dcc81f313dd960ad0) fix(core): canonicalize resource dir to fix scope check, closes [#5196](https://www.github.com/tauri-apps/tauri/pull/5196) ([#5218](https://www.github.com/tauri-apps/tauri/pull/5218)) on 2022-09-29 +- Added `title` option on the system tray configuration (macOS only). + - [8f1ace77](https://www.github.com/tauri-apps/tauri/commit/8f1ace77956ac3477826ceb059a191e55b3fff93) feat: expose `set_title` for MacOS tray ([#5182](https://www.github.com/tauri-apps/tauri/pull/5182)) on 2022-09-30 +- Added the `user_agent` option to the window configuration. + - [a6c94119](https://www.github.com/tauri-apps/tauri/commit/a6c94119d8545d509723b147c273ca5edfe3729f) feat(core): expose user_agent to window config ([#5317](https://www.github.com/tauri-apps/tauri/pull/5317)) on 2022-10-02 +- Add `mime_type` module. + - [54c337e0](https://www.github.com/tauri-apps/tauri/commit/54c337e06f3bc624c4780cf002bc54790f446c90) feat(cli): hotreload support for frontend static files, closes [#2173](https://www.github.com/tauri-apps/tauri/pull/2173) ([#5256](https://www.github.com/tauri-apps/tauri/pull/5256)) on 2022-09-28 + +## \[1.1.1] + +- Add missing allowlist config for `set_cursor_grab`, `set_cursor_visible`, `set_cursor_icon` and `set_cursor_position` APIs. + - [c764408d](https://www.github.com/tauri-apps/tauri/commit/c764408da7fae123edd41115bda42fa75a4731d2) fix: Add missing allowlist config for cursor apis, closes [#5207](https://www.github.com/tauri-apps/tauri/pull/5207) ([#5211](https://www.github.com/tauri-apps/tauri/pull/5211)) on 2022-09-16 + +## \[1.1.0] + +- Allow adding `build > beforeBundleCommand` in tauri.conf.json to run a shell command before the bundling phase. + - [57ab9847](https://www.github.com/tauri-apps/tauri/commit/57ab9847eb2d8c9a5da584b873b7c072e9ee26bf) feat(cli): add `beforeBundleCommand`, closes [#4879](https://www.github.com/tauri-apps/tauri/pull/4879) ([#4893](https://www.github.com/tauri-apps/tauri/pull/4893)) on 2022-08-09 +- Change `before_dev_command` and `before_build_command` config value to allow configuring the current working directory. + - [d6f7d3cf](https://www.github.com/tauri-apps/tauri/commit/d6f7d3cfe8a7ec8d68c8341016c4e0a3103da587) Add cwd option to `before` commands, add wait option to dev [#4740](https://www.github.com/tauri-apps/tauri/pull/4740) [#3551](https://www.github.com/tauri-apps/tauri/pull/3551) ([#4834](https://www.github.com/tauri-apps/tauri/pull/4834)) on 2022-08-02 +- Allow configuring the `before_dev_command` to force the CLI to wait for the command to finish before proceeding. + - [d6f7d3cf](https://www.github.com/tauri-apps/tauri/commit/d6f7d3cfe8a7ec8d68c8341016c4e0a3103da587) Add cwd option to `before` commands, add wait option to dev [#4740](https://www.github.com/tauri-apps/tauri/pull/4740) [#3551](https://www.github.com/tauri-apps/tauri/pull/3551) ([#4834](https://www.github.com/tauri-apps/tauri/pull/4834)) on 2022-08-02 +- Added support to configuration files in TOML format (Tauri.toml file). + - [ae83d008](https://www.github.com/tauri-apps/tauri/commit/ae83d008f9e1b89bfc8dddaca42aa5c1fbc36f6d) feat: add support to TOML config file `Tauri.toml`, closes [#4806](https://www.github.com/tauri-apps/tauri/pull/4806) ([#4813](https://www.github.com/tauri-apps/tauri/pull/4813)) on 2022-08-02 +- Refactored the `config::parse` module. + - [ae83d008](https://www.github.com/tauri-apps/tauri/commit/ae83d008f9e1b89bfc8dddaca42aa5c1fbc36f6d) feat: add support to TOML config file `Tauri.toml`, closes [#4806](https://www.github.com/tauri-apps/tauri/pull/4806) ([#4813](https://www.github.com/tauri-apps/tauri/pull/4813)) on 2022-08-02 +- Update windows to 0.39.0 and webview2-com to 0.19.1. + - [e6d9b670](https://www.github.com/tauri-apps/tauri/commit/e6d9b670b0b314ed667b0e164f2c8d27048e678f) refactor: remove unneeded focus code ([#5065](https://www.github.com/tauri-apps/tauri/pull/5065)) on 2022-09-03 + +## \[1.0.3] + +- Added `menu_on_left_click: bool` to the `SystemTrayConfig`. + - [f8a3becb](https://www.github.com/tauri-apps/tauri/commit/f8a3becb287942db7f7b551b5db6aeb5a2e939ee) feat(core): add option to disable tray menu on left click, closes [#4584](https://www.github.com/tauri-apps/tauri/pull/4584) ([#4587](https://www.github.com/tauri-apps/tauri/pull/4587)) on 2022-07-05 +- Added `config::parse::read_platform` and `config::parse::get_platform_config_filename`. + - [8e3e7fc6](https://www.github.com/tauri-apps/tauri/commit/8e3e7fc64641afc7a6833bc93205e6f525562545) feat(cli): improve bundle identifier validation, closes [#4589](https://www.github.com/tauri-apps/tauri/pull/4589) ([#4596](https://www.github.com/tauri-apps/tauri/pull/4596)) on 2022-07-05 + +## \[1.0.2] + +- Expose `platform::windows_version` function. + - [bf764e83](https://www.github.com/tauri-apps/tauri/commit/bf764e83e01e7443e6cc54572001e1c98c357465) feat(utils): expose `windows_version` function ([#4534](https://www.github.com/tauri-apps/tauri/pull/4534)) on 2022-06-30 + +## \[1.0.1] + +- Changed the `BundleConfig::targets` to a `BundleTarget` enum to enhance generated documentation. + - [31c15cd2](https://www.github.com/tauri-apps/tauri/commit/31c15cd2bd94dbe39fb94982a15cbe02ac5d8925) docs(config): enhance documentation for bundle targets, closes [#3251](https://www.github.com/tauri-apps/tauri/pull/3251) ([#4418](https://www.github.com/tauri-apps/tauri/pull/4418)) on 2022-06-21 +- Added `platform::is_windows_7`. + - [57039fb2](https://www.github.com/tauri-apps/tauri/commit/57039fb2166571de85271b014a8711a29f06be1a) fix(core): add windows 7 notification support ([#4491](https://www.github.com/tauri-apps/tauri/pull/4491)) on 2022-06-28 +- Suppress unused variable warning in release builds. + - [45981851](https://www.github.com/tauri-apps/tauri/commit/45981851e35119266c1a079e1ff27a39f1fdfaed) chore(lint): unused variable warnings for release builds ([#4411](https://www.github.com/tauri-apps/tauri/pull/4411)) on 2022-06-22 +- Added webview install mode options. + - [2ca762d2](https://www.github.com/tauri-apps/tauri/commit/2ca762d207030a892a6d128b519e150e2d733468) feat(bundler): extend webview2 installation options, closes [#2882](https://www.github.com/tauri-apps/tauri/pull/2882) [#2452](https://www.github.com/tauri-apps/tauri/pull/2452) ([#4466](https://www.github.com/tauri-apps/tauri/pull/4466)) on 2022-06-26 + +## \[1.0.0] + +- Upgrade to `stable`! + - [f4bb30cc](https://www.github.com/tauri-apps/tauri/commit/f4bb30cc73d6ba9b9ef19ef004dc5e8e6bb901d3) feat(covector): prepare for v1 ([#4351](https://www.github.com/tauri-apps/tauri/pull/4351)) on 2022-06-15 + +## \[1.0.0-rc.9] + +- Added a config flag to bundle the media framework used by webkit2gtk `tauri.conf.json > tauri > bundle > appimage > bundleMediaFramework`. + - [d335fae9](https://www.github.com/tauri-apps/tauri/commit/d335fae92cdcbb0ee18aad4e54558914afa3e778) feat(bundler): bundle additional gstreamer files, closes [#4092](https://www.github.com/tauri-apps/tauri/pull/4092) ([#4271](https://www.github.com/tauri-apps/tauri/pull/4271)) on 2022-06-10 + +## \[1.0.0-rc.8] + +- **Breaking change:** `PackageInfo::version` is now a `semver::Version` instead of a `String`. + - [2badbd2d](https://www.github.com/tauri-apps/tauri/commit/2badbd2d7ed51bf33c1b547b4c837b600574bd4a) refactor: force semver versions, change updater `should_install` sig ([#4215](https://www.github.com/tauri-apps/tauri/pull/4215)) on 2022-05-25 + - [a7388e23](https://www.github.com/tauri-apps/tauri/commit/a7388e23c3b9019d48b078cae00a75c74d74d11b) fix(ci): adjust change file to include tauri-utils and tauri-codegen on 2022-05-27 + +## \[1.0.0-rc.7] + +- Allow configuring the display options for the MSI execution allowing quieter updates. + - [9f2c3413](https://www.github.com/tauri-apps/tauri/commit/9f2c34131952ea83c3f8e383bc3cec7e1450429f) feat(core): configure msiexec display options, closes [#3951](https://www.github.com/tauri-apps/tauri/pull/3951) ([#4061](https://www.github.com/tauri-apps/tauri/pull/4061)) on 2022-05-15 + +## \[1.0.0-rc.6] + +- Added `$schema` support to `tauri.conf.json`. + - [715cbde3](https://www.github.com/tauri-apps/tauri/commit/715cbde3842a916c4ebeab2cab348e1774b5c192) feat(config): add `$schema` to `tauri.conf.json`, closes [#3464](https://www.github.com/tauri-apps/tauri/pull/3464) ([#4031](https://www.github.com/tauri-apps/tauri/pull/4031)) on 2022-05-03 +- The `dangerous_allow_asset_csp_modification` configuration value has been changed to allow a list of CSP directives to disable. + - [164078c0](https://www.github.com/tauri-apps/tauri/commit/164078c0b719ccbc12e956fecf8a7d4a3c5044e1) feat: allow limiting dangerousDisableAssetCspModification, closes [#3831](https://www.github.com/tauri-apps/tauri/pull/3831) ([#4021](https://www.github.com/tauri-apps/tauri/pull/4021)) on 2022-05-02 + +## \[1.0.0-rc.5] + +- Added the `io` module with the `read_line` method. + - [b5622882](https://www.github.com/tauri-apps/tauri/commit/b5622882cf3748e1e5a90915f415c0cd922aaaf8) fix(cli): exit on non-compilation Cargo errors, closes [#3930](https://www.github.com/tauri-apps/tauri/pull/3930) ([#3942](https://www.github.com/tauri-apps/tauri/pull/3942)) on 2022-04-22 +- **Breaking change:** Removed the `useBootstrapper` option. Use https://github.com/tauri-apps/fix-path-env-rs instead. + - [6a5ff08c](https://www.github.com/tauri-apps/tauri/commit/6a5ff08ce9052b656aa40accedfd4315825164a3) refactor: remove bootstrapper, closes [#3786](https://www.github.com/tauri-apps/tauri/pull/3786) ([#3832](https://www.github.com/tauri-apps/tauri/pull/3832)) on 2022-03-31 + +## \[1.0.0-rc.4] + +- Added an option to disable the CSP injection of distributable assets nonces and hashes. + - [f6e32ee1](https://www.github.com/tauri-apps/tauri/commit/f6e32ee1880eb364ed76beb937c9d12e14d54910) feat(core): add dangerous option to disable compile time CSP injection ([#3775](https://www.github.com/tauri-apps/tauri/pull/3775)) on 2022-03-28 + +- Use the default value for `MacConfig.minimumSystemVersion` if the value is set to an empty string. + - [c81534eb](https://www.github.com/tauri-apps/tauri/commit/c81534ebd873c358e0346c7949aeb171803149a5) feat(cli): use default macOS minimum system version when it is empty ([#3658](https://www.github.com/tauri-apps/tauri/pull/3658)) on 2022-03-13 + +- Replace multiple dependencies who's C code compiled concurrently and caused + the other ones to bloat compile time significantly. + +- `zstd` -> `brotli` + +- `blake3` -> a vendored version of the blake3 reference + +- `ring` -> `getrandom` + +See https://github.com/tauri-apps/tauri/pull/3773 for more information about +these specific choices. + +- [8661e3e2](https://www.github.com/tauri-apps/tauri/commit/8661e3e24d96c399bfbcdee5d8e9d6beba2265a7) replace dependencies with long build times when used together (closes [#3571](https://www.github.com/tauri-apps/tauri/pull/3571)) ([#3773](https://www.github.com/tauri-apps/tauri/pull/3773)) on 2022-03-27 + +## \[1.0.0-rc.3] + +- Use `is_symlink` API compatible with Rust v1.57 instead of std/fs/struct.Metadata.html#method.is_symlink. + - [73388119](https://www.github.com/tauri-apps/tauri/commit/73388119e653e7902b19beef2ab6d7c5f8a7b83a) use older symlink check function ([#3579](https://www.github.com/tauri-apps/tauri/pull/3579)) on 2022-03-01 + +## \[1.0.0-rc.2] + +- Changed the default value for `tauri > bundle > macOS > minimumSystemVersion` to `10.13`. + - [fce344b9](https://www.github.com/tauri-apps/tauri/commit/fce344b90b7227f8f5514853c2f885fb24d3648e) feat(core): set default value for `minimum_system_version` to 10.13 ([#3497](https://www.github.com/tauri-apps/tauri/pull/3497)) on 2022-02-17 + +## \[1.0.0-rc.1] + +- Change default value for the `freezePrototype` configuration to `false`. + - [3a4c0160](https://www.github.com/tauri-apps/tauri/commit/3a4c01606184be762adee055ddac803de0d28527) fix(core): change default `freezePrototype` to false, closes [#3416](https://www.github.com/tauri-apps/tauri/pull/3416) [#3406](https://www.github.com/tauri-apps/tauri/pull/3406) ([#3423](https://www.github.com/tauri-apps/tauri/pull/3423)) on 2022-02-12 + +## \[1.0.0-rc.0] + +- The `allowlist` configuration now includes a `clipboard` object, controlling the exposure of the `writeText` and `readText` APIs. + - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 +- The dialog allowlist now includes flags for the `message`, `ask` and `confirm` APIs. + - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 +- The `allowlist` configuration now includes a `process` object, controlling the exposure of the `relaunch` and `exit` APIs. + - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 +- The `window` allowlist now includes options to enable all window modification APIs: `center`, `close`, `create`, `hide`, `maximize`, `minimize`, `print`, `requestUserAttention`, `setAlwaysOnTop`, `setDecorations`, `setFocus`, `setFullscreen`, `setIcon`, `setMaxSize`, `setMinSize`, `setPosition`, `setResizable`, `setSize`, `setSkipTaskbar`, `setTitle`, `show`, `startDragging`, `unmaximize` and `unminimize`. + - [d660cab3](https://www.github.com/tauri-apps/tauri/commit/d660cab38d7d703e8b2bb85a3e9462d9e28b086b) feat: enhance allowlist configuration \[TRI-027] ([#11](https://www.github.com/tauri-apps/tauri/pull/11)) on 2022-01-09 +- Added `asset` allowlist configuration, which enables the `asset` protocol and defines it access scope. + - [7920ff14](https://www.github.com/tauri-apps/tauri/commit/7920ff14e6424079c48ea5645d9aa13e7a272b87) feat: scope the `fs` API and the `asset` protocol \[TRI-026] \[TRI-010] \[TRI-011] ([#10](https://www.github.com/tauri-apps/tauri/pull/10)) on 2022-01-09 +- Change `CliArg` numeric types from `u64` to `usize`. + - [1f988535](https://www.github.com/tauri-apps/tauri/commit/1f98853573a837dd0cfc2161b206a5033ec2da5e) chore(deps) Update Tauri Core ([#2480](https://www.github.com/tauri-apps/tauri/pull/2480)) on 2021-08-24 +- Apply `nonce` to `script` and `style` tags and set them on the `CSP` (`script-src` and `style-src` fetch directives). + - [cf54dcf9](https://www.github.com/tauri-apps/tauri/commit/cf54dcf9c81730e42c9171daa9c8aa474c95b522) feat: improve `CSP` security with nonces and hashes, add `devCsp` \[TRI-004] ([#8](https://www.github.com/tauri-apps/tauri/pull/8)) on 2022-01-09 +- The path returned from `tauri::api::process::current_binary` is now cached when loading the binary. + - [7c3db7a3](https://www.github.com/tauri-apps/tauri/commit/7c3db7a3811fd4de3e71c78cfd00894fa51ab786) cache current binary path much sooner ([#45](https://www.github.com/tauri-apps/tauri/pull/45)) on 2022-02-01 +- Added `dev_csp` to the `security` configuration object. + - [cf54dcf9](https://www.github.com/tauri-apps/tauri/commit/cf54dcf9c81730e42c9171daa9c8aa474c95b522) feat: improve `CSP` security with nonces and hashes, add `devCsp` \[TRI-004] ([#8](https://www.github.com/tauri-apps/tauri/pull/8)) on 2022-01-09 +- Fixes resource directory resolution on Linux. + - [1a28904b](https://www.github.com/tauri-apps/tauri/commit/1a28904b8ebea92e143d5dc21ebd209e9edec531) fix(core): resource path resolution on Linux, closes [#2493](https://www.github.com/tauri-apps/tauri/pull/2493) on 2021-08-22 +- Allow using a fixed version for the Webview2 runtime via the `tauri > bundle > windows > webviewFixedRuntimePath` config option. + - [85df94f2](https://www.github.com/tauri-apps/tauri/commit/85df94f2b0d40255812b42c5e32a70c4b45392df) feat(core): config for fixed webview2 runtime version path ([#27](https://www.github.com/tauri-apps/tauri/pull/27)) on 2021-11-02 +- The updater `pubkey` is now a required field for security reasons. Sign your updates with the `tauri signer` command. + - [d95cc831](https://www.github.com/tauri-apps/tauri/commit/d95cc83105dda52df7514e30e54f3676cdb374ee) feat: enforce updater public key \[TRI-015] ([#42](https://www.github.com/tauri-apps/tauri/pull/42)) on 2022-01-09 +- Added the `isolation` pattern. + - [d5d6d2ab](https://www.github.com/tauri-apps/tauri/commit/d5d6d2abc17cd89c3a079d2ce01581193469dbc0) Isolation Pattern ([#43](https://www.github.com/tauri-apps/tauri/pull/43)) Co-authored-by: Ngo Iok Ui (Wu Yu Wei) Co-authored-by: Lucas Fernandes Nogueira on 2022-01-17 +- Adds support for using JSON5 format for the `tauri.conf.json` file, along with also supporting the `.json5` extension. + +Here is the logic flow that determines if JSON or JSON5 will be used to parse the config: + +1. Check if `tauri.conf.json` exists + a. Parse it with `serde_json` + b. Parse it with `json5` if `serde_json` fails + c. Return original `serde_json` error if all above steps failed +2. Check if `tauri.conf.json5` exists + a. Parse it with `json5` + b. Return error if all above steps failed +3. Return error if all above steps failed + +- [995de57a](https://www.github.com/tauri-apps/tauri/commit/995de57a76cf51215277673e526d7ec32b86b564) Add seamless support for using JSON5 in the config file ([#47](https://www.github.com/tauri-apps/tauri/pull/47)) on 2022-02-03 +- Move the copying of resources and sidecars from `cli.rs` to `tauri-build` so using the Cargo CLI directly processes the files for the application execution in development. + - [5eb72c24](https://www.github.com/tauri-apps/tauri/commit/5eb72c24deddf5a01093bea96b90c0d8806afc3f) refactor: copy resources and sidecars on the Cargo build script ([#3357](https://www.github.com/tauri-apps/tauri/pull/3357)) on 2022-02-08 +- **Breaking change**\* Remove default webview window when `tauri.conf.json > tauri > windows` is not set. + - [c119060e](https://www.github.com/tauri-apps/tauri/commit/c119060e3d9a5a824639fb6b3c45a87e7a62e4e2) refactor(core): empty default value for config > tauri > windows ([#3380](https://www.github.com/tauri-apps/tauri/pull/3380)) on 2022-02-10 +- The minimum Rust version is now `1.56`. + - [a9dfc015](https://www.github.com/tauri-apps/tauri/commit/a9dfc015505afe91281c2027954ffcc588b1a59c) feat: update to edition 2021 and set minimum rust to 1.56 ([#2789](https://www.github.com/tauri-apps/tauri/pull/2789)) on 2021-10-22 +- Adds `scope` glob array config under `tauri > allowlist > fs`. + Adds `assetScope` glob array config under `tauri > allowlist > protocol`. + Adds `scope` URL array config under `tauri > allowlist > http`. + - [7920ff14](https://www.github.com/tauri-apps/tauri/commit/7920ff14e6424079c48ea5645d9aa13e7a272b87) feat: scope the `fs` API and the `asset` protocol \[TRI-026] \[TRI-010] \[TRI-011] ([#10](https://www.github.com/tauri-apps/tauri/pull/10)) on 2022-01-09 + - [0ad1c651](https://www.github.com/tauri-apps/tauri/commit/0ad1c6515f696fadefddbf133a9561836b3d5934) feat(core): add `http` allowlist scope \[TRI-008] ([#24](https://www.github.com/tauri-apps/tauri/pull/24)) on 2021-10-29 +- The `shell` allowlist now includes a `sidecar` flag, which enables the use of the `shell` API to execute sidecars. + - [eed01728](https://www.github.com/tauri-apps/tauri/commit/eed017287fed2ade689af4268e8b63b9c9f2e585) feat(core): add `shell > sidecar` allowlist and `process` feature flag \[TRI-037] ([#18](https://www.github.com/tauri-apps/tauri/pull/18)) on 2021-10-24 +- Force updater endpoint URL to use `https` on release builds. + - [c077f449](https://www.github.com/tauri-apps/tauri/commit/c077f449270cffbf7956b1af81e1fb237ebf564a) feat: force endpoint URL to use https on release \[TRI-015] ([#41](https://www.github.com/tauri-apps/tauri/pull/41)) on 2022-01-09 + +## \[1.0.0-beta.3] + +- Fixes minimum window height being used as maximum height. + - [e3f99165](https://www.github.com/tauri-apps/tauri/commit/e3f9916526b226866137cb663e5cafab2b6a0e01) fix(core) minHeight being used as maxHeight ([#2247](https://www.github.com/tauri-apps/tauri/pull/2247)) on 2021-07-19 +- Implement `Debug` on public API structs and enums. + - [fa9341ba](https://www.github.com/tauri-apps/tauri/commit/fa9341ba18ba227735341530900714dba0f27291) feat(core): implement `Debug` on public API structs/enums, closes [#2292](https://www.github.com/tauri-apps/tauri/pull/2292) ([#2387](https://www.github.com/tauri-apps/tauri/pull/2387)) on 2021-08-11 +- Keep original value on `config > package > productName` on Linux (previously converted to kebab-case). + - [3f039cb8](https://www.github.com/tauri-apps/tauri/commit/3f039cb8a308b0f18deaa37d7cfb1cc50d308d0e) fix: keep original `productName` for .desktop `Name` field, closes [#2295](https://www.github.com/tauri-apps/tauri/pull/2295) ([#2384](https://www.github.com/tauri-apps/tauri/pull/2384)) on 2021-08-10 +- Inject the invoke key on regular `` tags. + - [d0142e87](https://www.github.com/tauri-apps/tauri/commit/d0142e87ddf5231fd46e2cbe4769bb16f3fe01e9) fix(core): invoke key injection on regular JS scripts, closes [#2342](https://www.github.com/tauri-apps/tauri/pull/2342) ([#2344](https://www.github.com/tauri-apps/tauri/pull/2344)) on 2021-08-03 + +## \[1.0.0-beta.2] + +- Inject invoke key on `script` tags with `type="module"`. + - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on `` tags. + - [d0142e87](https://www.github.com/tauri-apps/tauri/commit/d0142e87ddf5231fd46e2cbe4769bb16f3fe01e9) fix(core): invoke key injection on regular JS scripts, closes [#2342](https://www.github.com/tauri-apps/tauri/pull/2342) ([#2344](https://www.github.com/tauri-apps/tauri/pull/2344)) on 2021-08-03 + +- Remove salt-related APIs (no longer needed after the `__TAURI_INVOKE_KEY__` implementation). + - [e2a0704c](https://www.github.com/tauri-apps/tauri/commit/e2a0704c6c7a447b628a95f8920f9bbe9feef229) refactor(core): remove salt APIs ([#2426](https://www.github.com/tauri-apps/tauri/pull/2426)) on 2021-08-14 + +- Update minimum Rust version to 1.54.0. + - [a5394716](https://www.github.com/tauri-apps/tauri/commit/a53947160985a4f5b0ad1fbb4aa6865d6f852c66) chore: update rust to 1.54.0 ([#2434](https://www.github.com/tauri-apps/tauri/pull/2434)) on 2021-08-15 + +- Run the setup callback after preparing the system tray. + - [1792c455](https://www.github.com/tauri-apps/tauri/commit/1792c45592cd4999af063fa89017f52a985553c1) fix(core): run setup after preparing system tray ([#2312](https://www.github.com/tauri-apps/tauri/pull/2312)) on 2021-07-28 + +- Fixes a consistency issue on the order of `tauri::process::Command` emitted events. + - [737da872](https://www.github.com/tauri-apps/tauri/commit/737da87244cbdeb1158c93944bcb5e10bb383b31) fix(core): random shell command output order, closes [#2184](https://www.github.com/tauri-apps/tauri/pull/2184) ([#2376](https://www.github.com/tauri-apps/tauri/pull/2376)) on 2021-08-09 + +- Force data directory even on non-local window. + - [70a19414](https://www.github.com/tauri-apps/tauri/commit/70a1941468f55f0dc09ac2e13802945891d766f4) fix(core): Force data_directory on Windows ([#2288](https://www.github.com/tauri-apps/tauri/pull/2288)) on 2021-07-23 + +- Allow creation of empty Window with `create_tao_window()` and management with `send_tao_window_event()` on the AppHandler. + - [88080855](https://www.github.com/tauri-apps/tauri/commit/8808085541a629b8e22b612a06cef01cf9b3722e) feat(window): Allow creation of Window without `wry` ([#2321](https://www.github.com/tauri-apps/tauri/pull/2321)) on 2021-07-29 + - [15566cfd](https://www.github.com/tauri-apps/tauri/commit/15566cfd64f5072fa4980a6ce5b33259958e9021) feat(core): add API to send wry window message to the event loop ([#2339](https://www.github.com/tauri-apps/tauri/pull/2339)) on 2021-08-02 + +- Make `ClipboardManager` and `GlobalShortcutManager` public as they are exposed in the `AppHandle`. + - [6e0dbf63](https://www.github.com/tauri-apps/tauri/commit/6e0dbf639ac2c79e00fee9270a2ca8e613dc1f98) fix(core): Expose `ClipboardManager` and `GlobalShortcutManager` ([#2263](https://www.github.com/tauri-apps/tauri/pull/2263)) on 2021-08-03 + +- - Support [macOS tray icon template](https://developer.apple.com/documentation/appkit/nsimage/1520017-template?language=objc) to adjust automatically based on taskbar color. + +- Images you mark as template images should consist of only black and clear colors. You can use the alpha channel in the image to adjust the opacity of black content, however. + +- [426a6b49](https://www.github.com/tauri-apps/tauri/commit/426a6b49962de8faf061db2e820ac10fcbb300d6) feat(macOS): Implement tray icon template ([#2322](https://www.github.com/tauri-apps/tauri/pull/2322)) on 2021-07-29 + +- Add `Event::Ready` on the `run()` callback. Triggered once when the event loop is ready. + - [28c6b7ad](https://www.github.com/tauri-apps/tauri/commit/28c6b7adfe98e701b158e936eafb7541ddc700e0) feat: add `Event::Ready` ([#2433](https://www.github.com/tauri-apps/tauri/pull/2433)) on 2021-08-15 + +- - Do not run the updater with UAC task if server don't tell us. (Allow toggling server-side) + +- The updater expect a field named `with_elevated_task` with a `boolean` and will not run if the task is not installed first. (windows only) + +- [c5761190](https://www.github.com/tauri-apps/tauri/commit/c576119013297f3731d76924a887c5c2a62c13ba) fix(updater): Run elevated task only if server tell us ([#2357](https://www.github.com/tauri-apps/tauri/pull/2357)) on 2021-08-08 + +- Add `try_state` API to the `Manager` trait. + - [84a0e04c](https://www.github.com/tauri-apps/tauri/commit/84a0e04cbe242b2b7abb388da2d878fce10bc27d) feat(core): `try_state` API on the `Manager` trait ([#2341](https://www.github.com/tauri-apps/tauri/pull/2341)) on 2021-08-02 + +## \[1.0.0-beta.5] + +- Allow preventing window close when the user requests it. + - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 +- Add `App#run` method with callback argument (event loop event handler). + - [8157a68a](https://www.github.com/tauri-apps/tauri/commit/8157a68af1d94de1b90a14aa44139bb123b3436b) feat(core): allow listening to event loop events & prevent window close ([#2131](https://www.github.com/tauri-apps/tauri/pull/2131)) on 2021-07-06 +- Fixes `data-tauri-drag-region` not firing its events. + - [578610a2](https://www.github.com/tauri-apps/tauri/commit/578610a29d5cefb8df070606b7587318b14c397a) fix(core): fix drag-region not sending its events correctly ([#2196](https://www.github.com/tauri-apps/tauri/pull/2196)) on 2021-07-12 +- Fix macOS `EXC_BAD_ACCESS` panic when app is code-signed. + - [456a94f6](https://www.github.com/tauri-apps/tauri/commit/456a94f6637746800b9b85fc3922e82871603402) fix(macOS): updater `EXC_BAD_ACCESS` ([#2181](https://www.github.com/tauri-apps/tauri/pull/2181)) on 2021-07-12 +- Fixes SVG loading on custom protocol. + - [e663bdd5](https://www.github.com/tauri-apps/tauri/commit/e663bdd5938830ab4eba961e69c3985191b499dd) fix(core): svg mime type ([#2129](https://www.github.com/tauri-apps/tauri/pull/2129)) on 2021-06-30 +- Expose `gtk_window` getter. + - [e0a8e09c](https://www.github.com/tauri-apps/tauri/commit/e0a8e09cab6799eeb9ec524b5f7780d1e5a84299) feat(core): expose `gtk_window`, closes [#2083](https://www.github.com/tauri-apps/tauri/pull/2083) ([#2141](https://www.github.com/tauri-apps/tauri/pull/2141)) on 2021-07-02 +- Inject invoke key on `script` tags with `type="module"`. + - [f03eea9c](https://www.github.com/tauri-apps/tauri/commit/f03eea9c9b964709532afbc4d1dd343b3fd96081) feat(core): inject invoke key on ` + + diff --git a/crates/tauri/test/fixture/isolation/isolation-dist/index.js b/crates/tauri/test/fixture/isolation/isolation-dist/index.js new file mode 100644 index 000000000000..6510a210e450 --- /dev/null +++ b/crates/tauri/test/fixture/isolation/isolation-dist/index.js @@ -0,0 +1,8 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +window.__TAURI_ISOLATION_HOOK__ = (payload, options) => { + console.log('hook', payload, options) + return payload +} diff --git a/core/tauri/test/fixture/src-tauri/icons/icon.ico b/crates/tauri/test/fixture/isolation/src-tauri/icons/icon.ico similarity index 100% rename from core/tauri/test/fixture/src-tauri/icons/icon.ico rename to crates/tauri/test/fixture/isolation/src-tauri/icons/icon.ico diff --git a/core/tauri/test/fixture/src-tauri/icons/icon.ico~dev b/crates/tauri/test/fixture/isolation/src-tauri/icons/icon.ico~dev similarity index 100% rename from core/tauri/test/fixture/src-tauri/icons/icon.ico~dev rename to crates/tauri/test/fixture/isolation/src-tauri/icons/icon.ico~dev diff --git a/core/tauri/test/fixture/src-tauri/icons/icon.png b/crates/tauri/test/fixture/isolation/src-tauri/icons/icon.png similarity index 100% rename from core/tauri/test/fixture/src-tauri/icons/icon.png rename to crates/tauri/test/fixture/isolation/src-tauri/icons/icon.png diff --git a/crates/tauri/test/fixture/isolation/src-tauri/tauri.conf.json b/crates/tauri/test/fixture/isolation/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..c4e9c6dc1ce5 --- /dev/null +++ b/crates/tauri/test/fixture/isolation/src-tauri/tauri.conf.json @@ -0,0 +1,27 @@ +{ + "$schema": "../../../../../../crates/tauri-schema-generator/schemas/config.schema.json", + "identifier": "isolation.tauri.example", + "build": { + "frontendDist": "../dist", + "devUrl": "http://localhost:4000" + }, + "app": { + "windows": [ + { + "title": "Isolation Tauri App" + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; connect-src ipc: http://ipc.localhost", + "pattern": { + "use": "isolation", + "options": { + "dir": "../isolation-dist" + } + } + } + }, + "bundle": { + "active": true + } +} diff --git a/tooling/cli/node/test/jest/fixtures/app/src-tauri/icons/icon.ico b/crates/tauri/test/fixture/src-tauri/icons/icon.ico similarity index 100% rename from tooling/cli/node/test/jest/fixtures/app/src-tauri/icons/icon.ico rename to crates/tauri/test/fixture/src-tauri/icons/icon.ico diff --git a/tooling/cli/templates/plugin/with-api/examples/svelte-app/src-tauri/icons/icon.ico b/crates/tauri/test/fixture/src-tauri/icons/icon.ico~dev similarity index 100% rename from tooling/cli/templates/plugin/with-api/examples/svelte-app/src-tauri/icons/icon.ico rename to crates/tauri/test/fixture/src-tauri/icons/icon.ico~dev diff --git a/tooling/cli/node/test/jest/fixtures/app/src-tauri/icons/32x32.png b/crates/tauri/test/fixture/src-tauri/icons/icon.png similarity index 100% rename from tooling/cli/node/test/jest/fixtures/app/src-tauri/icons/32x32.png rename to crates/tauri/test/fixture/src-tauri/icons/icon.png diff --git a/crates/tauri/test/fixture/src-tauri/tauri.conf.json b/crates/tauri/test/fixture/src-tauri/tauri.conf.json new file mode 100644 index 000000000000..f5b75e3eb055 --- /dev/null +++ b/crates/tauri/test/fixture/src-tauri/tauri.conf.json @@ -0,0 +1,22 @@ +{ + "$schema": "../../../../../crates/tauri-schema-generator/schemas/config.schema.json", + "identifier": "studio.tauri.example", + "build": { + "frontendDist": "../dist", + "devUrl": "http://localhost:4000" + }, + "app": { + "windows": [ + { + "title": "Tauri App" + } + ], + "security": { + "csp": "default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; connect-src ipc: http://ipc.localhost", + "headers": null + } + }, + "bundle": { + "active": true + } +} diff --git a/core/tauri/test/fixture/test.txt b/crates/tauri/test/fixture/test.txt similarity index 100% rename from core/tauri/test/fixture/test.txt rename to crates/tauri/test/fixture/test.txt diff --git a/core/tauri/test/updater/fixture/archives/archive.linux.tar.gz b/crates/tauri/test/updater/fixture/archives/archive.linux.tar.gz similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.linux.tar.gz rename to crates/tauri/test/updater/fixture/archives/archive.linux.tar.gz diff --git a/core/tauri/test/updater/fixture/archives/archive.linux.tar.gz.sig b/crates/tauri/test/updater/fixture/archives/archive.linux.tar.gz.sig similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.linux.tar.gz.sig rename to crates/tauri/test/updater/fixture/archives/archive.linux.tar.gz.sig diff --git a/core/tauri/test/updater/fixture/archives/archive.macos.tar.gz b/crates/tauri/test/updater/fixture/archives/archive.macos.tar.gz similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.macos.tar.gz rename to crates/tauri/test/updater/fixture/archives/archive.macos.tar.gz diff --git a/core/tauri/test/updater/fixture/archives/archive.macos.tar.gz.sig b/crates/tauri/test/updater/fixture/archives/archive.macos.tar.gz.sig similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.macos.tar.gz.sig rename to crates/tauri/test/updater/fixture/archives/archive.macos.tar.gz.sig diff --git a/core/tauri/test/updater/fixture/archives/archive.windows.zip b/crates/tauri/test/updater/fixture/archives/archive.windows.zip similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.windows.zip rename to crates/tauri/test/updater/fixture/archives/archive.windows.zip diff --git a/core/tauri/test/updater/fixture/archives/archive.windows.zip.sig b/crates/tauri/test/updater/fixture/archives/archive.windows.zip.sig similarity index 100% rename from core/tauri/test/updater/fixture/archives/archive.windows.zip.sig rename to crates/tauri/test/updater/fixture/archives/archive.windows.zip.sig diff --git a/core/tauri/test/updater/fixture/bad_signature/update.key b/crates/tauri/test/updater/fixture/bad_signature/update.key similarity index 100% rename from core/tauri/test/updater/fixture/bad_signature/update.key rename to crates/tauri/test/updater/fixture/bad_signature/update.key diff --git a/core/tauri/test/updater/fixture/bad_signature/update.key.pub b/crates/tauri/test/updater/fixture/bad_signature/update.key.pub similarity index 100% rename from core/tauri/test/updater/fixture/bad_signature/update.key.pub rename to crates/tauri/test/updater/fixture/bad_signature/update.key.pub diff --git a/core/tauri/test/updater/fixture/good_signature/update.key b/crates/tauri/test/updater/fixture/good_signature/update.key similarity index 100% rename from core/tauri/test/updater/fixture/good_signature/update.key rename to crates/tauri/test/updater/fixture/good_signature/update.key diff --git a/core/tauri/test/updater/fixture/good_signature/update.key.pub b/crates/tauri/test/updater/fixture/good_signature/update.key.pub similarity index 100% rename from core/tauri/test/updater/fixture/good_signature/update.key.pub rename to crates/tauri/test/updater/fixture/good_signature/update.key.pub diff --git a/crates/tests/acl/Cargo.toml b/crates/tests/acl/Cargo.toml new file mode 100644 index 000000000000..0fe970b9990d --- /dev/null +++ b/crates/tests/acl/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "acl-tests" +version = "0.1.0" +authors.workspace = true +homepage.workspace = true +repository.workspace = true +categories.workspace = true +license.workspace = true +edition.workspace = true +rust-version.workspace = true +publish = false + +[dev-dependencies] +tauri-utils = { path = "../../tauri-utils/", features = ["build"] } +serde_json = "1" +insta = "1" diff --git a/crates/tests/acl/fixtures/capabilities/basic-ping/cap.toml b/crates/tests/acl/fixtures/capabilities/basic-ping/cap.toml new file mode 100644 index 000000000000..95755ed0f73d --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/basic-ping/cap.toml @@ -0,0 +1,4 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +permissions = ["ping:allow-ping"] diff --git a/crates/tests/acl/fixtures/capabilities/basic-ping/required-plugins.json b/crates/tests/acl/fixtures/capabilities/basic-ping/required-plugins.json new file mode 100644 index 000000000000..4239d5ee3abd --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/basic-ping/required-plugins.json @@ -0,0 +1 @@ +["ping"] diff --git a/crates/tests/acl/fixtures/capabilities/file-explorer-remote/cap.toml b/crates/tests/acl/fixtures/capabilities/file-explorer-remote/cap.toml new file mode 100644 index 000000000000..242461ce8156 --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/file-explorer-remote/cap.toml @@ -0,0 +1,7 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +permissions = ["fs:read", "fs:allow-app"] +local = false +[remote] +urls = ["https://tauri.app"] diff --git a/crates/tests/acl/fixtures/capabilities/file-explorer-remote/required-plugins.json b/crates/tests/acl/fixtures/capabilities/file-explorer-remote/required-plugins.json new file mode 100644 index 000000000000..9ab323181acf --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/file-explorer-remote/required-plugins.json @@ -0,0 +1 @@ +["fs"] diff --git a/crates/tests/acl/fixtures/capabilities/file-explorer/cap.toml b/crates/tests/acl/fixtures/capabilities/file-explorer/cap.toml new file mode 100644 index 000000000000..e76764f72706 --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/file-explorer/cap.toml @@ -0,0 +1,4 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +permissions = ["fs:read", "fs:allow-app"] diff --git a/crates/tests/acl/fixtures/capabilities/file-explorer/required-plugins.json b/crates/tests/acl/fixtures/capabilities/file-explorer/required-plugins.json new file mode 100644 index 000000000000..9ab323181acf --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/file-explorer/required-plugins.json @@ -0,0 +1 @@ +["fs"] diff --git a/crates/tests/acl/fixtures/capabilities/multiwebview/cap.toml b/crates/tests/acl/fixtures/capabilities/multiwebview/cap.toml new file mode 100644 index 000000000000..eada13bee78a --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/multiwebview/cap.toml @@ -0,0 +1,5 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +webviews = ["child1", "child2"] +permissions = ["ping:allow-ping"] diff --git a/crates/tests/acl/fixtures/capabilities/multiwebview/required-plugins.json b/crates/tests/acl/fixtures/capabilities/multiwebview/required-plugins.json new file mode 100644 index 000000000000..4239d5ee3abd --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/multiwebview/required-plugins.json @@ -0,0 +1 @@ +["ping"] diff --git a/crates/tests/acl/fixtures/capabilities/multiwindow/cap-external.toml b/crates/tests/acl/fixtures/capabilities/multiwindow/cap-external.toml new file mode 100644 index 000000000000..ce92e9ec3293 --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/multiwindow/cap-external.toml @@ -0,0 +1,4 @@ +identifier = "run-app-external-url" +description = "external window capability" +windows = ["external"] +permissions = ["fs:read", "fs:deny-home"] diff --git a/crates/tests/acl/fixtures/capabilities/multiwindow/cap-main.json b/crates/tests/acl/fixtures/capabilities/multiwindow/cap-main.json new file mode 100644 index 000000000000..bf49929c56cb --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/multiwindow/cap-main.json @@ -0,0 +1,20 @@ +{ + "identifier": "run-app", + "description": "ap capability", + "windows": ["main"], + "permissions": [ + { + "identifier": "fs:read", + "allow": [ + { + "path": "$CONFIG/*" + } + ] + }, + "fs:allow-app", + "fs:deny-home", + "fs:allow-read-resources", + "fs:allow-move-temp", + "fs:read-download-dir" + ] +} diff --git a/crates/tests/acl/fixtures/capabilities/multiwindow/required-plugins.json b/crates/tests/acl/fixtures/capabilities/multiwindow/required-plugins.json new file mode 100644 index 000000000000..9ab323181acf --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/multiwindow/required-plugins.json @@ -0,0 +1 @@ +["fs"] diff --git a/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/cap.toml b/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/cap.toml new file mode 100644 index 000000000000..f39ea410e9ce --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/cap.toml @@ -0,0 +1,9 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +permissions = [ + "os:allow-apt-linux", + "os:allow-library-folder-macos", + "os:deny-webview-folder-windows", + "os:open-browser", +] diff --git a/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/required-plugins.json b/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/required-plugins.json new file mode 100644 index 000000000000..349a761c03f9 --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/platform-specific-permissions/required-plugins.json @@ -0,0 +1 @@ +["os"] diff --git a/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json b/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json new file mode 100644 index 000000000000..26355eed581a --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json @@ -0,0 +1,39 @@ +{ + "identifier": "run-app", + "description": "app capability", + "windows": ["main"], + "permissions": [ + { + "identifier": "fs:read", + "allow": [ + { + "path": "$HOME/.config/**" + } + ] + }, + "fs:deny-home", + { + "identifier": "fs:allow-read-resources", + "deny": [ + { + "path": "$RESOURCE/**/*.key" + } + ] + }, + "fs:allow-move-temp", + { + "identifier": "fs:allow-app", + "allow": [ + { + "path": "$APP/**" + } + ], + "deny": [ + { + "path": "$APP/*.db" + } + ] + }, + "fs:read-download-dir" + ] +} diff --git a/crates/tests/acl/fixtures/capabilities/scope-extended/required-plugins.json b/crates/tests/acl/fixtures/capabilities/scope-extended/required-plugins.json new file mode 100644 index 000000000000..9ab323181acf --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/scope-extended/required-plugins.json @@ -0,0 +1 @@ +["fs"] diff --git a/crates/tests/acl/fixtures/capabilities/scope/cap.toml b/crates/tests/acl/fixtures/capabilities/scope/cap.toml new file mode 100644 index 000000000000..227c91bab4f3 --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/scope/cap.toml @@ -0,0 +1,11 @@ +identifier = "run-app" +description = "app capability" +windows = ["main"] +permissions = [ + "fs:read", + "fs:allow-app", + "fs:deny-home", + "fs:allow-read-resources", + "fs:allow-move-temp", + "fs:read-download-dir", +] diff --git a/crates/tests/acl/fixtures/capabilities/scope/required-plugins.json b/crates/tests/acl/fixtures/capabilities/scope/required-plugins.json new file mode 100644 index 000000000000..9ab323181acf --- /dev/null +++ b/crates/tests/acl/fixtures/capabilities/scope/required-plugins.json @@ -0,0 +1 @@ +["fs"] diff --git a/crates/tests/acl/fixtures/plugins/fs/deny-home.toml b/crates/tests/acl/fixtures/plugins/fs/deny-home.toml new file mode 100644 index 000000000000..34b0c9563676 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/deny-home.toml @@ -0,0 +1,6 @@ + +[[permission]] +identifier = "deny-home" +description = "Denies accessing the $HOME path." +[[permission.scope.deny]] +path = "$HOME" diff --git a/crates/tests/acl/fixtures/plugins/fs/move-tmp.toml b/crates/tests/acl/fixtures/plugins/fs/move-tmp.toml new file mode 100644 index 000000000000..db5854c3a0a6 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/move-tmp.toml @@ -0,0 +1,6 @@ +[[permission]] +identifier = "allow-move-temp" +description = "Enables the move command with the $TEMP base directory." +commands.allow = ["move"] +[[permission.scope.allow]] +path = "$TEMP/*" diff --git a/crates/tests/acl/fixtures/plugins/fs/read-dir.toml b/crates/tests/acl/fixtures/plugins/fs/read-dir.toml new file mode 100644 index 000000000000..05c3452b2368 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/read-dir.toml @@ -0,0 +1,4 @@ +[[permission]] +identifier = "allow-read-dir" +description = "Enables the read_dir command without any pre-configured scope." +commands.allow = ["read_dir"] diff --git a/crates/tests/acl/fixtures/plugins/fs/read-download-dir.toml b/crates/tests/acl/fixtures/plugins/fs/read-download-dir.toml new file mode 100644 index 000000000000..b5a5b7f6ce36 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/read-download-dir.toml @@ -0,0 +1,4 @@ +[[set]] +identifier = "read-download-dir" +description = "allows all read the $DOWNLOAD dir" +permissions = ["allow-read-dir", "allow-download-dir"] diff --git a/crates/tests/acl/fixtures/plugins/fs/read-file.toml b/crates/tests/acl/fixtures/plugins/fs/read-file.toml new file mode 100644 index 000000000000..c2b37b40938e --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/read-file.toml @@ -0,0 +1,4 @@ +[[permission]] +identifier = "allow-read-file" +description = "Enables the read_file command without any pre-configured scope." +commands.allow = ["read_file"] diff --git a/crates/tests/acl/fixtures/plugins/fs/read-resources.toml b/crates/tests/acl/fixtures/plugins/fs/read-resources.toml new file mode 100644 index 000000000000..9a8572d7c805 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/read-resources.toml @@ -0,0 +1,8 @@ +[[permission]] +identifier = "allow-read-resources" +description = "Enables the read_file and read_dir command using the $RESOURCE base directory." +commands.allow = ["read_file", "read_dir"] +[[permission.scope.allow]] +path = "$RESOURCE/**" +[[permission.scope.allow]] +path = "$RESOURCE" diff --git a/crates/tests/acl/fixtures/plugins/fs/read.toml b/crates/tests/acl/fixtures/plugins/fs/read.toml new file mode 100644 index 000000000000..ab9c72c61c45 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/read.toml @@ -0,0 +1,4 @@ +[[set]] +identifier = "read" +description = "allows all read APIs" +permissions = ["allow-read-dir", "allow-read-file"] diff --git a/crates/tests/acl/fixtures/plugins/fs/scope.toml b/crates/tests/acl/fixtures/plugins/fs/scope.toml new file mode 100644 index 000000000000..6d8a29a3f4e0 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/fs/scope.toml @@ -0,0 +1,13 @@ +[[permission]] +identifier = "allow-app" +description = "Allows accessing the $APP path." +[[permission.scope.allow]] +path = "$APP" + +[[permission]] +identifier = "allow-download-dir" +description = "Allows accessing the $DOWNLOAD directory." +[[permission.scope.allow]] +path = "$DOWNLOAD" +[[permission.scope.allow]] +path = "$DOWNLOAD/**" diff --git a/crates/tests/acl/fixtures/plugins/os/linux.toml b/crates/tests/acl/fixtures/plugins/os/linux.toml new file mode 100644 index 000000000000..89787e121ffb --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/os/linux.toml @@ -0,0 +1,7 @@ +[[permission]] +identifier = "allow-apt-linux" +platforms = ["linux"] +description = "Allows spawning the apt command on Linux" +commands.allow = ["spawn"] +[[permission.scope.allow]] +command = "apt" diff --git a/crates/tests/acl/fixtures/plugins/os/macos.toml b/crates/tests/acl/fixtures/plugins/os/macos.toml new file mode 100644 index 000000000000..1b59b0b1b751 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/os/macos.toml @@ -0,0 +1,7 @@ + +[[permission]] +identifier = "allow-library-folder-macos" +platforms = ["macOS"] +description = "Allows access to the $HOME/Library folder on maOS" +[[permission.scope.allow]] +path = "$HOME/Library/**" diff --git a/crates/tests/acl/fixtures/plugins/os/open-browser.toml b/crates/tests/acl/fixtures/plugins/os/open-browser.toml new file mode 100644 index 000000000000..b72436924c29 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/os/open-browser.toml @@ -0,0 +1,28 @@ +[[permission]] +identifier = "allow-servo-linux" +platforms = ["linux"] +description = "Allows starting servo on Linux" +commands.allow = ["spawn"] +[[permission.scope.allow]] +command = "servo" + +[[permission]] +identifier = "allow-edge-windows" +platforms = ["windows"] +description = "Allows starting edge on Windows" +commands.allow = ["spawn"] +[[permission.scope.allow]] +command = "edge" + +[[permission]] +identifier = "allow-safari-macos" +platforms = ["macOS"] +description = "Allows starting safari on macOS" +commands.allow = ["spawn"] +[[permission.scope.allow]] +command = "safari" + +[[set]] +identifier = "open-browser" +description = "allows opening a URL on the platform browser" +permissions = ["allow-servo-linux", "allow-edge-windows", "allow-safari-macos"] diff --git a/crates/tests/acl/fixtures/plugins/os/windows.toml b/crates/tests/acl/fixtures/plugins/os/windows.toml new file mode 100644 index 000000000000..577b0c9677cb --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/os/windows.toml @@ -0,0 +1,6 @@ +[[permission]] +identifier = "deny-webview-folder-windows" +platforms = ["windows"] +description = "Denies access to the webview folder on Windows" +[[permission.scope.deny]] +path = "$APP/EBWebView/**" diff --git a/crates/tests/acl/fixtures/plugins/ping/ping.toml b/crates/tests/acl/fixtures/plugins/ping/ping.toml new file mode 100644 index 000000000000..dfd151dddf11 --- /dev/null +++ b/crates/tests/acl/fixtures/plugins/ping/ping.toml @@ -0,0 +1,4 @@ +[[permission]] +identifier = "allow-ping" +description = "Enables the ping command without any pre-configured scope." +commands.allow = ["ping"] diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__basic-ping.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__basic-ping.snap new file mode 100644 index 000000000000..dae9eff35ebe --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__basic-ping.snap @@ -0,0 +1,38 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:ping|ping": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + }, + denied_commands: {}, + command_scope: {}, + global_scope: {}, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap new file mode 100644 index 000000000000..f0bc309e7240 --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap @@ -0,0 +1,408 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:fs|read_dir": [ + ResolvedCommand { + context: Remote { + url: RemoteUrlPattern( + UrlPattern { + protocol: Component { + pattern_string: "https", + regexp: Ok( + Regex( + "(?u)^https$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "https", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + username: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + password: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + hostname: Component { + pattern_string: "tauri.app", + regexp: Ok( + Regex( + "(?u)^tauri\\.app$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "tauri.app", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + port: Component { + pattern_string: "", + regexp: Ok( + Regex( + "(?u)^$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + pathname: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + search: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + hash: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + }, + "https://tauri.app", + ), + }, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + "plugin:fs|read_file": [ + ResolvedCommand { + context: Remote { + url: RemoteUrlPattern( + UrlPattern { + protocol: Component { + pattern_string: "https", + regexp: Ok( + Regex( + "(?u)^https$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "https", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + username: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + password: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + hostname: Component { + pattern_string: "tauri.app", + regexp: Ok( + Regex( + "(?u)^tauri\\.app$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "tauri.app", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + port: Component { + pattern_string: "", + regexp: Ok( + Regex( + "(?u)^$", + ), + ), + group_name_list: [], + matcher: Matcher { + prefix: "", + suffix: "", + inner: Literal { + literal: "", + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + pathname: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + search: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + hash: Component { + pattern_string: "*", + regexp: Ok( + Regex( + "(?u)^(.*)$", + ), + ), + group_name_list: [ + "0", + ], + matcher: Matcher { + prefix: "", + suffix: "", + inner: SingleCapture { + filter: None, + allow_empty: true, + }, + ignore_case: false, + }, + has_regexp_group: false, + }, + }, + "https://tauri.app", + ), + }, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + }, + denied_commands: {}, + command_scope: {}, + global_scope: { + "fs": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$APP", + ), + }, + ), + ], + deny: [], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap new file mode 100644 index 000000000000..b2ff838da677 --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap @@ -0,0 +1,78 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:fs|read_dir": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + "plugin:fs|read_file": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + }, + denied_commands: {}, + command_scope: {}, + global_scope: { + "fs": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$APP", + ), + }, + ), + ], + deny: [], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwebview.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwebview.snap new file mode 100644 index 000000000000..1b58f4373ed8 --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwebview.snap @@ -0,0 +1,87 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:ping|ping": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [ + Pattern { + original: "child1", + tokens: [ + Char( + 'c', + ), + Char( + 'h', + ), + Char( + 'i', + ), + Char( + 'l', + ), + Char( + 'd', + ), + Char( + '1', + ), + ], + is_recursive: false, + }, + Pattern { + original: "child2", + tokens: [ + Char( + 'c', + ), + Char( + 'h', + ), + Char( + 'i', + ), + Char( + 'l', + ), + Char( + 'd', + ), + Char( + '2', + ), + ], + is_recursive: false, + }, + ], + scope_id: None, + }, + ], + }, + denied_commands: {}, + command_scope: {}, + global_scope: {}, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap new file mode 100644 index 000000000000..46054f148f3a --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap @@ -0,0 +1,344 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:fs|move": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 3, + ), + }, + ], + "plugin:fs|read_dir": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 4, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "external", + tokens: [ + Char( + 'e', + ), + Char( + 'x', + ), + Char( + 't', + ), + Char( + 'e', + ), + Char( + 'r', + ), + Char( + 'n', + ), + Char( + 'a', + ), + Char( + 'l', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + "plugin:fs|read_file": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "external", + tokens: [ + Char( + 'e', + ), + Char( + 'x', + ), + Char( + 't', + ), + Char( + 'e', + ), + Char( + 'r', + ), + Char( + 'n', + ), + Char( + 'a', + ), + Char( + 'l', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$CONFIG/*", + ), + }, + ), + ], + deny: [], + }, + 2: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + ], + deny: [], + }, + 3: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$TEMP/*", + ), + }, + ), + ], + deny: [], + }, + 4: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$DOWNLOAD", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD/**", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "fs": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$APP", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$HOME", + ), + }, + ), + Map( + { + "path": String( + "$HOME", + ), + }, + ), + ], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap new file mode 100644 index 000000000000..79fce76d651d --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap @@ -0,0 +1,285 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:fs|move": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 3, + ), + }, + ], + "plugin:fs|read_dir": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 4, + ), + }, + ], + "plugin:fs|read_file": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$HOME/.config/**", + ), + }, + ), + ], + deny: [], + }, + 2: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$RESOURCE/**/*.key", + ), + }, + ), + ], + }, + 3: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$TEMP/*", + ), + }, + ), + ], + deny: [], + }, + 4: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$DOWNLOAD", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD/**", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "fs": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$APP/**", + ), + }, + ), + Map( + { + "path": String( + "$APP", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$HOME", + ), + }, + ), + Map( + { + "path": String( + "$APP/*.db", + ), + }, + ), + ], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap new file mode 100644 index 000000000000..c38697f41c2b --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap @@ -0,0 +1,247 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:fs|move": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ], + "plugin:fs|read_dir": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 3, + ), + }, + ], + "plugin:fs|read_file": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: None, + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$RESOURCE/**", + ), + }, + ), + Map( + { + "path": String( + "$RESOURCE", + ), + }, + ), + ], + deny: [], + }, + 2: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$TEMP/*", + ), + }, + ), + ], + deny: [], + }, + 3: ResolvedScope { + allow: [ + Map( + { + "path": String( + "$DOWNLOAD", + ), + }, + ), + Map( + { + "path": String( + "$DOWNLOAD/**", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "fs": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$APP", + ), + }, + ), + ], + deny: [ + Map( + { + "path": String( + "$HOME", + ), + }, + ), + ], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/linux/acl_tests__tests__platform-specific-permissions.snap b/crates/tests/acl/fixtures/snapshots/linux/acl_tests__tests__platform-specific-permissions.snap new file mode 100644 index 000000000000..62cdda315e97 --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/linux/acl_tests__tests__platform-specific-permissions.snap @@ -0,0 +1,97 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:os|spawn": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 2, + ), + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "command": String( + "apt", + ), + }, + ), + ], + deny: [], + }, + 2: ResolvedScope { + allow: [ + Map( + { + "command": String( + "servo", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "os": ResolvedScope { + allow: [], + deny: [], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/macOS/acl_tests__tests__platform-specific-permissions.snap b/crates/tests/acl/fixtures/snapshots/macOS/acl_tests__tests__platform-specific-permissions.snap new file mode 100644 index 000000000000..b8b4d0b32e2f --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/macOS/acl_tests__tests__platform-specific-permissions.snap @@ -0,0 +1,66 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:os|spawn": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "command": String( + "safari", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "os": ResolvedScope { + allow: [ + Map( + { + "path": String( + "$HOME/Library/**", + ), + }, + ), + ], + deny: [], + }, + }, +} diff --git a/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap b/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap new file mode 100644 index 000000000000..618dcd1a7aab --- /dev/null +++ b/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap @@ -0,0 +1,66 @@ +--- +source: crates/tests/acl/src/lib.rs +expression: resolved +--- +Resolved { + allowed_commands: { + "plugin:os|spawn": [ + ResolvedCommand { + context: Local, + windows: [ + Pattern { + original: "main", + tokens: [ + Char( + 'm', + ), + Char( + 'a', + ), + Char( + 'i', + ), + Char( + 'n', + ), + ], + is_recursive: false, + }, + ], + webviews: [], + scope_id: Some( + 1, + ), + }, + ], + }, + denied_commands: {}, + command_scope: { + 1: ResolvedScope { + allow: [ + Map( + { + "command": String( + "edge", + ), + }, + ), + ], + deny: [], + }, + }, + global_scope: { + "os": ResolvedScope { + allow: [], + deny: [ + Map( + { + "path": String( + "$APP/EBWebView/**", + ), + }, + ), + ], + }, + }, +} diff --git a/crates/tests/acl/src/lib.rs b/crates/tests/acl/src/lib.rs new file mode 100644 index 000000000000..7fc51addfb23 --- /dev/null +++ b/crates/tests/acl/src/lib.rs @@ -0,0 +1,82 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[cfg(test)] +mod tests { + use std::{ + collections::BTreeMap, + env::temp_dir, + fs::{read_dir, read_to_string}, + path::Path, + }; + + use tauri_utils::{ + acl::{build::parse_capabilities, manifest::Manifest, resolved::Resolved}, + platform::Target, + }; + + fn load_plugins(plugins: &[String]) -> BTreeMap { + let mut manifests = BTreeMap::new(); + + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let out_dir = temp_dir(); + + for plugin in plugins { + let plugin_path = manifest_dir.join("fixtures").join("plugins").join(plugin); + + let permission_files = tauri_utils::acl::build::define_permissions( + &format!("{}/*.toml", plugin_path.display()), + plugin, + &out_dir, + |_| true, + ) + .expect("failed to define permissions"); + let manifest = Manifest::new(permission_files, None); + manifests.insert(plugin.to_string(), manifest); + } + + manifests + } + + #[test] + fn resolve_acl() { + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let fixtures_path = manifest_dir.join("fixtures").join("capabilities"); + for fixture_path in read_dir(fixtures_path).expect("failed to read fixtures") { + let fixture_entry = fixture_path.expect("failed to read fixture entry"); + + let mut settings = insta::Settings::clone_current(); + settings.set_snapshot_path( + if fixture_entry.path().file_name().unwrap() == "platform-specific-permissions" { + Path::new("../fixtures/snapshots").join(Target::current().to_string()) + } else { + Path::new("../fixtures/snapshots").to_path_buf() + }, + ); + let _guard = settings.bind_to_scope(); + + let fixture_plugins_str = read_to_string(fixture_entry.path().join("required-plugins.json")) + .expect("failed to read fixture required-plugins.json file"); + let fixture_plugins: Vec = serde_json::from_str(&fixture_plugins_str) + .expect("required-plugins.json is not a valid JSON"); + + let manifests = load_plugins(&fixture_plugins); + let capabilities = parse_capabilities(&format!("{}/cap*", fixture_entry.path().display())) + .expect("failed to parse capabilities"); + + let resolved = Resolved::resolve(&manifests, capabilities, Target::current()) + .expect("failed to resolve ACL"); + + insta::assert_debug_snapshot!( + fixture_entry + .path() + .file_name() + .unwrap() + .to_string_lossy() + .to_string(), + resolved + ); + } + } +} diff --git a/crates/tests/app-updater/frameworks/test.framework/Headers b/crates/tests/app-updater/frameworks/test.framework/Headers new file mode 100644 index 000000000000..a177d2a6b926 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/crates/tests/app-updater/frameworks/test.framework/Modules b/crates/tests/app-updater/frameworks/test.framework/Modules new file mode 100644 index 000000000000..5736f3186e79 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/crates/tests/app-updater/frameworks/test.framework/Resources b/crates/tests/app-updater/frameworks/test.framework/Resources new file mode 100644 index 000000000000..953ee36f3bb7 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/A/Headers/test.h b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Headers/test.h new file mode 100644 index 000000000000..3539143d0dd8 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Headers/test.h @@ -0,0 +1,18 @@ +// +// test.h +// test +// +// Created by Trey Smith on 9/15/23. +// + +#import + +//! Project version number for test. +FOUNDATION_EXPORT double testVersionNumber; + +//! Project version string for test. +FOUNDATION_EXPORT const unsigned char testVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/A/Modules/module.modulemap b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 000000000000..f1545257a73d --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module test { + umbrella header "test.h" + + export * + module * { export * } +} diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/A/Resources/Info.plist b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Resources/Info.plist new file mode 100644 index 000000000000..6f736f0a2b46 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,46 @@ + + + + + BuildMachineOSBuild + 22D68 + CFBundleDevelopmentRegion + en + CFBundleExecutable + test + CFBundleIdentifier + com.tauri.test + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + test + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + + DTPlatformName + macosx + DTPlatformVersion + 13.3 + DTSDKBuild + 22E245 + DTSDKName + macosx13.3 + DTXcode + 1431 + DTXcodeBuild + 14E300c + LSMinimumSystemVersion + 13.2 + + diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/A/_CodeSignature/CodeResources b/crates/tests/app-updater/frameworks/test.framework/Versions/A/_CodeSignature/CodeResources new file mode 100644 index 000000000000..82d2063275e6 --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Versions/A/_CodeSignature/CodeResources @@ -0,0 +1,142 @@ + + + + + files + + Resources/Info.plist + + /aPV7Q20g0elr7OiZJoUNggTOcg= + + + files2 + + Headers/test.h + + hash2 + + 5RA6Mnq5sNoaC4wKcFe6zymVmEL5Vb44G4BGqFjgZMM= + + + Modules/module.modulemap + + hash2 + + C6uLLSnQu9M2qLElVCkeo2JpnvWMxtArinQzmlh3v2A= + + + Resources/Info.plist + + hash2 + + nPMotNIMgvMfHtkRdpeehzfBiCZLnksfiD3nldUPzTE= + + + + rules + + ^Resources/ + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^version.plist$ + + + rules2 + + .*\.dSYM($|/) + + weight + 11 + + ^(.*/)?\.DS_Store$ + + omit + + weight + 2000 + + ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ + + nested + + weight + 10 + + ^.* + + ^Info\.plist$ + + omit + + weight + 20 + + ^PkgInfo$ + + omit + + weight + 20 + + ^Resources/ + + weight + 20 + + ^Resources/.*\.lproj/ + + optional + + weight + 1000 + + ^Resources/.*\.lproj/locversion.plist$ + + omit + + weight + 1100 + + ^Resources/Base\.lproj/ + + weight + 1010 + + ^[^/]+$ + + nested + + weight + 10 + + ^embedded\.provisionprofile$ + + weight + 20 + + ^version\.plist$ + + weight + 20 + + + + diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/A/test b/crates/tests/app-updater/frameworks/test.framework/Versions/A/test new file mode 100644 index 000000000000..687eb01d82bd Binary files /dev/null and b/crates/tests/app-updater/frameworks/test.framework/Versions/A/test differ diff --git a/crates/tests/app-updater/frameworks/test.framework/Versions/Current b/crates/tests/app-updater/frameworks/test.framework/Versions/Current new file mode 100644 index 000000000000..8c7e5a667f1b --- /dev/null +++ b/crates/tests/app-updater/frameworks/test.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/crates/tests/restart/Cargo.toml b/crates/tests/restart/Cargo.toml new file mode 100644 index 000000000000..a1351ab18331 --- /dev/null +++ b/crates/tests/restart/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "restart" +version = "0.1.0" +authors = ["Tauri Programme within The Commons Conservancy"] +license = "Apache-2.0 OR MIT" +edition = "2021" + +[dependencies.tauri] +path = "../../tauri" + +[dev-dependencies] +tempfile = "3" + +[features] +process-relaunch-dangerous-allow-symlink-macos = [] diff --git a/crates/tests/restart/LICENSE.spdx b/crates/tests/restart/LICENSE.spdx new file mode 100644 index 000000000000..e3b1b803726f --- /dev/null +++ b/crates/tests/restart/LICENSE.spdx @@ -0,0 +1 @@ +../../../LICENSE.spdx \ No newline at end of file diff --git a/crates/tests/restart/LICENSE_APACHE-2.0 b/crates/tests/restart/LICENSE_APACHE-2.0 new file mode 100644 index 000000000000..5ee573597fa5 --- /dev/null +++ b/crates/tests/restart/LICENSE_APACHE-2.0 @@ -0,0 +1 @@ +../../../LICENSE_APACHE-2.0 \ No newline at end of file diff --git a/crates/tests/restart/LICENSE_MIT b/crates/tests/restart/LICENSE_MIT new file mode 100644 index 000000000000..71b6663417bc --- /dev/null +++ b/crates/tests/restart/LICENSE_MIT @@ -0,0 +1 @@ +../../../LICENSE_MIT \ No newline at end of file diff --git a/crates/tests/restart/build.rs b/crates/tests/restart/build.rs new file mode 100644 index 000000000000..35b4e027dbfd --- /dev/null +++ b/crates/tests/restart/build.rs @@ -0,0 +1,5 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +fn main() {} diff --git a/crates/tests/restart/src/main.rs b/crates/tests/restart/src/main.rs new file mode 100644 index 000000000000..85b9bd46d487 --- /dev/null +++ b/crates/tests/restart/src/main.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use tauri::Env; + +fn main() { + let mut argv = std::env::args(); + let argc = argv.len(); + if argc == 0 || argc > 2 { + panic!("restart test binary expect either no arguments or `restart`.") + } + + println!( + "{}", + tauri::process::current_binary(&Default::default()) + .expect("tauri::process::current_binary could not resolve") + .display() + ); + + match argv.nth(1).as_deref() { + Some("restart") => { + let mut env = Env::default(); + env.args_os.clear(); + tauri::process::restart(&env) + } + Some(invalid) => panic!("only argument `restart` is allowed, {invalid} is invalid"), + None => {} + }; +} diff --git a/crates/tests/restart/tests/restart.rs b/crates/tests/restart/tests/restart.rs new file mode 100644 index 000000000000..89bfdd01b8d3 --- /dev/null +++ b/crates/tests/restart/tests/restart.rs @@ -0,0 +1,125 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use std::io; +use std::path::{Path, PathBuf}; +use std::process::Command; + +/// Helper for generic catch-all errors. +type Result = std::result::Result<(), Box>; + +/// +#[cfg(windows)] +const ERROR_PRIVILEGE_NOT_HELD: i32 = 1314; + +/// Represents a successfully created symlink. +enum Symlink { + /// Path to the created symlink + Created(PathBuf), + + /// A symlink that failed due to missing permissions (Windows). + #[allow(dead_code)] + Privilege, +} + +/// Compile the test binary, run it, and compare it with expected output. +/// +/// Failing to create a symlink due to permissions issues is also a success +/// for the purpose of this runner. +fn symlink_runner(create_symlinks: impl Fn(&Path) -> io::Result) -> Result { + let mut compiled_binary = PathBuf::from(env!("OUT_DIR")).join("../../../restart"); + if cfg!(windows) { + compiled_binary.set_extension("exe"); + } + println!("{compiled_binary:?}"); + + // set up all the temporary file paths + let temp = tempfile::TempDir::new()?; + let bin = temp.path().canonicalize()?.join("restart.exe"); + + // copy the built restart test binary to our temporary directory + std::fs::copy(compiled_binary, &bin)?; + + if let Symlink::Created(link) = create_symlinks(&bin)? { + // run the command from the symlink, so that we can test if restart resolves it correctly + let mut cmd = Command::new(link); + + // add the restart parameter so that the invocation will call tauri::process::restart + cmd.arg("restart"); + + let output = cmd.output()?; + + // run `TempDir` destructors to prevent resource leaking if the assertion fails + drop(temp); + + if output.status.success() { + // gather the output into a string + let stdout = String::from_utf8_lossy(&output.stdout); + + // we expect the output to be the bin path, twice + assert_eq!(stdout, format!("{bin}\n{bin}\n", bin = bin.display())); + } else if cfg!(all( + target_os = "macos", + not(feature = "process-relaunch-dangerous-allow-symlink-macos") + )) { + // we expect this to fail on macOS without the dangerous symlink flag set + let stderr = String::from_utf8_lossy(&output.stderr); + + // make sure it's the error that we expect + assert!(stderr.contains( + "StartingBinary found current_exe() that contains a symlink on a non-allowed platform" + )); + } else { + // we didn't expect the program to fail in this configuration, just panic + panic!("restart integration test runner failed for unknown reason"); + } + } + + Ok(()) +} + +/// Cross-platform way to create a symlink +/// +/// Symlinks that failed to create due to permissions issues (like on Windows) +/// are also seen as successful for the purpose of this testing suite. +fn create_symlink(original: &Path, link: PathBuf) -> io::Result { + #[cfg(unix)] + return std::os::unix::fs::symlink(original, &link).map(|()| Symlink::Created(link)); + + #[cfg(windows)] + return match std::os::windows::fs::symlink_file(original, &link) { + Ok(()) => Ok(Symlink::Created(link)), + Err(e) => match e.raw_os_error() { + Some(ERROR_PRIVILEGE_NOT_HELD) => Ok(Symlink::Privilege), + _ => Err(e), + }, + }; +} + +/// Only use 1 test to prevent cargo from waiting on itself. +/// +/// While not ideal, this is fine because they use the same solution for both cases. +#[test] +fn restart_symlinks() -> Result { + // single symlink + symlink_runner(|bin| { + let mut link = bin.to_owned(); + link.set_file_name("symlink"); + link.set_extension("exe"); + create_symlink(bin, link) + })?; + + // nested symlinks + symlink_runner(|bin| { + let mut link1 = bin.to_owned(); + link1.set_file_name("symlink1"); + link1.set_extension("exe"); + create_symlink(bin, link1.clone())?; + + let mut link2 = bin.to_owned(); + link2.set_file_name("symlink2"); + link2.set_extension("exe"); + create_symlink(&link1, link2) + }) +} diff --git a/dependabot.yml b/dependabot.yml new file mode 100644 index 000000000000..29c8dca9c347 --- /dev/null +++ b/dependabot.yml @@ -0,0 +1,105 @@ +# Copyright 2019-2024 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT + +version: 2 +updates: + # Crates + - package-ecosystem: 'cargo' + directory: '/crates/tauri' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-build' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-codegen' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-macros' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-runtime' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-runtime-wry' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-utils' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-cli' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-bundler' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'cargo' + directory: '/crates/tauri-macos-sign' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + + # NPM Packages + - package-ecosystem: 'npm' + directory: '/packages/api' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 + - package-ecosystem: 'npm' + directory: '/packages/cli' + schedule: + internal: 'daily' + labels: + - 'type: chore' + # disable version updates + open-pull-requests-limit: 0 diff --git a/examples/.icons/128x128.png b/examples/.icons/128x128.png index 6be5e50e9b9a..77e7d2338e9d 100644 Binary files a/examples/.icons/128x128.png and b/examples/.icons/128x128.png differ diff --git a/examples/.icons/128x128@2x.png b/examples/.icons/128x128@2x.png index e81becee571e..0f7976f1a004 100644 Binary files a/examples/.icons/128x128@2x.png and b/examples/.icons/128x128@2x.png differ diff --git a/examples/.icons/32x32.png b/examples/.icons/32x32.png index a437dd51741e..98fda06fcb02 100644 Binary files a/examples/.icons/32x32.png and b/examples/.icons/32x32.png differ diff --git a/examples/.icons/Square107x107Logo.png b/examples/.icons/Square107x107Logo.png index 0ca4f2719883..f35d84ff1334 100644 Binary files a/examples/.icons/Square107x107Logo.png and b/examples/.icons/Square107x107Logo.png differ diff --git a/examples/.icons/Square142x142Logo.png b/examples/.icons/Square142x142Logo.png index b81f820394d1..1823bb2696be 100644 Binary files a/examples/.icons/Square142x142Logo.png and b/examples/.icons/Square142x142Logo.png differ diff --git a/examples/.icons/Square150x150Logo.png b/examples/.icons/Square150x150Logo.png index 624c7bfba049..dc2b22cea563 100644 Binary files a/examples/.icons/Square150x150Logo.png and b/examples/.icons/Square150x150Logo.png differ diff --git a/examples/.icons/Square284x284Logo.png b/examples/.icons/Square284x284Logo.png index c021d2ba7661..0ed3984c5fb4 100644 Binary files a/examples/.icons/Square284x284Logo.png and b/examples/.icons/Square284x284Logo.png differ diff --git a/examples/.icons/Square30x30Logo.png b/examples/.icons/Square30x30Logo.png index 621970023096..60bf0eadf75c 100644 Binary files a/examples/.icons/Square30x30Logo.png and b/examples/.icons/Square30x30Logo.png differ diff --git a/examples/.icons/Square310x310Logo.png b/examples/.icons/Square310x310Logo.png index f9bc04839491..c8ca0ad132e0 100644 Binary files a/examples/.icons/Square310x310Logo.png and b/examples/.icons/Square310x310Logo.png differ diff --git a/examples/.icons/Square44x44Logo.png b/examples/.icons/Square44x44Logo.png index d5fbfb2ab4e5..8756459b63d6 100644 Binary files a/examples/.icons/Square44x44Logo.png and b/examples/.icons/Square44x44Logo.png differ diff --git a/examples/.icons/Square71x71Logo.png b/examples/.icons/Square71x71Logo.png index 63440d798493..2c8023cc8244 100644 Binary files a/examples/.icons/Square71x71Logo.png and b/examples/.icons/Square71x71Logo.png differ diff --git a/examples/.icons/Square89x89Logo.png b/examples/.icons/Square89x89Logo.png index f3f705af2f2e..2c5e6034ff53 100644 Binary files a/examples/.icons/Square89x89Logo.png and b/examples/.icons/Square89x89Logo.png differ diff --git a/examples/.icons/StoreLogo.png b/examples/.icons/StoreLogo.png index 455638826192..17d142c0a432 100644 Binary files a/examples/.icons/StoreLogo.png and b/examples/.icons/StoreLogo.png differ diff --git a/examples/.icons/icon.icns b/examples/.icons/icon.icns index 8254645a797e..5594104c8149 100644 Binary files a/examples/.icons/icon.icns and b/examples/.icons/icon.icns differ diff --git a/examples/.icons/icon.ico b/examples/.icons/icon.ico index b3636e4b22ba..06c23c82fea6 100644 Binary files a/examples/.icons/icon.ico and b/examples/.icons/icon.ico differ diff --git a/examples/.icons/icon.png b/examples/.icons/icon.png index e1cd2619e0b5..d1756ce45d62 100644 Binary files a/examples/.icons/icon.png and b/examples/.icons/icon.png differ diff --git a/examples/api/.gitignore b/examples/api/.gitignore index 7c9b894420ed..fb4eb33aceac 100644 --- a/examples/api/.gitignore +++ b/examples/api/.gitignore @@ -1,3 +1,2 @@ -/node_modules/ -/.vscode/ -.DS_Store +/dist/* +!/dist/.gitkeep diff --git a/examples/api/.setup-cross.sh b/examples/api/.setup-cross.sh new file mode 100644 index 000000000000..109d3f3ab8f9 --- /dev/null +++ b/examples/api/.setup-cross.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +export ICONS_VOLUME="$(realpath ../.icons)" +export DIST_VOLUME="$(realpath dist)" +export ISOLATION_VOLUME="$(realpath isolation-dist)" +export WORKSPACE_VOLUME="$(realpath ../..)" diff --git a/examples/api/.taurignore b/examples/api/.taurignore new file mode 100644 index 000000000000..848a0f2aa2db --- /dev/null +++ b/examples/api/.taurignore @@ -0,0 +1,3 @@ +src-tauri/locales/ +src-tauri/Cross.toml +src-tauri/.gitignore diff --git a/examples/api/README.md b/examples/api/README.md index d9fe94b1f479..51890cec70ce 100644 --- a/examples/api/README.md +++ b/examples/api/README.md @@ -1,4 +1,5 @@ # API example + This example demonstrates Tauri's API capabilities using the `@tauri-apps/api` package. It's used as the main validation app, serving as the testbed of our development process. In the future, this app will be used on Tauri's integration tests. @@ -7,36 +8,35 @@ In the future, this app will be used on Tauri's integration tests. ## Running the example - Compile Tauri -go to root of the Tauri repo and run: -Linux / Mac: + go to root of the Tauri repo and run: + Linux / Mac: + ``` # choose to install node cli (1) bash .scripts/setup.sh ``` Windows: + ``` ./.scripts/setup.ps1 ``` - Install dependencies (Run inside of this folder `examples/api/`) + ```bash -# with yarn -$ yarn -# with npm -$ npm install +$ pnpm i ``` - Run the app in development mode (Run inside of this folder `examples/api/`) + ```bash -# with yarn -$ yarn tauri dev -# with npm -$ npm run tauri dev +$ pnpm tauri dev ``` - Build an run the release app (Run inside of this folder `examples/api/`) + ```bash -$ yarn tauri build +$ pnpm tauri build $ ./src-tauri/target/release/app ``` diff --git a/.github/config.yml b/examples/api/dist/.gitkeep similarity index 100% rename from .github/config.yml rename to examples/api/dist/.gitkeep diff --git a/examples/api/dist/assets/index.css b/examples/api/dist/assets/index.css deleted file mode 100644 index bb235641fc94..000000000000 --- a/examples/api/dist/assets/index.css +++ /dev/null @@ -1 +0,0 @@ -#dialog-filter.svelte-1eg58yg{width:260px}#request-body.svelte-1xfmj7b{width:100%;margin-right:10px;font-size:12px}form.svelte-1tppwwz.svelte-1tppwwz{margin-top:24px}.flex-row.svelte-1tppwwz.svelte-1tppwwz{flex-direction:row}.grow.svelte-1tppwwz.svelte-1tppwwz{flex-grow:1}.window-controls.svelte-1tppwwz input.svelte-1tppwwz{width:50px}.window-property.svelte-1tppwwz.svelte-1tppwwz{margin-top:12px}.window-property.svelte-1tppwwz span.svelte-1tppwwz{font-size:.8rem}.env-vars.svelte-1g38c1n{width:300px}.container.svelte-1fam3xt{margin:1em}.view-container.svelte-1fam3xt{width:15em;margin-left:.5em}#response.svelte-1fam3xt{white-space:pre-line} diff --git a/examples/api/dist/assets/index.js b/examples/api/dist/assets/index.js deleted file mode 100644 index 293475b1f8ef..000000000000 --- a/examples/api/dist/assets/index.js +++ /dev/null @@ -1,40 +0,0 @@ -var Io=Object.defineProperty,No=Object.defineProperties;var qo=Object.getOwnPropertyDescriptors;var Fi=Object.getOwnPropertySymbols;var Bo=Object.prototype.hasOwnProperty,Go=Object.prototype.propertyIsEnumerable;var Ui=(e,t,n)=>t in e?Io(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n,Hi=(e,t)=>{for(var n in t||(t={}))Bo.call(t,n)&&Ui(e,n,t[n]);if(Fi)for(var n of Fi(t))Go.call(t,n)&&Ui(e,n,t[n]);return e},Ii=(e,t)=>No(e,qo(t));import{S as K,i as X,s as Y,e as u,a as v,t as S,b as a,c as P,d as r,l as T,f as G,n as I,g as W,r as x,o as Ke,h as On,j as E,p as Xe,k as fe,m as Vo,q as Ni,u as Ye,v as qi,w as J,x as Bi,y as Gi,z as Vi,A as Ji,B as $i,C as Ki,D as Jo,E as Xi,F as Yi,G as $o,H as Ko,I as Xo}from"./vendor.js";const Yo=function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))i(o);new MutationObserver(o=>{for(const l of o)if(l.type==="childList")for(const s of l.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&i(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const l={};return o.integrity&&(l.integrity=o.integrity),o.referrerpolicy&&(l.referrerPolicy=o.referrerpolicy),o.crossorigin==="use-credentials"?l.credentials="include":o.crossorigin==="anonymous"?l.credentials="omit":l.credentials="same-origin",l}function i(o){if(o.ep)return;o.ep=!0;const l=n(o);fetch(o.href,l)}};Yo();/*! ***************************************************************************** -Copyright (c) Microsoft Corporation. - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. -***************************************************************************** */var Qi=function(e,t){return(Qi=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,i){n.__proto__=i}||function(n,i){for(var o in i)Object.prototype.hasOwnProperty.call(i,o)&&(n[o]=i[o])})(e,t)};function Ln(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");function n(){this.constructor=e}Qi(e,t),e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}var dt=function(){return(dt=Object.assign||function(e){for(var t,n=1,i=arguments.length;n0&&o[o.length-1])||f[0]!==6&&f[0]!==2)){s=0;continue}if(f[0]===3&&(!o||f[1]>o[0]&&f[1]{n(2,l=p)}),eo().then(p=>{n(0,i=p)}),io().then(p=>{n(1,o=p)});async function s(){await oo()}async function c(){await Dn()}return[i,o,l,s,c]}class tr extends K{constructor(t){super();X(this,t,xo,Zo,Y,{})}}function ro(){return _(this,void 0,void 0,function(){return g(this,function(e){return[2,z({__tauriModule:"Cli",message:{cmd:"cliMatches"}})]})})}Object.freeze({__proto__:null,getMatches:ro});function er(e){let t,n,i,o,l,s,c,p,h,f,M;return{c(){t=u("div"),n=S(`This binary can be run on the terminal and takes the following arguments: - `),i=u("ul"),i.innerHTML=`
  • --config PATH
  • -
  • --theme light|dark|system
  • -
  • --verbose
  • `,o=S(` - Additionally, it has a `),l=u("i"),l.textContent="update --background",s=S(` subcommand. - Note that the arguments are only parsed, not implemented. - `),c=u("br"),p=v(),h=u("button"),h.textContent="Get matches",a(h,"class","button"),a(h,"id","cli-matches")},m(m,d){P(m,t,d),r(t,n),r(t,i),r(t,o),r(t,l),r(t,s),r(t,c),r(t,p),r(t,h),f||(M=T(h,"click",e[0]),f=!0)},p:I,i:I,o:I,d(m){m&&W(t),f=!1,M()}}}function nr(e,t,n){let{onMessage:i}=t;function o(){ro().then(i).catch(i)}return e.$$set=l=>{"onMessage"in l&&n(1,i=l.onMessage)},[o,i]}class ir extends K{constructor(t){super();X(this,t,nr,er,Y,{onMessage:1})}}function lo(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Event",message:{cmd:"unlisten",event:e,eventId:t}})]})})}function so(e,t,n){return _(this,void 0,void 0,function(){return g(this,function(i){switch(i.label){case 0:return[4,z({__tauriModule:"Event",message:{cmd:"emit",event:e,windowLabel:t,payload:typeof n=="string"?n:JSON.stringify(n)}})];case 1:return i.sent(),[2]}})})}function Rn(e,t,n){return _(this,void 0,void 0,function(){var i=this;return g(this,function(o){return[2,z({__tauriModule:"Event",message:{cmd:"listen",event:e,windowLabel:t,handler:Wt(n)}}).then(function(l){return function(){return _(i,void 0,void 0,function(){return g(this,function(s){return[2,lo(e,l)]})})}})]})})}function uo(e,t,n){return _(this,void 0,void 0,function(){return g(this,function(i){return[2,Rn(e,t,function(o){n(o),lo(e,o.id).catch(function(){})})]})})}function he(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,Rn(e,null,t)]})})}function ao(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,uo(e,null,t)]})})}function Ze(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,so(e,void 0,t)]})})}Object.freeze({__proto__:null,listen:he,once:ao,emit:Ze});function or(e){let t,n,i,o,l,s,c,p;return{c(){t=u("div"),n=u("button"),n.textContent="Call Log API",i=v(),o=u("button"),o.textContent="Call Request (async) API",l=v(),s=u("button"),s.textContent="Send event to Rust",a(n,"class","button"),a(n,"id","log"),a(o,"class","button"),a(o,"id","request"),a(s,"class","button"),a(s,"id","event")},m(h,f){P(h,t,f),r(t,n),r(t,i),r(t,o),r(t,l),r(t,s),c||(p=[T(n,"click",e[0]),T(o,"click",e[1]),T(s,"click",e[2])],c=!0)},p:I,i:I,o:I,d(h){h&&W(t),c=!1,x(p)}}}function rr(e,t,n){let{onMessage:i}=t,o;Ke(async()=>{o=await he("rust-event",i)}),On(()=>{o&&o()});function l(){pe("log_operation",{event:"tauri-click",payload:"this payload is optional because we used Option in Rust"})}function s(){pe("perform_request",{endpoint:"dummy endpoint arg",body:{id:5,name:"test"}}).then(i).catch(i)}function c(){Ze("js-event","this is the payload string")}return e.$$set=p=>{"onMessage"in p&&n(3,i=p.onMessage)},[l,s,c,i]}class lr extends K{constructor(t){super();X(this,t,rr,or,Y,{onMessage:3})}}function jn(e){return e===void 0&&(e={}),_(this,void 0,void 0,function(){return g(this,function(t){return typeof e=="object"&&Object.freeze(e),[2,z({__tauriModule:"Dialog",message:{cmd:"openDialog",options:e}})]})})}function co(e){return e===void 0&&(e={}),_(this,void 0,void 0,function(){return g(this,function(t){return typeof e=="object"&&Object.freeze(e),[2,z({__tauriModule:"Dialog",message:{cmd:"saveDialog",options:e}})]})})}function sr(e){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"Dialog",message:{cmd:"messageDialog",message:e}})]})})}function ur(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Dialog",message:{cmd:"askDialog",title:t,message:e}})]})})}function ar(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Dialog",message:{cmd:"confirmDialog",title:t,message:e}})]})})}Object.freeze({__proto__:null,open:jn,save:co,message:sr,ask:ur,confirm:ar});var Bt;function cr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Fs",message:{cmd:"readTextFile",path:e,options:t}})]})})}function Fn(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){var n;return g(this,function(i){switch(i.label){case 0:return[4,z({__tauriModule:"Fs",message:{cmd:"readFile",path:e,options:t}})];case 1:return n=i.sent(),[2,Uint8Array.from(n)]}})})}function dr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return typeof t=="object"&&Object.freeze(t),typeof e=="object"&&Object.freeze(e),[2,z({__tauriModule:"Fs",message:{cmd:"writeFile",path:e.path,contents:Array.from(new TextEncoder().encode(e.contents)),options:t}})]})})}function fr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return typeof t=="object"&&Object.freeze(t),typeof e=="object"&&Object.freeze(e),[2,z({__tauriModule:"Fs",message:{cmd:"writeFile",path:e.path,contents:Array.from(e.contents),options:t}})]})})}function fo(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Fs",message:{cmd:"readDir",path:e,options:t}})]})})}function pr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Fs",message:{cmd:"createDir",path:e,options:t}})]})})}function hr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Fs",message:{cmd:"removeDir",path:e,options:t}})]})})}function mr(e,t,n){return n===void 0&&(n={}),_(this,void 0,void 0,function(){return g(this,function(i){return[2,z({__tauriModule:"Fs",message:{cmd:"copyFile",source:e,destination:t,options:n}})]})})}function vr(e,t){return t===void 0&&(t={}),_(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"Fs",message:{cmd:"removeFile",path:e,options:t}})]})})}function _r(e,t,n){return n===void 0&&(n={}),_(this,void 0,void 0,function(){return g(this,function(i){return[2,z({__tauriModule:"Fs",message:{cmd:"renameFile",oldPath:e,newPath:t,options:n}})]})})}(function(e){e[e.Audio=1]="Audio",e[e.Cache=2]="Cache",e[e.Config=3]="Config",e[e.Data=4]="Data",e[e.LocalData=5]="LocalData",e[e.Desktop=6]="Desktop",e[e.Document=7]="Document",e[e.Download=8]="Download",e[e.Executable=9]="Executable",e[e.Font=10]="Font",e[e.Home=11]="Home",e[e.Picture=12]="Picture",e[e.Public=13]="Public",e[e.Runtime=14]="Runtime",e[e.Template=15]="Template",e[e.Video=16]="Video",e[e.Resource=17]="Resource",e[e.App=18]="App",e[e.Log=19]="Log"})(Bt||(Bt={}));Object.freeze({__proto__:null,get BaseDirectory(){return Bt},get Dir(){return Bt},readTextFile:cr,readBinaryFile:Fn,writeFile:dr,writeBinaryFile:fr,readDir:fo,createDir:pr,removeDir:hr,copyFile:mr,removeFile:vr,renameFile:_r});function gr(e){let t,n,i,o,l,s,c,p,h,f,M,m,d,b,k,w,A,C,j,F;return{c(){t=u("div"),n=u("input"),i=v(),o=u("input"),l=v(),s=u("div"),c=u("input"),p=v(),h=u("label"),h.textContent="Multiple",f=v(),M=u("div"),m=u("input"),d=v(),b=u("label"),b.textContent="Directory",k=v(),w=u("button"),w.textContent="Open dialog",A=v(),C=u("button"),C.textContent="Open save dialog",a(n,"id","dialog-default-path"),a(n,"placeholder","Default path"),a(o,"id","dialog-filter"),a(o,"placeholder","Extensions filter, comma-separated"),a(o,"class","svelte-1eg58yg"),a(c,"type","checkbox"),a(c,"id","dialog-multiple"),a(h,"for","dialog-multiple"),a(m,"type","checkbox"),a(m,"id","dialog-directory"),a(b,"for","dialog-directory"),a(w,"class","button"),a(w,"id","open-dialog"),a(C,"class","button"),a(C,"id","save-dialog")},m(U,O){P(U,t,O),r(t,n),E(n,e[0]),r(t,i),r(t,o),E(o,e[1]),r(t,l),r(t,s),r(s,c),c.checked=e[2],r(s,p),r(s,h),r(t,f),r(t,M),r(M,m),m.checked=e[3],r(M,d),r(M,b),r(t,k),r(t,w),r(t,A),r(t,C),j||(F=[T(n,"input",e[8]),T(o,"input",e[9]),T(c,"change",e[10]),T(m,"change",e[11]),T(w,"click",e[4]),T(C,"click",e[5])],j=!0)},p(U,[O]){O&1&&n.value!==U[0]&&E(n,U[0]),O&2&&o.value!==U[1]&&E(o,U[1]),O&4&&(c.checked=U[2]),O&8&&(m.checked=U[3])},i:I,o:I,d(U){U&&W(t),j=!1,x(F)}}}function br(e,t){var n=new Blob([e],{type:"application/octet-binary"}),i=new FileReader;i.onload=function(o){var l=o.target.result;t(l.substr(l.indexOf(",")+1))},i.readAsDataURL(n)}function wr(e,t,n){let{onMessage:i}=t,{insecureRenderHtml:o}=t,l=null,s=null,c=!1,p=!1;function h(){jn({title:"My wonderful open dialog",defaultPath:l,filters:s?[{name:"Tauri Example",extensions:s.split(",").map(k=>k.trim())}]:[],multiple:c,directory:p}).then(function(k){if(Array.isArray(k))i(k);else{var w=k,A=w.match(/\S+\.\S+$/g);Fn(w).then(function(C){A&&(w.includes(".png")||w.includes(".jpg"))?br(new Uint8Array(C),function(j){var F="data:image/png;base64,"+j;o('')}):i(k)}).catch(i(k))}}).catch(i)}function f(){co({title:"My wonderful save dialog",defaultPath:l,filters:s?[{name:"Tauri Example",extensions:s.split(",").map(k=>k.trim())}]:[]}).then(i).catch(i)}function M(){l=this.value,n(0,l)}function m(){s=this.value,n(1,s)}function d(){c=this.checked,n(2,c)}function b(){p=this.checked,n(3,p)}return e.$$set=k=>{"onMessage"in k&&n(6,i=k.onMessage),"insecureRenderHtml"in k&&n(7,o=k.insecureRenderHtml)},[l,s,c,p,h,f,i,o,M,m,d,b]}class yr extends K{constructor(t){super();X(this,t,wr,gr,Y,{onMessage:6,insecureRenderHtml:7})}}function po(e,t,n){const i=e.slice();return i[9]=t[n],i}function ho(e){let t,n=e[9][0]+"",i,o;return{c(){t=u("option"),i=S(n),t.__value=o=e[9][1],t.value=t.__value},m(l,s){P(l,t,s),r(t,i)},p:I,d(l){l&&W(t)}}}function Mr(e){let t,n,i,o,l,s,c,p,h,f,M,m,d,b=e[2],k=[];for(let w=0;wisNaN(parseInt(m))).map(m=>[m,Bt[m]]);function p(){const m=l.match(/\S+\.\S+$/g),d={dir:mo()};(m?Fn(l,d):fo(l,d)).then(function(k){if(m)if(l.includes(".png")||l.includes(".jpg"))kr(new Uint8Array(k),function(w){const A="data:image/png;base64,"+w;o('')});else{const w=String.fromCharCode.apply(null,k);o(''),setTimeout(()=>{const A=document.getElementById("file-response");A.value=w,document.getElementById("file-save").addEventListener("click",function(){writeFile({file:l,contents:A.value},{dir:mo()}).catch(i)})})}else i(k)}).catch(i)}function h(){n(1,s.src=Zi(l),s)}function f(){l=this.value,n(0,l)}function M(m){Vo[m?"unshift":"push"](()=>{s=m,n(1,s)})}return e.$$set=m=>{"onMessage"in m&&n(5,i=m.onMessage),"insecureRenderHtml"in m&&n(6,o=m.insecureRenderHtml)},[l,s,c,p,h,i,o,f,M]}class Tr extends K{constructor(t){super();X(this,t,zr,Mr,Y,{onMessage:5,insecureRenderHtml:6})}}var me;(function(e){e[e.JSON=1]="JSON",e[e.Text=2]="Text",e[e.Binary=3]="Binary"})(me||(me={}));var Un=function(){function e(t,n){this.type=t,this.payload=n}return e.form=function(t){var n={};for(var i in t){var o=t[i];n[i]=typeof o=="string"?o:Array.from(o)}return new e("Form",n)},e.json=function(t){return new e("Json",t)},e.text=function(t){return new e("Text",t)},e.bytes=function(t){return new e("Bytes",Array.from(t))},e}(),vo=function(e){this.url=e.url,this.status=e.status,this.ok=this.status>=200&&this.status<300,this.headers=e.headers,this.rawHeaders=e.rawHeaders,this.data=e.data},_o=function(){function e(t){this.id=t}return e.prototype.drop=function(){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"Http",message:{cmd:"dropClient",client:this.id}})]})})},e.prototype.request=function(t){return _(this,void 0,void 0,function(){var n;return g(this,function(i){return(n=!t.responseType||t.responseType===me.JSON)&&(t.responseType=me.Text),[2,z({__tauriModule:"Http",message:{cmd:"httpRequest",client:this.id,options:t}}).then(function(o){var l=new vo(o);if(n){try{l.data=JSON.parse(l.data)}catch(s){if(l.ok&&l.data==="")l.data={};else if(l.ok)throw Error("Failed to parse response `".concat(l.data,"` as JSON: ").concat(s,";\n try setting the `responseType` option to `ResponseType.Text` or `ResponseType.Binary` if the API does not return a JSON response."))}return l}return l})]})})},e.prototype.get=function(t,n){return _(this,void 0,void 0,function(){return g(this,function(i){return[2,this.request(dt({method:"GET",url:t},n))]})})},e.prototype.post=function(t,n,i){return _(this,void 0,void 0,function(){return g(this,function(o){return[2,this.request(dt({method:"POST",url:t,body:n},i))]})})},e.prototype.put=function(t,n,i){return _(this,void 0,void 0,function(){return g(this,function(o){return[2,this.request(dt({method:"PUT",url:t,body:n},i))]})})},e.prototype.patch=function(t,n){return _(this,void 0,void 0,function(){return g(this,function(i){return[2,this.request(dt({method:"PATCH",url:t},n))]})})},e.prototype.delete=function(t,n){return _(this,void 0,void 0,function(){return g(this,function(i){return[2,this.request(dt({method:"DELETE",url:t},n))]})})},e}();function Hn(e){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"Http",message:{cmd:"createClient",options:e}}).then(function(n){return new _o(n)})]})})}var In=null;function Cr(e,t){var n;return _(this,void 0,void 0,function(){return g(this,function(i){switch(i.label){case 0:return In!==null?[3,2]:[4,Hn()];case 1:In=i.sent(),i.label=2;case 2:return[2,In.request(dt({url:e,method:(n=t==null?void 0:t.method)!==null&&n!==void 0?n:"GET"},t))]}})})}Object.freeze({__proto__:null,getClient:Hn,fetch:Cr,Body:Un,Client:_o,Response:vo,get ResponseType(){return me}});function Sr(e){let t,n,i,o,l,s,c,p,h,f,M,m,d,b,k,w,A;return{c(){t=u("form"),n=u("select"),i=u("option"),i.textContent="GET",o=u("option"),o.textContent="POST",l=u("option"),l.textContent="PUT",s=u("option"),s.textContent="PATCH",c=u("option"),c.textContent="DELETE",p=v(),h=u("input"),f=v(),M=u("br"),m=v(),d=u("textarea"),b=v(),k=u("button"),k.textContent="Make request",i.__value="GET",i.value=i.__value,o.__value="POST",o.value=o.__value,l.__value="PUT",l.value=l.__value,s.__value="PATCH",s.value=s.__value,c.__value="DELETE",c.value=c.__value,a(n,"class","button"),a(n,"id","request-method"),e[0]===void 0&&Ni(()=>e[5].call(n)),a(h,"id","request-url"),a(h,"placeholder","Type the request URL..."),a(d,"id","request-body"),a(d,"placeholder","Request body"),a(d,"rows","5"),a(d,"class","svelte-1xfmj7b"),a(k,"class","button"),a(k,"id","make-request")},m(C,j){P(C,t,j),r(t,n),r(n,i),r(n,o),r(n,l),r(n,s),r(n,c),Ye(n,e[0]),r(t,p),r(t,h),E(h,e[1]),r(t,f),r(t,M),r(t,m),r(t,d),E(d,e[2]),r(t,b),r(t,k),w||(A=[T(n,"change",e[5]),T(h,"input",e[6]),T(d,"input",e[7]),T(t,"submit",Xe(e[3]))],w=!0)},p(C,[j]){j&1&&Ye(n,C[0]),j&2&&h.value!==C[1]&&E(h,C[1]),j&4&&E(d,C[2])},i:I,o:I,d(C){C&&W(t),w=!1,x(A)}}}function Ar(e,t,n){let i="GET",o="https://jsonplaceholder.typicode.com/todos/1",l="",{onMessage:s}=t;async function c(){const M=await Hn().catch(k=>{throw s(k),k}),b={url:o||""||"",method:i||"GET"||"GET"};l.startsWith("{")&&l.endsWith("}")||l.startsWith("[")&&l.endsWith("]")?b.body=Un.json(JSON.parse(l)):l!==""&&(b.body=Un.text(l)),M.request(b).then(s).catch(s)}function p(){i=qi(this),n(0,i)}function h(){o=this.value,n(1,o)}function f(){l=this.value,n(2,l)}return e.$$set=M=>{"onMessage"in M&&n(4,s=M.onMessage)},[i,o,l,c,s,p,h,f]}class Pr extends K{constructor(t){super();X(this,t,Ar,Sr,Y,{onMessage:4})}}function Wr(e){let t,n,i;return{c(){t=u("button"),t.textContent="Send test notification",a(t,"class","button"),a(t,"id","notification")},m(o,l){P(o,t,l),n||(i=T(t,"click",Or),n=!0)},p:I,i:I,o:I,d(o){o&&W(t),n=!1,i()}}}function Or(){new Notification("Notification title",{body:"This is the notification body"})}function Lr(e,t,n){let{onMessage:i}=t;return e.$$set=o=>{"onMessage"in o&&n(0,i=o.onMessage)},[i]}class Er extends K{constructor(t){super();X(this,t,Lr,Wr,Y,{onMessage:0})}}var ve,xe=function(e,t){this.type="Logical",this.width=e,this.height=t},Gt=function(){function e(t,n){this.type="Physical",this.width=t,this.height=n}return e.prototype.toLogical=function(t){return new xe(this.width/t,this.height/t)},e}(),go=function(e,t){this.type="Logical",this.x=e,this.y=t},Vt=function(){function e(t,n){this.type="Physical",this.x=t,this.y=n}return e.prototype.toLogical=function(t){return new go(this.x/t,this.y/t)},e}();function Dr(){return new Jt(window.__TAURI_METADATA__.__currentWindow.label,{skip:!0})}function bo(){return window.__TAURI_METADATA__.__windows.map(function(e){return new Jt(e.label,{skip:!0})})}(function(e){e[e.Critical=1]="Critical",e[e.Informational=2]="Informational"})(ve||(ve={}));var _e,wo=["tauri://created","tauri://error"],yo=function(){function e(t){this.label=t,this.listeners=Object.create(null)}return e.prototype.listen=function(t,n){return _(this,void 0,void 0,function(){var i=this;return g(this,function(o){return this._handleTauriEvent(t,n)?[2,Promise.resolve(function(){var l=i.listeners[t];l.splice(l.indexOf(n),1)})]:[2,Rn(t,this.label,n)]})})},e.prototype.once=function(t,n){return _(this,void 0,void 0,function(){var i=this;return g(this,function(o){return this._handleTauriEvent(t,n)?[2,Promise.resolve(function(){var l=i.listeners[t];l.splice(l.indexOf(n),1)})]:[2,uo(t,this.label,n)]})})},e.prototype.emit=function(t,n){return _(this,void 0,void 0,function(){var i,o;return g(this,function(l){if(wo.includes(t)){for(i=0,o=this.listeners[t]||[];ie[31].call(n)),a(s,"type","checkbox"),a(f,"type","checkbox"),a(d,"title","Unminimizes after 2 seconds"),a(k,"title","Unminimizes after 2 seconds"),a(A,"title","Visible again after 2 seconds"),a(F,"type","checkbox"),a(q,"type","checkbox"),a(B,"type","checkbox"),a(Q,"type","checkbox"),a(it,"type","number"),a(it,"min","0"),a(it,"class","svelte-1tppwwz"),a(ot,"type","number"),a(ot,"min","0"),a(ot,"class","svelte-1tppwwz"),a(ft,"class","flex col grow svelte-1tppwwz"),a(rt,"type","number"),a(rt,"min","400"),a(rt,"class","svelte-1tppwwz"),a(lt,"type","number"),a(lt,"min","400"),a(lt,"class","svelte-1tppwwz"),a(pt,"class","flex col grow svelte-1tppwwz"),a(ht,"type","number"),a(ht,"class","svelte-1tppwwz"),a(mt,"type","number"),a(mt,"class","svelte-1tppwwz"),a(N,"class","flex col grow svelte-1tppwwz"),a(at,"type","number"),a(at,"min","400"),a(at,"class","svelte-1tppwwz"),a(ct,"type","number"),a(ct,"min","400"),a(ct,"class","svelte-1tppwwz"),a(jt,"class","flex col grow svelte-1tppwwz"),a(et,"class","window-controls flex flex-row svelte-1tppwwz"),a(t,"class","flex col"),a(Kt,"class","svelte-1tppwwz"),a(Xt,"class","svelte-1tppwwz"),a(vt,"class","grow window-property svelte-1tppwwz"),a(Yt,"class","svelte-1tppwwz"),a(Qt,"class","svelte-1tppwwz"),a(_t,"class","grow window-property svelte-1tppwwz"),a(Ft,"class","flex"),a(Zt,"class","svelte-1tppwwz"),a(xt,"class","svelte-1tppwwz"),a(gt,"class","grow window-property svelte-1tppwwz"),a(te,"class","svelte-1tppwwz"),a(ee,"class","svelte-1tppwwz"),a(bt,"class","grow window-property svelte-1tppwwz"),a(Ut,"class","flex"),a(ne,"class","svelte-1tppwwz"),a(ie,"class","svelte-1tppwwz"),a(wt,"class","grow window-property svelte-1tppwwz"),a(oe,"class","svelte-1tppwwz"),a(re,"class","svelte-1tppwwz"),a(yt,"class","grow window-property svelte-1tppwwz"),a(Ht,"class","flex"),a(le,"class","svelte-1tppwwz"),a(se,"class","svelte-1tppwwz"),a(Mt,"class","grow window-property svelte-1tppwwz"),a(ue,"class","svelte-1tppwwz"),a(ae,"class","svelte-1tppwwz"),a(kt,"class","grow window-property svelte-1tppwwz"),a(It,"class","flex"),a(St,"id","title"),a(ce,"class","button"),a(ce,"type","submit"),a(zt,"class","svelte-1tppwwz"),a(At,"id","url"),a(de,"class","button"),a(de,"id","open-url"),a(Tt,"class","svelte-1tppwwz"),a(Pt,"class","button"),a(Pt,"title","Minimizes the window, requests attention for 3s and then resets it"),a(Nt,"class","button")},m(y,L){P(y,t,L),r(t,n);for(let V=0;V{typeof N=="string"&&o[i].setIcon(N)})}function be(){const N=Math.random().toString().replace(".",""),Ct=new Jt(N);n(1,o[N]=Ct,o),Ct.once("tauri://error",function(){l("Error creating new webview")})}function Ot(){o[i].innerSize().then(N=>{n(20,q=N),n(7,d=q.width),n(8,b=q.height)}),o[i].outerSize().then(N=>{n(21,tt=N)})}function we(){o[i].innerPosition().then(N=>{n(18,O=N)}),o[i].outerPosition().then(N=>{n(19,H=N),n(13,j=H.x),n(14,F=H.y)})}async function $t(N){ut&&ut(),$&&$(),$=await N.listen("tauri://move",we),ut=await N.listen("tauri://resize",Ot)}async function et(){await o[i].minimize(),await o[i].requestUserAttention(ve.Critical),await new Promise(N=>setTimeout(N,3e3)),await o[i].requestUserAttention(null)}function ft(){i=qi(this),n(0,i),n(1,o)}function Lt(){c=this.checked,n(2,c)}function ye(){p=this.checked,n(3,p)}const it=()=>o[i].center();function Me(){h=this.checked,n(16,h)}function Et(){f=this.checked,n(4,f)}function ke(){M=this.checked,n(5,M)}function ot(){m=this.checked,n(6,m)}function ze(){j=J(this.value),n(13,j)}function pt(){F=J(this.value),n(14,F)}function Dt(){d=J(this.value),n(7,d)}function Te(){b=J(this.value),n(8,b)}function rt(){k=J(this.value),n(9,k)}function Ce(){w=J(this.value),n(10,w)}function Rt(){A=J(this.value),n(11,A)}function Se(){C=J(this.value),n(12,C)}function lt(){B=this.value,n(22,B)}function Ae(){s=this.value,n(15,s)}return e.$$set=N=>{"onMessage"in N&&n(30,l=N.onMessage)},e.$$.update=()=>{e.$$.dirty[0]&7&&o[i].setResizable(c),e.$$.dirty[0]&11&&(p?o[i].maximize():o[i].unmaximize()),e.$$.dirty[0]&19&&o[i].setDecorations(f),e.$$.dirty[0]&35&&o[i].setAlwaysOnTop(M),e.$$.dirty[0]&67&&o[i].setFullscreen(m),e.$$.dirty[0]&387&&o[i].setSize(new Gt(d,b)),e.$$.dirty[0]&1539&&(k&&w?o[i].setMinSize(new xe(k,w)):o[i].setMinSize(null)),e.$$.dirty[0]&6147&&(A&&C?o[i].setMaxSize(new xe(A,C)):o[i].setMaxSize(null)),e.$$.dirty[0]&24579&&o[i].setPosition(new Vt(j,F)),e.$$.dirty[0]&3&&o[i].scaleFactor().then(N=>n(17,U=N)),e.$$.dirty[0]&3&&$t(o[i])},[i,o,c,p,f,M,m,d,b,k,w,A,C,j,F,s,h,U,O,H,q,tt,B,R,nt,D,Q,ge,be,et,l,ft,Lt,ye,it,Me,Et,ke,ot,ze,pt,Dt,Te,rt,Ce,Rt,Se,lt,Ae]}class Ir extends K{constructor(t){super();X(this,t,Hr,Ur,Y,{onMessage:30},[-1,-1])}}function To(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"GlobalShortcut",message:{cmd:"register",shortcut:e,handler:Wt(t)}})]})})}function Nr(e,t){return _(this,void 0,void 0,function(){return g(this,function(n){return[2,z({__tauriModule:"GlobalShortcut",message:{cmd:"registerAll",shortcuts:e,handler:Wt(t)}})]})})}function qr(e){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"GlobalShortcut",message:{cmd:"isRegistered",shortcut:e}})]})})}function Co(e){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"GlobalShortcut",message:{cmd:"unregister",shortcut:e}})]})})}function So(){return _(this,void 0,void 0,function(){return g(this,function(e){return[2,z({__tauriModule:"GlobalShortcut",message:{cmd:"unregisterAll"}})]})})}Object.freeze({__proto__:null,register:To,registerAll:Nr,isRegistered:qr,unregister:Co,unregisterAll:So});function Ao(e,t,n){const i=e.slice();return i[9]=t[n],i}function Po(e){let t,n=e[9]+"",i,o,l,s,c;function p(){return e[8](e[9])}return{c(){t=u("div"),i=S(n),o=v(),l=u("button"),l.textContent="Unregister",a(l,"type","button")},m(h,f){P(h,t,f),r(t,i),r(t,o),r(t,l),s||(c=T(l,"click",p),s=!0)},p(h,f){e=h,f&2&&n!==(n=e[9]+"")&&G(i,n)},d(h){h&&W(t),s=!1,c()}}}function Wo(e){let t,n,i;return{c(){t=u("button"),t.textContent="Unregister all",a(t,"type","button")},m(o,l){P(o,t,l),n||(i=T(t,"click",e[5]),n=!0)},p:I,d(o){o&&W(t),n=!1,i()}}}function Br(e){let t,n,i,o,l,s,c,p,h,f,M=e[1],m=[];for(let b=0;bn(1,i=m));let s="CmdOrControl+X";function c(){const m=s;To(m,()=>{o(`Shortcut ${m} triggered`)}).then(()=>{l.update(d=>[...d,m]),o(`Shortcut ${m} registered successfully`)}).catch(o)}function p(m){const d=m;Co(d).then(()=>{l.update(b=>b.filter(k=>k!==d)),o(`Shortcut ${d} unregistered`)}).catch(o)}function h(){So().then(()=>{l.update(()=>[]),o("Unregistered all shortcuts")}).catch(o)}function f(){s=this.value,n(0,s)}const M=m=>p(m);return e.$$set=m=>{"onMessage"in m&&n(6,o=m.onMessage)},[s,i,l,c,p,h,o,f,M]}class Vr extends K{constructor(t){super();X(this,t,Gr,Br,Y,{onMessage:6})}}function Oo(e){let t,n,i,o,l;return{c(){t=u("input"),n=v(),i=u("button"),i.textContent="Write",a(t,"placeholder","write to stdin"),a(i,"class","button")},m(s,c){P(s,t,c),E(t,e[3]),P(s,n,c),P(s,i,c),o||(l=[T(t,"input",e[10]),T(i,"click",e[7])],o=!0)},p(s,c){c&8&&t.value!==s[3]&&E(t,s[3])},d(s){s&&W(t),s&&W(n),s&&W(i),o=!1,x(l)}}}function Jr(e){let t,n,i,o,l,s,c,p,h,f,M,m,d,b,k,w=e[4]&&Oo(e);return{c(){t=u("div"),n=u("div"),i=u("input"),o=v(),l=u("button"),l.textContent="Run",s=v(),c=u("button"),c.textContent="Kill",p=v(),w&&w.c(),h=v(),f=u("div"),M=u("input"),m=v(),d=u("input"),a(l,"class","button"),a(c,"class","button"),a(M,"placeholder","Working directory"),a(d,"class","env-vars svelte-1g38c1n"),a(d,"placeholder","Environment variables")},m(A,C){P(A,t,C),r(t,n),r(n,i),E(i,e[0]),r(n,o),r(n,l),r(n,s),r(n,c),r(n,p),w&&w.m(n,null),r(t,h),r(t,f),r(f,M),E(M,e[1]),r(f,m),r(f,d),E(d,e[2]),b||(k=[T(i,"input",e[9]),T(l,"click",e[5]),T(c,"click",e[6]),T(M,"input",e[11]),T(d,"input",e[12])],b=!0)},p(A,[C]){C&1&&i.value!==A[0]&&E(i,A[0]),A[4]?w?w.p(A,C):(w=Oo(A),w.c(),w.m(n,null)):w&&(w.d(1),w=null),C&2&&M.value!==A[1]&&E(M,A[1]),C&4&&d.value!==A[2]&&E(d,A[2])},i:I,o:I,d(A){A&&W(t),w&&w.d(),b=!1,x(k)}}}function $r(e,t,n){const i=navigator.userAgent.includes("Windows");let o=i?"cmd":"sh",l=i?["/C"]:["-c"],{onMessage:s}=t,c='echo "hello world"',p=null,h="SOMETHING=value ANOTHER=2",f="",M;function m(){return h.split(" ").reduce((F,U)=>{let[O,H]=U.split("=");return Ii(Hi({},F),{[O]:H})},{})}function d(){n(4,M=null);const F=new to(o,[...l,c],{cwd:p||null,env:m()});F.on("close",U=>{s(`command finished with code ${U.code} and signal ${U.signal}`),n(4,M=null)}),F.on("error",U=>s(`command error: "${U}"`)),F.stdout.on("data",U=>s(`command stdout: "${U}"`)),F.stderr.on("data",U=>s(`command stderr: "${U}"`)),F.spawn().then(U=>{n(4,M=U)}).catch(s)}function b(){M.kill().then(()=>s("killed child process")).catch(s)}function k(){M.write(f).catch(s)}function w(){c=this.value,n(0,c)}function A(){f=this.value,n(3,f)}function C(){p=this.value,n(1,p)}function j(){h=this.value,n(2,h)}return e.$$set=F=>{"onMessage"in F&&n(8,s=F.onMessage)},[c,p,h,f,M,d,b,k,s,w,A,C,j]}class Kr extends K{constructor(t){super();X(this,t,$r,Jr,Y,{onMessage:8})}}function Lo(){return _(this,void 0,void 0,function(){function e(){t&&t(),t=void 0}var t;return g(this,function(n){return[2,new Promise(function(i,o){he("tauri://update-status",function(l){var s;(s=l==null?void 0:l.payload).error?(e(),o(s.error)):s.status==="DONE"&&(e(),i())}).then(function(l){t=l}).catch(function(l){throw e(),l}),Ze("tauri://update-install").catch(function(l){throw e(),l})})]})})}function Eo(){return _(this,void 0,void 0,function(){function e(){t&&t(),t=void 0}var t;return g(this,function(n){return[2,new Promise(function(i,o){ao("tauri://update-available",function(l){var s;s=l==null?void 0:l.payload,e(),i({manifest:s,shouldUpdate:!0})}).catch(function(l){throw e(),l}),he("tauri://update-status",function(l){var s;(s=l==null?void 0:l.payload).error?(e(),o(s.error)):s.status==="UPTODATE"&&(e(),i({shouldUpdate:!1}))}).then(function(l){t=l}).catch(function(l){throw e(),l}),Ze("tauri://update").catch(function(l){throw e(),l})})]})})}Object.freeze({__proto__:null,installUpdate:Lo,checkUpdate:Eo});function Xr(e){let t,n,i,o,l,s;return{c(){t=u("div"),n=u("button"),n.textContent="Check update",i=v(),o=u("button"),o.textContent="Install update",a(n,"class","button"),a(n,"id","check_update"),a(o,"class","button hidden"),a(o,"id","start_update")},m(c,p){P(c,t,p),r(t,n),r(t,i),r(t,o),l||(s=[T(n,"click",e[0]),T(o,"click",e[1])],l=!0)},p:I,i:I,o:I,d(c){c&&W(t),l=!1,x(s)}}}function Yr(e,t,n){let{onMessage:i}=t,o;Ke(async()=>{o=await he("tauri://update-status",i)}),On(()=>{o&&o()});async function l(){try{document.getElementById("check_update").classList.add("hidden");const{shouldUpdate:c,manifest:p}=await Eo();i(`Should update: ${c}`),i(p),c&&document.getElementById("start_update").classList.remove("hidden")}catch(c){i(c)}}async function s(){try{document.getElementById("start_update").classList.add("hidden"),await Lo(),i("Installation complete, restart required."),await Dn()}catch(c){i(c)}}return e.$$set=c=>{"onMessage"in c&&n(2,i=c.onMessage)},[l,s,i]}class Qr extends K{constructor(t){super();X(this,t,Yr,Xr,Y,{onMessage:2})}}function Do(e){return _(this,void 0,void 0,function(){return g(this,function(t){return[2,z({__tauriModule:"Clipboard",message:{cmd:"writeText",data:e}})]})})}function Ro(){return _(this,void 0,void 0,function(){return g(this,function(e){return[2,z({__tauriModule:"Clipboard",message:{cmd:"readText"}})]})})}Object.freeze({__proto__:null,writeText:Do,readText:Ro});function Zr(e){let t,n,i,o,l,s,c,p,h;return{c(){t=u("div"),n=u("div"),i=u("input"),o=v(),l=u("button"),l.textContent="Write",s=v(),c=u("button"),c.textContent="Read",a(i,"placeholder","Text to write to the clipboard"),a(l,"type","button"),a(c,"type","button")},m(f,M){P(f,t,M),r(t,n),r(n,i),E(i,e[0]),r(n,o),r(n,l),r(t,s),r(t,c),p||(h=[T(i,"input",e[4]),T(l,"click",e[1]),T(c,"click",e[2])],p=!0)},p(f,[M]){M&1&&i.value!==f[0]&&E(i,f[0])},i:I,o:I,d(f){f&&W(t),p=!1,x(h)}}}function xr(e,t,n){let{onMessage:i}=t,o="clipboard message";function l(){Do(o).then(()=>{i("Wrote to the clipboard")}).catch(i)}function s(){Ro().then(p=>{i(`Clipboard contents: ${p}`)}).catch(i)}function c(){o=this.value,n(0,o)}return e.$$set=p=>{"onMessage"in p&&n(3,i=p.onMessage)},[o,l,s,i,c]}class tl extends K{constructor(t){super();X(this,t,xr,Zr,Y,{onMessage:3})}}function el(e){let t;return{c(){t=u("div"),t.innerHTML=`

    Not available for Linux

    - `},m(n,i){P(n,t,i)},p:I,i:I,o:I,d(n){n&&W(t)}}}function nl(e,t,n){let{onMessage:i}=t;const o=window.constraints={audio:!0,video:!0};function l(c){const p=document.querySelector("video"),h=c.getVideoTracks();i("Got stream with constraints:",o),i(`Using video device: ${h[0].label}`),window.stream=c,p.srcObject=c}function s(c){if(c.name==="ConstraintNotSatisfiedError"){const p=o.video;i(`The resolution ${p.width.exact}x${p.height.exact} px is not supported by your device.`)}else c.name==="PermissionDeniedError"&&i("Permissions have not been granted to use your camera and microphone, you need to allow the page access to your devices in order for the demo to work.");i(`getUserMedia error: ${c.name}`,c)}return Ke(async()=>{try{const c=await navigator.mediaDevices.getUserMedia(o);l(c)}catch(c){s(c)}}),On(()=>{window.stream.getTracks().forEach(function(c){c.stop()})}),e.$$set=c=>{"onMessage"in c&&n(0,i=c.onMessage)},[i]}class il extends K{constructor(t){super();X(this,t,nl,el,Y,{onMessage:0})}}function ol(e){let t,n,i,o,l,s,c,p,h,f,M,m;return{c(){t=u("input"),n=v(),i=u("input"),o=v(),l=u("button"),l.textContent="Post it.",s=v(),c=u("p"),c.textContent="Result:",p=v(),h=u("pre"),f=S(e[2]),a(l,"type","button")},m(d,b){P(d,t,b),E(t,e[0]),P(d,n,b),P(d,i,b),E(i,e[1]),P(d,o,b),P(d,l,b),P(d,s,b),P(d,c,b),P(d,p,b),P(d,h,b),r(h,f),M||(m=[T(t,"input",e[4]),T(i,"input",e[5]),T(l,"click",e[3])],M=!0)},p(d,[b]){b&1&&t.value!==d[0]&&E(t,d[0]),b&2&&i.value!==d[1]&&E(i,d[1]),b&4&&G(f,d[2])},i:I,o:I,d(d){d&&W(t),d&&W(n),d&&W(i),d&&W(o),d&&W(l),d&&W(s),d&&W(c),d&&W(p),d&&W(h),M=!1,x(m)}}}function rl(e,t,n){let i="baz",o="qux",l=null;async function s(){let h=navigator.userAgent.includes("Windows")?"https://customprotocol.test/example.html":"customprotocol://test/example.html";const M=await(await fetch(h,{method:"POST",body:JSON.stringify({foo:i,bar:o})})).json();n(2,l=JSON.stringify(M))}function c(){i=this.value,n(0,i)}function p(){o=this.value,n(1,o)}return[i,o,l,s,c,p]}class ll extends K{constructor(t){super();X(this,t,rl,ol,Y,{})}}function jo(e,t,n){const i=e.slice();return i[10]=t[n],i}function Fo(e,t,n){const i=e.slice();return i[13]=t[n],i}function Uo(e){let t,n=e[13].label+"",i,o,l,s,c;function p(){return e[9](e[13])}return{c(){t=u("p"),i=S(n),o=v(),a(t,"class",l="nv noselect "+(e[0]===e[13]?"nv_selected":""))},m(h,f){P(h,t,f),r(t,i),r(t,o),s||(c=T(t,"click",p),s=!0)},p(h,f){e=h,f&1&&l!==(l="nv noselect "+(e[0]===e[13]?"nv_selected":""))&&a(t,"class",l)},d(h){h&&W(t),s=!1,c()}}}function sl(e){let t,n=e[10].html+"",i;return{c(){i=Vi(),t=new Xo(i)},m(o,l){t.m(n,o,l),P(o,i,l)},p(o,l){l&2&&n!==(n=o[10].html+"")&&t.p(n)},d(o){o&&W(i),o&&t.d()}}}function ul(e){let t,n=e[10].text+"",i;return{c(){t=u("p"),i=S(n)},m(o,l){P(o,t,l),r(t,i)},p(o,l){l&2&&n!==(n=o[10].text+"")&&G(i,n)},d(o){o&&W(t)}}}function Ho(e){let t;function n(l,s){return l[10].text?ul:sl}let i=n(e),o=i(e);return{c(){o.c(),t=Vi()},m(l,s){o.m(l,s),P(l,t,s)},p(l,s){i===(i=n(l))&&o?o.p(l,s):(o.d(1),o=i(l),o&&(o.c(),o.m(t.parentNode,t)))},d(l){o.d(l),l&&W(t)}}}function al(e){let t,n,i,o,l,s,c,p,h,f,M,m,d,b,k,w,A,C,j,F,U,O,H=e[2],q=[];for(let R=0;RDocumentation - Github - Source`,c=v(),p=u("div"),h=u("div");for(let R=0;R{Yi(D,1)}),Jo()}tt?(m=new tt(ut(R)),Ji(m.$$.fragment),Xi(m.$$.fragment,1),$i(m,M,null)):m=null}if(nt&2){$=R[1];let D;for(D=0;D<$.length;D+=1){const Q=jo(R,$,D);B[D]?B[D].p(Q,nt):(B[D]=Ho(Q),B[D].c(),B[D].m(b,null))}for(;D{Ko(cl,()=>{pe("menu_toggle")})});const o=[{label:"Welcome",component:tr},{label:"Messages",component:lr},{label:"CLI",component:ir},{label:"Dialog",component:yr},{label:"File system",component:Tr},{label:"HTTP",component:Pr},{label:"HTTP Form",component:ll},{label:"Notifications",component:Er},{label:"Window",component:Ir},{label:"Shortcuts",component:Vr},{label:"Shell",component:Kr},{label:"Updater",component:Qr},{label:"Clipboard",component:tl},{label:"WebRTC",component:il}];let l=o[0],s=Gi([]);Bi(e,s,d=>n(1,i=d));function c(d){n(0,l=d)}function p(d){s.update(b=>[{text:`[${new Date().toLocaleTimeString()}]: `+(typeof d=="string"?d:JSON.stringify(d))},...b])}function h(d){s.update(b=>[{html:d},...b])}function f(){s.update(()=>[])}function M(){En("https://tauri.studio/")}return[l,i,o,s,c,p,h,f,M,d=>c(d)]}class fl extends K{constructor(t){super();X(this,t,dl,al,Y,{})}}new fl({target:document.body}); diff --git a/examples/api/dist/assets/vendor.js b/examples/api/dist/assets/vendor.js deleted file mode 100644 index 3a009e0cb5cd..000000000000 --- a/examples/api/dist/assets/vendor.js +++ /dev/null @@ -1,9 +0,0 @@ -function w(){}function U(e){return e()}function z(){return Object.create(null)}function K(e){e.forEach(U)}function se(e){return typeof e=="function"}function fe(e,t){return e!=e?t==t:e!==t||e&&typeof e=="object"||typeof e=="function"}function oe(e){return Object.keys(e).length===0}function ae(e,...t){if(e==null)return w;const n=e.subscribe(...t);return n.unsubscribe?()=>n.unsubscribe():n}function Ae(e,t,n){e.$$.on_destroy.push(ae(t,n))}function Se(e,t){e.appendChild(t)}function ue(e,t,n){e.insertBefore(t,n||null)}function F(e){e.parentNode.removeChild(e)}function je(e,t){for(let n=0;ne.removeEventListener(t,n,i)}function Le(e){return function(t){return t.preventDefault(),e.call(this,t)}}function Te(e,t,n){n==null?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n)}function Be(e){return e===""?null:+e}function le(e){return Array.from(e.childNodes)}function De(e,t){t=""+t,e.wholeText!==t&&(e.data=t)}function He(e,t){e.value=t==null?"":t}function Ne(e,t){for(let n=0;n{S.delete(e),i&&(n&&e.d(1),i())}),e.o(t)}}function Xe(e){e&&e.c()}function ye(e,t,n,i){const{fragment:r,on_mount:c,on_destroy:o,after_update:f}=e.$$;r&&r.m(t,n),i||P(()=>{const s=c.map(U).filter(se);o?o.push(...s):K(s),e.$$.on_mount=[]}),f.forEach(P)}function ge(e,t){const n=e.$$;n.fragment!==null&&(K(n.on_destroy),n.fragment&&n.fragment.d(t),n.on_destroy=n.fragment=null,n.ctx=[])}function _e(e,t){e.$$.dirty[0]===-1&&(O.push(e),pe(),e.$$.dirty.fill(0)),e.$$.dirty[t/31|0]|=1<{const y=m.length?m[0]:h;return s.ctx&&r(s.ctx[a],s.ctx[a]=y)&&(!s.skip_bound&&s.bound[a]&&s.bound[a](y),l&&_e(e,a)),h}):[],s.update(),l=!0,K(s.before_update),s.fragment=i?i(s.ctx):!1,t.target){if(t.hydrate){const a=le(t.target);s.fragment&&s.fragment.l(a),a.forEach(F)}else s.fragment&&s.fragment.c();t.intro&&me(e.$$.fragment),ye(e,t.target,t.anchor,t.customElement),J()}C(f)}class Qe{$destroy(){ge(this,1),this.$destroy=w}$on(t,n){const i=this.$$.callbacks[t]||(this.$$.callbacks[t]=[]);return i.push(n),()=>{const r=i.indexOf(n);r!==-1&&i.splice(r,1)}}$set(t){this.$$set&&!oe(t)&&(this.$$.skip_bound=!0,this.$$set(t),this.$$.skip_bound=!1)}}const x=[];function We(e,t=w){let n;const i=[];function r(f){if(fe(e,f)&&(e=f,n)){const s=!x.length;for(let l=0;l{const a=i.indexOf(l);a!==-1&&i.splice(a,1),i.length===0&&(n(),n=null)}}return{set:r,update:c,subscribe:o}}/*! - * hotkeys-js v3.8.5 - * A simple micro-library for defining and dispatching keyboard shortcuts. It has no dependencies. - * - * Copyright (c) 2021 kenny wong - * http://jaywcjlove.github.io/hotkeys - * - * Licensed under the MIT license. - */var B=typeof navigator!="undefined"?navigator.userAgent.toLowerCase().indexOf("firefox")>0:!1;function D(e,t,n){e.addEventListener?e.addEventListener(t,n,!1):e.attachEvent&&e.attachEvent("on".concat(t),function(){n(window.event)})}function Q(e,t){for(var n=t.slice(0,t.length-1),i=0;i=0;)t[n-1]+=",",t.splice(n,1),n=t.lastIndexOf("");return t}function be(e,t){for(var n=e.length>=t.length?e:t,i=e.length>=t.length?t:e,r=!0,c=0;c=0&&u.splice(n,1),e.key&&e.key.toLowerCase()==="meta"&&u.splice(0,u.length),(t===93||t===224)&&(t=91),t in p){p[t]=!1;for(var i in v)v[i]===t&&(_[i]=!1)}}function $e(e){if(!e)Object.keys(d).forEach(function(o){return delete d[o]});else if(Array.isArray(e))e.forEach(function(o){o.key&&H(o)});else if(typeof e=="object")e.key&&H(e);else if(typeof e=="string"){for(var t=arguments.length,n=new Array(t>1?t-1:0),i=1;i1?Q(v,l):[];d[m]=d[m].map(function(g){var re=r?g.method===r:!0;return re&&g.scope===i&&be(g.mods,y)?{}:g})}})};function ne(e,t,n){var i;if(t.scope===n||t.scope==="all"){i=t.mods.length>0;for(var r in p)Object.prototype.hasOwnProperty.call(p,r)&&(!p[r]&&t.mods.indexOf(+r)>-1||p[r]&&t.mods.indexOf(+r)===-1)&&(i=!1);(t.mods.length===0&&!p[16]&&!p[18]&&!p[17]&&!p[91]||i||t.shortcut==="*")&&t.method(e,t)===!1&&(e.preventDefault?e.preventDefault():e.returnValue=!1,e.stopPropagation&&e.stopPropagation(),e.cancelBubble&&(e.cancelBubble=!0))}}function ie(e){var t=d["*"],n=e.keyCode||e.which||e.charCode;if(!!_.filter.call(this,e)){if((n===93||n===224)&&(n=91),u.indexOf(n)===-1&&n!==229&&u.push(n),["ctrlKey","altKey","shiftKey","metaKey"].forEach(function(y){var g=Z[y];e[y]&&u.indexOf(g)===-1?u.push(g):!e[y]&&u.indexOf(g)>-1?u.splice(u.indexOf(g),1):y==="metaKey"&&e[y]&&u.length===3&&(e.ctrlKey||e.shiftKey||e.altKey||(u=u.slice(u.indexOf(g))))}),n in p){p[n]=!0;for(var i in v)v[i]===n&&(_[i]=!0);if(!t)return}for(var r in p)Object.prototype.hasOwnProperty.call(p,r)&&(p[r]=e[Z[r]]);e.getModifierState&&!(e.altKey&&!e.ctrlKey)&&e.getModifierState("AltGraph")&&(u.indexOf(17)===-1&&u.push(17),u.indexOf(18)===-1&&u.push(18),p[17]=!0,p[18]=!0);var c=$();if(t)for(var o=0;o-1}function _(e,t,n){u=[];var i=W(e),r=[],c="all",o=document,f=0,s=!1,l=!0,a="+";for(n===void 0&&typeof t=="function"&&(n=t),Object.prototype.toString.call(t)==="[object Object]"&&(t.scope&&(c=t.scope),t.element&&(o=t.element),t.keyup&&(s=t.keyup),t.keydown!==void 0&&(l=t.keydown),typeof t.splitKey=="string"&&(a=t.splitKey)),typeof t=="string"&&(c=t);f1&&(r=Q(v,e)),e=e[e.length-1],e=e==="*"?"*":k(e),e in d||(d[e]=[]),d[e].push({keyup:s,keydown:l,scope:c,mods:r,shortcut:i[f],method:n,key:i[f],splitKey:a});typeof o!="undefined"&&!Ee(o)&&window&&(ee.push(o),D(o,"keydown",function(h){ie(h)}),D(window,"focus",function(){u=[]}),D(o,"keyup",function(h){ie(h),Oe(h)}))}var N={setScope:te,getScope:$,deleteScope:Ke,getPressedKeyCodes:ve,isPressed:xe,filter:we,unbind:$e};for(var q in N)Object.prototype.hasOwnProperty.call(N,q)&&(_[q]=N[q]);if(typeof window!="undefined"){var Ce=window.hotkeys;_.noConflict=function(e){return e&&window.hotkeys===_&&(window.hotkeys=Ce),_},window.hotkeys=_}export{Xe as A,ye as B,Ve as C,Re as D,me as E,ge as F,Ge as G,_ as H,Ue as I,Qe as S,ke as a,Te as b,ue as c,Se as d,ce as e,De as f,F as g,Fe as h,Je as i,He as j,je as k,Pe as l,V as m,w as n,ze as o,Le as p,P as q,K as r,fe as s,G as t,Ne as u,qe as v,Be as w,Ae as x,We as y,Me as z}; diff --git a/examples/api/dist/global.css b/examples/api/dist/global.css deleted file mode 100644 index 3645dd44467e..000000000000 --- a/examples/api/dist/global.css +++ /dev/null @@ -1,192 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Tauri&display=swap'); - -* { - font-family: Tauri, Arial, Helvetica, sans-serif; -} - -body { - background: rgb(24, 25, 26, 0.8); -} - -.noselect { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.logo-container { - width: 95%; - margin: 0px auto; -} - -.logo-link { - font-weight: 700; - position: absolute; - top: 150px; - right: 10px; -} - -.logo { - cursor: pointer; -} - -#response { - height: 100%; - max-height: 100%; - margin-top: 1em; - background: rgb(36, 37, 38, 0.8); - color: #f0f4f5; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); - font-family: 'Courier New', Courier, monospace; - font-size: 12px; - word-wrap: break-word; - padding: 0px 15px; - overflow-y: auto; -} - -input, -select, -textarea { - background: rgb(53, 53, 53, 0.9); - color: #fff; - font-family: system-ui, sans-serif; - border: none !important; - border-radius: 0.25rem; - font-size: 1rem; - line-height: 1.2; - padding: 0.25rem 0.5rem; - margin: 0.25rem; - transition: 0.2s ease; -} - -button:hover, -button:focus { - background: #ffe07a; -} - -button:focus { - outline: 1px solid #fff; - outline-offset: -4px; -} - -button:active { - transform: scale(0.99); -} - -.button { - border: 0; - border-radius: 0.25rem; - background: #67d6ed; - color: rgb(0, 0, 0); - font-family: system-ui, sans-serif; - font-size: 1rem; - line-height: 1.2; - white-space: nowrap; - text-decoration: none; - padding: 0.25rem 0.5rem; - margin: 0.25rem; - cursor: pointer; - transition: 0.2s ease; -} - -.dark-link { - color: white; - text-decoration: none !important; - padding: 0.5em; - background: rgb(36, 37, 38); - transition: 0.2s ease; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); -} - -.dark-link:hover { - background: #3d392a; -} - -.nv { - color: #fff; - cursor: pointer; - transition: 0.25s ease; -} - -.nv:hover { - color: #ffe07a; - padding-left: 8px; - border-left: solid 5px #ffe07a; -} - -.nv_selected { - color: #67d6ed; - padding-left: 8px; - border-left: solid 5px #67d6ed; -} - -.content { - background: rgb(36, 37, 38, 0.5); - color: #f0f4f5; - padding: 20px; - width: 100%; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); -} - -main { - height: 100%; -} - -[type='radio']:checked ~ label { - background: rgb(36, 37, 38); - color: #67d6ed; - border-bottom: 1px solid transparent; - z-index: 2; -} - -[type='radio']:checked ~ label ~ .content { - z-index: 1; -} - -.flex { - display: flex; -} - -.row { - flex-direction: row; -} - -.col { - flex-direction: column; -} - -.just-around { - justify-content: space-between; -} - -.hidden { - display: none; -} - -.alert { - width: auto; - height: 40px; - display: flex; - justify-content: left; - align-items: center; - border-radius: 5px; - padding-left: 10px; - padding-right: 40px; - font-size: 15px; - color: #000; - margin-bottom: 10px; - margin-top: 10px; - box-shadow: rgba(0, 0, 0, 0.06) 0px 0px 10px; - border-left: 6px solid #ff0000; - background: #f0f4f5; -} - -#file-response { - height: 400px; -} diff --git a/examples/api/dist/index.html b/examples/api/dist/index.html deleted file mode 100644 index 988c1f27a1b9..000000000000 --- a/examples/api/dist/index.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - Svelte + Vite App - - - - - - -
    - - - diff --git a/examples/api/index.html b/examples/api/index.html index c2847e399947..010944d8e277 100644 --- a/examples/api/index.html +++ b/examples/api/index.html @@ -1,10 +1,9 @@ - - + + - - Svelte + Vite App + API Example App diff --git a/examples/api/isolation-dist/index.html b/examples/api/isolation-dist/index.html index 1a12b0bc4607..a97caa83afe5 100644 --- a/examples/api/isolation-dist/index.html +++ b/examples/api/isolation-dist/index.html @@ -1,10 +1,10 @@ - + - - - Isolation Secure Script - - - - + + + Isolation Secure Script + + + + diff --git a/examples/api/isolation-dist/index.js b/examples/api/isolation-dist/index.js index f3a30af5d778..1324ffc314c0 100644 --- a/examples/api/isolation-dist/index.js +++ b/examples/api/isolation-dist/index.js @@ -1,3 +1,7 @@ -window.__TAURI_ISOLATION_HOOK__= (payload) => { +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +window.__TAURI_ISOLATION_HOOK__ = (payload, options) => { return payload } diff --git a/examples/api/jsconfig.json b/examples/api/jsconfig.json index 42585941e160..5696a2de74a0 100644 --- a/examples/api/jsconfig.json +++ b/examples/api/jsconfig.json @@ -1,14 +1,14 @@ { "compilerOptions": { - "moduleResolution": "node", - "target": "esnext", - "module": "esnext", + "moduleResolution": "bundler", + "target": "ESNext", + "module": "ESNext", /** * svelte-preprocess cannot figure out whether you have * a value or a type, so tell TypeScript to enforce using * `import type` instead of `import` for Types. */ - "importsNotUsedAsValues": "error", + "verbatimModuleSyntax": true, "isolatedModules": true, "resolveJsonModule": true, /** @@ -18,8 +18,6 @@ "sourceMap": true, "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "baseUrl": ".", /** * Typecheck JS in `.svelte` and `.js` files by default. * Disable this if you'd like to use dynamic types. diff --git a/examples/api/package.json b/examples/api/package.json index 53f0c67dc713..17d4a7382721 100644 --- a/examples/api/package.json +++ b/examples/api/package.json @@ -1,20 +1,24 @@ { - "name": "svelte-app", + "name": "api", + "private": true, "version": "1.0.0", "type": "module", "scripts": { - "dev": "vite --clearScreen false --port 5000", + "dev": "vite", "build": "vite build", - "serve": "vite preview", - "tauri": "node ../../tooling/cli/node/tauri.js" + "preview": "vite preview", + "tauri": "node ../../packages/cli/tauri.js" }, "dependencies": { - "@tauri-apps/api": "../../tooling/api/dist", - "hotkeys-js": "^3.8.5" + "@tauri-apps/api": "../../packages/api/dist" }, "devDependencies": { - "svelte": "3.35.0", - "@sveltejs/vite-plugin-svelte": "^1.0.0-next.11", - "vite": "^2.6.4" + "@iconify-json/codicon": "^1.2.6", + "@iconify-json/ph": "^1.2.1", + "@sveltejs/vite-plugin-svelte": "5.0.1", + "@unocss/extractor-svelte": "0.65.1", + "svelte": "5.10.1", + "unocss": "0.65.1", + "vite": "6.0.3" } -} \ No newline at end of file +} diff --git a/examples/api/public/global.css b/examples/api/public/global.css deleted file mode 100644 index 3645dd44467e..000000000000 --- a/examples/api/public/global.css +++ /dev/null @@ -1,192 +0,0 @@ -@import url('https://fonts.googleapis.com/css2?family=Tauri&display=swap'); - -* { - font-family: Tauri, Arial, Helvetica, sans-serif; -} - -body { - background: rgb(24, 25, 26, 0.8); -} - -.noselect { - -webkit-touch-callout: none; - -webkit-user-select: none; - -khtml-user-select: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; -} - -.logo-container { - width: 95%; - margin: 0px auto; -} - -.logo-link { - font-weight: 700; - position: absolute; - top: 150px; - right: 10px; -} - -.logo { - cursor: pointer; -} - -#response { - height: 100%; - max-height: 100%; - margin-top: 1em; - background: rgb(36, 37, 38, 0.8); - color: #f0f4f5; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); - font-family: 'Courier New', Courier, monospace; - font-size: 12px; - word-wrap: break-word; - padding: 0px 15px; - overflow-y: auto; -} - -input, -select, -textarea { - background: rgb(53, 53, 53, 0.9); - color: #fff; - font-family: system-ui, sans-serif; - border: none !important; - border-radius: 0.25rem; - font-size: 1rem; - line-height: 1.2; - padding: 0.25rem 0.5rem; - margin: 0.25rem; - transition: 0.2s ease; -} - -button:hover, -button:focus { - background: #ffe07a; -} - -button:focus { - outline: 1px solid #fff; - outline-offset: -4px; -} - -button:active { - transform: scale(0.99); -} - -.button { - border: 0; - border-radius: 0.25rem; - background: #67d6ed; - color: rgb(0, 0, 0); - font-family: system-ui, sans-serif; - font-size: 1rem; - line-height: 1.2; - white-space: nowrap; - text-decoration: none; - padding: 0.25rem 0.5rem; - margin: 0.25rem; - cursor: pointer; - transition: 0.2s ease; -} - -.dark-link { - color: white; - text-decoration: none !important; - padding: 0.5em; - background: rgb(36, 37, 38); - transition: 0.2s ease; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); -} - -.dark-link:hover { - background: #3d392a; -} - -.nv { - color: #fff; - cursor: pointer; - transition: 0.25s ease; -} - -.nv:hover { - color: #ffe07a; - padding-left: 8px; - border-left: solid 5px #ffe07a; -} - -.nv_selected { - color: #67d6ed; - padding-left: 8px; - border-left: solid 5px #67d6ed; -} - -.content { - background: rgb(36, 37, 38, 0.5); - color: #f0f4f5; - padding: 20px; - width: 100%; - border: solid 1px rgba(255, 255, 255, 0.055); - box-shadow: 0 1px 5px 0 rgb(0 0 0 / 20%); -} - -main { - height: 100%; -} - -[type='radio']:checked ~ label { - background: rgb(36, 37, 38); - color: #67d6ed; - border-bottom: 1px solid transparent; - z-index: 2; -} - -[type='radio']:checked ~ label ~ .content { - z-index: 1; -} - -.flex { - display: flex; -} - -.row { - flex-direction: row; -} - -.col { - flex-direction: column; -} - -.just-around { - justify-content: space-between; -} - -.hidden { - display: none; -} - -.alert { - width: auto; - height: 40px; - display: flex; - justify-content: left; - align-items: center; - border-radius: 5px; - padding-left: 10px; - padding-right: 40px; - font-size: 15px; - color: #000; - margin-bottom: 10px; - margin-top: 10px; - box-shadow: rgba(0, 0, 0, 0.06) 0px 0px 10px; - border-left: 6px solid #ff0000; - background: #f0f4f5; -} - -#file-response { - height: 400px; -} diff --git a/examples/api/public/tauri logo.png b/examples/api/public/tauri logo.png deleted file mode 100644 index 2c53b8c4bd72..000000000000 Binary files a/examples/api/public/tauri logo.png and /dev/null differ diff --git a/examples/api/dist/tauri logo.png b/examples/api/public/tauri_logo.png similarity index 100% rename from examples/api/dist/tauri logo.png rename to examples/api/public/tauri_logo.png diff --git a/examples/api/src-tauri/.gitignore b/examples/api/src-tauri/.gitignore index c1237045915f..7ba10a9f4a0a 100644 --- a/examples/api/src-tauri/.gitignore +++ b/examples/api/src-tauri/.gitignore @@ -1,4 +1,6 @@ # Generated by Cargo # will have compiled files and executables /target/ -WixTools + +# cargo-mobile +/gen diff --git a/examples/api/src-tauri/.license_template b/examples/api/src-tauri/.license_template deleted file mode 100644 index 9601f8a1b49f..000000000000 --- a/examples/api/src-tauri/.license_template +++ /dev/null @@ -1,3 +0,0 @@ -// Copyright {20\d{2}(-20\d{2})?} Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT \ No newline at end of file diff --git a/examples/api/src-tauri/.taurignore b/examples/api/src-tauri/.taurignore new file mode 100644 index 000000000000..cbff5293847b --- /dev/null +++ b/examples/api/src-tauri/.taurignore @@ -0,0 +1 @@ +tauri-plugin-sample/ \ No newline at end of file diff --git a/examples/api/src-tauri/Cargo.lock b/examples/api/src-tauri/Cargo.lock deleted file mode 100644 index fd7f14f36f78..000000000000 --- a/examples/api/src-tauri/Cargo.lock +++ /dev/null @@ -1,4312 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "adler32" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" - -[[package]] -name = "aead" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" -dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug", -] - -[[package]] -name = "aes-gcm" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5f85a83a7d8b0442b6aa7b504b8212c1733da07b98aae43d4bc21b2cb3cdf6" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anyhow" -version = "1.0.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" - -[[package]] -name = "api" -version = "0.1.0" -dependencies = [ - "serde", - "serde_json", - "tauri", - "tauri-build", -] - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "ashpd" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "098dee97729c0164b39a8a7de9c20e4b0eb9cd57f87c8bb465224587b44b1683" -dependencies = [ - "enumflags2", - "futures", - "rand 0.8.5", - "serde", - "serde_repr", - "zbus", -] - -[[package]] -name = "async-broadcast" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90622698a1218e0b2fb846c97b5f19a0831f6baddee73d9454156365ccfa473b" -dependencies = [ - "easy-parallel", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi", -] - -[[package]] -name = "async-lock" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e97a171d191782fba31bb902b14ad94e24a68145032b7eedf871ab0bc0d077b6" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-recursion" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7d78656ba01f1b93024b7c3a0467f1608e4be67d725749fdcd7d2c7678fd7a2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-task" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d306121baf53310a3fd342d88dc0824f6bbeace68347593658525565abee8" - -[[package]] -name = "async-trait" -version = "0.1.52" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atk" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3d816ce6f0e2909a96830d6911c2aff044370b1ef92d7f267b43bae5addedd" -dependencies = [ - "atk-sys", - "bitflags", - "glib", - "libc", -] - -[[package]] -name = "atk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58aeb089fb698e06db8089971c7ee317ab9644bade33383f63631437b03aafb6" -dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "attohttpc" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69e13a99a7e6e070bb114f7ff381e58c7ccc188630121fc4c2fe4bcf24cd072" -dependencies = [ - "flate2", - "http", - "log", - "native-tls", - "openssl", - "serde", - "serde_json", - "serde_urlencoded", - "url", - "wildmatch", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec 0.5.2", - "constant_time_eq", -] - -[[package]] -name = "blake3" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" -dependencies = [ - "arrayref", - "arrayvec 0.7.2", - "cc", - "cfg-if", - "constant_time_eq", - "digest", - "rayon", -] - -[[package]] -name = "block" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" - -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "memchr", -] - -[[package]] -name = "bumpalo" -version = "3.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" - -[[package]] -name = "cache-padded" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1db59621ec70f09c5e9b597b220c7a2b43611f4710dc03ceb8748637775692c" - -[[package]] -name = "cairo-rs" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8b14c80d8d1a02fa6d914b9d1afeeca9bc34257f8300d9696e1e331ae114223" -dependencies = [ - "bitflags", - "cairo-sys-rs", - "glib", - "libc", - "thiserror", -] - -[[package]] -name = "cairo-sys-rs" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c55d429bef56ac9172d25fecb85dc8068307d17acd74b377866b7a1ef25d3c8" -dependencies = [ - "glib-sys 0.15.6", - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "cargo_toml" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e270ef0cd868745878982f7ce470aa898d0d4bb248af67f0cf66f54617913ef" -dependencies = [ - "serde", - "serde_derive", - "toml", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" -dependencies = [ - "jobserver", -] - -[[package]] -name = "cfb" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca453e8624711b2f0f4eb47076a318feda166252a827ee25d067b43de83dcba0" -dependencies = [ - "byteorder", - "uuid", -] - -[[package]] -name = "cfg-expr" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b412e83326147c2bb881f8b40edfbf9905b9b8abaebd0e47ca190ba62fda8f0e" -dependencies = [ - "smallvec", -] - -[[package]] -name = "cfg-expr" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3431df59f28accaf4cb4eed4a9acc66bea3f3c3753aa6cdc2f024174ef232af7" -dependencies = [ - "smallvec", -] - -[[package]] -name = "cfg-expr" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e068cb2806bbc15b439846dc16c5f89f8599f2c3e4d73d4449d38f9b2f0b6c5" -dependencies = [ - "smallvec", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - -[[package]] -name = "chrono" -version = "0.4.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" -dependencies = [ - "libc", - "num-integer", - "num-traits", - "time", - "winapi", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array", -] - -[[package]] -name = "clap" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5177fac1ab67102d8989464efd043c6ff44191b1557ec1ddd489b4f7e1447e77" -dependencies = [ - "atty", - "bitflags", - "indexmap", - "os_str_bytes", - "strsim 0.10.0", - "termcolor", - "textwrap", -] - -[[package]] -name = "cocoa" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f63902e9223530efb4e26ccd0cf55ec30d592d3b42e21a28defc42a9586e832" -dependencies = [ - "bitflags", - "block", - "cocoa-foundation", - "core-foundation", - "core-graphics", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "cocoa-foundation" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" -dependencies = [ - "bitflags", - "block", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", - "objc", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "core-foundation" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "core-foundation-sys" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" - -[[package]] -name = "core-graphics" -version = "0.22.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb" -dependencies = [ - "bitflags", - "core-foundation", - "core-graphics-types", - "foreign-types", - "libc", -] - -[[package]] -name = "core-graphics-types" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" -dependencies = [ - "bitflags", - "core-foundation", - "foreign-types", - "libc", -] - -[[package]] -name = "cpufeatures" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" -dependencies = [ - "libc", -] - -[[package]] -name = "crc32fast" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "crypto-common" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" -dependencies = [ - "generic-array", - "typenum", -] - -[[package]] -name = "cssparser" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "754b69d351cdc2d8ee09ae203db831e005560fc6030da058f86ad60c92a9cb0a" -dependencies = [ - "cssparser-macros", - "dtoa-short", - "itoa 0.4.8", - "matches", - "phf 0.8.0", - "proc-macro2", - "quote", - "smallvec", - "syn", -] - -[[package]] -name = "cssparser-macros" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfae75de57f2b2e85e8768c3ea840fd159c8f33e2b6522c7835b7abac81be16e" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ctor" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - -[[package]] -name = "cty" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" - -[[package]] -name = "darling" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d706e75d87e35569db781a9b5e2416cff1236a47ed380831f959382ccd5f858" -dependencies = [ - "darling_core 0.10.2", - "darling_macro 0.10.2", -] - -[[package]] -name = "darling" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4" -dependencies = [ - "darling_core 0.13.1", - "darling_macro 0.13.1", -] - -[[package]] -name = "darling_core" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c960ae2da4de88a91b2d920c2a7233b400bc33cb28453a2987822d8392519b" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.9.3", - "syn", -] - -[[package]] -name = "darling_core" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim 0.10.0", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" -dependencies = [ - "darling_core 0.10.2", - "quote", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b" -dependencies = [ - "darling_core 0.13.1", - "quote", - "syn", -] - -[[package]] -name = "deflate" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4" -dependencies = [ - "adler32", - "byteorder", -] - -[[package]] -name = "deflate" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" -dependencies = [ - "adler32", - "byteorder", -] - -[[package]] -name = "derivative" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.4.0", - "syn", -] - -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer", - "crypto-common", - "subtle", -] - -[[package]] -name = "dirs" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901" -dependencies = [ - "libc", - "redox_users 0.3.5", - "winapi", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users 0.4.0", - "winapi", -] - -[[package]] -name = "dispatch" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" - -[[package]] -name = "dtoa-short" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03329ae10e79ede66c9ce4dc930aa8599043b0743008548680f25b91502d6" -dependencies = [ - "dtoa", -] - -[[package]] -name = "easy-parallel" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6907e25393cdcc1f4f3f513d9aac1e840eb1cc341a0fccb01171f7d14d10b946" - -[[package]] -name = "either" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" - -[[package]] -name = "embed_plist" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ef6b89e5b37196644d8796de5268852ff179b44e96276cf4290264843743bb7" - -[[package]] -name = "enumflags2" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25c90b056b3f84111cf183cbeddef0d3a0bbe9a674f057e1a1533c315f24def" -dependencies = [ - "enumflags2_derive", - "serde", -] - -[[package]] -name = "enumflags2_derive" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "144ec79496cbab6f84fa125dc67be9264aef22eb8a28da8454d9c33f15108da4" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "event-listener" -version = "2.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77f3309417938f28bf8228fcff79a4a37103981e3e186d2ccd19c74b38f4eb71" - -[[package]] -name = "fastrand" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] - -[[package]] -name = "field-offset" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e1c54951450cbd39f3dbcf1005ac413b49487dabf18a720ad2383eccfeffb92" -dependencies = [ - "memoffset", - "rustc_version 0.3.3", -] - -[[package]] -name = "filetime" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.10", - "winapi", -] - -[[package]] -name = "flate2" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" -dependencies = [ - "cfg-if", - "crc32fast", - "libc", - "miniz_oxide 0.4.4", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "foreign-types" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" -dependencies = [ - "foreign-types-shared", -] - -[[package]] -name = "foreign-types-shared" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "futf" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df420e2e84819663797d1ec6544b13c5be84629e7bb00dc960d6917db2987843" -dependencies = [ - "mac", - "new_debug_unreachable", -] - -[[package]] -name = "futures" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" - -[[package]] -name = "futures-executor" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" - -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite", - "waker-fn", -] - -[[package]] -name = "futures-macro" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "futures-sink" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" - -[[package]] -name = "futures-task" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" - -[[package]] -name = "futures-util" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gdk" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6e05c1f572ab0e1f15be94217f0dc29088c248b14f792a5ff0af0d84bcda9e8" -dependencies = [ - "bitflags", - "cairo-rs", - "gdk-pixbuf", - "gdk-sys", - "gio", - "glib", - "libc", - "pango", -] - -[[package]] -name = "gdk-pixbuf" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8750501d75f318c2ec0314701bc8403901303210def80bafd13f6b6059a3f45" -dependencies = [ - "bitflags", - "gdk-pixbuf-sys", - "gio", - "glib", - "libc", -] - -[[package]] -name = "gdk-pixbuf-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413424d9818621fa3cfc8a3a915cdb89a7c3c507d56761b4ec83a9a98e587171" -dependencies = [ - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "gdk-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e7a08c1e8f06f4177fb7e51a777b8c1689f743a7bc11ea91d44d2226073a88" -dependencies = [ - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "pango-sys", - "pkg-config", - "system-deps 6.0.2", -] - -[[package]] -name = "gdkx11-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4b7f8c7a84b407aa9b143877e267e848ff34106578b64d1e0a24bf550716178" -dependencies = [ - "gdk-sys", - "glib-sys 0.15.6", - "libc", - "system-deps 6.0.2", - "x11", -] - -[[package]] -name = "generator" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1d9279ca822891c1a4dae06d185612cf8fc6acfe5dff37781b41297811b12ee" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "winapi", -] - -[[package]] -name = "generic-array" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - -[[package]] -name = "getrandom" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", -] - -[[package]] -name = "ghash" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1583cc1656d7839fd3732b80cf4f38850336cdb9b8ded1cd399ca62958de3c99" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gio" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96efd8a1c00d890f6b45671916e165b5e43ccec61957d443aff6d7e44f62d348" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-io", - "gio-sys 0.15.6", - "glib", - "libc", - "once_cell", - "thiserror", -] - -[[package]] -name = "gio-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a41df66e57fcc287c4bcf74fc26b884f31901ea9792ec75607289b456f48fa" -dependencies = [ - "glib-sys 0.14.0", - "gobject-sys 0.14.0", - "libc", - "system-deps 3.2.0", - "winapi", -] - -[[package]] -name = "gio-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0fa5052773f5a56b8ae47dab09d040f5d9ce1311f4f99006e16e9a08269296" -dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "system-deps 6.0.2", - "winapi", -] - -[[package]] -name = "glib" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa570813c504bdf7539a9400180c2dd4b789a819556fb86da7226d7d1b037b49" -dependencies = [ - "bitflags", - "futures-channel", - "futures-core", - "futures-executor", - "futures-task", - "glib-macros", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "once_cell", - "smallvec", - "thiserror", -] - -[[package]] -name = "glib-macros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41bfd8d227dead0829ac142454e97531b93f576d0805d779c42bfd799c65c572" -dependencies = [ - "anyhow", - "heck 0.4.0", - "proc-macro-crate 1.1.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "glib-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c1d60554a212445e2a858e42a0e48cece1bd57b311a19a9468f70376cf554ae" -dependencies = [ - "libc", - "system-deps 3.2.0", -] - -[[package]] -name = "glib-sys" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4366377bd56697de8aaee24e673c575d2694d72e7756324ded2b0428829a7b8" -dependencies = [ - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "globset" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd" -dependencies = [ - "aho-corasick", - "bstr", - "fnv", - "log", - "regex", -] - -[[package]] -name = "gobject-sys" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa92cae29759dae34ab5921d73fff5ad54b3d794ab842c117e36cafc7994c3f5" -dependencies = [ - "glib-sys 0.14.0", - "libc", - "system-deps 3.2.0", -] - -[[package]] -name = "gobject-sys" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df6859463843c20cf3837e3a9069b6ab2051aeeadf4c899d33344f4aea83189a" -dependencies = [ - "glib-sys 0.15.6", - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "gtk" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d1326b36af927fe46ae2f89a8fec38c6f0d279ebc5ef07ffeeabb70300bfc" -dependencies = [ - "atk", - "bitflags", - "cairo-rs", - "field-offset", - "futures-channel", - "gdk", - "gdk-pixbuf", - "gio", - "glib", - "gtk-sys", - "gtk3-macros", - "libc", - "once_cell", - "pango", - "pkg-config", -] - -[[package]] -name = "gtk-sys" -version = "0.15.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5bc2f0587cba247f60246a0ca11fe25fb733eabc3de12d1965fc07efab87c84" -dependencies = [ - "atk-sys", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "pango-sys", - "system-deps 6.0.2", -] - -[[package]] -name = "gtk3-macros" -version = "0.15.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24f518afe90c23fba585b2d7697856f9e6a7bbc62f65588035e66f6afb01a2e9" -dependencies = [ - "anyhow", - "proc-macro-crate 1.1.3", - "proc-macro-error", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" - -[[package]] -name = "heck" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" -dependencies = [ - "unicode-segmentation", -] - -[[package]] -name = "heck" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "html5ever" -version = "0.25.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" -dependencies = [ - "log", - "mac", - "markup5ever", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "http" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" -dependencies = [ - "bytes", - "fnv", - "itoa 1.0.1", -] - -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - -[[package]] -name = "ico" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a4b3331534254a9b64095ae60d3dc2a8225a7a70229cd5888be127cdc1f6804" -dependencies = [ - "byteorder", - "png 0.11.0", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "ignore" -version = "0.4.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d" -dependencies = [ - "crossbeam-utils", - "globset", - "lazy_static", - "log", - "memchr", - "regex", - "same-file", - "thread_local", - "walkdir", - "winapi-util", -] - -[[package]] -name = "indexmap" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "infer" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92b41dab759f9e8427c03f519c344a14655490b8db548dac1e57a75b3258391" -dependencies = [ - "cfb", -] - -[[package]] -name = "inflate" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5f9f47468e9a76a6452271efadc88fe865a82be91fe75e6c0c57b87ccea59d4" -dependencies = [ - "adler32", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - -[[package]] -name = "javascriptcore-rs" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf053e7843f2812ff03ef5afe34bb9c06ffee120385caad4f6b9967fcd37d41c" -dependencies = [ - "bitflags", - "glib", - "javascriptcore-rs-sys", -] - -[[package]] -name = "javascriptcore-rs-sys" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "905fbb87419c5cde6e3269537e4ea7d46431f3008c5d057e915ef3f115e7793c" -dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "system-deps 5.0.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" - -[[package]] -name = "jobserver" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" -dependencies = [ - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "json-patch" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f995a3c8f2bc3dd52a18a583e90f9ec109c047fa1603a853e46bcda14d2e279d" -dependencies = [ - "serde", - "serde_json", - "treediff", -] - -[[package]] -name = "kuchiki" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ea8e9c6e031377cff82ee3001dc8026cdf431ed4e2e6b51f98ab8c73484a358" -dependencies = [ - "cssparser", - "html5ever", - "matches", - "selectors", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libappindicator" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b29fab3280d59f3d06725f75da9ef9a1b001b2c748b1abfebd1c966c61d7de" -dependencies = [ - "glib", - "gtk", - "gtk-sys", - "libappindicator-sys", - "log", -] - -[[package]] -name = "libappindicator-sys" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bdcb8c5cfc11febe2ff3f18386d6cb7d29f464cbaf6b286985c3f1a501d74f" -dependencies = [ - "gtk-sys", - "pkg-config", -] - -[[package]] -name = "libc" -version = "0.2.119" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" - -[[package]] -name = "lock_api" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" -dependencies = [ - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "loom" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc5c7d328e32cc4954e8e01193d7f0ef5ab257b5090b70a964e099a36034309" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "mac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" - -[[package]] -name = "mac-notification-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb6b71a9a89cd38b395d994214297447e8e63b1ba5708a9a2b0b1048ceda76" -dependencies = [ - "cc", - "chrono", - "dirs", - "objc-foundation", -] - -[[package]] -name = "malloc_buf" -version = "0.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] - -[[package]] -name = "markup5ever" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a24f40fb03852d1cdd84330cddcaf98e9ec08a7b7768e952fad3b4cf048ec8fd" -dependencies = [ - "log", - "phf 0.8.0", - "phf_codegen", - "string_cache", - "string_cache_codegen", - "tendril", -] - -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata", -] - -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - -[[package]] -name = "memchr" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minisign-verify" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ccf091884470c4b3a80ad6daadbb2e7736611d631cbf0c9e603bb7dbcfdfd9" - -[[package]] -name = "miniz_oxide" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" -dependencies = [ - "adler32", -] - -[[package]] -name = "miniz_oxide" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" -dependencies = [ - "adler", - "autocfg", -] - -[[package]] -name = "native-tls" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" -dependencies = [ - "lazy_static", - "libc", - "log", - "openssl", - "openssl-probe", - "openssl-sys", - "schannel", - "security-framework", - "security-framework-sys", - "tempfile", -] - -[[package]] -name = "ndk" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64d6af06fde0e527b1ba5c7b79a6cc89cfc46325b0b2887dffe8f70197e0c3c" -dependencies = [ - "bitflags", - "jni-sys", - "ndk-sys", - "num_enum", - "thiserror", -] - -[[package]] -name = "ndk-context" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5cc68637e21fe8f077f6a1c9e0b9ca495bb74895226b476310f613325884" - -[[package]] -name = "ndk-glue" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b1454575120e3265d2442222299c711ace58ba417532ee4f0fc71b860016b93" -dependencies = [ - "lazy_static", - "libc", - "log", - "ndk", - "ndk-context", - "ndk-macro", - "ndk-sys", -] - -[[package]] -name = "ndk-macro" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d1c6307dc424d0f65b9b06e94f88248e6305726b14729fd67a5e47b2dc481d" -dependencies = [ - "darling 0.10.2", - "proc-macro-crate 0.1.5", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "ndk-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1bcdd74c20ad5d95aacd60ef9ba40fdf77f767051040541df557b7a9b2a2121" - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nix" -version = "0.23.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6" -dependencies = [ - "bitflags", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" - -[[package]] -name = "notify-rust" -version = "4.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "367e1355a950d3e758e414f3ca1b3981a57a2aa1fa3338eb0059f5b230b6ffa4" -dependencies = [ - "mac-notification-sys", - "serde", - "winrt-notification", - "zbus", - "zvariant", - "zvariant_derive", -] - -[[package]] -name = "num-integer" -version = "0.1.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", - "objc_exception", -] - -[[package]] -name = "objc-foundation" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9" -dependencies = [ - "block", - "objc", - "objc_id", -] - -[[package]] -name = "objc_exception" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" -dependencies = [ - "cc", -] - -[[package]] -name = "objc_id" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" -dependencies = [ - "objc", -] - -[[package]] -name = "once_cell" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "open" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a82915836ef43159bb6a3c64d884c42329ccd0b8afdca737cf1e3dd701709dc" -dependencies = [ - "pathdiff", - "winapi", -] - -[[package]] -name = "openssl" -version = "0.10.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" -dependencies = [ - "bitflags", - "cfg-if", - "foreign-types", - "libc", - "once_cell", - "openssl-sys", -] - -[[package]] -name = "openssl-probe" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" - -[[package]] -name = "openssl-sys" -version = "0.9.72" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" -dependencies = [ - "autocfg", - "cc", - "libc", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "ordered-stream" -version = "0.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44630c059eacfd6e08bdaa51b1db2ce33119caa4ddc1235e923109aa5f25ccb1" -dependencies = [ - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "os_info" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "023df84d545ef479cf67fd2f4459a613585c9db4852c2fad12ab70587859d340" -dependencies = [ - "log", - "serde", - "winapi", -] - -[[package]] -name = "os_pipe" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c92f2b54f081d635c77e7120862d48db8e91f7f21cef23ab1b4fe9971c59f55" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "os_str_bytes" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64" -dependencies = [ - "memchr", -] - -[[package]] -name = "pango" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c7420fc01a390ec200da7395b64d705f5d82fe03e5d0708aee422c46538be7" -dependencies = [ - "bitflags", - "glib", - "libc", - "once_cell", - "pango-sys", -] - -[[package]] -name = "pango-sys" -version = "0.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7022c2fb88cd2d9d55e1a708a8c53a3ae8678234c4a54bf623400aeb7f31fac2" -dependencies = [ - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "libc", - "system-deps 6.0.2", -] - -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.10", - "smallvec", - "winapi", -] - -[[package]] -name = "pathdiff" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "phf" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" -dependencies = [ - "phf_macros 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", -] - -[[package]] -name = "phf" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fabbf1ead8a5bcbc20f5f8b939ee3f5b0f6f281b6ad3468b84656b658b455259" -dependencies = [ - "phf_macros 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", -] - -[[package]] -name = "phf_codegen" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", -] - -[[package]] -name = "phf_generator" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" -dependencies = [ - "phf_shared 0.8.0", - "rand 0.7.3", -] - -[[package]] -name = "phf_generator" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" -dependencies = [ - "phf_shared 0.10.0", - "rand 0.8.5", -] - -[[package]] -name = "phf_macros" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fde18ff429ffc8fe78e2bf7f8b7a5a5a6e2a8b58bc5a9ac69198bbda9189c" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_macros" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fdf3184dd560f160dd73922bea2d5cd6e8f064bf4b13110abd81b03697b4e0" -dependencies = [ - "phf_generator 0.10.0", - "phf_shared 0.10.0", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "phf_shared" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" -dependencies = [ - "siphasher", -] - -[[package]] -name = "phf_shared" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" -dependencies = [ - "siphasher", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkg-config" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" - -[[package]] -name = "png" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0b0cabbbd20c2d7f06dbf015e06aad59b6ca3d9ed14848783e98af9aaf19925" -dependencies = [ - "bitflags", - "deflate 0.7.20", - "inflate", - "num-iter", -] - -[[package]] -name = "png" -version = "0.16.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" -dependencies = [ - "bitflags", - "crc32fast", - "deflate 0.8.6", - "miniz_oxide 0.3.7", -] - -[[package]] -name = "polling" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "685404d509889fade3e86fe3a5803bca2ec09b0c0778d5ada6ec8bf7a8de5259" -dependencies = [ - "cfg-if", - "libc", - "log", - "wepoll-ffi", - "winapi", -] - -[[package]] -name = "pollster" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da3b0203fd7ee5720aa0b5e790b591aa5d3f41c3ed2c34a3a393382198af2f7" - -[[package]] -name = "polyval" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" -dependencies = [ - "cfg-if", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" -dependencies = [ - "thiserror", - "toml", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - -[[package]] -name = "proc-macro2" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc", - "rand_pcg", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom 0.2.5", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -dependencies = [ - "rand_core 0.5.1", -] - -[[package]] -name = "raw-window-handle" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fba75eee94a9d5273a68c9e1e105d9cffe1ef700532325788389e5a83e2522b7" -dependencies = [ - "cty", -] - -[[package]] -name = "rayon" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "lazy_static", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - -[[package]] -name = "redox_syscall" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_users" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" -dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", -] - -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom 0.2.5", - "redox_syscall 0.2.10", -] - -[[package]] -name = "regex" -version = "1.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "rfd" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aaf1d71ccd44689f7c2c72da1117fd8db71f72a76fe9b5c5dbb17ab903007e0" -dependencies = [ - "ashpd", - "block", - "dispatch", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "gtk-sys", - "js-sys", - "lazy_static", - "log", - "objc", - "objc-foundation", - "objc_id", - "pollster", - "raw-window-handle", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "windows 0.30.0", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - -[[package]] -name = "rustc_version" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver 1.0.6", -] - -[[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "schannel" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" -dependencies = [ - "lazy_static", - "winapi", -] - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "security-framework" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" -dependencies = [ - "bitflags", - "core-foundation", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework-sys" -version = "2.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" -dependencies = [ - "core-foundation-sys", - "libc", -] - -[[package]] -name = "selectors" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df320f1889ac4ba6bc0cdc9c9af7af4bd64bb927bccdf32d81140dc1f9be12fe" -dependencies = [ - "bitflags", - "cssparser", - "derive_more", - "fxhash", - "log", - "matches", - "phf 0.8.0", - "phf_codegen", - "precomputed-hash", - "servo_arc", - "smallvec", - "thin-slice", -] - -[[package]] -name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" - -[[package]] -name = "semver-parser" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] - -[[package]] -name = "serde" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" -dependencies = [ - "itoa 1.0.1", - "ryu", - "serde", -] - -[[package]] -name = "serde_repr" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa 1.0.1", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc" -dependencies = [ - "rustversion", - "serde", - "serde_with_macros", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e" -dependencies = [ - "darling 0.13.1", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serialize-to-javascript" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9823f2d3b6a81d98228151fdeaf848206a7855a7a042bbf9bf870449a66cafb" -dependencies = [ - "serde", - "serde_json", - "serialize-to-javascript-impl", -] - -[[package]] -name = "serialize-to-javascript-impl" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74064874e9f6a15f04c1f3cb627902d0e6b410abbf36668afa873c61889f1763" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "servo_arc" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d98238b800e0d1576d8b6e3de32827c2d74bee68bb97748dcf5071fb53965432" -dependencies = [ - "nodrop", - "stable_deref_trait", -] - -[[package]] -name = "sha1" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" -dependencies = [ - "sha1_smol", -] - -[[package]] -name = "sha1_smol" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" - -[[package]] -name = "sha2" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "shared_child" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d94659ad3c2137fef23ae75b03d5241d633f8acded53d672decfa0e6e0caef" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "siphasher" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a86232ab60fa71287d7f2ddae4a7073f6b7aac33631c3015abb556f08c6d0a3e" - -[[package]] -name = "slab" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" - -[[package]] -name = "smallvec" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" - -[[package]] -name = "socket2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "soup2-sys" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f056675eda9a7417163e5f742bb119e8e1d385edd2ada8f7031a7230a3ec10a" -dependencies = [ - "bitflags", - "gio-sys 0.14.0", - "glib-sys 0.14.0", - "gobject-sys 0.14.0", - "libc", - "system-deps 5.0.0", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "state" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cf4f5369e6d3044b5e365c9690f451516ac8f0954084622b49ea3fde2f6de5" -dependencies = [ - "loom", -] - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "string_cache" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33994d0838dc2d152d17a62adf608a869b5e846b65b389af7f3dbc1de45c5b26" -dependencies = [ - "lazy_static", - "new_debug_unreachable", - "parking_lot", - "phf_shared 0.10.0", - "precomputed-hash", - "serde", -] - -[[package]] -name = "string_cache_codegen" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" -dependencies = [ - "phf_generator 0.8.0", - "phf_shared 0.8.0", - "proc-macro2", - "quote", -] - -[[package]] -name = "strsim" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aaf86bbcfd1fa9670b7a129f64fc0c9fcbbfe4f1bc4210e9e98fe71ffc12cde2" - -[[package]] -name = "strum" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7ac893c7d471c8a21f31cfe213ec4f6d9afeed25537c772e08ef3f005f8729e" -dependencies = [ - "strum_macros 0.22.0", -] - -[[package]] -name = "strum_macros" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d06aaeeee809dbc59eb4556183dd927df67db1540de5be8d3ec0b6636358a5ec" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "strum_macros" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "339f799d8b549e3744c7ac7feb216383e4005d94bdb22561b3ab8f3b808ae9fb" -dependencies = [ - "heck 0.3.3", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "syn" -version = "1.0.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "system-deps" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480c269f870722b3b08d2f13053ce0c2ab722839f472863c3e2d61ff3a1c2fa6" -dependencies = [ - "anyhow", - "cfg-expr 0.8.1", - "heck 0.3.3", - "itertools", - "pkg-config", - "strum 0.21.0", - "strum_macros 0.21.1", - "thiserror", - "toml", - "version-compare 0.0.11", -] - -[[package]] -name = "system-deps" -version = "5.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18db855554db7bd0e73e06cf7ba3df39f97812cb11d3f75e71c39bf45171797e" -dependencies = [ - "cfg-expr 0.9.1", - "heck 0.3.3", - "pkg-config", - "toml", - "version-compare 0.0.11", -] - -[[package]] -name = "system-deps" -version = "6.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a45a1c4c9015217e12347f2a411b57ce2c4fc543913b14b6fe40483328e709" -dependencies = [ - "cfg-expr 0.10.2", - "heck 0.4.0", - "pkg-config", - "toml", - "version-compare 0.1.0", -] - -[[package]] -name = "tao" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b3b3bbc9151bce45db3cf9ccb808730c8df8786d0223f34591f6e5890503939" -dependencies = [ - "bitflags", - "cairo-rs", - "cc", - "cocoa", - "core-foundation", - "core-graphics", - "crossbeam-channel", - "dispatch", - "gdk", - "gdk-pixbuf", - "gdk-sys", - "gdkx11-sys", - "gio", - "glib", - "glib-sys 0.15.6", - "gtk", - "instant", - "lazy_static", - "libappindicator", - "libc", - "log", - "ndk", - "ndk-glue", - "ndk-sys", - "objc", - "parking_lot", - "raw-window-handle", - "scopeguard", - "serde", - "tao-core-video-sys", - "unicode-segmentation", - "windows 0.30.0", - "windows_macros", - "x11-dl", -] - -[[package]] -name = "tao-core-video-sys" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271450eb289cb4d8d0720c6ce70c72c8c858c93dd61fc625881616752e6b98f6" -dependencies = [ - "cfg-if", - "core-foundation-sys", - "libc", - "objc", -] - -[[package]] -name = "tar" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" -dependencies = [ - "filetime", - "libc", - "xattr", -] - -[[package]] -name = "tauri" -version = "1.0.0-rc.3" -dependencies = [ - "anyhow", - "attohttpc", - "base64", - "bincode", - "cfg_aliases", - "clap", - "dirs-next", - "either", - "embed_plist", - "flate2", - "futures", - "futures-lite", - "glib", - "glob", - "gtk", - "http", - "ico", - "ignore", - "infer", - "memchr", - "minisign-verify", - "notify-rust", - "once_cell", - "open", - "os_info", - "os_pipe", - "percent-encoding", - "png 0.16.8", - "rand 0.8.5", - "raw-window-handle", - "regex", - "rfd", - "semver 1.0.6", - "serde", - "serde_json", - "serde_repr", - "serialize-to-javascript", - "shared_child", - "state", - "tar", - "tauri-macros", - "tauri-runtime", - "tauri-runtime-wry", - "tauri-utils", - "tempfile", - "thiserror", - "tokio", - "url", - "uuid", - "windows 0.30.0", - "zip", -] - -[[package]] -name = "tauri-build" -version = "1.0.0-rc.3" -dependencies = [ - "anyhow", - "cargo_toml", - "serde_json", - "tauri-codegen", - "tauri-utils", - "winres", -] - -[[package]] -name = "tauri-codegen" -version = "1.0.0-rc.2" -dependencies = [ - "base64", - "blake3", - "ico", - "png 0.16.8", - "proc-macro2", - "quote", - "regex", - "serde", - "serde_json", - "sha2", - "tauri-utils", - "thiserror", - "uuid", - "walkdir", - "zstd", -] - -[[package]] -name = "tauri-macros" -version = "1.0.0-rc.2" -dependencies = [ - "heck 0.4.0", - "proc-macro2", - "quote", - "syn", - "tauri-codegen", - "tauri-utils", -] - -[[package]] -name = "tauri-runtime" -version = "0.3.2" -dependencies = [ - "gtk", - "http", - "http-range", - "infer", - "serde", - "serde_json", - "tauri-utils", - "thiserror", - "uuid", - "webview2-com", - "windows 0.30.0", -] - -[[package]] -name = "tauri-runtime-wry" -version = "0.3.2" -dependencies = [ - "gtk", - "tauri-runtime", - "tauri-utils", - "uuid", - "webview2-com", - "windows 0.30.0", - "wry", -] - -[[package]] -name = "tauri-utils" -version = "1.0.0-rc.2" -dependencies = [ - "aes-gcm", - "ctor", - "glob", - "heck 0.4.0", - "html5ever", - "json-patch", - "kuchiki", - "once_cell", - "phf 0.10.1", - "proc-macro2", - "quote", - "ring", - "serde", - "serde_json", - "serde_with", - "serialize-to-javascript", - "thiserror", - "url", - "walkdir", - "zstd", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall 0.2.10", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "tendril" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9ef557cb397a4f0a5a3a628f06515f78563f2209e64d47055d9dc6052bf5e33" -dependencies = [ - "futf", - "mac", - "utf-8", -] - -[[package]] -name = "termcolor" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.14.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0066c8d12af8b5acd21e00547c3797fde4e8677254a7ee429176ccebbe93dd80" - -[[package]] -name = "thin-slice" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" - -[[package]] -name = "thiserror" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "tinyvec" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - -[[package]] -name = "tokio" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" -dependencies = [ - "bytes", - "memchr", - "num_cpus", - "pin-project-lite", -] - -[[package]] -name = "toml" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" -dependencies = [ - "serde", -] - -[[package]] -name = "tracing" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tracing-core" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" -dependencies = [ - "lazy_static", - "valuable", -] - -[[package]] -name = "tracing-log" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6923477a48e41c1951f1999ef8bb5a3023eb723ceadafe78ffb65dc366761e3" -dependencies = [ - "lazy_static", - "log", - "tracing-core", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce" -dependencies = [ - "ansi_term", - "lazy_static", - "matchers", - "regex", - "sharded-slab", - "smallvec", - "thread_local", - "tracing", - "tracing-core", - "tracing-log", -] - -[[package]] -name = "treediff" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "761e8d5ad7ce14bb82b7e61ccc0ca961005a275a060b9644a2431aa11553c2ff" -dependencies = [ - "serde_json", -] - -[[package]] -name = "typenum" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unicode-bidi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" - -[[package]] -name = "unicode-normalization" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" - -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - -[[package]] -name = "universal-hash" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", - "serde", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.5", -] - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - -[[package]] -name = "version-compare" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c18c859eead79d8b95d09e4678566e8d70105c4e7b251f707a03df32442661b" - -[[package]] -name = "version-compare" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe88247b92c1df6b6de80ddc290f3976dbdf2f5f5d3fd049a9fb598c6dd5ca73" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" - -[[package]] -name = "wasm-bindgen" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" -dependencies = [ - "bumpalo", - "lazy_static", - "log", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" - -[[package]] -name = "web-sys" -version = "0.3.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webkit2gtk" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cbd39499e917de9dad36eb11c09f665eb984d432638ae7971feed98eb96df88" -dependencies = [ - "bitflags", - "cairo-rs", - "gdk", - "gdk-sys", - "gio", - "gio-sys 0.15.6", - "glib", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "gtk", - "gtk-sys", - "javascriptcore-rs", - "libc", - "once_cell", - "webkit2gtk-sys", -] - -[[package]] -name = "webkit2gtk-sys" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcce6f1e0fc7715d651dba29875741509f5fc12f4e2976907272a74405f2b01" -dependencies = [ - "atk-sys", - "bitflags", - "cairo-sys-rs", - "gdk-pixbuf-sys", - "gdk-sys", - "gio-sys 0.15.6", - "glib-sys 0.15.6", - "gobject-sys 0.15.5", - "gtk-sys", - "javascriptcore-rs-sys", - "libc", - "pango-sys", - "pkg-config", - "soup2-sys", - "system-deps 5.0.0", -] - -[[package]] -name = "webview2-com" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb8e90ac2d9ce39cdb70017aaec641be09fbdd702b7b332b9896d053eb469524" -dependencies = [ - "webview2-com-macros", - "webview2-com-sys", - "windows 0.30.0", - "windows_macros", -] - -[[package]] -name = "webview2-com-macros" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1515c6c82fcee93f6edaacc72c8e233dbe4ff3ca569dce1901dfc36c404a3e99" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "webview2-com-sys" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92160310b3322397e4ff8a8285a7429d73a07a68fda44ee80879605b93e53f76" -dependencies = [ - "regex", - "serde", - "serde_json", - "thiserror", - "windows 0.30.0", - "windows-bindgen", -] - -[[package]] -name = "wepoll-ffi" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" -dependencies = [ - "cc", -] - -[[package]] -name = "wildmatch" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6c48bd20df7e4ced539c12f570f937c6b4884928a87fee70a479d72f031d4e0" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9f39345ae0c8ab072c0ac7fe8a8b411636aa34f89be19ddd0d9226544f13944" -dependencies = [ - "windows_i686_gnu 0.24.0", - "windows_i686_msvc 0.24.0", - "windows_x86_64_gnu 0.24.0", - "windows_x86_64_msvc 0.24.0", -] - -[[package]] -name = "windows" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b749ebd2304aa012c5992d11a25d07b406bdbe5f79d371cb7a918ce501a19eb0" -dependencies = [ - "windows_aarch64_msvc", - "windows_i686_gnu 0.30.0", - "windows_i686_msvc 0.30.0", - "windows_x86_64_gnu 0.30.0", - "windows_x86_64_msvc 0.30.0", -] - -[[package]] -name = "windows-bindgen" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944c545fcae9dd66488308f8b69aa3ba34f53714416ecfcdcbbfa4b6821e27c6" -dependencies = [ - "windows_quote", - "windows_reader", -] - -[[package]] -name = "windows_aarch64_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29277a4435d642f775f63c7d1faeb927adba532886ce0287bd985bffb16b6bca" - -[[package]] -name = "windows_gen" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30dff4d91d22520628bb94b66f2bb313cb16a09a515a32320a84a1b449bc94c0" -dependencies = [ - "windows_quote", - "windows_reader", -] - -[[package]] -name = "windows_i686_gnu" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0866510a3eca9aed73a077490bbbf03e5eaac4e1fd70849d89539e5830501fd" - -[[package]] -name = "windows_i686_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145e1989da93956c68d1864f32fb97c8f561a8f89a5125f6a2b7ea75524e4b8" - -[[package]] -name = "windows_i686_msvc" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf0ffed56b7e9369a29078d2ab3aaeceea48eb58999d2cff3aa2494a275b95c6" - -[[package]] -name = "windows_i686_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a09e3a0d4753b73019db171c1339cd4362c8c44baf1bcea336235e955954a6" - -[[package]] -name = "windows_macros" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62ae44ab917e9005fe710d99d52d227ca0164b10a09be90649142cc3fab825d3" -dependencies = [ - "syn", - "windows_gen", - "windows_quote", - "windows_reader", -] - -[[package]] -name = "windows_quote" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71f02c51a77e6248c1206aaa920802c32d50a05205e229b118d7f3afd3036667" - -[[package]] -name = "windows_reader" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44e6df0da993cda589c5ac852272fbb2a0ead67a031a017dd3eac11528a2d72" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "384a173630588044205a2993b6864a2f56e5a8c1e7668c07b93ec18cf4888dc4" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca64fcb0220d58db4c119e050e7af03c69e6f4f415ef69ec1773d9aab422d5a" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bd8f062d8ca5446358159d79a90be12c543b3a965c847c8f3eedf14b321d399" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08cabc9f0066848fef4bc6a1c1668e6efce38b661d2aeec75d18d8617eebb5f1" - -[[package]] -name = "winres" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" -dependencies = [ - "toml", -] - -[[package]] -name = "winrt-notification" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "007a0353840b23e0c6dc73e5b962ff58ed7f6bc9ceff3ce7fe6fbad8d496edf4" -dependencies = [ - "strum 0.22.0", - "windows 0.24.0", - "xml-rs", -] - -[[package]] -name = "wry" -version = "0.13.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9514586e5c964d30cc7123c9aea9880ff7b3cb1c43f6a1dc8703941eb72ac89f" -dependencies = [ - "cocoa", - "core-graphics", - "gdk", - "gio", - "glib", - "gtk", - "http", - "libc", - "log", - "objc", - "objc_id", - "once_cell", - "serde", - "serde_json", - "tao", - "thiserror", - "url", - "webkit2gtk", - "webkit2gtk-sys", - "webview2-com", - "windows 0.30.0", - "windows_macros", -] - -[[package]] -name = "x11" -version = "2.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a" -dependencies = [ - "libc", - "pkg-config", -] - -[[package]] -name = "x11-dl" -version = "2.19.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea26926b4ce81a6f5d9d0f3a0bc401e5a37c6ae14a1bfaa8ff6099ca80038c59" -dependencies = [ - "lazy_static", - "libc", - "pkg-config", -] - -[[package]] -name = "xattr" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" -dependencies = [ - "libc", -] - -[[package]] -name = "xml-rs" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d7d3948613f75c98fd9328cfdcc45acc4d360655289d0a7d4ec931392200a3" - -[[package]] -name = "zbus" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb86f3d4592e26a48b2719742aec94f8ae6238ebde20d98183ee185d1275e9a" -dependencies = [ - "async-broadcast", - "async-channel", - "async-executor", - "async-io", - "async-lock", - "async-recursion", - "async-task", - "async-trait", - "byteorder", - "derivative", - "enumflags2", - "event-listener", - "futures-core", - "futures-sink", - "futures-util", - "hex", - "lazy_static", - "nix", - "once_cell", - "ordered-stream", - "rand 0.8.5", - "serde", - "serde_repr", - "sha1", - "static_assertions", - "winapi", - "zbus_macros", - "zbus_names", - "zvariant", -] - -[[package]] -name = "zbus_macros" -version = "2.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36823cc10fddc3c6b19f048903262dacaf8274170e9a255784bdd8b4570a8040" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "regex", - "syn", -] - -[[package]] -name = "zbus_names" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45dfcdcf87b71dad505d30cc27b1b7b88a64b6d1c435648f48f9dbc1fdc4b7e1" -dependencies = [ - "serde", - "static_assertions", - "zvariant", -] - -[[package]] -name = "zip" -version = "0.5.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ab48844d61251bb3835145c521d88aa4031d7139e8485990f60ca911fa0815" -dependencies = [ - "byteorder", - "crc32fast", - "thiserror", -] - -[[package]] -name = "zstd" -version = "0.10.0+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" -dependencies = [ - "zstd-safe", -] - -[[package]] -name = "zstd-safe" -version = "4.1.4+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" -dependencies = [ - "libc", - "zstd-sys", -] - -[[package]] -name = "zstd-sys" -version = "1.6.3+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "zvariant" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ea5dc38b2058fae6a5b79009388143dadce1e91c26a67f984a0fc0381c8033" -dependencies = [ - "byteorder", - "enumflags2", - "libc", - "serde", - "static_assertions", - "zvariant_derive", -] - -[[package]] -name = "zvariant_derive" -version = "3.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c2cecc5a61c2a053f7f653a24cd15b3b0195d7f7ddb5042c837fb32e161fb7a" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn", -] diff --git a/examples/api/src-tauri/Cargo.toml b/examples/api/src-tauri/Cargo.toml index 35842a1e626e..a0d8fadc7482 100644 --- a/examples/api/src-tauri/Cargo.toml +++ b/examples/api/src-tauri/Cargo.toml @@ -3,25 +3,41 @@ name = "api" version = "0.1.0" description = "An example Tauri Application showcasing the api" edition = "2021" -rust-version = "1.57" +rust-version = "1.77.2" license = "Apache-2.0 OR MIT" +[lib] +name = "api_lib" +crate-type = ["staticlib", "cdylib", "rlib"] + [build-dependencies] -tauri-build = { path = "../../../core/tauri-build", features = ["isolation"] } +tauri-build = { path = "../../../crates/tauri-build", features = [ + "codegen", + "isolation", +] } [dependencies] serde_json = "1.0" -serde = { version = "1.0", features = [ "derive" ] } -tauri = { path = "../../../core/tauri", features = ["api-all", "cli", "icon-ico", "icon-png", "isolation", "macos-private-api", "system-tray", "updater"] } +serde = { version = "1.0", features = ["derive"] } +tiny_http = "0.11" +log = "0.4" +tauri-plugin-sample = { path = "./tauri-plugin-sample/" } +tauri-plugin-log = "2.0.0-rc" -[features] -default = [ "custom-protocol" ] -custom-protocol = [ "tauri/custom-protocol" ] +[dependencies.tauri] +path = "../../../crates/tauri" +features = [ + "protocol-asset", + "image-ico", + "image-png", + "isolation", + "macos-private-api", + "tray-icon", +] -# default to small, optimized release binaries -[profile.release] -panic = "abort" -codegen-units = 1 -lto = true -incremental = false -opt-level = "s" +[dev-dependencies.tauri] +path = "../../../crates/tauri" +features = ["test"] + +[features] +prod = ["tauri/custom-protocol"] diff --git a/examples/api/src-tauri/Cross.toml b/examples/api/src-tauri/Cross.toml new file mode 100644 index 000000000000..2b237981c9ee --- /dev/null +++ b/examples/api/src-tauri/Cross.toml @@ -0,0 +1,17 @@ +[build.env] +# must set ICONS_VOLUME, DIST_VOLUME, ISOLATION_VOLUME and WORKSPACE_VOLUME environment variables +# ICONS_VOLUME: absolute path to the .icons folder +# DIST_VOLUME: absolute path to the dist folder +# ISOLATION_VOLUME: absolute path to the isolation dist folder +# WORKSPACE_VOLUME: absolute path to the workspace +# this can be done running `$ . .setup-cross.sh` in the examples/api folder +volumes = [ + "ICONS_VOLUME", + "DIST_VOLUME", + "ISOLATION_VOLUME", + "WORKSPACE_VOLUME", +] + +[target.aarch64-unknown-linux-gnu] +image = "aarch64-unknown-linux-gnu:latest" +#image = "ghcr.io/tauri-apps/tauri/aarch64-unknown-linux-gnu:latest" diff --git a/examples/api/src-tauri/build.rs b/examples/api/src-tauri/build.rs index 017a75d00194..b874ad414257 100644 --- a/examples/api/src-tauri/build.rs +++ b/examples/api/src-tauri/build.rs @@ -1,14 +1,51 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use tauri_build::{try_build, Attributes, WindowsAttributes}; +use tauri_build::WindowsAttributes; fn main() { - if let Err(error) = try_build( - Attributes::new() - .windows_attributes(WindowsAttributes::new().window_icon_path("../../.icons/icon.ico")), - ) { - panic!("error found during tauri-build: {:#?}", error); + tauri_build::try_build( + tauri_build::Attributes::new() + .codegen(tauri_build::CodegenContext::new()) + .windows_attributes(WindowsAttributes::new_without_app_manifest()) + .plugin( + "app-menu", + tauri_build::InlinedPlugin::new().commands(&["toggle", "popup"]), + ) + .app_manifest(tauri_build::AppManifest::new().commands(&[ + "log_operation", + "perform_request", + "echo", + ])), + ) + .expect("failed to run tauri-build"); + + // workaround needed to prevent `STATUS_ENTRYPOINT_NOT_FOUND` error in tests + // see https://github.com/tauri-apps/tauri/pull/4383#issuecomment-1212221864 + let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap(); + let target_env = std::env::var("CARGO_CFG_TARGET_ENV"); + let is_tauri_workspace = std::env::var("__TAURI_WORKSPACE__").map_or(false, |v| v == "true"); + if is_tauri_workspace && target_os == "windows" && Ok("msvc") == target_env.as_deref() { + embed_manifest_for_tests(); } } + +fn embed_manifest_for_tests() { + static WINDOWS_MANIFEST_FILE: &str = "windows-app-manifest.xml"; + + let manifest = std::env::current_dir() + .unwrap() + .join("../../../crates/tauri-build/src") + .join(WINDOWS_MANIFEST_FILE); + + println!("cargo:rerun-if-changed={}", manifest.display()); + // Embed the Windows application manifest file. + println!("cargo:rustc-link-arg=/MANIFEST:EMBED"); + println!( + "cargo:rustc-link-arg=/MANIFESTINPUT:{}", + manifest.to_str().unwrap() + ); + // Turn linker warnings into errors. + println!("cargo:rustc-link-arg=/WX"); +} diff --git a/examples/api/src-tauri/capabilities/.gitignore b/examples/api/src-tauri/capabilities/.gitignore new file mode 100644 index 000000000000..c75f615b12f1 --- /dev/null +++ b/examples/api/src-tauri/capabilities/.gitignore @@ -0,0 +1 @@ +schemas/ diff --git a/examples/api/src-tauri/capabilities/main.json b/examples/api/src-tauri/capabilities/main.json new file mode 100644 index 000000000000..21f8d1f9b630 --- /dev/null +++ b/examples/api/src-tauri/capabilities/main.json @@ -0,0 +1,16 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "secondary-window", + "description": "capability for secondary window", + "windows": ["main-*"], + "permissions": [ + { + "identifier": "sample:allow-ping", + "deny": [ + { + "path": "tauri.app" + } + ] + } + ] +} diff --git a/examples/api/src-tauri/capabilities/run-app.json b/examples/api/src-tauri/capabilities/run-app.json new file mode 100644 index 000000000000..7a93931b52a2 --- /dev/null +++ b/examples/api/src-tauri/capabilities/run-app.json @@ -0,0 +1,66 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "run-app", + "description": "permissions to run the app", + "windows": ["main", "main-*"], + "permissions": [ + "core:window:allow-is-enabled", + "core:window:allow-set-enabled", + { + "identifier": "allow-log-operation", + "allow": [ + { + "event": "tauri-click" + } + ] + }, + "allow-perform-request", + "allow-echo", + "app-menu:default", + "sample:allow-ping-scoped", + "sample:global-scope", + "core:default", + "core:app:allow-app-hide", + "core:app:allow-app-show", + "core:app:allow-set-app-theme", + "core:window:allow-set-theme", + "core:window:allow-center", + "core:window:allow-request-user-attention", + "core:window:allow-set-resizable", + "core:window:allow-set-maximizable", + "core:window:allow-set-minimizable", + "core:window:allow-set-closable", + "core:window:allow-set-title", + "core:window:allow-maximize", + "core:window:allow-unmaximize", + "core:window:allow-minimize", + "core:window:allow-unminimize", + "core:window:allow-show", + "core:window:allow-hide", + "core:window:allow-close", + "core:window:allow-set-decorations", + "core:window:allow-set-shadow", + "core:window:allow-set-effects", + "core:window:allow-set-always-on-top", + "core:window:allow-set-always-on-bottom", + "core:window:allow-set-content-protected", + "core:window:allow-set-size", + "core:window:allow-set-min-size", + "core:window:allow-set-max-size", + "core:window:allow-set-position", + "core:window:allow-set-fullscreen", + "core:window:allow-set-focus", + "core:window:allow-set-skip-taskbar", + "core:window:allow-set-cursor-grab", + "core:window:allow-set-cursor-visible", + "core:window:allow-set-cursor-icon", + "core:window:allow-set-cursor-position", + "core:window:allow-set-ignore-cursor-events", + "core:window:allow-start-dragging", + "core:window:allow-set-progress-bar", + "core:window:allow-set-icon", + "core:window:allow-toggle-maximize", + "core:webview:allow-create-webview-window", + "core:webview:allow-print" + ] +} diff --git a/examples/api/src-tauri/permissions/app-menu/default.toml b/examples/api/src-tauri/permissions/app-menu/default.toml new file mode 100644 index 000000000000..b17fbd19a85c --- /dev/null +++ b/examples/api/src-tauri/permissions/app-menu/default.toml @@ -0,0 +1,3 @@ +[default] +description = "Default permissions for the plugin" +permissions = ["allow-toggle", "allow-popup"] diff --git a/examples/api/src-tauri/permissions/autogenerated/echo.toml b/examples/api/src-tauri/permissions/autogenerated/echo.toml new file mode 100644 index 000000000000..d8c458ee874c --- /dev/null +++ b/examples/api/src-tauri/permissions/autogenerated/echo.toml @@ -0,0 +1,11 @@ +# Automatically generated - DO NOT EDIT! + +[[permission]] +identifier = "allow-echo" +description = "Enables the echo command without any pre-configured scope." +commands.allow = ["echo"] + +[[permission]] +identifier = "deny-echo" +description = "Denies the echo command without any pre-configured scope." +commands.deny = ["echo"] diff --git a/examples/api/src-tauri/permissions/autogenerated/log_operation.toml b/examples/api/src-tauri/permissions/autogenerated/log_operation.toml new file mode 100644 index 000000000000..a1e88b5958ea --- /dev/null +++ b/examples/api/src-tauri/permissions/autogenerated/log_operation.toml @@ -0,0 +1,11 @@ +# Automatically generated - DO NOT EDIT! + +[[permission]] +identifier = "allow-log-operation" +description = "Enables the log_operation command without any pre-configured scope." +commands.allow = ["log_operation"] + +[[permission]] +identifier = "deny-log-operation" +description = "Denies the log_operation command without any pre-configured scope." +commands.deny = ["log_operation"] diff --git a/examples/api/src-tauri/permissions/autogenerated/perform_request.toml b/examples/api/src-tauri/permissions/autogenerated/perform_request.toml new file mode 100644 index 000000000000..0d12b9d1c6bb --- /dev/null +++ b/examples/api/src-tauri/permissions/autogenerated/perform_request.toml @@ -0,0 +1,11 @@ +# Automatically generated - DO NOT EDIT! + +[[permission]] +identifier = "allow-perform-request" +description = "Enables the perform_request command without any pre-configured scope." +commands.allow = ["perform_request"] + +[[permission]] +identifier = "deny-perform-request" +description = "Denies the perform_request command without any pre-configured scope." +commands.deny = ["perform_request"] diff --git a/examples/api/src-tauri/src/cmd.rs b/examples/api/src-tauri/src/cmd.rs index 525246f3283b..80ae03d106d4 100644 --- a/examples/api/src-tauri/src/cmd.rs +++ b/examples/api/src-tauri/src/cmd.rs @@ -1,24 +1,52 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use serde::Deserialize; -use tauri::command; +use serde::{Deserialize, Serialize}; +use tauri::{command, ipc::CommandScope}; #[derive(Debug, Deserialize)] -#[allow(dead_code)] +#[allow(unused)] pub struct RequestBody { id: i32, name: String, } +#[derive(Debug, Deserialize)] +pub struct LogScope { + event: String, +} + #[command] -pub fn log_operation(event: String, payload: Option) { - println!("{} {:?}", event, payload); +pub fn log_operation( + event: String, + payload: Option, + command_scope: CommandScope, +) -> Result<(), &'static str> { + if command_scope.denies().iter().any(|s| s.event == event) { + Err("denied") + } else if !command_scope.allows().iter().any(|s| s.event == event) { + Err("not allowed") + } else { + log::info!("{} {:?}", event, payload); + Ok(()) + } +} + +#[derive(Serialize)] +pub struct ApiResponse { + message: String, } #[command] -pub fn perform_request(endpoint: String, body: RequestBody) -> String { +pub fn perform_request(endpoint: String, body: RequestBody) -> ApiResponse { println!("{} {:?}", endpoint, body); - "message response".into() + ApiResponse { + message: "message response".into(), + } +} + +#[command] +pub fn echo(request: tauri::ipc::Request<'_>) -> tauri::ipc::Response { + tauri::ipc::Response::new(request.body().clone()) } diff --git a/examples/api/src-tauri/src/lib.rs b/examples/api/src-tauri/src/lib.rs new file mode 100644 index 000000000000..512f43c0aac0 --- /dev/null +++ b/examples/api/src-tauri/src/lib.rs @@ -0,0 +1,201 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +mod cmd; +#[cfg(desktop)] +mod menu_plugin; +#[cfg(desktop)] +mod tray; + +use serde::Serialize; +use tauri::{ + ipc::Channel, + webview::{PageLoadEvent, WebviewWindowBuilder}, + App, Emitter, Listener, Runtime, WebviewUrl, +}; +#[allow(unused)] +use tauri::{Manager, RunEvent}; +use tauri_plugin_sample::{PingRequest, SampleExt}; + +#[derive(Clone, Serialize)] +struct Reply { + data: String, +} + +#[cfg(target_os = "macos")] +pub struct AppMenu(pub std::sync::Mutex>>); + +#[cfg(all(desktop, not(test)))] +pub struct PopupMenu(tauri::menu::Menu); + +#[cfg_attr(mobile, tauri::mobile_entry_point)] +pub fn run() { + run_app(tauri::Builder::default(), |_app| {}) +} + +pub fn run_app) + Send + 'static>( + builder: tauri::Builder, + setup: F, +) { + #[allow(unused_mut)] + let mut builder = builder + .plugin( + tauri_plugin_log::Builder::default() + .level(log::LevelFilter::Info) + .build(), + ) + .plugin(tauri_plugin_sample::init()) + .setup(move |app| { + #[cfg(all(desktop, not(test)))] + { + let handle = app.handle(); + tray::create_tray(handle)?; + handle.plugin(menu_plugin::init())?; + } + + #[cfg(target_os = "macos")] + app.manage(AppMenu::(Default::default())); + + #[cfg(all(desktop, not(test)))] + app.manage(PopupMenu( + tauri::menu::MenuBuilder::new(app) + .check("check", "Tauri is awesome!") + .text("text", "Do something") + .copy() + .build()?, + )); + + let mut window_builder = WebviewWindowBuilder::new(app, "main", WebviewUrl::default()); + + #[cfg(all(desktop, not(test)))] + { + window_builder = window_builder + .title("Tauri API Validation") + .inner_size(1000., 800.) + .min_inner_size(600., 400.) + .menu(tauri::menu::Menu::default(app.handle())?); + } + + let webview = window_builder.build()?; + + #[cfg(debug_assertions)] + webview.open_devtools(); + + let value = Some("test".to_string()); + let response = app.sample().ping(PingRequest { + value: value.clone(), + on_event: Channel::new(|event| { + println!("got channel event: {:?}", event); + Ok(()) + }), + }); + log::info!("got response: {:?}", response); + if let Ok(res) = response { + assert_eq!(res.value, value); + } + + #[cfg(desktop)] + std::thread::spawn(|| { + let server = match tiny_http::Server::http("localhost:3003") { + Ok(s) => s, + Err(e) => { + eprintln!("{}", e); + std::process::exit(1); + } + }; + loop { + if let Ok(mut request) = server.recv() { + let mut body = Vec::new(); + let _ = request.as_reader().read_to_end(&mut body); + let response = tiny_http::Response::new( + tiny_http::StatusCode(200), + request.headers().to_vec(), + std::io::Cursor::new(body), + request.body_length(), + None, + ); + let _ = request.respond(response); + } + } + }); + + setup(app); + + Ok(()) + }) + .on_page_load(|webview, payload| { + if payload.event() == PageLoadEvent::Finished { + let webview_ = webview.clone(); + webview.listen("js-event", move |event| { + println!("got js-event with message '{:?}'", event.payload()); + let reply = Reply { + data: "something else".to_string(), + }; + + webview_ + .emit("rust-event", Some(reply)) + .expect("failed to emit"); + }); + } + }); + + #[allow(unused_mut)] + let mut app = builder + .invoke_handler(tauri::generate_handler![ + cmd::log_operation, + cmd::perform_request, + cmd::echo + ]) + .build(tauri::tauri_build_context!()) + .expect("error while building tauri application"); + + #[cfg(target_os = "macos")] + app.set_activation_policy(tauri::ActivationPolicy::Regular); + + app.run(move |_app_handle, _event| { + #[cfg(all(desktop, not(test)))] + match &_event { + RunEvent::ExitRequested { api, code, .. } => { + // Keep the event loop running even if all windows are closed + // This allow us to catch tray icon events when there is no window + // if we manually requested an exit (code is Some(_)) we will let it go through + if code.is_none() { + api.prevent_exit(); + } + } + RunEvent::WindowEvent { + event: tauri::WindowEvent::CloseRequested { api, .. }, + label, + .. + } => { + println!("closing window..."); + // run the window destroy manually just for fun :) + // usually you'd show a dialog here to ask for confirmation or whatever + api.prevent_close(); + _app_handle + .get_webview_window(label) + .unwrap() + .destroy() + .unwrap(); + } + _ => (), + } + }) +} + +#[cfg(test)] +mod tests { + use tauri::Manager; + + #[test] + fn run_app() { + super::run_app(tauri::test::mock_builder(), |app| { + let window = app.get_webview_window("main").unwrap(); + std::thread::spawn(move || { + std::thread::sleep(std::time::Duration::from_secs(1)); + window.close().unwrap(); + }); + }) + } +} diff --git a/examples/api/src-tauri/src/main.rs b/examples/api/src-tauri/src/main.rs index f21f415dd364..12e1627af079 100644 --- a/examples/api/src-tauri/src/main.rs +++ b/examples/api/src-tauri/src/main.rs @@ -1,258 +1,10 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -#![cfg_attr( - all(not(debug_assertions), target_os = "windows"), - windows_subsystem = "windows" -)] - -mod cmd; -mod menu; - -#[cfg(target_os = "linux")] -use std::path::PathBuf; -use std::sync::atomic::{AtomicBool, Ordering}; - -use serde::{Deserialize, Serialize}; -use tauri::{ - api::dialog::ask, http::ResponseBuilder, window::WindowBuilder, CustomMenuItem, - GlobalShortcutManager, Manager, RunEvent, SystemTray, SystemTrayEvent, SystemTrayMenu, WindowUrl, -}; - -#[derive(Clone, Serialize)] -struct Reply { - data: String, -} - -#[derive(Serialize, Deserialize)] -struct HttpPost { - foo: String, - bar: String, -} - -#[derive(Serialize)] -struct HttpReply { - msg: String, - request: HttpPost, -} - -#[tauri::command] -async fn menu_toggle(window: tauri::Window) { - window.menu_handle().toggle().unwrap(); -} +// Prevents additional console window on Windows in release, DO NOT REMOVE!! +#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { - let tray_menu1 = SystemTrayMenu::new() - .add_item(CustomMenuItem::new("toggle", "Toggle")) - .add_item(CustomMenuItem::new("new", "New window")) - .add_item(CustomMenuItem::new("icon_1", "Tray Icon 1")) - .add_item(CustomMenuItem::new("icon_2", "Tray Icon 2")) - .add_item(CustomMenuItem::new("switch_menu", "Switch Menu")) - .add_item(CustomMenuItem::new("exit_app", "Quit")); - let tray_menu2 = SystemTrayMenu::new() - .add_item(CustomMenuItem::new("toggle", "Toggle")) - .add_item(CustomMenuItem::new("new", "New window")) - .add_item(CustomMenuItem::new("switch_menu", "Switch Menu")) - .add_item(CustomMenuItem::new("exit_app", "Quit")); - let is_menu1 = AtomicBool::new(true); - - #[allow(unused_mut)] - let mut app = tauri::Builder::default() - .setup(|app| { - #[cfg(debug_assertions)] - app.get_window("main").unwrap().open_devtools(); - Ok(()) - }) - .on_page_load(|window, _| { - let window_ = window.clone(); - window.listen("js-event", move |event| { - println!("got js-event with message '{:?}'", event.payload()); - let reply = Reply { - data: "something else".to_string(), - }; - - window_ - .emit("rust-event", Some(reply)) - .expect("failed to emit"); - }); - }) - .register_uri_scheme_protocol("customprotocol", move |_app_handle, request| { - if request.method() == "POST" { - let request: HttpPost = serde_json::from_slice(request.body()).unwrap(); - return ResponseBuilder::new() - .mimetype("application/json") - .header("Access-Control-Allow-Origin", "*") - .status(200) - .body(serde_json::to_vec(&HttpReply { - request, - msg: "Hello from rust!".to_string(), - })?); - } - - ResponseBuilder::new() - .mimetype("text/html") - .status(404) - .body(Vec::new()) - }) - .menu(menu::get_menu()) - .on_menu_event(|event| { - println!("{:?}", event.menu_item_id()); - }) - .system_tray(SystemTray::new().with_menu(tray_menu1.clone())) - .on_system_tray_event(move |app, event| match event { - SystemTrayEvent::LeftClick { - position: _, - size: _, - .. - } => { - let window = app.get_window("main").unwrap(); - window.show().unwrap(); - window.set_focus().unwrap(); - } - SystemTrayEvent::MenuItemClick { id, .. } => { - let item_handle = app.tray_handle().get_item(&id); - match id.as_str() { - "exit_app" => { - // exit the app - app.exit(0); - } - "toggle" => { - let window = app.get_window("main").unwrap(); - let new_title = if window.is_visible().unwrap() { - window.hide().unwrap(); - "Show" - } else { - window.show().unwrap(); - "Hide" - }; - item_handle.set_title(new_title).unwrap(); - } - "new" => { - WindowBuilder::new(app, "new", WindowUrl::App("index.html".into())) - .title("Tauri") - .build() - .unwrap(); - } - #[cfg(target_os = "macos")] - "icon_1" => { - app.tray_handle().set_icon_as_template(true).unwrap(); - - app - .tray_handle() - .set_icon(tauri::TrayIcon::Raw( - include_bytes!("../../../.icons/tray_icon_with_transparency.png").to_vec(), - )) - .unwrap(); - } - #[cfg(target_os = "macos")] - "icon_2" => { - app.tray_handle().set_icon_as_template(true).unwrap(); - - app - .tray_handle() - .set_icon(tauri::TrayIcon::Raw( - include_bytes!("../../../.icons/tray_icon_with_transparency.png").to_vec(), - )) - .unwrap(); - } - #[cfg(target_os = "linux")] - "icon_1" => app - .tray_handle() - .set_icon(tauri::TrayIcon::File(PathBuf::from( - "../../../.icons/tray_icon_with_transparency.png", - ))) - .unwrap(), - #[cfg(target_os = "linux")] - "icon_2" => app - .tray_handle() - .set_icon(tauri::TrayIcon::File(PathBuf::from( - "../../../.icons/tray_icon.png", - ))) - .unwrap(), - #[cfg(target_os = "windows")] - "icon_1" => app - .tray_handle() - .set_icon(tauri::TrayIcon::Raw( - include_bytes!("../../../.icons/tray_icon_with_transparency.ico").to_vec(), - )) - .unwrap(), - #[cfg(target_os = "windows")] - "icon_2" => app - .tray_handle() - .set_icon(tauri::TrayIcon::Raw( - include_bytes!("../../../.icons/icon.ico").to_vec(), - )) - .unwrap(), - "switch_menu" => { - let flag = is_menu1.load(Ordering::Relaxed); - app - .tray_handle() - .set_menu(if flag { - tray_menu2.clone() - } else { - tray_menu1.clone() - }) - .unwrap(); - is_menu1.store(!flag, Ordering::Relaxed); - } - _ => {} - } - } - _ => {} - }) - .invoke_handler(tauri::generate_handler![ - cmd::log_operation, - cmd::perform_request, - menu_toggle, - ]) - .build(tauri::generate_context!()) - .expect("error while building tauri application"); - - #[cfg(target_os = "macos")] - app.set_activation_policy(tauri::ActivationPolicy::Regular); - - app.run(|app_handle, e| match e { - // Application is ready (triggered only once) - RunEvent::Ready => { - let app_handle = app_handle.clone(); - app_handle - .global_shortcut_manager() - .register("CmdOrCtrl+1", move || { - let app_handle = app_handle.clone(); - let window = app_handle.get_window("main").unwrap(); - window.set_title("New title!").unwrap(); - }) - .unwrap(); - } - - // Triggered when a window is trying to close - RunEvent::CloseRequested { label, api, .. } => { - let app_handle = app_handle.clone(); - let window = app_handle.get_window(&label).unwrap(); - // use the exposed close api, and prevent the event loop to close - api.prevent_close(); - // ask the user if he wants to quit - ask( - Some(&window), - "Tauri API", - "Are you sure that you want to close this window?", - move |answer| { - if answer { - // .close() cannot be called on the main thread - std::thread::spawn(move || { - app_handle.get_window(&label).unwrap().close().unwrap(); - }); - } - }, - ); - } - - // Keep the event loop running even if all windows are closed - // This allow us to catch system tray events when there is no window - RunEvent::ExitRequested { api, .. } => { - api.prevent_exit(); - } - _ => {} - }) + api_lib::run(); } diff --git a/examples/api/src-tauri/src/menu.rs b/examples/api/src-tauri/src/menu.rs deleted file mode 100644 index 026f3b7a470c..000000000000 --- a/examples/api/src-tauri/src/menu.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2019-2021 Tauri Programme within The Commons Conservancy -// SPDX-License-Identifier: Apache-2.0 -// SPDX-License-Identifier: MIT - -use tauri::{CustomMenuItem, Menu, MenuItem, Submenu}; - -pub fn get_menu() -> Menu { - #[allow(unused_mut)] - let mut disable_item = - CustomMenuItem::new("disable-menu", "Disable menu").accelerator("CmdOrControl+D"); - #[allow(unused_mut)] - let mut test_item = CustomMenuItem::new("test", "Test").accelerator("CmdOrControl+T"); - #[cfg(target_os = "macos")] - { - disable_item = disable_item.native_image(tauri::NativeImage::MenuOnState); - test_item = test_item.native_image(tauri::NativeImage::Add); - } - - // create a submenu - let my_sub_menu = Menu::with_items([disable_item.into()]); - - let my_app_menu = Menu::new() - .add_native_item(MenuItem::Copy) - .add_submenu(Submenu::new("Sub menu", my_sub_menu)); - - let test_menu = Menu::new() - .add_item(CustomMenuItem::new( - "selected/disabled", - "Selected and disabled", - )) - .add_native_item(MenuItem::Separator) - .add_item(test_item); - - // add all our childs to the menu (order is how they'll appear) - Menu::new() - .add_submenu(Submenu::new("My app", my_app_menu)) - .add_submenu(Submenu::new("Other menu", test_menu)) -} diff --git a/examples/api/src-tauri/src/menu_plugin.rs b/examples/api/src-tauri/src/menu_plugin.rs new file mode 100644 index 000000000000..b4bbe3989033 --- /dev/null +++ b/examples/api/src-tauri/src/menu_plugin.rs @@ -0,0 +1,49 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT +#![cfg(all(desktop, not(test)))] + +use tauri::{ + command, + plugin::{Builder, TauriPlugin}, + Runtime, +}; + +#[cfg(not(target_os = "macos"))] +#[command] +pub fn toggle(window: tauri::Window) { + if window.is_menu_visible().unwrap_or_default() { + let _ = window.hide_menu(); + } else { + let _ = window.show_menu(); + } +} + +#[cfg(target_os = "macos")] +#[command] +pub fn toggle( + app: tauri::AppHandle, + app_menu: tauri::State<'_, crate::AppMenu>, +) { + if let Some(menu) = app.remove_menu().unwrap() { + app_menu.0.lock().unwrap().replace(menu); + } else { + app + .set_menu(app_menu.0.lock().unwrap().clone().expect("no app menu")) + .unwrap(); + } +} + +#[command] +pub fn popup( + window: tauri::Window, + popup_menu: tauri::State<'_, crate::PopupMenu>, +) { + window.popup_menu(&popup_menu.0).unwrap(); +} + +pub fn init() -> TauriPlugin { + Builder::new("app-menu") + .invoke_handler(tauri::generate_handler![popup, toggle]) + .build() +} diff --git a/examples/api/src-tauri/src/tray.rs b/examples/api/src-tauri/src/tray.rs new file mode 100644 index 000000000000..963e215b7a48 --- /dev/null +++ b/examples/api/src-tauri/src/tray.rs @@ -0,0 +1,128 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#![cfg(all(desktop, not(test)))] + +use std::sync::atomic::{AtomicBool, Ordering}; +use tauri::{ + include_image, + menu::{Menu, MenuItem}, + tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}, + Manager, Runtime, WebviewUrl, +}; + +pub fn create_tray(app: &tauri::AppHandle) -> tauri::Result<()> { + let toggle_i = MenuItem::with_id(app, "toggle", "Toggle", true, None::<&str>)?; + let new_window_i = MenuItem::with_id(app, "new-window", "New window", true, None::<&str>)?; + let icon_i_1 = MenuItem::with_id(app, "icon-1", "Icon 1", true, None::<&str>)?; + let icon_i_2 = MenuItem::with_id(app, "icon-2", "Icon 2", true, None::<&str>)?; + #[cfg(target_os = "macos")] + let set_title_i = MenuItem::with_id(app, "set-title", "Set Title", true, None::<&str>)?; + let switch_i = MenuItem::with_id(app, "switch-menu", "Switch Menu", true, None::<&str>)?; + let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None::<&str>)?; + let remove_tray_i = + MenuItem::with_id(app, "remove-tray", "Remove Tray icon", true, None::<&str>)?; + let menu1 = Menu::with_items( + app, + &[ + &toggle_i, + &new_window_i, + &icon_i_1, + &icon_i_2, + #[cfg(target_os = "macos")] + &set_title_i, + &switch_i, + &quit_i, + &remove_tray_i, + ], + )?; + let menu2 = Menu::with_items( + app, + &[&toggle_i, &new_window_i, &switch_i, &quit_i, &remove_tray_i], + )?; + + let is_menu1 = AtomicBool::new(true); + + let _ = TrayIconBuilder::with_id("tray-1") + .tooltip("Tauri") + .icon(app.default_window_icon().unwrap().clone()) + .menu(&menu1) + .show_menu_on_left_click(false) + .on_menu_event(move |app, event| match event.id.as_ref() { + "quit" => { + app.exit(0); + } + "remove-tray" => { + app.remove_tray_by_id("tray-1"); + } + "toggle" => { + if let Some(window) = app.get_webview_window("main") { + let new_title = if window.is_visible().unwrap_or_default() { + let _ = window.hide(); + "Show" + } else { + let _ = window.show(); + let _ = window.set_focus(); + "Hide" + }; + toggle_i.set_text(new_title).unwrap(); + } + } + "new-window" => { + let _webview = + tauri::WebviewWindowBuilder::new(app, "new", WebviewUrl::App("index.html".into())) + .title("Tauri") + .build() + .unwrap(); + } + #[cfg(target_os = "macos")] + "set-title" => { + if let Some(tray) = app.tray_by_id("tray-1") { + let _ = tray.set_title(Some("Tauri")); + } + } + i @ "icon-1" | i @ "icon-2" => { + if let Some(tray) = app.tray_by_id("tray-1") { + let icon = if i == "icon-1" { + include_image!("../../.icons/icon.ico") + } else { + include_image!("../../.icons/tray_icon_with_transparency.png") + }; + let _ = tray.set_icon(Some(icon)); + } + } + "switch-menu" => { + let flag = is_menu1.load(Ordering::Relaxed); + let (menu, tooltip) = if flag { + (menu2.clone(), "Menu 2") + } else { + (menu1.clone(), "Tauri") + }; + if let Some(tray) = app.tray_by_id("tray-1") { + let _ = tray.set_menu(Some(menu)); + let _ = tray.set_tooltip(Some(tooltip)); + } + is_menu1.store(!flag, Ordering::Relaxed); + } + + _ => {} + }) + .on_tray_icon_event(|tray, event| { + if let TrayIconEvent::Click { + button: MouseButton::Left, + button_state: MouseButtonState::Up, + .. + } = event + { + let app = tray.app_handle(); + if let Some(window) = app.get_webview_window("main") { + let _ = window.show(); + let _ = window.set_focus(); + } + } + }) + .build(app); + + Ok(()) +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/.gitignore b/examples/api/src-tauri/tauri-plugin-sample/.gitignore new file mode 100644 index 000000000000..24ae128058bf --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/.gitignore @@ -0,0 +1 @@ +.tauri diff --git a/examples/api/src-tauri/tauri-plugin-sample/Cargo.toml b/examples/api/src-tauri/tauri-plugin-sample/Cargo.toml new file mode 100644 index 000000000000..15b0f050016d --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "tauri-plugin-sample" +version = "0.1.0" +edition = "2021" +links = "tauri-plugin-sample" + +[dependencies] +tauri = { path = "../../../../crates/tauri" } +log = "0.4" +serde = "1" +thiserror = "2" + +[build-dependencies] +tauri-plugin = { path = "../../../../crates/tauri-plugin", features = [ + "build", +] } diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/.gitignore b/examples/api/src-tauri/tauri-plugin-sample/android/.gitignore new file mode 100644 index 000000000000..ae485e87f4d8 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/.gitignore @@ -0,0 +1,2 @@ +/build +.tauri diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts b/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts new file mode 100644 index 000000000000..e61b6d737a39 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/build.gradle.kts @@ -0,0 +1,44 @@ +plugins { + id("com.android.library") + id("org.jetbrains.kotlin.android") +} + +android { + namespace = "com.plugin.sample" + compileSdk = 34 + + defaultConfig { + minSdk = 21 + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 + } + kotlinOptions { + jvmTarget = "1.8" + } +} + +dependencies { + + implementation("androidx.core:core-ktx:1.9.0") + implementation("androidx.appcompat:appcompat:1.6.0") + implementation("com.google.android.material:material:1.7.0") + testImplementation("junit:junit:4.13.2") + androidTestImplementation("androidx.test.ext:junit:1.1.5") + androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") + implementation(project(":tauri-android")) +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/proguard-rules.pro b/examples/api/src-tauri/tauri-plugin-sample/android/proguard-rules.pro new file mode 100644 index 000000000000..481bb4348141 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/settings.gradle b/examples/api/src-tauri/tauri-plugin-sample/android/settings.gradle new file mode 100644 index 000000000000..d7782a40dd6c --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/settings.gradle @@ -0,0 +1,31 @@ +pluginManagement { + repositories { + mavenCentral() + gradlePluginPortal() + google() + } + resolutionStrategy { + eachPlugin { + switch (requested.id.id) { + case "com.android.library": + useVersion("8.0.2") + break + case "org.jetbrains.kotlin.android": + useVersion("1.8.20") + break + } + } + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + mavenCentral() + google() + + } +} + +include ':tauri-android' +project(':tauri-android').projectDir = new File('./.tauri/tauri-api') diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/src/androidTest/java/com/plugin/sample/ExampleInstrumentedTest.kt b/examples/api/src-tauri/tauri-plugin-sample/android/src/androidTest/java/com/plugin/sample/ExampleInstrumentedTest.kt new file mode 100644 index 000000000000..795867b2ab84 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/src/androidTest/java/com/plugin/sample/ExampleInstrumentedTest.kt @@ -0,0 +1,28 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.plugin.sample + +import androidx.test.platform.app.InstrumentationRegistry +import androidx.test.ext.junit.runners.AndroidJUnit4 + +import org.junit.Test +import org.junit.runner.RunWith + +import org.junit.Assert.* + +/** + * Instrumented test, which will execute on an Android device. + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +@RunWith(AndroidJUnit4::class) +class ExampleInstrumentedTest { + @Test + fun useAppContext() { + // Context of the app under test. + val appContext = InstrumentationRegistry.getInstrumentation().targetContext + assertEquals("com.plugin.sample", appContext.packageName) + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/src/main/AndroidManifest.xml b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/AndroidManifest.xml new file mode 100644 index 000000000000..a5918e68abcd --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/AndroidManifest.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/Example.kt b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/Example.kt new file mode 100644 index 000000000000..63d3581dabfd --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/Example.kt @@ -0,0 +1,14 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.plugin.sample + +import android.util.Log + +class Example { + fun pong(value: String): String { + Log.i("Pong", value) + return value + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/ExamplePlugin.kt b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/ExamplePlugin.kt new file mode 100644 index 000000000000..793dc37e80af --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/src/main/java/com/plugin/sample/ExamplePlugin.kt @@ -0,0 +1,38 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.plugin.sample + +import android.app.Activity +import app.tauri.annotation.Command +import app.tauri.annotation.InvokeArg +import app.tauri.annotation.TauriPlugin +import app.tauri.plugin.Channel +import app.tauri.plugin.JSObject +import app.tauri.plugin.Plugin +import app.tauri.plugin.Invoke + +@InvokeArg +class PingArgs { + var value: String? = null + var onEvent: Channel? = null +} + +@TauriPlugin +class ExamplePlugin(private val activity: Activity): Plugin(activity) { + private val implementation = Example() + + @Command + fun ping(invoke: Invoke) { + val args = invoke.parseArgs(PingArgs::class.java) + + val event = JSObject() + event.put("kind", "ping") + args.onEvent?.send(event) + + val ret = JSObject() + ret.put("value", implementation.pong(args.value ?: "default value :(")) + invoke.resolve(ret) + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/android/src/test/java/com/plugin/sample/ExampleUnitTest.kt b/examples/api/src-tauri/tauri-plugin-sample/android/src/test/java/com/plugin/sample/ExampleUnitTest.kt new file mode 100644 index 000000000000..db6837ef44a1 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/android/src/test/java/com/plugin/sample/ExampleUnitTest.kt @@ -0,0 +1,21 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package com.plugin.sample + +import org.junit.Test + +import org.junit.Assert.* + +/** + * Example local unit test, which will execute on the development machine (host). + * + * See [testing documentation](http://d.android.com/tools/testing). + */ +class ExampleUnitTest { + @Test + fun addition_isCorrect() { + assertEquals(4, 2 + 2) + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/api-iife.js b/examples/api/src-tauri/tauri-plugin-sample/api-iife.js new file mode 100644 index 000000000000..cb6dfc79db57 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/api-iife.js @@ -0,0 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +if ('__TAURI__' in window) { + window.__TAURI__.sample = {} +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/build.rs b/examples/api/src-tauri/tauri-plugin-sample/build.rs new file mode 100644 index 000000000000..9ab61beb34a5 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/build.rs @@ -0,0 +1,13 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +const COMMANDS: &[&str] = &["ping"]; + +fn main() { + tauri_plugin::Builder::new(COMMANDS) + .android_path("android") + .ios_path("ios") + .global_api_script_path("./api-iife.js") + .build(); +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/ios/.gitignore b/examples/api/src-tauri/tauri-plugin-sample/ios/.gitignore new file mode 100644 index 000000000000..5922fdaa5638 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/ios/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/config/registries.json +.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata +.netrc +Package.resolved diff --git a/examples/api/src-tauri/tauri-plugin-sample/ios/Package.swift b/examples/api/src-tauri/tauri-plugin-sample/ios/Package.swift new file mode 100644 index 000000000000..537153abfcae --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/ios/Package.swift @@ -0,0 +1,35 @@ +// swift-tools-version:5.3 +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +import PackageDescription + +let package = Package( + name: "tauri-plugin-sample", + platforms: [ + .macOS(.v10_13), + .iOS(.v13), + ], + products: [ + // Products define the executables and libraries a package produces, and make them visible to other packages. + .library( + name: "tauri-plugin-sample", + type: .static, + targets: ["tauri-plugin-sample"]), + ], + dependencies: [ + // Dependencies declare other packages that this package depends on. + .package(name: "Tauri", path: "../../../../../crates/tauri/mobile/ios-api") + ], + targets: [ + // Targets are the basic building blocks of a package. A target can define a module or a test suite. + // Targets can depend on other targets in this package, and on products in packages this package depends on. + .target( + name: "tauri-plugin-sample", + dependencies: [ + .byName(name: "Tauri") + ], + path: "Sources") + ] +) diff --git a/examples/api/src-tauri/tauri-plugin-sample/ios/README.md b/examples/api/src-tauri/tauri-plugin-sample/ios/README.md new file mode 100644 index 000000000000..545904443264 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/ios/README.md @@ -0,0 +1,3 @@ +# Tauri Plugin sample + +A description of this package. diff --git a/examples/api/src-tauri/tauri-plugin-sample/ios/Sources/ExamplePlugin.swift b/examples/api/src-tauri/tauri-plugin-sample/ios/Sources/ExamplePlugin.swift new file mode 100644 index 000000000000..86083f3984b0 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/ios/Sources/ExamplePlugin.swift @@ -0,0 +1,26 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +import SwiftRs +import Tauri +import UIKit +import WebKit + +class PingArgs: Decodable { + let value: String? + let onEvent: Channel? +} + +class ExamplePlugin: Plugin { + @objc public func ping(_ invoke: Invoke) throws { + let args = try invoke.parseArgs(PingArgs.self) + try args.onEvent?.send(["kind": "ping"]) + invoke.resolve(["value": args.value ?? ""]) + } +} + +@_cdecl("init_plugin_sample") +func initPlugin() -> Plugin { + return ExamplePlugin() +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/ios/Tests/PluginTests/PluginTests.swift b/examples/api/src-tauri/tauri-plugin-sample/ios/Tests/PluginTests/PluginTests.swift new file mode 100644 index 000000000000..114c4bec592e --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/ios/Tests/PluginTests/PluginTests.swift @@ -0,0 +1,12 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +import XCTest +@testable import ExamplePlugin + +final class ExamplePluginTests: XCTestCase { + func testExample() throws { + let plugin = ExamplePlugin() + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/.gitignore b/examples/api/src-tauri/tauri-plugin-sample/permissions/.gitignore new file mode 100644 index 000000000000..8629fe20694d --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/.gitignore @@ -0,0 +1 @@ +schemas/ \ No newline at end of file diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/commands/ping.toml b/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/commands/ping.toml new file mode 100644 index 000000000000..1d1358807e5b --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/commands/ping.toml @@ -0,0 +1,13 @@ +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../schemas/schema.json" + +[[permission]] +identifier = "allow-ping" +description = "Enables the ping command without any pre-configured scope." +commands.allow = ["ping"] + +[[permission]] +identifier = "deny-ping" +description = "Denies the ping command without any pre-configured scope." +commands.deny = ["ping"] diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/reference.md b/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/reference.md new file mode 100644 index 000000000000..f6c599938f7e --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/autogenerated/reference.md @@ -0,0 +1,62 @@ + +## Permission Table + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    IdentifierDescription
    + +`sample:allow-ping` + + + +Enables the ping command without any pre-configured scope. + +
    + +`sample:deny-ping` + + + +Denies the ping command without any pre-configured scope. + +
    + +`sample:global-scope` + + + +Sets a global scope. + +
    + +`sample:allow-ping-scoped` + + + +Enables the ping command with a test scope. + +
    diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/global-scope.toml b/examples/api/src-tauri/tauri-plugin-sample/permissions/global-scope.toml new file mode 100644 index 000000000000..d80fb78793a2 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/global-scope.toml @@ -0,0 +1,7 @@ +"$schema" = "schemas/schema.json" + +[[permission]] +identifier = "global-scope" +description = "Sets a global scope." +[[permission.scope.allow]] +path = "global" diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/ping-scoped.toml b/examples/api/src-tauri/tauri-plugin-sample/permissions/ping-scoped.toml new file mode 100644 index 000000000000..f6a050284646 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/ping-scoped.toml @@ -0,0 +1,8 @@ +"$schema" = "schemas/schema.json" + +[[permission]] +identifier = "allow-ping-scoped" +description = "Enables the ping command with a test scope." +commands.allow = ["ping"] +[[permission.scope.allow]] +path = "x" diff --git a/examples/api/src-tauri/tauri-plugin-sample/permissions/schemas/schema.json b/examples/api/src-tauri/tauri-plugin-sample/permissions/schemas/schema.json new file mode 100644 index 000000000000..73caf69daefc --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/permissions/schemas/schema.json @@ -0,0 +1,320 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "PermissionFile", + "description": "Permission file that can define a default permission, a set of permissions or a list of inlined permissions.", + "type": "object", + "properties": { + "default": { + "description": "The default permission set for the plugin", + "anyOf": [ + { + "$ref": "#/definitions/DefaultPermission" + }, + { + "type": "null" + } + ] + }, + "set": { + "description": "A list of permissions sets defined", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionSet" + } + }, + "permission": { + "description": "A list of inlined permissions", + "default": [], + "type": "array", + "items": { + "$ref": "#/definitions/Permission" + } + } + }, + "definitions": { + "DefaultPermission": { + "description": "The default permission set of the plugin.\n\n Works similarly to a permission with the \"default\" identifier.", + "type": "object", + "required": [ + "permissions" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "description": { + "description": "Human-readable description of what the permission does.\n Tauri convention is to use

    headings in markdown content\n for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PermissionSet": { + "description": "A set of direct permissions grouped together under a new name.", + "type": "object", + "required": [ + "description", + "identifier", + "permissions" + ], + "properties": { + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does.", + "type": "string" + }, + "permissions": { + "description": "All permissions this set contains.", + "type": "array", + "items": { + "$ref": "#/definitions/PermissionKind" + } + } + } + }, + "Permission": { + "description": "Descriptions of explicit privileges of commands.\n\n It can enable commands to be accessible in the frontend of the application.\n\n If the scope is defined it can be used to fine grain control the access of individual or multiple commands.", + "type": "object", + "required": [ + "identifier" + ], + "properties": { + "version": { + "description": "The version of the permission.", + "type": [ + "integer", + "null" + ], + "format": "uint64", + "minimum": 1.0 + }, + "identifier": { + "description": "A unique identifier for the permission.", + "type": "string" + }, + "description": { + "description": "Human-readable description of what the permission does.\n Tauri internal convention is to use

    headings in markdown content\n for Tauri documentation generation purposes.", + "type": [ + "string", + "null" + ] + }, + "commands": { + "description": "Allowed or denied commands when using this permission.", + "default": { + "allow": [], + "deny": [] + }, + "allOf": [ + { + "$ref": "#/definitions/Commands" + } + ] + }, + "scope": { + "description": "Allowed or denied scoped when using this permission.", + "allOf": [ + { + "$ref": "#/definitions/Scopes" + } + ] + }, + "platforms": { + "description": "Target platforms this permission applies. By default all platforms are affected by this permission.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Target" + } + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\n If two commands clash inside of `allow` and `deny`, it should be denied by default.", + "type": "object", + "properties": { + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + }, + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "An argument for fine grained behavior control of Tauri commands.\n\n It can be of any serde serializable type and is used to allow or prevent certain actions inside a Tauri command.\n The configured scope is passed to the command and will be enforced by the command implementation.\n\n ## Example\n\n ```json\n {\n \"allow\": [{ \"path\": \"$HOME/**\" }],\n \"deny\": [{ \"path\": \"$HOME/secret.txt\" }]\n }\n ```", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.", + "type": [ + "array", + "null" + ], + "items": { + "$ref": "#/definitions/Value" + } + } + } + }, + "Value": { + "description": "All supported ACL values.", + "anyOf": [ + { + "description": "Represents a null JSON value.", + "type": "null" + }, + { + "description": "Represents a [`bool`].", + "type": "boolean" + }, + { + "description": "Represents a valid ACL [`Number`].", + "allOf": [ + { + "$ref": "#/definitions/Number" + } + ] + }, + { + "description": "Represents a [`String`].", + "type": "string" + }, + { + "description": "Represents a list of other [`Value`]s.", + "type": "array", + "items": { + "$ref": "#/definitions/Value" + } + }, + { + "description": "Represents a map of [`String`] keys to [`Value`]s.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/Value" + } + } + ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "Target": { + "description": "Platform target.", + "oneOf": [ + { + "description": "MacOS.", + "type": "string", + "enum": [ + "macOS" + ] + }, + { + "description": "Windows.", + "type": "string", + "enum": [ + "windows" + ] + }, + { + "description": "Linux.", + "type": "string", + "enum": [ + "linux" + ] + }, + { + "description": "Android.", + "type": "string", + "enum": [ + "android" + ] + }, + { + "description": "iOS.", + "type": "string", + "enum": [ + "iOS" + ] + } + ] + }, + "PermissionKind": { + "type": "string", + "oneOf": [ + { + "description": "Enables the ping command without any pre-configured scope.", + "type": "string", + "const": "allow-ping" + }, + { + "description": "Denies the ping command without any pre-configured scope.", + "type": "string", + "const": "deny-ping" + }, + { + "description": "Sets a global scope.", + "type": "string", + "const": "global-scope" + }, + { + "description": "Enables the ping command with a test scope.", + "type": "string", + "const": "allow-ping-scoped" + } + ] + } + } +} \ No newline at end of file diff --git a/examples/api/src-tauri/tauri-plugin-sample/src/desktop.rs b/examples/api/src-tauri/tauri-plugin-sample/src/desktop.rs new file mode 100644 index 000000000000..d3b79bbc7a45 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/src/desktop.rs @@ -0,0 +1,30 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use serde::de::DeserializeOwned; +use tauri::{plugin::PluginApi, AppHandle, Runtime}; + +use crate::models::*; + +pub fn init( + app: &AppHandle, + _api: PluginApi, +) -> crate::Result> { + Ok(Sample(app.clone())) +} + +/// A helper class to access the sample APIs. +pub struct Sample(AppHandle); + +impl Sample { + pub fn ping(&self, payload: PingRequest) -> crate::Result { + payload.on_event.send(Event { + kind: "ping".to_string(), + value: payload.value.clone(), + })?; + Ok(PingResponse { + value: payload.value, + }) + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/src/error.rs b/examples/api/src-tauri/tauri-plugin-sample/src/error.rs new file mode 100644 index 000000000000..c30dbabdce1e --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/src/error.rs @@ -0,0 +1,14 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +#[derive(Debug, thiserror::Error)] +pub enum Error { + #[cfg(mobile)] + #[error(transparent)] + PluginInvoke(#[from] tauri::plugin::mobile::PluginInvokeError), + #[error(transparent)] + Tauri(#[from] tauri::Error), +} + +pub type Result = std::result::Result; diff --git a/examples/api/src-tauri/tauri-plugin-sample/src/lib.rs b/examples/api/src-tauri/tauri-plugin-sample/src/lib.rs new file mode 100644 index 000000000000..db923fa129a0 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/src/lib.rs @@ -0,0 +1,87 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use serde::Deserialize; +use std::path::PathBuf; +use tauri::{ + plugin::{Builder, TauriPlugin}, + Manager, Runtime, +}; + +pub use models::*; + +#[cfg(desktop)] +mod desktop; +#[cfg(mobile)] +mod mobile; + +mod error; +mod models; + +#[cfg(desktop)] +use desktop::Sample; +#[cfg(mobile)] +use mobile::Sample; + +pub use error::*; + +/// Extensions to [`tauri::App`], [`tauri::AppHandle`] and [`tauri::Window`] to access the sample APIs. +pub trait SampleExt { + fn sample(&self) -> &Sample; +} + +impl> crate::SampleExt for T { + fn sample(&self) -> &Sample { + self.state::>().inner() + } +} + +#[allow(dead_code)] +#[derive(Debug, Deserialize)] +struct PingScope { + path: PathBuf, +} + +#[allow(dead_code)] +#[derive(Debug, Deserialize)] +struct SampleScope { + path: PathBuf, +} + +#[tauri::command] +fn ping( + app: tauri::AppHandle, + value: Option, + scope: tauri::ipc::CommandScope, + global_scope: tauri::ipc::GlobalScope, +) -> std::result::Result { + println!("local scope {:?}", scope); + println!("global scope {:?}", global_scope); + app + .sample() + .ping(PingRequest { + value, + on_event: tauri::ipc::Channel::new(|_| Ok(())), + }) + .map_err(|e| e.to_string()) +} + +pub fn init() -> TauriPlugin { + Builder::new("sample") + .setup(|app, api| { + #[cfg(mobile)] + let sample = mobile::init(app, api)?; + #[cfg(desktop)] + let sample = desktop::init(app, api)?; + app.manage(sample); + + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ping]) + .on_navigation(|window, url| { + println!("navigation {} {url}", window.label()); + true + }) + .build() +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/src/mobile.rs b/examples/api/src-tauri/tauri-plugin-sample/src/mobile.rs new file mode 100644 index 000000000000..ed5f86782db2 --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/src/mobile.rs @@ -0,0 +1,41 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use serde::de::DeserializeOwned; +use tauri::{ + plugin::{PluginApi, PluginHandle}, + AppHandle, Runtime, +}; + +use crate::models::*; + +#[cfg(target_os = "android")] +const PLUGIN_IDENTIFIER: &str = "com.plugin.sample"; + +#[cfg(target_os = "ios")] +tauri::ios_plugin_binding!(init_plugin_sample); + +// initializes the Kotlin or Swift plugin classes +pub fn init( + _app: &AppHandle, + api: PluginApi, +) -> crate::Result> { + #[cfg(target_os = "android")] + let handle = api.register_android_plugin(PLUGIN_IDENTIFIER, "ExamplePlugin")?; + #[cfg(target_os = "ios")] + let handle = api.register_ios_plugin(init_plugin_sample)?; + Ok(Sample(handle)) +} + +/// A helper class to access the sample APIs. +pub struct Sample(PluginHandle); + +impl Sample { + pub fn ping(&self, payload: PingRequest) -> crate::Result { + self + .0 + .run_mobile_plugin("ping", payload) + .map_err(Into::into) + } +} diff --git a/examples/api/src-tauri/tauri-plugin-sample/src/models.rs b/examples/api/src-tauri/tauri-plugin-sample/src/models.rs new file mode 100644 index 000000000000..a6b11d42a62c --- /dev/null +++ b/examples/api/src-tauri/tauri-plugin-sample/src/models.rs @@ -0,0 +1,24 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +use serde::{Deserialize, Serialize}; +use tauri::ipc::Channel; + +#[derive(Serialize)] +pub struct Event { + pub kind: String, + pub value: Option, +} + +#[derive(Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PingRequest { + pub value: Option, + pub on_event: Channel, +} + +#[derive(Debug, Clone, Default, Deserialize, Serialize)] +pub struct PingResponse { + pub value: Option, +} diff --git a/examples/api/src-tauri/tauri.conf.json b/examples/api/src-tauri/tauri.conf.json index a541e7674274..b09d914364a9 100644 --- a/examples/api/src-tauri/tauri.conf.json +++ b/examples/api/src-tauri/tauri.conf.json @@ -1,22 +1,42 @@ { + "$schema": "../../../crates/tauri-schema-generator/schemas/config.schema.json", + "productName": "Tauri API", + "version": "1.0.0", + "identifier": "com.tauri.api", "build": { - "distDir": "../dist", - "devPath": "http://localhost:5000", - "beforeDevCommand": "yarn dev", - "beforeBuildCommand": "yarn build" + "frontendDist": "../dist", + "devUrl": "http://localhost:1420", + "beforeDevCommand": "pnpm dev", + "beforeBuildCommand": "pnpm build" }, - "package": { - "productName": "Tauri API", - "version": "../package.json" - }, - "tauri": { - "pattern": { - "use": "isolation", - "options": { - "dir": "../isolation-dist/" - } - }, + "app": { + "withGlobalTauri": true, "macOSPrivateApi": true, + "security": { + "pattern": { + "use": "isolation", + "options": { + "dir": "../isolation-dist/" + } + }, + "csp": { + "default-src": "'self' customprotocol: asset:", + "connect-src": "ipc: http://ipc.localhost", + "font-src": ["https://fonts.gstatic.com"], + "img-src": "'self' asset: http://asset.localhost blob: data:", + "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com" + }, + "freezePrototype": true, + "assetProtocol": { + "enable": true, + "scope": { + "allow": ["$APPDATA/db/**", "$RESOURCE/**"], + "deny": ["$APPDATA/db/*.stronghold"] + } + } + } + }, + "plugins": { "cli": { "description": "Tauri API example", "args": [ @@ -36,7 +56,6 @@ { "short": "v", "name": "verbose", - "multipleOccurrences": true, "description": "Verbosity level" } ], @@ -52,87 +71,29 @@ ] } } - }, - "bundle": { - "active": true, - "identifier": "com.tauri.api", - "icon": [ - "../../.icons/32x32.png", - "../../.icons/128x128.png", - "../../.icons/128x128@2x.png", - "../../.icons/icon.icns", - "../../.icons/icon.ico" - ], - "windows": { - "wix": { - "language": { - "en-US": {}, - "pt-BR": { - "localePath": "locales/pt-BR.wxl" - } - } - } - } - }, - "updater": { - "active": true, - "dialog": false, - "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK", - "endpoints": [ - "https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}" - ] - }, - "allowlist": { - "all": true, - "fs": { - "scope": { - "allow": ["$APP/db/**", "$DOWNLOAD/**", "$RESOURCE/**"], - "deny": ["$APP/db/*.stronghold"] - } - }, - "shell": { - "scope": [ - { - "name": "sh", - "cmd": "sh", - "args": ["-c", { "validator": "\\S+" }] - }, - { - "name": "cmd", - "cmd": "cmd", - "args": ["/C", { "validator": "\\S+" }] + } + }, + "bundle": { + "active": true, + "icon": [ + "../../.icons/32x32.png", + "../../.icons/128x128.png", + "../../.icons/128x128@2x.png", + "../../.icons/icon.icns", + "../../.icons/icon.ico" + ], + "windows": { + "wix": { + "language": { + "en-US": {}, + "pt-BR": { + "localePath": "locales/pt-BR.wxl" } - ] - }, - "protocol": { - "asset": true, - "assetScope": { - "allow": ["$APP/db/**", "$RESOURCE/**"], - "deny": ["$APP/db/*.stronghold"] } }, - "http": { - "scope": ["https://jsonplaceholder.typicode.com/todos/*"] + "nsis": { + "compression": "none" } - }, - "windows": [ - { - "title": "Tauri API Validation", - "transparent": true - } - ], - "security": { - "csp": { - "default-src": "'self' customprotocol: asset:", - "font-src": ["https://fonts.gstatic.com"], - "img-src": "'self' asset: https://asset.localhost blob: data:", - "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com" - }, - "freezePrototype": true - }, - "systemTray": { - "iconPath": "../../.icons/tray_icon_with_transparency.png", - "iconAsTemplate": true } } } diff --git a/examples/api/src/App.svelte b/examples/api/src/App.svelte index cf966d5aaeec..da3373ae2950 100644 --- a/examples/api/src/App.svelte +++ b/examples/api/src/App.svelte @@ -1,173 +1,364 @@ -
    - -
    -
    + + + +
    + +
    +
    +

    {selected.label}

    +
    +
    + +
    +
    -
    -
    -

    - Tauri Console - clear -

    - {#each $responses as r} - {#if r.text} -

    {r.text}

    - {:else} - {@html r.html} - {/if} - {/each} -
    -
    - +
    +
    +
    +

    Console

    +
    (e.key === 'Enter' ? clear() : {})} + on:click={clear} + > +
    +
    +
    +
    + {#each $messages as r} + {@html r.html} + {/each} +
    +
    + +
    diff --git a/examples/api/src/app.css b/examples/api/src/app.css new file mode 100644 index 000000000000..f2d03802efa6 --- /dev/null +++ b/examples/api/src/app.css @@ -0,0 +1,50 @@ +:root { + line-height: 1.5; +} + +input, +select { + min-width: 0; +} + +*:not(h1, h2, h3, h4, h5, h6) { + margin: 0; + padding: 0; +} + +* { + box-sizing: border-box; + font-family: 'Rubik', sans-serif; +} + +::-webkit-scrollbar { + width: 0.25rem; + height: 3px; +} + +::-webkit-scrollbar-track { + background: transparent; +} + +::-webkit-scrollbar-thumb { + border-radius: 0.25rem; +} + +code { + padding: 0.05rem 0.25rem; +} + +code.code-block { + padding: 0.5rem; +} + +#sidebar { + width: 18.75rem; +} + +@media screen and (max-width: 640px) { + #sidebar { + --translate-x: -18.75rem; + transform: translateX(var(--translate-x)); + } +} diff --git a/examples/api/src/components/Cli.svelte b/examples/api/src/components/Cli.svelte deleted file mode 100644 index a38b4f2e6c54..000000000000 --- a/examples/api/src/components/Cli.svelte +++ /dev/null @@ -1,24 +0,0 @@ - - -
    - This binary can be run on the terminal and takes the following arguments: -
      -
    • --config PATH
    • -
    • --theme light|dark|system
    • -
    • --verbose
    • -
    - Additionally, it has a update --background subcommand. - Note that the arguments are only parsed, not implemented. -
    - -
    diff --git a/examples/api/src/components/Clipboard.svelte b/examples/api/src/components/Clipboard.svelte deleted file mode 100644 index 57430243a14e..000000000000 --- a/examples/api/src/components/Clipboard.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - -
    -
    - - -
    - -
    diff --git a/examples/api/src/components/Communication.svelte b/examples/api/src/components/Communication.svelte deleted file mode 100644 index c25a2731e862..000000000000 --- a/examples/api/src/components/Communication.svelte +++ /dev/null @@ -1,50 +0,0 @@ - - -
    - - - -
    diff --git a/examples/api/src/components/Dialog.svelte b/examples/api/src/components/Dialog.svelte deleted file mode 100644 index ed065df9a789..000000000000 --- a/examples/api/src/components/Dialog.svelte +++ /dev/null @@ -1,122 +0,0 @@ - - -
    - - -
    - - -
    -
    - - -
    - - - -
    - - diff --git a/examples/api/src/components/FileSystem.svelte b/examples/api/src/components/FileSystem.svelte deleted file mode 100644 index e128249ab065..000000000000 --- a/examples/api/src/components/FileSystem.svelte +++ /dev/null @@ -1,99 +0,0 @@ - - -
    - - - - - - file -
    diff --git a/examples/api/src/components/Http.svelte b/examples/api/src/components/Http.svelte deleted file mode 100644 index 2dc92169aca6..000000000000 --- a/examples/api/src/components/Http.svelte +++ /dev/null @@ -1,64 +0,0 @@ - - -
    - - -
    -