diff --git a/.changes/api-emit-to.md b/.changes/api-emit-to.md new file mode 100644 index 000000000000..359bac12431d --- /dev/null +++ b/.changes/api-emit-to.md @@ -0,0 +1,5 @@ +--- +'@tauri-apps/api': 'patch:feat' +--- + +Added `emitTo` api to `event` module which is equivalent to the rust `emit_to` method. Also added `emitTo` method on `Window`, `Webivew` and `WebviewWindow` classes. diff --git a/.changes/api-event-resource-refactor.md b/.changes/api-event-resource-refactor.md index d8d3fc850455..b7a81fdf6fc7 100644 --- a/.changes/api-event-resource-refactor.md +++ b/.changes/api-event-resource-refactor.md @@ -1,5 +1,5 @@ --- -"@tauri-apps/api": patch:breaking +'@tauri-apps/api': patch:breaking --- -Removed event callback's `windowLabel` field and added a `windowSource` object instead. +Removed event callback's `windowLabel`. diff --git a/.changes/tauri-close-requested-another-webview.md b/.changes/tauri-close-requested-another-webview.md new file mode 100644 index 000000000000..d8d7a1efa02d --- /dev/null +++ b/.changes/tauri-close-requested-another-webview.md @@ -0,0 +1,5 @@ +--- +'tauri': 'patch:bug' +--- + +Fix can not prevent closing a window from another webview. diff --git a/.changes/tauri-event-after-multiwebview.md b/.changes/tauri-event-after-multiwebview.md new file mode 100644 index 000000000000..39d54cdfc381 --- /dev/null +++ b/.changes/tauri-event-after-multiwebview.md @@ -0,0 +1,12 @@ +--- +'tauri': 'patch:breaking' +--- + +Refactored the event system to better accommodate the new window types: + +- Added `EventTarget` enum. +- Added `App/AppHandle::listen`, `App/AppHandle::once` and `App/AppHandle::unlisten` to listen to events targeting `App/AppHandle` +- `App/AppHandle/Window/Webview/WebviewWindow::emit` will now emit to all event listeners. +- `App/AppHandle/Window/Webview/WebviewWindow::emit_to` will emit to event targets that match the given label, see `EventTarget` enum. +- `App/AppHandle/Window/Webview/WebviewWindow::emit_filter` will emit to event targets based on a filter callback which now takes `&EventTarget` instead of `&Window`. +- Renamed `Manager::listen_global` and `Manager::once_global` to `listen_any` and `once_any` respectively to be consistent with `EventTarget::Any`, it will now also listen to any event to any target (aka event sniffer). diff --git a/.changes/tauri-utils-config-error-box.md b/.changes/tauri-utils-config-error-box.md new file mode 100644 index 000000000000..c67ec5ba0415 --- /dev/null +++ b/.changes/tauri-utils-config-error-box.md @@ -0,0 +1,5 @@ +--- +'tauri-utils': 'patch:breaking' +--- + +Changed `error` field in `ConfigError::FormatToml` to be boxed `Box` to reduce the enum `ConfigError` size in memory. diff --git a/core/tauri-runtime-wry/src/lib.rs b/core/tauri-runtime-wry/src/lib.rs index 09234926b7e6..cc0ee472b68e 100644 --- a/core/tauri-runtime-wry/src/lib.rs +++ b/core/tauri-runtime-wry/src/lib.rs @@ -2902,7 +2902,7 @@ fn handle_event_loop( if window.is_window_transparent { if let Some(surface) = &mut window.surface { if let Some(window) = &window.inner { - clear_window_surface(&window, surface) + clear_window_surface(window, surface) } } } diff --git a/core/tauri-utils/src/config/parse.rs b/core/tauri-utils/src/config/parse.rs index d82c6a27edde..016c57896820 100644 --- a/core/tauri-utils/src/config/parse.rs +++ b/core/tauri-utils/src/config/parse.rs @@ -108,7 +108,7 @@ pub enum ConfigError { path: PathBuf, /// The parsing [`toml::Error`]. - error: ::toml::de::Error, + error: Box<::toml::de::Error>, }, /// Unknown config file name encountered. @@ -381,7 +381,7 @@ fn do_parse_json5(raw: &str, path: &Path) -> Result(raw: &str, path: &Path) -> Result { ::toml::from_str(raw).map_err(|error| ConfigError::FormatToml { path: path.into(), - error, + error: Box::new(error), }) } diff --git a/core/tauri/build.rs b/core/tauri/build.rs index 5f6450a574a7..801cb6300b77 100644 --- a/core/tauri/build.rs +++ b/core/tauri/build.rs @@ -32,7 +32,12 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[ ), ( "event", - &[("listen", true), ("unlisten", true), ("emit", true)], + &[ + ("listen", true), + ("unlisten", true), + ("emit", true), + ("emit_to", true), + ], ), ( "window", diff --git a/core/tauri/permissions/app/.schema.json b/core/tauri/permissions/app/.schema.json deleted file mode 100644 index d5a469447e42..000000000000 --- a/core/tauri/permissions/app/.schema.json +++ /dev/null @@ -1,339 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-app-hide -> Enables the app_hide command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-app-hide" - ] - }, - { - "description": "deny-app-hide -> Denies the app_hide command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-app-hide" - ] - }, - { - "description": "allow-app-show -> Enables the app_show command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-app-show" - ] - }, - { - "description": "deny-app-show -> Denies the app_show command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-app-show" - ] - }, - { - "description": "allow-name -> Enables the name command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-name" - ] - }, - { - "description": "deny-name -> Denies the name command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-name" - ] - }, - { - "description": "allow-tauri-version -> Enables the tauri_version command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-tauri-version" - ] - }, - { - "description": "deny-tauri-version -> Denies the tauri_version command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-tauri-version" - ] - }, - { - "description": "allow-version -> Enables the version command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-version" - ] - }, - { - "description": "deny-version -> Denies the version command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-version" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/app/schemas/schema.json b/core/tauri/permissions/app/schemas/schema.json index fb66b856dbfa..a30cf6141dd9 100644 --- a/core/tauri/permissions/app/schemas/schema.json +++ b/core/tauri/permissions/app/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -233,97 +324,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/event/.schema.json b/core/tauri/permissions/event/.schema.json deleted file mode 100644 index c073cc382c7d..000000000000 --- a/core/tauri/permissions/event/.schema.json +++ /dev/null @@ -1,311 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-emit -> Enables the emit command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-emit" - ] - }, - { - "description": "deny-emit -> Denies the emit command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-emit" - ] - }, - { - "description": "allow-listen -> Enables the listen command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-listen" - ] - }, - { - "description": "deny-listen -> Denies the listen command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-listen" - ] - }, - { - "description": "allow-unlisten -> Enables the unlisten command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-unlisten" - ] - }, - { - "description": "deny-unlisten -> Denies the unlisten command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-unlisten" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/event/autogenerated/commands/emit_to.toml b/core/tauri/permissions/event/autogenerated/commands/emit_to.toml new file mode 100644 index 000000000000..dd6510d1c799 --- /dev/null +++ b/core/tauri/permissions/event/autogenerated/commands/emit_to.toml @@ -0,0 +1,16 @@ +# Copyright 2019-2023 Tauri Programme within The Commons Conservancy +# SPDX-License-Identifier: Apache-2.0 +# SPDX-License-Identifier: MIT +# Automatically generated - DO NOT EDIT! + +"$schema" = "../../../schemas/schema.json" + +[[permission]] +identifier = "allow-emit-to" +description = "Enables the emit_to command without any pre-configured scope." +commands.allow = ["emit_to"] + +[[permission]] +identifier = "deny-emit-to" +description = "Denies the emit_to command without any pre-configured scope." +commands.deny = ["emit_to"] diff --git a/core/tauri/permissions/event/autogenerated/default.toml b/core/tauri/permissions/event/autogenerated/default.toml index 5c608785857d..88b763d3a375 100644 --- a/core/tauri/permissions/event/autogenerated/default.toml +++ b/core/tauri/permissions/event/autogenerated/default.toml @@ -5,4 +5,4 @@ [default] description = "Default permissions for the plugin." -permissions = ["allow-listen", "allow-unlisten", "allow-emit"] +permissions = ["allow-listen", "allow-unlisten", "allow-emit", "allow-emit-to"] diff --git a/core/tauri/permissions/event/schemas/schema.json b/core/tauri/permissions/event/schemas/schema.json index a834b2f037ce..39723deaa556 100644 --- a/core/tauri/permissions/event/schemas/schema.json +++ b/core/tauri/permissions/event/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,94 +138,27 @@ "$ref": "#/definitions/Scopes" } ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-emit -> Enables the emit command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-emit" - ] - }, - { - "description": "deny-emit -> Denies the emit command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-emit" - ] - }, - { - "description": "allow-listen -> Enables the listen command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-listen" - ] - }, - { - "description": "deny-listen -> Denies the listen command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-listen" - ] - }, - { - "description": "allow-unlisten -> Enables the unlisten command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-unlisten" - ] - }, - { - "description": "deny-unlisten -> Denies the unlisten command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-unlisten" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } }, - "permissions": { - "description": "All permissions this set contains.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionKind" + "type": "string" } } } @@ -296,6 +227,89 @@ } } ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "PermissionKind": { + "type": "string", + "oneOf": [ + { + "description": "allow-emit -> Enables the emit command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-emit" + ] + }, + { + "description": "deny-emit -> Denies the emit command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-emit" + ] + }, + { + "description": "allow-emit-to -> Enables the emit_to command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-emit-to" + ] + }, + { + "description": "deny-emit-to -> Denies the emit_to command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-emit-to" + ] + }, + { + "description": "allow-listen -> Enables the listen command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-listen" + ] + }, + { + "description": "deny-listen -> Denies the listen command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-listen" + ] + }, + { + "description": "allow-unlisten -> Enables the unlisten command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-unlisten" + ] + }, + { + "description": "deny-unlisten -> Denies the unlisten command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-unlisten" + ] + }, + { + "description": "default -> Default permissions for the plugin.", + "type": "string", + "enum": [ + "default" + ] + } + ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/menu/.schema.json b/core/tauri/permissions/menu/.schema.json deleted file mode 100644 index dc3a04544fd3..000000000000 --- a/core/tauri/permissions/menu/.schema.json +++ /dev/null @@ -1,577 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-append -> Enables the append command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-append" - ] - }, - { - "description": "deny-append -> Denies the append command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-append" - ] - }, - { - "description": "allow-create-default -> Enables the create_default command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-create-default" - ] - }, - { - "description": "deny-create-default -> Denies the create_default command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-create-default" - ] - }, - { - "description": "allow-get -> Enables the get command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-get" - ] - }, - { - "description": "deny-get -> Denies the get command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-get" - ] - }, - { - "description": "allow-insert -> Enables the insert command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-insert" - ] - }, - { - "description": "deny-insert -> Denies the insert command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-insert" - ] - }, - { - "description": "allow-is-checked -> Enables the is_checked command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-checked" - ] - }, - { - "description": "deny-is-checked -> Denies the is_checked command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-checked" - ] - }, - { - "description": "allow-is-enabled -> Enables the is_enabled command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-enabled" - ] - }, - { - "description": "deny-is-enabled -> Denies the is_enabled command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-enabled" - ] - }, - { - "description": "allow-items -> Enables the items command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-items" - ] - }, - { - "description": "deny-items -> Denies the items command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-items" - ] - }, - { - "description": "allow-new -> Enables the new command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-new" - ] - }, - { - "description": "deny-new -> Denies the new command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-new" - ] - }, - { - "description": "allow-popup -> Enables the popup command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-popup" - ] - }, - { - "description": "deny-popup -> Denies the popup command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-popup" - ] - }, - { - "description": "allow-prepend -> Enables the prepend command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-prepend" - ] - }, - { - "description": "deny-prepend -> Denies the prepend command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-prepend" - ] - }, - { - "description": "allow-remove -> Enables the remove command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-remove" - ] - }, - { - "description": "deny-remove -> Denies the remove command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-remove" - ] - }, - { - "description": "allow-remove-at -> Enables the remove_at command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-remove-at" - ] - }, - { - "description": "deny-remove-at -> Denies the remove_at command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-remove-at" - ] - }, - { - "description": "allow-set-accelerator -> Enables the set_accelerator command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-accelerator" - ] - }, - { - "description": "deny-set-accelerator -> Denies the set_accelerator command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-accelerator" - ] - }, - { - "description": "allow-set-as-app-menu -> Enables the set_as_app_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-as-app-menu" - ] - }, - { - "description": "deny-set-as-app-menu -> Denies the set_as_app_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-as-app-menu" - ] - }, - { - "description": "allow-set-as-help-menu-for-nsapp -> Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-as-help-menu-for-nsapp" - ] - }, - { - "description": "deny-set-as-help-menu-for-nsapp -> Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-as-help-menu-for-nsapp" - ] - }, - { - "description": "allow-set-as-window-menu -> Enables the set_as_window_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-as-window-menu" - ] - }, - { - "description": "deny-set-as-window-menu -> Denies the set_as_window_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-as-window-menu" - ] - }, - { - "description": "allow-set-as-windows-menu-for-nsapp -> Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-as-windows-menu-for-nsapp" - ] - }, - { - "description": "deny-set-as-windows-menu-for-nsapp -> Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-as-windows-menu-for-nsapp" - ] - }, - { - "description": "allow-set-checked -> Enables the set_checked command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-checked" - ] - }, - { - "description": "deny-set-checked -> Denies the set_checked command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-checked" - ] - }, - { - "description": "allow-set-enabled -> Enables the set_enabled command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-enabled" - ] - }, - { - "description": "deny-set-enabled -> Denies the set_enabled command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-enabled" - ] - }, - { - "description": "allow-set-icon -> Enables the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-icon" - ] - }, - { - "description": "deny-set-icon -> Denies the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-icon" - ] - }, - { - "description": "allow-set-text -> Enables the set_text command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-text" - ] - }, - { - "description": "deny-set-text -> Denies the set_text command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-text" - ] - }, - { - "description": "allow-text -> Enables the text command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-text" - ] - }, - { - "description": "deny-text -> Denies the text command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-text" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/menu/schemas/schema.json b/core/tauri/permissions/menu/schemas/schema.json index 0b611d169df9..8ff323665c23 100644 --- a/core/tauri/permissions/menu/schemas/schema.json +++ b/core/tauri/permissions/menu/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -471,97 +562,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/path/.schema.json b/core/tauri/permissions/path/.schema.json deleted file mode 100644 index 6b58359d679a..000000000000 --- a/core/tauri/permissions/path/.schema.json +++ /dev/null @@ -1,381 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-basename -> Enables the basename command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-basename" - ] - }, - { - "description": "deny-basename -> Denies the basename command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-basename" - ] - }, - { - "description": "allow-dirname -> Enables the dirname command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-dirname" - ] - }, - { - "description": "deny-dirname -> Denies the dirname command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-dirname" - ] - }, - { - "description": "allow-extname -> Enables the extname command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-extname" - ] - }, - { - "description": "deny-extname -> Denies the extname command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-extname" - ] - }, - { - "description": "allow-is-absolute -> Enables the is_absolute command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-absolute" - ] - }, - { - "description": "deny-is-absolute -> Denies the is_absolute command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-absolute" - ] - }, - { - "description": "allow-join -> Enables the join command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-join" - ] - }, - { - "description": "deny-join -> Denies the join command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-join" - ] - }, - { - "description": "allow-normalize -> Enables the normalize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-normalize" - ] - }, - { - "description": "deny-normalize -> Denies the normalize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-normalize" - ] - }, - { - "description": "allow-resolve -> Enables the resolve command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-resolve" - ] - }, - { - "description": "deny-resolve -> Denies the resolve command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-resolve" - ] - }, - { - "description": "allow-resolve-directory -> Enables the resolve_directory command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-resolve-directory" - ] - }, - { - "description": "deny-resolve-directory -> Denies the resolve_directory command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-resolve-directory" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/path/schemas/schema.json b/core/tauri/permissions/path/schemas/schema.json index 17cb3e2d33e2..f38071e8114a 100644 --- a/core/tauri/permissions/path/schemas/schema.json +++ b/core/tauri/permissions/path/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -275,97 +366,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/resources/.schema.json b/core/tauri/permissions/resources/.schema.json deleted file mode 100644 index 42ed3743b2ef..000000000000 --- a/core/tauri/permissions/resources/.schema.json +++ /dev/null @@ -1,283 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-close -> Enables the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-close" - ] - }, - { - "description": "deny-close -> Denies the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-close" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/resources/schemas/schema.json b/core/tauri/permissions/resources/schemas/schema.json index 079c6294cb7a..31df6c016976 100644 --- a/core/tauri/permissions/resources/schemas/schema.json +++ b/core/tauri/permissions/resources/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,66 +138,27 @@ "$ref": "#/definitions/Scopes" } ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-close -> Enables the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-close" - ] - }, - { - "description": "deny-close -> Denies the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-close" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf two commands clash inside of `allow` and `deny`, it should be denied by default.", "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" + "allow": { + "description": "Allowed command.", + "default": [], + "type": "array", + "items": { + "type": "string" + } }, - "permissions": { - "description": "All permissions this set contains.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionKind" + "type": "string" } } } @@ -268,6 +227,47 @@ } } ] + }, + "Number": { + "description": "A valid ACL number.", + "anyOf": [ + { + "description": "Represents an [`i64`].", + "type": "integer", + "format": "int64" + }, + { + "description": "Represents a [`f64`].", + "type": "number", + "format": "double" + } + ] + }, + "PermissionKind": { + "type": "string", + "oneOf": [ + { + "description": "allow-close -> Enables the close command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-close" + ] + }, + { + "description": "deny-close -> Denies the close command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-close" + ] + }, + { + "description": "default -> Default permissions for the plugin.", + "type": "string", + "enum": [ + "default" + ] + } + ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/tray/.schema.json b/core/tauri/permissions/tray/.schema.json deleted file mode 100644 index d25757ffe982..000000000000 --- a/core/tauri/permissions/tray/.schema.json +++ /dev/null @@ -1,395 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-new -> Enables the new command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-new" - ] - }, - { - "description": "deny-new -> Denies the new command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-new" - ] - }, - { - "description": "allow-set-icon -> Enables the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-icon" - ] - }, - { - "description": "deny-set-icon -> Denies the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-icon" - ] - }, - { - "description": "allow-set-icon-as-template -> Enables the set_icon_as_template command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-icon-as-template" - ] - }, - { - "description": "deny-set-icon-as-template -> Denies the set_icon_as_template command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-icon-as-template" - ] - }, - { - "description": "allow-set-menu -> Enables the set_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-menu" - ] - }, - { - "description": "deny-set-menu -> Denies the set_menu command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-menu" - ] - }, - { - "description": "allow-set-show-menu-on-left-click -> Enables the set_show_menu_on_left_click command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-show-menu-on-left-click" - ] - }, - { - "description": "deny-set-show-menu-on-left-click -> Denies the set_show_menu_on_left_click command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-show-menu-on-left-click" - ] - }, - { - "description": "allow-set-temp-dir-path -> Enables the set_temp_dir_path command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-temp-dir-path" - ] - }, - { - "description": "deny-set-temp-dir-path -> Denies the set_temp_dir_path command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-temp-dir-path" - ] - }, - { - "description": "allow-set-title -> Enables the set_title command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-title" - ] - }, - { - "description": "deny-set-title -> Denies the set_title command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-title" - ] - }, - { - "description": "allow-set-tooltip -> Enables the set_tooltip command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-tooltip" - ] - }, - { - "description": "deny-set-tooltip -> Denies the set_tooltip command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-tooltip" - ] - }, - { - "description": "allow-set-visible -> Enables the set_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-visible" - ] - }, - { - "description": "deny-set-visible -> Denies the set_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-visible" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/tray/schemas/schema.json b/core/tauri/permissions/tray/schemas/schema.json index 029cd0ff0244..9d2ff991e05d 100644 --- a/core/tauri/permissions/tray/schemas/schema.json +++ b/core/tauri/permissions/tray/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -289,97 +380,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/webview/.schema.json b/core/tauri/permissions/webview/.schema.json deleted file mode 100644 index 688de14a55c0..000000000000 --- a/core/tauri/permissions/webview/.schema.json +++ /dev/null @@ -1,409 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-create-webview -> Enables the create_webview command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-create-webview" - ] - }, - { - "description": "deny-create-webview -> Denies the create_webview command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-create-webview" - ] - }, - { - "description": "allow-create-webview-window -> Enables the create_webview_window command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-create-webview-window" - ] - }, - { - "description": "deny-create-webview-window -> Denies the create_webview_window command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-create-webview-window" - ] - }, - { - "description": "allow-internal-toggle-devtools -> Enables the internal_toggle_devtools command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-internal-toggle-devtools" - ] - }, - { - "description": "deny-internal-toggle-devtools -> Denies the internal_toggle_devtools command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-internal-toggle-devtools" - ] - }, - { - "description": "allow-print -> Enables the print command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-print" - ] - }, - { - "description": "deny-print -> Denies the print command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-print" - ] - }, - { - "description": "allow-set-webview-focus -> Enables the set_webview_focus command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-webview-focus" - ] - }, - { - "description": "deny-set-webview-focus -> Denies the set_webview_focus command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-webview-focus" - ] - }, - { - "description": "allow-set-webview-position -> Enables the set_webview_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-webview-position" - ] - }, - { - "description": "deny-set-webview-position -> Denies the set_webview_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-webview-position" - ] - }, - { - "description": "allow-set-webview-size -> Enables the set_webview_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-webview-size" - ] - }, - { - "description": "deny-set-webview-size -> Denies the set_webview_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-webview-size" - ] - }, - { - "description": "allow-webview-close -> Enables the webview_close command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-webview-close" - ] - }, - { - "description": "deny-webview-close -> Denies the webview_close command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-webview-close" - ] - }, - { - "description": "allow-webview-position -> Enables the webview_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-webview-position" - ] - }, - { - "description": "deny-webview-position -> Denies the webview_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-webview-position" - ] - }, - { - "description": "allow-webview-size -> Enables the webview_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-webview-size" - ] - }, - { - "description": "deny-webview-size -> Denies the webview_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-webview-size" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/webview/schemas/schema.json b/core/tauri/permissions/webview/schemas/schema.json index b82f1587a149..dd0a74532e39 100644 --- a/core/tauri/permissions/webview/schemas/schema.json +++ b/core/tauri/permissions/webview/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -303,97 +394,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/permissions/window/.schema.json b/core/tauri/permissions/window/.schema.json deleted file mode 100644 index 3b2d603b8f9b..000000000000 --- a/core/tauri/permissions/window/.schema.json +++ /dev/null @@ -1,1109 +0,0 @@ -{ - "$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" - } - ] - }, - "permission": { - "description": "A list of inlined permissions", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/Permission" - } - }, - "set": { - "description": "A list of permissions sets defined", - "default": [], - "type": "array", - "items": { - "$ref": "#/definitions/PermissionSet" - } - }, - "test": { - "description": "Test something!!", - "anyOf": [ - { - "$ref": "#/definitions/PermissionSet" - }, - { - "type": "null" - } - ] - } - }, - "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, - "DefaultPermission": { - "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", - "type": "object", - "required": [ - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "type": "string" - } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" - }, - { - "description": "Represents a [`f64`].", - "type": "number", - "format": "double" - } - ] - }, - "Permission": { - "description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", - "type": "object", - "required": [ - "identifier" - ], - "properties": { - "commands": { - "description": "Allowed or denied commands when using this permission.", - "default": { - "allow": [], - "deny": [] - }, - "allOf": [ - { - "$ref": "#/definitions/Commands" - } - ] - }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "scope": { - "description": "Allowed or denied scoped when using this permission.", - "default": { - "allow": null, - "deny": null - }, - "allOf": [ - { - "$ref": "#/definitions/Scopes" - } - ] - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 - } - } - }, - "PermissionKind": { - "type": "string", - "oneOf": [ - { - "description": "allow-available-monitors -> Enables the available_monitors command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-available-monitors" - ] - }, - { - "description": "deny-available-monitors -> Denies the available_monitors command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-available-monitors" - ] - }, - { - "description": "allow-center -> Enables the center command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-center" - ] - }, - { - "description": "deny-center -> Denies the center command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-center" - ] - }, - { - "description": "allow-close -> Enables the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-close" - ] - }, - { - "description": "deny-close -> Denies the close command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-close" - ] - }, - { - "description": "allow-create -> Enables the create command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-create" - ] - }, - { - "description": "deny-create -> Denies the create command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-create" - ] - }, - { - "description": "allow-current-monitor -> Enables the current_monitor command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-current-monitor" - ] - }, - { - "description": "deny-current-monitor -> Denies the current_monitor command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-current-monitor" - ] - }, - { - "description": "allow-hide -> Enables the hide command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-hide" - ] - }, - { - "description": "deny-hide -> Denies the hide command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-hide" - ] - }, - { - "description": "allow-inner-position -> Enables the inner_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-inner-position" - ] - }, - { - "description": "deny-inner-position -> Denies the inner_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-inner-position" - ] - }, - { - "description": "allow-inner-size -> Enables the inner_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-inner-size" - ] - }, - { - "description": "deny-inner-size -> Denies the inner_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-inner-size" - ] - }, - { - "description": "allow-internal-on-mousedown -> Enables the internal_on_mousedown command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-internal-on-mousedown" - ] - }, - { - "description": "deny-internal-on-mousedown -> Denies the internal_on_mousedown command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-internal-on-mousedown" - ] - }, - { - "description": "allow-internal-on-mousemove -> Enables the internal_on_mousemove command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-internal-on-mousemove" - ] - }, - { - "description": "deny-internal-on-mousemove -> Denies the internal_on_mousemove command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-internal-on-mousemove" - ] - }, - { - "description": "allow-internal-toggle-maximize -> Enables the internal_toggle_maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-internal-toggle-maximize" - ] - }, - { - "description": "deny-internal-toggle-maximize -> Denies the internal_toggle_maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-internal-toggle-maximize" - ] - }, - { - "description": "allow-is-closable -> Enables the is_closable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-closable" - ] - }, - { - "description": "deny-is-closable -> Denies the is_closable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-closable" - ] - }, - { - "description": "allow-is-decorated -> Enables the is_decorated command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-decorated" - ] - }, - { - "description": "deny-is-decorated -> Denies the is_decorated command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-decorated" - ] - }, - { - "description": "allow-is-focused -> Enables the is_focused command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-focused" - ] - }, - { - "description": "deny-is-focused -> Denies the is_focused command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-focused" - ] - }, - { - "description": "allow-is-fullscreen -> Enables the is_fullscreen command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-fullscreen" - ] - }, - { - "description": "deny-is-fullscreen -> Denies the is_fullscreen command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-fullscreen" - ] - }, - { - "description": "allow-is-maximizable -> Enables the is_maximizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-maximizable" - ] - }, - { - "description": "deny-is-maximizable -> Denies the is_maximizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-maximizable" - ] - }, - { - "description": "allow-is-maximized -> Enables the is_maximized command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-maximized" - ] - }, - { - "description": "deny-is-maximized -> Denies the is_maximized command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-maximized" - ] - }, - { - "description": "allow-is-minimizable -> Enables the is_minimizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-minimizable" - ] - }, - { - "description": "deny-is-minimizable -> Denies the is_minimizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-minimizable" - ] - }, - { - "description": "allow-is-minimized -> Enables the is_minimized command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-minimized" - ] - }, - { - "description": "deny-is-minimized -> Denies the is_minimized command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-minimized" - ] - }, - { - "description": "allow-is-resizable -> Enables the is_resizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-resizable" - ] - }, - { - "description": "deny-is-resizable -> Denies the is_resizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-resizable" - ] - }, - { - "description": "allow-is-visible -> Enables the is_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-is-visible" - ] - }, - { - "description": "deny-is-visible -> Denies the is_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-is-visible" - ] - }, - { - "description": "allow-maximize -> Enables the maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-maximize" - ] - }, - { - "description": "deny-maximize -> Denies the maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-maximize" - ] - }, - { - "description": "allow-minimize -> Enables the minimize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-minimize" - ] - }, - { - "description": "deny-minimize -> Denies the minimize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-minimize" - ] - }, - { - "description": "allow-outer-position -> Enables the outer_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-outer-position" - ] - }, - { - "description": "deny-outer-position -> Denies the outer_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-outer-position" - ] - }, - { - "description": "allow-outer-size -> Enables the outer_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-outer-size" - ] - }, - { - "description": "deny-outer-size -> Denies the outer_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-outer-size" - ] - }, - { - "description": "allow-primary-monitor -> Enables the primary_monitor command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-primary-monitor" - ] - }, - { - "description": "deny-primary-monitor -> Denies the primary_monitor command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-primary-monitor" - ] - }, - { - "description": "allow-request-user-attention -> Enables the request_user_attention command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-request-user-attention" - ] - }, - { - "description": "deny-request-user-attention -> Denies the request_user_attention command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-request-user-attention" - ] - }, - { - "description": "allow-scale-factor -> Enables the scale_factor command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-scale-factor" - ] - }, - { - "description": "deny-scale-factor -> Denies the scale_factor command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-scale-factor" - ] - }, - { - "description": "allow-set-always-on-bottom -> Enables the set_always_on_bottom command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-always-on-bottom" - ] - }, - { - "description": "deny-set-always-on-bottom -> Denies the set_always_on_bottom command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-always-on-bottom" - ] - }, - { - "description": "allow-set-always-on-top -> Enables the set_always_on_top command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-always-on-top" - ] - }, - { - "description": "deny-set-always-on-top -> Denies the set_always_on_top command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-always-on-top" - ] - }, - { - "description": "allow-set-closable -> Enables the set_closable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-closable" - ] - }, - { - "description": "deny-set-closable -> Denies the set_closable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-closable" - ] - }, - { - "description": "allow-set-content-protected -> Enables the set_content_protected command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-content-protected" - ] - }, - { - "description": "deny-set-content-protected -> Denies the set_content_protected command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-content-protected" - ] - }, - { - "description": "allow-set-cursor-grab -> Enables the set_cursor_grab command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-cursor-grab" - ] - }, - { - "description": "deny-set-cursor-grab -> Denies the set_cursor_grab command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-cursor-grab" - ] - }, - { - "description": "allow-set-cursor-icon -> Enables the set_cursor_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-cursor-icon" - ] - }, - { - "description": "deny-set-cursor-icon -> Denies the set_cursor_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-cursor-icon" - ] - }, - { - "description": "allow-set-cursor-position -> Enables the set_cursor_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-cursor-position" - ] - }, - { - "description": "deny-set-cursor-position -> Denies the set_cursor_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-cursor-position" - ] - }, - { - "description": "allow-set-cursor-visible -> Enables the set_cursor_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-cursor-visible" - ] - }, - { - "description": "deny-set-cursor-visible -> Denies the set_cursor_visible command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-cursor-visible" - ] - }, - { - "description": "allow-set-decorations -> Enables the set_decorations command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-decorations" - ] - }, - { - "description": "deny-set-decorations -> Denies the set_decorations command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-decorations" - ] - }, - { - "description": "allow-set-effects -> Enables the set_effects command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-effects" - ] - }, - { - "description": "deny-set-effects -> Denies the set_effects command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-effects" - ] - }, - { - "description": "allow-set-focus -> Enables the set_focus command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-focus" - ] - }, - { - "description": "deny-set-focus -> Denies the set_focus command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-focus" - ] - }, - { - "description": "allow-set-fullscreen -> Enables the set_fullscreen command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-fullscreen" - ] - }, - { - "description": "deny-set-fullscreen -> Denies the set_fullscreen command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-fullscreen" - ] - }, - { - "description": "allow-set-icon -> Enables the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-icon" - ] - }, - { - "description": "deny-set-icon -> Denies the set_icon command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-icon" - ] - }, - { - "description": "allow-set-ignore-cursor-events -> Enables the set_ignore_cursor_events command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-ignore-cursor-events" - ] - }, - { - "description": "deny-set-ignore-cursor-events -> Denies the set_ignore_cursor_events command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-ignore-cursor-events" - ] - }, - { - "description": "allow-set-max-size -> Enables the set_max_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-max-size" - ] - }, - { - "description": "deny-set-max-size -> Denies the set_max_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-max-size" - ] - }, - { - "description": "allow-set-maximizable -> Enables the set_maximizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-maximizable" - ] - }, - { - "description": "deny-set-maximizable -> Denies the set_maximizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-maximizable" - ] - }, - { - "description": "allow-set-min-size -> Enables the set_min_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-min-size" - ] - }, - { - "description": "deny-set-min-size -> Denies the set_min_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-min-size" - ] - }, - { - "description": "allow-set-minimizable -> Enables the set_minimizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-minimizable" - ] - }, - { - "description": "deny-set-minimizable -> Denies the set_minimizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-minimizable" - ] - }, - { - "description": "allow-set-position -> Enables the set_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-position" - ] - }, - { - "description": "deny-set-position -> Denies the set_position command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-position" - ] - }, - { - "description": "allow-set-progress-bar -> Enables the set_progress_bar command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-progress-bar" - ] - }, - { - "description": "deny-set-progress-bar -> Denies the set_progress_bar command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-progress-bar" - ] - }, - { - "description": "allow-set-resizable -> Enables the set_resizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-resizable" - ] - }, - { - "description": "deny-set-resizable -> Denies the set_resizable command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-resizable" - ] - }, - { - "description": "allow-set-shadow -> Enables the set_shadow command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-shadow" - ] - }, - { - "description": "deny-set-shadow -> Denies the set_shadow command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-shadow" - ] - }, - { - "description": "allow-set-size -> Enables the set_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-size" - ] - }, - { - "description": "deny-set-size -> Denies the set_size command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-size" - ] - }, - { - "description": "allow-set-skip-taskbar -> Enables the set_skip_taskbar command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-skip-taskbar" - ] - }, - { - "description": "deny-set-skip-taskbar -> Denies the set_skip_taskbar command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-skip-taskbar" - ] - }, - { - "description": "allow-set-title -> Enables the set_title command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-set-title" - ] - }, - { - "description": "deny-set-title -> Denies the set_title command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-set-title" - ] - }, - { - "description": "allow-show -> Enables the show command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-show" - ] - }, - { - "description": "deny-show -> Denies the show command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-show" - ] - }, - { - "description": "allow-start-dragging -> Enables the start_dragging command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-start-dragging" - ] - }, - { - "description": "deny-start-dragging -> Denies the start_dragging command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-start-dragging" - ] - }, - { - "description": "allow-theme -> Enables the theme command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-theme" - ] - }, - { - "description": "deny-theme -> Denies the theme command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-theme" - ] - }, - { - "description": "allow-title -> Enables the title command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-title" - ] - }, - { - "description": "deny-title -> Denies the title command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-title" - ] - }, - { - "description": "allow-toggle-maximize -> Enables the toggle_maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-toggle-maximize" - ] - }, - { - "description": "deny-toggle-maximize -> Denies the toggle_maximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-toggle-maximize" - ] - }, - { - "description": "allow-unmaximize -> Enables the unmaximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-unmaximize" - ] - }, - { - "description": "deny-unmaximize -> Denies the unmaximize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-unmaximize" - ] - }, - { - "description": "allow-unminimize -> Enables the unminimize command without any pre-configured scope.", - "type": "string", - "enum": [ - "allow-unminimize" - ] - }, - { - "description": "deny-unminimize -> Denies the unminimize command without any pre-configured scope.", - "type": "string", - "enum": [ - "deny-unminimize" - ] - }, - { - "description": "default -> Default permissions for the plugin.", - "type": "string", - "enum": [ - "default" - ] - } - ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "type": [ - "array", - "null" - ], - "items": { - "$ref": "#/definitions/Value" - } - } - } - }, - "Value": { - "description": "All supported ACL values.", - "anyOf": [ - { - "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" - } - } - ] - } - } -} \ No newline at end of file diff --git a/core/tauri/permissions/window/schemas/schema.json b/core/tauri/permissions/window/schemas/schema.json index d3b4d9103cb6..af63424a8207 100644 --- a/core/tauri/permissions/window/schemas/schema.json +++ b/core/tauri/permissions/window/schemas/schema.json @@ -15,46 +15,24 @@ } ] }, - "permission": { - "description": "A list of inlined permissions", + "set": { + "description": "A list of permissions sets defined", "default": [], "type": "array", "items": { - "$ref": "#/definitions/Permission" + "$ref": "#/definitions/PermissionSet" } }, - "set": { - "description": "A list of permissions sets defined", + "permission": { + "description": "A list of inlined permissions", "default": [], "type": "array", "items": { - "$ref": "#/definitions/PermissionSet" + "$ref": "#/definitions/Permission" } } }, "definitions": { - "Commands": { - "description": "Allowed and denied commands inside a permission.\n\nIf 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" - } - } - } - }, "DefaultPermission": { "description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.", "type": "object", @@ -62,6 +40,15 @@ "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.", "type": [ @@ -75,32 +62,34 @@ "items": { "type": "string" } - }, - "version": { - "description": "The version of the permission.", - "type": [ - "integer", - "null" - ], - "format": "uint64", - "minimum": 1.0 } } }, - "Number": { - "description": "A valid ACL number.", - "anyOf": [ - { - "description": "Represents an [`i64`].", - "type": "integer", - "format": "int64" + "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": "Represents a [`f64`].", - "type": "number", - "format": "double" + "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\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.", @@ -109,6 +98,26 @@ "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.", + "type": [ + "string", + "null" + ] + }, "commands": { "description": "Allowed or denied commands when using this permission.", "default": { @@ -121,17 +130,6 @@ } ] }, - "description": { - "description": "Human-readable description of what the permission does.", - "type": [ - "string", - "null" - ] - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, "scope": { "description": "Allowed or denied scoped when using this permission.", "default": {}, @@ -140,18 +138,111 @@ "$ref": "#/definitions/Scopes" } ] + } + } + }, + "Commands": { + "description": "Allowed and denied commands inside a permission.\n\nIf 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" + } }, - "version": { - "description": "The version of the permission.", + "deny": { + "description": "Denied command, which takes priority.", + "default": [], + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "Scopes": { + "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", + "type": "object", + "properties": { + "allow": { + "description": "Data that defines what is allowed by the scope.", "type": [ - "integer", + "array", "null" ], - "format": "uint64", - "minimum": 1.0 + "items": { + "$ref": "#/definitions/Value" + } + }, + "deny": { + "description": "Data that defines what is denied by the scope.", + "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" + } + ] + }, "PermissionKind": { "type": "string", "oneOf": [ @@ -225,6 +316,20 @@ "deny-current-monitor" ] }, + { + "description": "allow-destroy -> Enables the destroy command without any pre-configured scope.", + "type": "string", + "enum": [ + "allow-destroy" + ] + }, + { + "description": "deny-destroy -> Denies the destroy command without any pre-configured scope.", + "type": "string", + "enum": [ + "deny-destroy" + ] + }, { "description": "allow-hide -> Enables the hide command without any pre-configured scope.", "type": "string", @@ -1017,97 +1122,6 @@ ] } ] - }, - "PermissionSet": { - "description": "A set of direct permissions grouped together under a new name.", - "type": "object", - "required": [ - "description", - "identifier", - "permissions" - ], - "properties": { - "description": { - "description": "Human-readable description of what the permission does.", - "type": "string" - }, - "identifier": { - "description": "A unique identifier for the permission.", - "type": "string" - }, - "permissions": { - "description": "All permissions this set contains.", - "type": "array", - "items": { - "$ref": "#/definitions/PermissionKind" - } - } - } - }, - "Scopes": { - "description": "A restriction of the command/endpoint functionality.\n\nIt can be of any serde serializable type and is used for allowing or preventing certain actions inside a Tauri command.\n\nThe scope is passed to the command and handled/enforced by the command itself.", - "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.", - "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" - } - } - ] } } } \ No newline at end of file diff --git a/core/tauri/scripts/bundle.global.js b/core/tauri/scripts/bundle.global.js index 44ca577ae5b5..3531a725c214 100644 --- a/core/tauri/scripts/bundle.global.js +++ b/core/tauri/scripts/bundle.global.js @@ -1 +1 @@ -var __TAURI_IIFE__=function(e){"use strict";function t(e,t,n,i){if("a"===n&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?i:"a"===n?i.call(e):i?i.value:t.get(e)}function n(e,t,n,i,r){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?r.call(e,n):r?r.value=n:t.set(e,n),n}var i,r;function a(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}"function"==typeof SuppressedError&&SuppressedError;class s{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),this.id=a((e=>{t(this,i,"f").call(this,e)}))}set onmessage(e){n(this,i,e,"f")}get onmessage(){return t(this,i,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}i=new WeakMap;class l{constructor(e,t,n){this.plugin=e,this.event=t,this.channelId=n}async unregister(){return o(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function o(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}class u{get rid(){return t(this,r,"f")}constructor(e){r.set(this,void 0),n(this,r,e,"f")}async close(){return o("plugin:resources|close",{rid:this.rid})}}r=new WeakMap;var c=Object.freeze({__proto__:null,Channel:s,PluginListener:l,Resource:u,addPluginListener:async function(e,t,n){const i=new s;return i.onmessage=n,o(`plugin:${e}|register_listener`,{event:t,handler:i}).then((()=>new l(e,t,i.id)))},convertFileSrc:function(e,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,t)},invoke:o,transformCallback:a});var d,p=Object.freeze({__proto__:null,getName:async function(){return o("plugin:app|name")},getTauriVersion:async function(){return o("plugin:app|tauri_version")},getVersion:async function(){return o("plugin:app|version")},hide:async function(){return o("plugin:app|app_hide")},show:async function(){return o("plugin:app|app_show")}});async function h(e,t){await o("plugin:event|unlisten",{event:e,eventId:t})}async function y(e,t,n){return o("plugin:event|listen",{event:e,target:n?.target,handler:a(t)}).then((t=>async()=>h(e,t)))}async function w(e,t,n){return y(e,(n=>{t(n),h(e,n.id).catch((()=>{}))}),n)}async function g(e,t,n){await o("plugin:event|emit",{event:e,target:n?.target,payload:t})}!function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WEBVIEW_CREATED="tauri://webview-created",e.WEBVIEW_FILE_DROP="tauri://file-drop",e.WEBVIEW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WEBVIEW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled"}(d||(d={}));var b=Object.freeze({__proto__:null,get TauriEvent(){return d},emit:g,listen:y,once:w});class _{constructor(e,t){this.type="Logical",this.width=e,this.height=t}}class m{constructor(e,t){this.type="Physical",this.width=e,this.height=t}toLogical(e){return new _(this.width/e,this.height/e)}}class f{constructor(e,t){this.type="Logical",this.x=e,this.y=t}}class v{constructor(e,t){this.type="Physical",this.x=e,this.y=t}toLogical(e){return new f(this.x/e,this.y/e)}}var k,E,A=Object.freeze({__proto__:null,LogicalPosition:f,LogicalSize:_,PhysicalPosition:v,PhysicalSize:m});!function(e){e[e.Critical=1]="Critical",e[e.Informational=2]="Informational"}(k||(k={}));class D{constructor(e){this._preventDefault=!1,this.event=e.event,this.source=e.source,this.id=e.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}}function I(){return new S(window.__TAURI_INTERNALS__.metadata.currentWindow.label,{skip:!0})}function L(){return window.__TAURI_INTERNALS__.metadata.windows.map((e=>new S(e.label,{skip:!0})))}!function(e){e.None="none",e.Normal="normal",e.Indeterminate="indeterminate",e.Paused="paused",e.Error="error"}(E||(E={}));const P=["tauri://created","tauri://error"];class S{constructor(e,t={}){this.label=e,this.listeners=Object.create(null),t?.skip||o("plugin:window|create",{options:{...t,parent:"string"==typeof t.parent?t.parent:t.parent?.label,label:e}}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){return L().find((t=>t.label===e))??null}static getCurrent(){return I()}static getAll(){return L()}static async getFocusedWindow(){for(const e of L())if(await e.isFocused())return e;return null}async listen(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):y(e,t,{target:{kind:"window",label:this.label}})}async once(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):w(e,t,{target:{kind:"window",label:this.label}})}async emit(e,t){if(P.includes(e)){for(const n of this.listeners[e]||[])n({event:e,id:-1,source:{kind:"window",label:this.label},payload:t});return Promise.resolve()}return g(e,t,{target:{kind:"window",label:this.label}})}_handleTauriEvent(e,t){return!!P.includes(e)&&(e in this.listeners?this.listeners[e].push(t):this.listeners[e]=[t],!0)}async scaleFactor(){return o("plugin:window|scale_factor",{label:this.label})}async innerPosition(){return o("plugin:window|inner_position",{label:this.label}).then((({x:e,y:t})=>new v(e,t)))}async outerPosition(){return o("plugin:window|outer_position",{label:this.label}).then((({x:e,y:t})=>new v(e,t)))}async innerSize(){return o("plugin:window|inner_size",{label:this.label}).then((({width:e,height:t})=>new m(e,t)))}async outerSize(){return o("plugin:window|outer_size",{label:this.label}).then((({width:e,height:t})=>new m(e,t)))}async isFullscreen(){return o("plugin:window|is_fullscreen",{label:this.label})}async isMinimized(){return o("plugin:window|is_minimized",{label:this.label})}async isMaximized(){return o("plugin:window|is_maximized",{label:this.label})}async isFocused(){return o("plugin:window|is_focused",{label:this.label})}async isDecorated(){return o("plugin:window|is_decorated",{label:this.label})}async isResizable(){return o("plugin:window|is_resizable",{label:this.label})}async isMaximizable(){return o("plugin:window|is_maximizable",{label:this.label})}async isMinimizable(){return o("plugin:window|is_minimizable",{label:this.label})}async isClosable(){return o("plugin:window|is_closable",{label:this.label})}async isVisible(){return o("plugin:window|is_visible",{label:this.label})}async title(){return o("plugin:window|title",{label:this.label})}async theme(){return o("plugin:window|theme",{label:this.label})}async center(){return o("plugin:window|center",{label:this.label})}async requestUserAttention(e){let t=null;return e&&(t=e===k.Critical?{type:"Critical"}:{type:"Informational"}),o("plugin:window|request_user_attention",{label:this.label,value:t})}async setResizable(e){return o("plugin:window|set_resizable",{label:this.label,value:e})}async setMaximizable(e){return o("plugin:window|set_maximizable",{label:this.label,value:e})}async setMinimizable(e){return o("plugin:window|set_minimizable",{label:this.label,value:e})}async setClosable(e){return o("plugin:window|set_closable",{label:this.label,value:e})}async setTitle(e){return o("plugin:window|set_title",{label:this.label,value:e})}async maximize(){return o("plugin:window|maximize",{label:this.label})}async unmaximize(){return o("plugin:window|unmaximize",{label:this.label})}async toggleMaximize(){return o("plugin:window|toggle_maximize",{label:this.label})}async minimize(){return o("plugin:window|minimize",{label:this.label})}async unminimize(){return o("plugin:window|unminimize",{label:this.label})}async show(){return o("plugin:window|show",{label:this.label})}async hide(){return o("plugin:window|hide",{label:this.label})}async close(){return o("plugin:window|close",{label:this.label})}async destroy(){return o("plugin:window|destroy",{label:this.label})}async setDecorations(e){return o("plugin:window|set_decorations",{label:this.label,value:e})}async setShadow(e){return o("plugin:window|set_shadow",{label:this.label,value:e})}async setEffects(e){return o("plugin:window|set_effects",{label:this.label,value:e})}async clearEffects(){return o("plugin:window|set_effects",{label:this.label,value:null})}async setAlwaysOnTop(e){return o("plugin:window|set_always_on_top",{label:this.label,value:e})}async setAlwaysOnBottom(e){return o("plugin:window|set_always_on_bottom",{label:this.label,value:e})}async setContentProtected(e){return o("plugin:window|set_content_protected",{label:this.label,value:e})}async setSize(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_size",{label:this.label,value:{type:e.type,data:{width:e.width,height:e.height}}})}async setMinSize(e){if(e&&"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_min_size",{label:this.label,value:e?{type:e.type,data:{width:e.width,height:e.height}}:null})}async setMaxSize(e){if(e&&"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_max_size",{label:this.label,value:e?{type:e.type,data:{width:e.width,height:e.height}}:null})}async setPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:window|set_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setFullscreen(e){return o("plugin:window|set_fullscreen",{label:this.label,value:e})}async setFocus(){return o("plugin:window|set_focus",{label:this.label})}async setIcon(e){return o("plugin:window|set_icon",{label:this.label,value:"string"==typeof e?e:Array.from(e)})}async setSkipTaskbar(e){return o("plugin:window|set_skip_taskbar",{label:this.label,value:e})}async setCursorGrab(e){return o("plugin:window|set_cursor_grab",{label:this.label,value:e})}async setCursorVisible(e){return o("plugin:window|set_cursor_visible",{label:this.label,value:e})}async setCursorIcon(e){return o("plugin:window|set_cursor_icon",{label:this.label,value:e})}async setCursorPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:window|set_cursor_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setIgnoreCursorEvents(e){return o("plugin:window|set_ignore_cursor_events",{label:this.label,value:e})}async startDragging(){return o("plugin:window|start_dragging",{label:this.label})}async startResizeDragging(e){return o("plugin:window|start_resize_dragging",{label:this.label,value:e})}async setProgressBar(e){return o("plugin:window|set_progress_bar",{label:this.label,value:e})}async setVisibleOnAllWorkspaces(e){return o("plugin:window|set_visible_on_all_workspaces",{label:this.label,value:e})}async onResized(e){return this.listen(d.WINDOW_RESIZED,(t=>{t.payload=R(t.payload),e(t)}))}async onMoved(e){return this.listen(d.WINDOW_MOVED,(t=>{t.payload=z(t.payload),e(t)}))}async onCloseRequested(e){return this.listen(d.WINDOW_CLOSE_REQUESTED,(t=>{const n=new D(t);Promise.resolve(e(n)).then((()=>{if(!n.isPreventDefault())return this.destroy()}))}))}async onFocusChanged(e){const t=await this.listen(d.WINDOW_FOCUS,(t=>{e({...t,payload:!0})})),n=await this.listen(d.WINDOW_BLUR,(t=>{e({...t,payload:!1})}));return()=>{t(),n()}}async onScaleChanged(e){return this.listen(d.WINDOW_SCALE_FACTOR_CHANGED,e)}async onThemeChanged(e){return this.listen(d.WINDOW_THEME_CHANGED,e)}}var T,C;function x(e){return null===e?null:{name:e.name,scaleFactor:e.scaleFactor,position:z(e.position),size:R(e.size)}}function z(e){return new v(e.x,e.y)}function R(e){return new m(e.width,e.height)}!function(e){e.AppearanceBased="appearanceBased",e.Light="light",e.Dark="dark",e.MediumLight="mediumLight",e.UltraDark="ultraDark",e.Titlebar="titlebar",e.Selection="selection",e.Menu="menu",e.Popover="popover",e.Sidebar="sidebar",e.HeaderView="headerView",e.Sheet="sheet",e.WindowBackground="windowBackground",e.HudWindow="hudWindow",e.FullScreenUI="fullScreenUI",e.Tooltip="tooltip",e.ContentBackground="contentBackground",e.UnderWindowBackground="underWindowBackground",e.UnderPageBackground="underPageBackground",e.Mica="mica",e.Blur="blur",e.Acrylic="acrylic",e.Tabbed="tabbed",e.TabbedDark="tabbedDark",e.TabbedLight="tabbedLight"}(T||(T={})),function(e){e.FollowsWindowActiveState="followsWindowActiveState",e.Active="active",e.Inactive="inactive"}(C||(C={}));var F=Object.freeze({__proto__:null,CloseRequestedEvent:D,get Effect(){return T},get EffectState(){return C},LogicalPosition:f,LogicalSize:_,PhysicalPosition:v,PhysicalSize:m,get ProgressBarStatus(){return E},get UserAttentionType(){return k},Window:S,availableMonitors:async function(){return o("plugin:window|available_monitors").then((e=>e.map(x)))},currentMonitor:async function(){return o("plugin:window|current_monitor").then(x)},getAll:L,getCurrent:I,primaryMonitor:async function(){return o("plugin:window|primary_monitor").then(x)}});function W(){return new M(I(),window.__TAURI_INTERNALS__.metadata.currentWebview.label,{skip:!0})}function O(){return window.__TAURI_INTERNALS__.metadata.webviews.map((e=>new M(S.getByLabel(e.windowLabel),e.label,{skip:!0})))}const N=["tauri://created","tauri://error"];class M{constructor(e,t,n){this.window=e,this.label=t,this.listeners=Object.create(null),n?.skip||o("plugin:webview|create_webview",{windowLabel:e.label,label:t,options:n}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){return O().find((t=>t.label===e))??null}static getCurrent(){return W()}static getAll(){return O()}async listen(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):y(e,t,{target:{kind:"webview",label:this.label}})}async once(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):w(e,t,{target:{kind:"webview",label:this.label}})}async emit(e,t){if(N.includes(e)){for(const n of this.listeners[e]||[])n({event:e,id:-1,source:{kind:"webview",label:this.label},payload:t});return Promise.resolve()}return g(e,t,{target:{kind:"webview",label:this.label}})}_handleTauriEvent(e,t){return!!N.includes(e)&&(e in this.listeners?this.listeners[e].push(t):this.listeners[e]=[t],!0)}async position(){return o("plugin:webview|webview_position",{label:this.label}).then((({x:e,y:t})=>new v(e,t)))}async size(){return o("plugin:webview|webview_size",{label:this.label}).then((({width:e,height:t})=>new m(e,t)))}async close(){return o("plugin:webview|close",{label:this.label})}async setSize(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:webview|set_webview_size",{label:this.label,value:{type:e.type,data:{width:e.width,height:e.height}}})}async setPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:webview|set_webview_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setFocus(){return o("plugin:webview|set_webview_focus",{label:this.label})}async onFileDropEvent(e){const t=await this.listen(d.WEBVIEW_FILE_DROP,(t=>{e({...t,payload:{type:"drop",paths:t.payload.paths,position:U(t.payload.position)}})})),n=await this.listen(d.WEBVIEW_FILE_DROP_HOVER,(t=>{e({...t,payload:{type:"hover",paths:t.payload.paths,position:U(t.payload.position)}})})),i=await this.listen(d.WEBVIEW_FILE_DROP_CANCELLED,(t=>{e({...t,payload:{type:"cancel"}})}));return()=>{t(),n(),i()}}}function U(e){return new v(e.x,e.y)}class B{constructor(e,t={}){this.label=e,this.listeners=Object.create(null),t?.skip||o("plugin:webview|create_webview_window",{options:{...t,parent:"string"==typeof t.parent?t.parent:t.parent?.label,label:e}}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){const t=O().find((t=>t.label===e))??null;return t?new B(t.label,{skip:!0}):null}static getCurrent(){const e=W();return new B(e.label,{skip:!0})}static getAll(){return O().map((e=>new B(e.label,{skip:!0})))}}var V,j;V=B,j=[M,S],(Array.isArray(j)?j:[j]).forEach((e=>{Object.getOwnPropertyNames(e.prototype).forEach((t=>{Object.defineProperty(V.prototype,t,Object.getOwnPropertyDescriptor(e.prototype,t)??Object.create(null))}))}));var H,G=Object.freeze({__proto__:null,Webview:M,WebviewWindow:B,getAll:O,getCurrent:W});!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.Document=6]="Document",e[e.Download=7]="Download",e[e.Picture=8]="Picture",e[e.Public=9]="Public",e[e.Video=10]="Video",e[e.Resource=11]="Resource",e[e.Temp=12]="Temp",e[e.AppConfig=13]="AppConfig",e[e.AppData=14]="AppData",e[e.AppLocalData=15]="AppLocalData",e[e.AppCache=16]="AppCache",e[e.AppLog=17]="AppLog",e[e.Desktop=18]="Desktop",e[e.Executable=19]="Executable",e[e.Font=20]="Font",e[e.Home=21]="Home",e[e.Runtime=22]="Runtime",e[e.Template=23]="Template"}(H||(H={}));var q=Object.freeze({__proto__:null,get BaseDirectory(){return H},appCacheDir:async function(){return o("plugin:path|resolve_directory",{directory:H.AppCache})},appConfigDir:async function(){return o("plugin:path|resolve_directory",{directory:H.AppConfig})},appDataDir:async function(){return o("plugin:path|resolve_directory",{directory:H.AppData})},appLocalDataDir:async function(){return o("plugin:path|resolve_directory",{directory:H.AppLocalData})},appLogDir:async function(){return o("plugin:path|resolve_directory",{directory:H.AppLog})},audioDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Audio})},basename:async function(e,t){return o("plugin:path|basename",{path:e,ext:t})},cacheDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Cache})},configDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Config})},dataDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Data})},delimiter:function(){return window.__TAURI_INTERNALS__.plugins.path.delimiter},desktopDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Desktop})},dirname:async function(e){return o("plugin:path|dirname",{path:e})},documentDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Document})},downloadDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Download})},executableDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Executable})},extname:async function(e){return o("plugin:path|extname",{path:e})},fontDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Font})},homeDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Home})},isAbsolute:async function(e){return o("plugin:path|isAbsolute",{path:e})},join:async function(...e){return o("plugin:path|join",{paths:e})},localDataDir:async function(){return o("plugin:path|resolve_directory",{directory:H.LocalData})},normalize:async function(e){return o("plugin:path|normalize",{path:e})},pictureDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Picture})},publicDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Public})},resolve:async function(...e){return o("plugin:path|resolve",{paths:e})},resolveResource:async function(e){return o("plugin:path|resolve_directory",{directory:H.Resource,path:e})},resourceDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Resource})},runtimeDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Runtime})},sep:function(){return window.__TAURI_INTERNALS__.plugins.path.sep},tempDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Temp})},templateDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Template})},videoDir:async function(){return o("plugin:path|resolve_directory",{directory:H.Video})}});class Q extends u{constructor(e,t){super(e),this.id=t}static async new(e){e?.menu&&(e.menu=[e.menu.rid,e.menu.kind]),e?.icon&&(e.icon="string"==typeof e.icon?e.icon:Array.from(e.icon));const t=new s;return e?.action&&(t.onmessage=e.action,delete e.action),o("plugin:tray|new",{options:e??{},handler:t}).then((([e,t])=>new Q(e,t)))}async setIcon(e){let t=null;return e&&(t="string"==typeof e?e:Array.from(e)),o("plugin:tray|set_icon",{rid:this.rid,icon:t})}async setMenu(e){return e&&(e=[e.rid,e.kind]),o("plugin:tray|set_menu",{rid:this.rid,menu:e})}async setTooltip(e){return o("plugin:tray|set_tooltip",{rid:this.rid,tooltip:e})}async setTitle(e){return o("plugin:tray|set_title",{rid:this.rid,title:e})}async setVisible(e){return o("plugin:tray|set_visible",{rid:this.rid,visible:e})}async setTempDirPath(e){return o("plugin:tray|set_temp_dir_path",{rid:this.rid,path:e})}async setIconAsTemplate(e){return o("plugin:tray|set_icon_as_template",{rid:this.rid,asTemplate:e})}async setMenuOnLeftClick(e){return o("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}}var $,Z,J,K=Object.freeze({__proto__:null,TrayIcon:Q});function Y(e){if("items"in e)e.items=e.items?.map((e=>"rid"in e?e:Y(e)));else if("action"in e&&e.action){const t=new s;return t.onmessage=e.action,delete e.action,{...e,handler:t}}return e}async function X(e,t){const n=new s;let i=null;return t&&"object"==typeof t&&("action"in t&&t.action&&(n.onmessage=t.action,delete t.action),"items"in t&&t.items&&(i=t.items.map((e=>"rid"in e?[e.rid,e.kind]:Y(e))))),o("plugin:menu|new",{kind:e,options:t?{...t,items:i}:void 0,handler:n})}class ee extends u{get id(){return t(this,$,"f")}get kind(){return t(this,Z,"f")}constructor(e,t,i){super(e),$.set(this,void 0),Z.set(this,void 0),n(this,$,t,"f"),n(this,Z,i,"f")}}$=new WeakMap,Z=new WeakMap;class te extends ee{constructor(e,t){super(e,t,"MenuItem")}static async new(e){return X("MenuItem",e).then((([e,t])=>new te(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}}class ne extends ee{constructor(e,t){super(e,t,"Check")}static async new(e){return X("Check",e).then((([e,t])=>new ne(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async isChecked(){return o("plugin:menu|is_checked",{rid:this.rid})}async setChecked(e){return o("plugin:menu|set_checked",{rid:this.rid,checked:e})}}!function(e){e.Add="Add",e.Advanced="Advanced",e.Bluetooth="Bluetooth",e.Bookmarks="Bookmarks",e.Caution="Caution",e.ColorPanel="ColorPanel",e.ColumnView="ColumnView",e.Computer="Computer",e.EnterFullScreen="EnterFullScreen",e.Everyone="Everyone",e.ExitFullScreen="ExitFullScreen",e.FlowView="FlowView",e.Folder="Folder",e.FolderBurnable="FolderBurnable",e.FolderSmart="FolderSmart",e.FollowLinkFreestanding="FollowLinkFreestanding",e.FontPanel="FontPanel",e.GoLeft="GoLeft",e.GoRight="GoRight",e.Home="Home",e.IChatTheater="IChatTheater",e.IconView="IconView",e.Info="Info",e.InvalidDataFreestanding="InvalidDataFreestanding",e.LeftFacingTriangle="LeftFacingTriangle",e.ListView="ListView",e.LockLocked="LockLocked",e.LockUnlocked="LockUnlocked",e.MenuMixedState="MenuMixedState",e.MenuOnState="MenuOnState",e.MobileMe="MobileMe",e.MultipleDocuments="MultipleDocuments",e.Network="Network",e.Path="Path",e.PreferencesGeneral="PreferencesGeneral",e.QuickLook="QuickLook",e.RefreshFreestanding="RefreshFreestanding",e.Refresh="Refresh",e.Remove="Remove",e.RevealFreestanding="RevealFreestanding",e.RightFacingTriangle="RightFacingTriangle",e.Share="Share",e.Slideshow="Slideshow",e.SmartBadge="SmartBadge",e.StatusAvailable="StatusAvailable",e.StatusNone="StatusNone",e.StatusPartiallyAvailable="StatusPartiallyAvailable",e.StatusUnavailable="StatusUnavailable",e.StopProgressFreestanding="StopProgressFreestanding",e.StopProgress="StopProgress",e.TrashEmpty="TrashEmpty",e.TrashFull="TrashFull",e.User="User",e.UserAccounts="UserAccounts",e.UserGroup="UserGroup",e.UserGuest="UserGuest"}(J||(J={}));class ie extends ee{constructor(e,t){super(e,t,"Icon")}static async new(e){return X("Icon",e).then((([e,t])=>new ie(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async setIcon(e){return o("plugin:menu|set_icon",{rid:this.rid,icon:e})}}class re extends ee{constructor(e,t){super(e,t,"Predefined")}static async new(e){return X("Predefined",e).then((([e,t])=>new re(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}}function ae([e,t,n]){switch(n){case"Submenu":return new se(e,t);case"Predefined":return new re(e,t);case"Check":return new ne(e,t);case"Icon":return new ie(e,t);default:return new te(e,t)}}class se extends ee{constructor(e,t){super(e,t,"Submenu")}static async new(e){return X("Submenu",e).then((([e,t])=>new se(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async append(e){return o("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async prepend(e){return o("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async insert(e,t){return o("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e)),position:t})}async remove(e){return o("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return o("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(ae)}async items(){return o("plugin:menu|items",{rid:this.rid,kind:this.kind}).then((e=>e.map(ae)))}async get(e){return o("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then((e=>e?ae(e):null))}async popup(e,t){let n=null;return e&&(n={type:e instanceof v?"Physical":"Logical",data:e}),o("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:t?.label??null,at:n})}async setAsWindowsMenuForNSApp(){return o("plugin:menu|set_as_windows_menu_for_nsapp",{rid:this.rid})}async setAsHelpMenuForNSApp(){return o("plugin:menu|set_as_help_menu_for_nsapp",{rid:this.rid})}}function le([e,t,n]){switch(n){case"Submenu":return new se(e,t);case"Predefined":return new re(e,t);case"Check":return new ne(e,t);case"Icon":return new ie(e,t);default:return new te(e,t)}}class oe extends ee{constructor(e,t){super(e,t,"Menu")}static async new(e){return X("Menu",e).then((([e,t])=>new oe(e,t)))}static async default(){return o("plugin:menu|create_default").then((([e,t])=>new oe(e,t)))}async append(e){return o("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async prepend(e){return o("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async insert(e,t){return o("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e)),position:t})}async remove(e){return o("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return o("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(le)}async items(){return o("plugin:menu|items",{rid:this.rid,kind:this.kind}).then((e=>e.map(le)))}async get(e){return o("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then((e=>e?le(e):null))}async popup(e,t){let n=null;return e&&(n={type:e instanceof v?"Physical":"Logical",data:e}),o("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:t?.label??null,at:n})}async setAsAppMenu(){return o("plugin:menu|set_as_app_menu",{rid:this.rid}).then((e=>e?new oe(e[0],e[1]):null))}async setAsWindowMenu(e){return o("plugin:menu|set_as_window_menu",{rid:this.rid,window:e?.label??null}).then((e=>e?new oe(e[0],e[1]):null))}}var ue=Object.freeze({__proto__:null,CheckMenuItem:ne,IconMenuItem:ie,Menu:oe,MenuItem:te,get NativeIcon(){return J},PredefinedMenuItem:re,Submenu:se});return e.app=p,e.core=c,e.dpi=A,e.event=b,e.menu=ue,e.path=q,e.tray=K,e.webview=G,e.window=F,e}({});window.__TAURI__=__TAURI_IIFE__; +var __TAURI_IIFE__=function(e){"use strict";function t(e,t,n,i){if("a"===n&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?i:"a"===n?i.call(e):i?i.value:t.get(e)}function n(e,t,n,i,r){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof t?e!==t||!r:!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?r.call(e,n):r?r.value=n:t.set(e,n),n}var i,r;function a(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}"function"==typeof SuppressedError&&SuppressedError;class s{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),this.id=a((e=>{t(this,i,"f").call(this,e)}))}set onmessage(e){n(this,i,e,"f")}get onmessage(){return t(this,i,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}i=new WeakMap;class l{constructor(e,t,n){this.plugin=e,this.event=t,this.channelId=n}async unregister(){return o(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function o(e,t={},n){return window.__TAURI_INTERNALS__.invoke(e,t,n)}class u{get rid(){return t(this,r,"f")}constructor(e){r.set(this,void 0),n(this,r,e,"f")}async close(){return o("plugin:resources|close",{rid:this.rid})}}r=new WeakMap;var c=Object.freeze({__proto__:null,Channel:s,PluginListener:l,Resource:u,addPluginListener:async function(e,t,n){const i=new s;return i.onmessage=n,o(`plugin:${e}|register_listener`,{event:t,handler:i}).then((()=>new l(e,t,i.id)))},convertFileSrc:function(e,t="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,t)},invoke:o,transformCallback:a});var d,p=Object.freeze({__proto__:null,getName:async function(){return o("plugin:app|name")},getTauriVersion:async function(){return o("plugin:app|tauri_version")},getVersion:async function(){return o("plugin:app|version")},hide:async function(){return o("plugin:app|app_hide")},show:async function(){return o("plugin:app|app_show")}});async function h(e,t){await o("plugin:event|unlisten",{event:e,eventId:t})}async function y(e,t,n){const i="string"==typeof n?.target?{kind:"AnyLabel",label:n.target}:n?.target??{kind:"Any"};return o("plugin:event|listen",{event:e,target:i,handler:a(t)}).then((t=>async()=>h(e,t)))}async function w(e,t,n){return y(e,(n=>{t(n),h(e,n.id).catch((()=>{}))}),n)}async function g(e,t){await o("plugin:event|emit",{event:e,payload:t})}async function b(e,t,n){const i="string"==typeof e?{kind:"AnyLabel",label:e}:e;await o("plugin:event|emit_to",{target:i,event:t,payload:n})}!function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WEBVIEW_CREATED="tauri://webview-created",e.WEBVIEW_FILE_DROP="tauri://file-drop",e.WEBVIEW_FILE_DROP_HOVER="tauri://file-drop-hover",e.WEBVIEW_FILE_DROP_CANCELLED="tauri://file-drop-cancelled"}(d||(d={}));var _=Object.freeze({__proto__:null,get TauriEvent(){return d},emit:g,emitTo:b,listen:y,once:w});class m{constructor(e,t){this.type="Logical",this.width=e,this.height=t}}class f{constructor(e,t){this.type="Physical",this.width=e,this.height=t}toLogical(e){return new m(this.width/e,this.height/e)}}class v{constructor(e,t){this.type="Logical",this.x=e,this.y=t}}class k{constructor(e,t){this.type="Physical",this.x=e,this.y=t}toLogical(e){return new v(this.x/e,this.y/e)}}var E,A,D=Object.freeze({__proto__:null,LogicalPosition:v,LogicalSize:m,PhysicalPosition:k,PhysicalSize:f});!function(e){e[e.Critical=1]="Critical",e[e.Informational=2]="Informational"}(E||(E={}));class P{constructor(e){this._preventDefault=!1,this.event=e.event,this.id=e.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}}function L(){return new T(window.__TAURI_INTERNALS__.metadata.currentWindow.label,{skip:!0})}function I(){return window.__TAURI_INTERNALS__.metadata.windows.map((e=>new T(e.label,{skip:!0})))}!function(e){e.None="none",e.Normal="normal",e.Indeterminate="indeterminate",e.Paused="paused",e.Error="error"}(A||(A={}));const S=["tauri://created","tauri://error"];class T{constructor(e,t={}){this.label=e,this.listeners=Object.create(null),t?.skip||o("plugin:window|create",{options:{...t,parent:"string"==typeof t.parent?t.parent:t.parent?.label,label:e}}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){return I().find((t=>t.label===e))??null}static getCurrent(){return L()}static getAll(){return I()}static async getFocusedWindow(){for(const e of I())if(await e.isFocused())return e;return null}async listen(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):y(e,t,{target:{kind:"Window",label:this.label}})}async once(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):w(e,t,{target:{kind:"Window",label:this.label}})}async emit(e,t){if(S.includes(e)){for(const n of this.listeners[e]||[])n({event:e,id:-1,payload:t});return Promise.resolve()}return g(e,t)}async emitTo(e,t,n){if(S.includes(t)){for(const e of this.listeners[t]||[])e({event:t,id:-1,payload:n});return Promise.resolve()}return b(e,t,n)}_handleTauriEvent(e,t){return!!S.includes(e)&&(e in this.listeners?this.listeners[e].push(t):this.listeners[e]=[t],!0)}async scaleFactor(){return o("plugin:window|scale_factor",{label:this.label})}async innerPosition(){return o("plugin:window|inner_position",{label:this.label}).then((({x:e,y:t})=>new k(e,t)))}async outerPosition(){return o("plugin:window|outer_position",{label:this.label}).then((({x:e,y:t})=>new k(e,t)))}async innerSize(){return o("plugin:window|inner_size",{label:this.label}).then((({width:e,height:t})=>new f(e,t)))}async outerSize(){return o("plugin:window|outer_size",{label:this.label}).then((({width:e,height:t})=>new f(e,t)))}async isFullscreen(){return o("plugin:window|is_fullscreen",{label:this.label})}async isMinimized(){return o("plugin:window|is_minimized",{label:this.label})}async isMaximized(){return o("plugin:window|is_maximized",{label:this.label})}async isFocused(){return o("plugin:window|is_focused",{label:this.label})}async isDecorated(){return o("plugin:window|is_decorated",{label:this.label})}async isResizable(){return o("plugin:window|is_resizable",{label:this.label})}async isMaximizable(){return o("plugin:window|is_maximizable",{label:this.label})}async isMinimizable(){return o("plugin:window|is_minimizable",{label:this.label})}async isClosable(){return o("plugin:window|is_closable",{label:this.label})}async isVisible(){return o("plugin:window|is_visible",{label:this.label})}async title(){return o("plugin:window|title",{label:this.label})}async theme(){return o("plugin:window|theme",{label:this.label})}async center(){return o("plugin:window|center",{label:this.label})}async requestUserAttention(e){let t=null;return e&&(t=e===E.Critical?{type:"Critical"}:{type:"Informational"}),o("plugin:window|request_user_attention",{label:this.label,value:t})}async setResizable(e){return o("plugin:window|set_resizable",{label:this.label,value:e})}async setMaximizable(e){return o("plugin:window|set_maximizable",{label:this.label,value:e})}async setMinimizable(e){return o("plugin:window|set_minimizable",{label:this.label,value:e})}async setClosable(e){return o("plugin:window|set_closable",{label:this.label,value:e})}async setTitle(e){return o("plugin:window|set_title",{label:this.label,value:e})}async maximize(){return o("plugin:window|maximize",{label:this.label})}async unmaximize(){return o("plugin:window|unmaximize",{label:this.label})}async toggleMaximize(){return o("plugin:window|toggle_maximize",{label:this.label})}async minimize(){return o("plugin:window|minimize",{label:this.label})}async unminimize(){return o("plugin:window|unminimize",{label:this.label})}async show(){return o("plugin:window|show",{label:this.label})}async hide(){return o("plugin:window|hide",{label:this.label})}async close(){return o("plugin:window|close",{label:this.label})}async destroy(){return o("plugin:window|destroy",{label:this.label})}async setDecorations(e){return o("plugin:window|set_decorations",{label:this.label,value:e})}async setShadow(e){return o("plugin:window|set_shadow",{label:this.label,value:e})}async setEffects(e){return o("plugin:window|set_effects",{label:this.label,value:e})}async clearEffects(){return o("plugin:window|set_effects",{label:this.label,value:null})}async setAlwaysOnTop(e){return o("plugin:window|set_always_on_top",{label:this.label,value:e})}async setAlwaysOnBottom(e){return o("plugin:window|set_always_on_bottom",{label:this.label,value:e})}async setContentProtected(e){return o("plugin:window|set_content_protected",{label:this.label,value:e})}async setSize(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_size",{label:this.label,value:{type:e.type,data:{width:e.width,height:e.height}}})}async setMinSize(e){if(e&&"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_min_size",{label:this.label,value:e?{type:e.type,data:{width:e.width,height:e.height}}:null})}async setMaxSize(e){if(e&&"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:window|set_max_size",{label:this.label,value:e?{type:e.type,data:{width:e.width,height:e.height}}:null})}async setPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:window|set_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setFullscreen(e){return o("plugin:window|set_fullscreen",{label:this.label,value:e})}async setFocus(){return o("plugin:window|set_focus",{label:this.label})}async setIcon(e){return o("plugin:window|set_icon",{label:this.label,value:"string"==typeof e?e:Array.from(e)})}async setSkipTaskbar(e){return o("plugin:window|set_skip_taskbar",{label:this.label,value:e})}async setCursorGrab(e){return o("plugin:window|set_cursor_grab",{label:this.label,value:e})}async setCursorVisible(e){return o("plugin:window|set_cursor_visible",{label:this.label,value:e})}async setCursorIcon(e){return o("plugin:window|set_cursor_icon",{label:this.label,value:e})}async setCursorPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:window|set_cursor_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setIgnoreCursorEvents(e){return o("plugin:window|set_ignore_cursor_events",{label:this.label,value:e})}async startDragging(){return o("plugin:window|start_dragging",{label:this.label})}async startResizeDragging(e){return o("plugin:window|start_resize_dragging",{label:this.label,value:e})}async setProgressBar(e){return o("plugin:window|set_progress_bar",{label:this.label,value:e})}async setVisibleOnAllWorkspaces(e){return o("plugin:window|set_visible_on_all_workspaces",{label:this.label,value:e})}async onResized(e){return this.listen(d.WINDOW_RESIZED,(t=>{t.payload=R(t.payload),e(t)}))}async onMoved(e){return this.listen(d.WINDOW_MOVED,(t=>{t.payload=W(t.payload),e(t)}))}async onCloseRequested(e){return this.listen(d.WINDOW_CLOSE_REQUESTED,(t=>{const n=new P(t);Promise.resolve(e(n)).then((()=>{if(!n.isPreventDefault())return this.destroy()}))}))}async onFocusChanged(e){const t=await this.listen(d.WINDOW_FOCUS,(t=>{e({...t,payload:!0})})),n=await this.listen(d.WINDOW_BLUR,(t=>{e({...t,payload:!1})}));return()=>{t(),n()}}async onScaleChanged(e){return this.listen(d.WINDOW_SCALE_FACTOR_CHANGED,e)}async onThemeChanged(e){return this.listen(d.WINDOW_THEME_CHANGED,e)}}var C,x;function z(e){return null===e?null:{name:e.name,scaleFactor:e.scaleFactor,position:W(e.position),size:R(e.size)}}function W(e){return new k(e.x,e.y)}function R(e){return new f(e.width,e.height)}!function(e){e.AppearanceBased="appearanceBased",e.Light="light",e.Dark="dark",e.MediumLight="mediumLight",e.UltraDark="ultraDark",e.Titlebar="titlebar",e.Selection="selection",e.Menu="menu",e.Popover="popover",e.Sidebar="sidebar",e.HeaderView="headerView",e.Sheet="sheet",e.WindowBackground="windowBackground",e.HudWindow="hudWindow",e.FullScreenUI="fullScreenUI",e.Tooltip="tooltip",e.ContentBackground="contentBackground",e.UnderWindowBackground="underWindowBackground",e.UnderPageBackground="underPageBackground",e.Mica="mica",e.Blur="blur",e.Acrylic="acrylic",e.Tabbed="tabbed",e.TabbedDark="tabbedDark",e.TabbedLight="tabbedLight"}(C||(C={})),function(e){e.FollowsWindowActiveState="followsWindowActiveState",e.Active="active",e.Inactive="inactive"}(x||(x={}));var F=Object.freeze({__proto__:null,CloseRequestedEvent:P,get Effect(){return C},get EffectState(){return x},LogicalPosition:v,LogicalSize:m,PhysicalPosition:k,PhysicalSize:f,get ProgressBarStatus(){return A},get UserAttentionType(){return E},Window:T,availableMonitors:async function(){return o("plugin:window|available_monitors").then((e=>e.map(z)))},currentMonitor:async function(){return o("plugin:window|current_monitor").then(z)},getAll:I,getCurrent:L,primaryMonitor:async function(){return o("plugin:window|primary_monitor").then(z)}});function O(){return new U(L(),window.__TAURI_INTERNALS__.metadata.currentWebview.label,{skip:!0})}function N(){return window.__TAURI_INTERNALS__.metadata.webviews.map((e=>new U(T.getByLabel(e.windowLabel),e.label,{skip:!0})))}const M=["tauri://created","tauri://error"];class U{constructor(e,t,n){this.window=e,this.label=t,this.listeners=Object.create(null),n?.skip||o("plugin:webview|create_webview",{windowLabel:e.label,label:t,options:n}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){return N().find((t=>t.label===e))??null}static getCurrent(){return O()}static getAll(){return N()}async listen(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):y(e,t,{target:{kind:"Webview",label:this.label}})}async once(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):w(e,t,{target:{kind:"Webview",label:this.label}})}async emit(e,t){if(M.includes(e)){for(const n of this.listeners[e]||[])n({event:e,id:-1,payload:t});return Promise.resolve()}return g(e,t)}async emitTo(e,t,n){if(M.includes(t)){for(const e of this.listeners[t]||[])e({event:t,id:-1,payload:n});return Promise.resolve()}return b(e,t,n)}_handleTauriEvent(e,t){return!!M.includes(e)&&(e in this.listeners?this.listeners[e].push(t):this.listeners[e]=[t],!0)}async position(){return o("plugin:webview|webview_position",{label:this.label}).then((({x:e,y:t})=>new k(e,t)))}async size(){return o("plugin:webview|webview_size",{label:this.label}).then((({width:e,height:t})=>new f(e,t)))}async close(){return o("plugin:webview|close",{label:this.label})}async setSize(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `size` argument must be either a LogicalSize or a PhysicalSize instance");return o("plugin:webview|set_webview_size",{label:this.label,value:{type:e.type,data:{width:e.width,height:e.height}}})}async setPosition(e){if(!e||"Logical"!==e.type&&"Physical"!==e.type)throw new Error("the `position` argument must be either a LogicalPosition or a PhysicalPosition instance");return o("plugin:webview|set_webview_position",{label:this.label,value:{type:e.type,data:{x:e.x,y:e.y}}})}async setFocus(){return o("plugin:webview|set_webview_focus",{label:this.label})}async onFileDropEvent(e){const t=await this.listen(d.WEBVIEW_FILE_DROP,(t=>{e({...t,payload:{type:"drop",paths:t.payload.paths,position:B(t.payload.position)}})})),n=await this.listen(d.WEBVIEW_FILE_DROP_HOVER,(t=>{e({...t,payload:{type:"hover",paths:t.payload.paths,position:B(t.payload.position)}})})),i=await this.listen(d.WEBVIEW_FILE_DROP_CANCELLED,(t=>{e({...t,payload:{type:"cancel"}})}));return()=>{t(),n(),i()}}}function B(e){return new k(e.x,e.y)}class V{constructor(e,t={}){this.label=e,this.listeners=Object.create(null),t?.skip||o("plugin:webview|create_webview_window",{options:{...t,parent:"string"==typeof t.parent?t.parent:t.parent?.label,label:e}}).then((async()=>this.emit("tauri://created"))).catch((async e=>this.emit("tauri://error",e)))}static getByLabel(e){const t=N().find((t=>t.label===e))??null;return t?new V(t.label,{skip:!0}):null}static getCurrent(){const e=O();return new V(e.label,{skip:!0})}static getAll(){return N().map((e=>new V(e.label,{skip:!0})))}async listen(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):y(e,t,{target:{kind:"WebviewWindow",label:this.label}})}async once(e,t){return this._handleTauriEvent(e,t)?Promise.resolve((()=>{const n=this.listeners[e];n.splice(n.indexOf(t),1)})):w(e,t,{target:{kind:"WebviewWindow",label:this.label}})}}var j,H;j=V,H=[T,U],(Array.isArray(H)?H:[H]).forEach((e=>{Object.getOwnPropertyNames(e.prototype).forEach((t=>{"object"==typeof j.prototype&&j.prototype&&t in j.prototype||Object.defineProperty(j.prototype,t,Object.getOwnPropertyDescriptor(e.prototype,t)??Object.create(null))}))}));var G,q=Object.freeze({__proto__:null,Webview:U,WebviewWindow:V,getAll:N,getCurrent:O});!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.Document=6]="Document",e[e.Download=7]="Download",e[e.Picture=8]="Picture",e[e.Public=9]="Public",e[e.Video=10]="Video",e[e.Resource=11]="Resource",e[e.Temp=12]="Temp",e[e.AppConfig=13]="AppConfig",e[e.AppData=14]="AppData",e[e.AppLocalData=15]="AppLocalData",e[e.AppCache=16]="AppCache",e[e.AppLog=17]="AppLog",e[e.Desktop=18]="Desktop",e[e.Executable=19]="Executable",e[e.Font=20]="Font",e[e.Home=21]="Home",e[e.Runtime=22]="Runtime",e[e.Template=23]="Template"}(G||(G={}));var Q=Object.freeze({__proto__:null,get BaseDirectory(){return G},appCacheDir:async function(){return o("plugin:path|resolve_directory",{directory:G.AppCache})},appConfigDir:async function(){return o("plugin:path|resolve_directory",{directory:G.AppConfig})},appDataDir:async function(){return o("plugin:path|resolve_directory",{directory:G.AppData})},appLocalDataDir:async function(){return o("plugin:path|resolve_directory",{directory:G.AppLocalData})},appLogDir:async function(){return o("plugin:path|resolve_directory",{directory:G.AppLog})},audioDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Audio})},basename:async function(e,t){return o("plugin:path|basename",{path:e,ext:t})},cacheDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Cache})},configDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Config})},dataDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Data})},delimiter:function(){return window.__TAURI_INTERNALS__.plugins.path.delimiter},desktopDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Desktop})},dirname:async function(e){return o("plugin:path|dirname",{path:e})},documentDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Document})},downloadDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Download})},executableDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Executable})},extname:async function(e){return o("plugin:path|extname",{path:e})},fontDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Font})},homeDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Home})},isAbsolute:async function(e){return o("plugin:path|isAbsolute",{path:e})},join:async function(...e){return o("plugin:path|join",{paths:e})},localDataDir:async function(){return o("plugin:path|resolve_directory",{directory:G.LocalData})},normalize:async function(e){return o("plugin:path|normalize",{path:e})},pictureDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Picture})},publicDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Public})},resolve:async function(...e){return o("plugin:path|resolve",{paths:e})},resolveResource:async function(e){return o("plugin:path|resolve_directory",{directory:G.Resource,path:e})},resourceDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Resource})},runtimeDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Runtime})},sep:function(){return window.__TAURI_INTERNALS__.plugins.path.sep},tempDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Temp})},templateDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Template})},videoDir:async function(){return o("plugin:path|resolve_directory",{directory:G.Video})}});class $ extends u{constructor(e,t){super(e),this.id=t}static async new(e){e?.menu&&(e.menu=[e.menu.rid,e.menu.kind]),e?.icon&&(e.icon="string"==typeof e.icon?e.icon:Array.from(e.icon));const t=new s;return e?.action&&(t.onmessage=e.action,delete e.action),o("plugin:tray|new",{options:e??{},handler:t}).then((([e,t])=>new $(e,t)))}async setIcon(e){let t=null;return e&&(t="string"==typeof e?e:Array.from(e)),o("plugin:tray|set_icon",{rid:this.rid,icon:t})}async setMenu(e){return e&&(e=[e.rid,e.kind]),o("plugin:tray|set_menu",{rid:this.rid,menu:e})}async setTooltip(e){return o("plugin:tray|set_tooltip",{rid:this.rid,tooltip:e})}async setTitle(e){return o("plugin:tray|set_title",{rid:this.rid,title:e})}async setVisible(e){return o("plugin:tray|set_visible",{rid:this.rid,visible:e})}async setTempDirPath(e){return o("plugin:tray|set_temp_dir_path",{rid:this.rid,path:e})}async setIconAsTemplate(e){return o("plugin:tray|set_icon_as_template",{rid:this.rid,asTemplate:e})}async setMenuOnLeftClick(e){return o("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}}var Z,J,K,Y=Object.freeze({__proto__:null,TrayIcon:$});function X(e){if("items"in e)e.items=e.items?.map((e=>"rid"in e?e:X(e)));else if("action"in e&&e.action){const t=new s;return t.onmessage=e.action,delete e.action,{...e,handler:t}}return e}async function ee(e,t){const n=new s;let i=null;return t&&"object"==typeof t&&("action"in t&&t.action&&(n.onmessage=t.action,delete t.action),"items"in t&&t.items&&(i=t.items.map((e=>"rid"in e?[e.rid,e.kind]:X(e))))),o("plugin:menu|new",{kind:e,options:t?{...t,items:i}:void 0,handler:n})}class te extends u{get id(){return t(this,Z,"f")}get kind(){return t(this,J,"f")}constructor(e,t,i){super(e),Z.set(this,void 0),J.set(this,void 0),n(this,Z,t,"f"),n(this,J,i,"f")}}Z=new WeakMap,J=new WeakMap;class ne extends te{constructor(e,t){super(e,t,"MenuItem")}static async new(e){return ee("MenuItem",e).then((([e,t])=>new ne(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}}class ie extends te{constructor(e,t){super(e,t,"Check")}static async new(e){return ee("Check",e).then((([e,t])=>new ie(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async isChecked(){return o("plugin:menu|is_checked",{rid:this.rid})}async setChecked(e){return o("plugin:menu|set_checked",{rid:this.rid,checked:e})}}!function(e){e.Add="Add",e.Advanced="Advanced",e.Bluetooth="Bluetooth",e.Bookmarks="Bookmarks",e.Caution="Caution",e.ColorPanel="ColorPanel",e.ColumnView="ColumnView",e.Computer="Computer",e.EnterFullScreen="EnterFullScreen",e.Everyone="Everyone",e.ExitFullScreen="ExitFullScreen",e.FlowView="FlowView",e.Folder="Folder",e.FolderBurnable="FolderBurnable",e.FolderSmart="FolderSmart",e.FollowLinkFreestanding="FollowLinkFreestanding",e.FontPanel="FontPanel",e.GoLeft="GoLeft",e.GoRight="GoRight",e.Home="Home",e.IChatTheater="IChatTheater",e.IconView="IconView",e.Info="Info",e.InvalidDataFreestanding="InvalidDataFreestanding",e.LeftFacingTriangle="LeftFacingTriangle",e.ListView="ListView",e.LockLocked="LockLocked",e.LockUnlocked="LockUnlocked",e.MenuMixedState="MenuMixedState",e.MenuOnState="MenuOnState",e.MobileMe="MobileMe",e.MultipleDocuments="MultipleDocuments",e.Network="Network",e.Path="Path",e.PreferencesGeneral="PreferencesGeneral",e.QuickLook="QuickLook",e.RefreshFreestanding="RefreshFreestanding",e.Refresh="Refresh",e.Remove="Remove",e.RevealFreestanding="RevealFreestanding",e.RightFacingTriangle="RightFacingTriangle",e.Share="Share",e.Slideshow="Slideshow",e.SmartBadge="SmartBadge",e.StatusAvailable="StatusAvailable",e.StatusNone="StatusNone",e.StatusPartiallyAvailable="StatusPartiallyAvailable",e.StatusUnavailable="StatusUnavailable",e.StopProgressFreestanding="StopProgressFreestanding",e.StopProgress="StopProgress",e.TrashEmpty="TrashEmpty",e.TrashFull="TrashFull",e.User="User",e.UserAccounts="UserAccounts",e.UserGroup="UserGroup",e.UserGuest="UserGuest"}(K||(K={}));class re extends te{constructor(e,t){super(e,t,"Icon")}static async new(e){return ee("Icon",e).then((([e,t])=>new re(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return o("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async setIcon(e){return o("plugin:menu|set_icon",{rid:this.rid,icon:e})}}class ae extends te{constructor(e,t){super(e,t,"Predefined")}static async new(e){return ee("Predefined",e).then((([e,t])=>new ae(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}}function se([e,t,n]){switch(n){case"Submenu":return new le(e,t);case"Predefined":return new ae(e,t);case"Check":return new ie(e,t);case"Icon":return new re(e,t);default:return new ne(e,t)}}class le extends te{constructor(e,t){super(e,t,"Submenu")}static async new(e){return ee("Submenu",e).then((([e,t])=>new le(e,t)))}async text(){return o("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return o("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return o("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return o("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async append(e){return o("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async prepend(e){return o("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async insert(e,t){return o("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e)),position:t})}async remove(e){return o("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return o("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(se)}async items(){return o("plugin:menu|items",{rid:this.rid,kind:this.kind}).then((e=>e.map(se)))}async get(e){return o("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then((e=>e?se(e):null))}async popup(e,t){let n=null;return e&&(n={type:e instanceof k?"Physical":"Logical",data:e}),o("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:t?.label??null,at:n})}async setAsWindowsMenuForNSApp(){return o("plugin:menu|set_as_windows_menu_for_nsapp",{rid:this.rid})}async setAsHelpMenuForNSApp(){return o("plugin:menu|set_as_help_menu_for_nsapp",{rid:this.rid})}}function oe([e,t,n]){switch(n){case"Submenu":return new le(e,t);case"Predefined":return new ae(e,t);case"Check":return new ie(e,t);case"Icon":return new re(e,t);default:return new ne(e,t)}}class ue extends te{constructor(e,t){super(e,t,"Menu")}static async new(e){return ee("Menu",e).then((([e,t])=>new ue(e,t)))}static async default(){return o("plugin:menu|create_default").then((([e,t])=>new ue(e,t)))}async append(e){return o("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async prepend(e){return o("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e))})}async insert(e,t){return o("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map((e=>"rid"in e?[e.rid,e.kind]:e)),position:t})}async remove(e){return o("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return o("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(oe)}async items(){return o("plugin:menu|items",{rid:this.rid,kind:this.kind}).then((e=>e.map(oe)))}async get(e){return o("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then((e=>e?oe(e):null))}async popup(e,t){let n=null;return e&&(n={type:e instanceof k?"Physical":"Logical",data:e}),o("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:t?.label??null,at:n})}async setAsAppMenu(){return o("plugin:menu|set_as_app_menu",{rid:this.rid}).then((e=>e?new ue(e[0],e[1]):null))}async setAsWindowMenu(e){return o("plugin:menu|set_as_window_menu",{rid:this.rid,window:e?.label??null}).then((e=>e?new ue(e[0],e[1]):null))}}var ce=Object.freeze({__proto__:null,CheckMenuItem:ie,IconMenuItem:re,Menu:ue,MenuItem:ne,get NativeIcon(){return K},PredefinedMenuItem:ae,Submenu:le});return e.app=p,e.core=c,e.dpi=D,e.event=_,e.menu=ce,e.path=Q,e.tray=Y,e.webview=q,e.window=F,e}({});window.__TAURI__=__TAURI_IIFE__; diff --git a/core/tauri/src/app.rs b/core/tauri/src/app.rs index 8804eed79bf8..88ed75afca7c 100644 --- a/core/tauri/src/app.rs +++ b/core/tauri/src/app.rs @@ -49,7 +49,7 @@ use std::{ sync::{mpsc::Sender, Arc}, }; -use crate::runtime::RuntimeHandle; +use crate::{event::EventId, runtime::RuntimeHandle, Event, EventTarget}; #[cfg(target_os = "macos")] use crate::ActivationPolicy; @@ -767,6 +767,65 @@ macro_rules! shared_app_impl { self.resources_table().clear(); } } + + /// Event system APIs. + impl $app { + /// Listen to an event on this app. + /// + /// # Examples + /// + /// ``` + /// use tauri::Manager; + /// + /// tauri::Builder::default() + /// .setup(|app| { + /// app.listen("component-loaded", move |event| { + /// println!("window just loaded a component"); + /// }); + /// + /// Ok(()) + /// }); + /// ``` + pub fn listen(&self, event: impl Into, handler: F) -> EventId + where + F: Fn(Event) + Send + 'static, + { + self.manager.listen(event.into(), EventTarget::App, handler) + } + + /// Unlisten to an event on this app. + /// + /// # Examples + /// + /// ``` + /// use tauri::Manager; + /// + /// tauri::Builder::default() + /// .setup(|app| { + /// let handler = app.listen("component-loaded", move |event| { + /// println!("app just loaded a component"); + /// }); + /// + /// // stop listening to the event when you do not need it anymore + /// app.unlisten(handler); + /// + /// Ok(()) + /// }); + /// ``` + pub fn unlisten(&self, id: EventId) { + self.manager.unlisten(id) + } + + /// Listen to an event on this app only once. + /// + /// See [`Self::listen`] for more information. + pub fn once(&self, event: impl Into, handler: F) + where + F: FnOnce(Event) + Send + 'static, + { + self.manager.once(event.into(), EventTarget::App, handler) + } + } }; } diff --git a/core/tauri/src/event/event-system-spec.md b/core/tauri/src/event/event-system-spec.md new file mode 100644 index 000000000000..2fc910bef1f2 --- /dev/null +++ b/core/tauri/src/event/event-system-spec.md @@ -0,0 +1,34 @@ +# Tauri Event System Specification + +## Emitters + +Emitters can emit to any and all listeners. + +- `App` and `AppHandle` +- `Window` +- `Webview` +- `WebviewWindow` +- Any type that implements `Manager` trait. + +## Emit functions + +- `emit`: emits an event to all listeners. +- `emit_to`: emits an event to a specified target. +- `emit_filter`: emits an event to targets based on a filtering callback. + +## Listeners + +Emitters can emit to any and all listeners. + +- `App` and `AppHandle` +- `Window` +- `Webview` +- `WebviewWindow` +- Any type that implements `Manager` trait but is limited to only using `listen_any/once_any`. + +## Listen functions + +- `listen`: Listens to all events targeting this listener type only. +- `once`: Listens to a single event targeting this listener type only. +- `listen_any` (available only through `Manager` trait): Listens to all events to any target (aka event sniffer). +- `once_any` (available only through `Manager` trait): Listens to a single event to any target (aka event sniffer). diff --git a/core/tauri/src/event/listener.rs b/core/tauri/src/event/listener.rs index 0fde794b6c15..640d5f4f7276 100644 --- a/core/tauri/src/event/listener.rs +++ b/core/tauri/src/event/listener.rs @@ -4,51 +4,76 @@ use crate::{Runtime, Webview}; -use super::{EmitArgs, Event, EventId}; +use super::{EmitArgs, Event, EventId, EventTarget}; use std::{ boxed::Box, cell::Cell, - collections::HashMap, + collections::{HashMap, HashSet}, sync::{ atomic::{AtomicU32, Ordering}, Arc, Mutex, }, }; +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +struct JsHandler { + target: EventTarget, + id: EventId, +} + /// What to do with the pending handler when resolving it? -enum Pending { +enum Pending { Unlisten(EventId), - Listen(EventId, String, Handler), + Listen { + id: EventId, + event: String, + handler: Handler, + }, Emit(EmitArgs), } -/// Stored in [`Listeners`] to be called upon when the event that stored it is triggered. -struct Handler { - webview: Option>, +/// Stored in [`Listeners`] to be called upon, when the event that stored it, is triggered. +struct Handler { + target: EventTarget, callback: Box, } +impl Handler { + fn new(target: EventTarget, callback: F) -> Self { + Self { + target, + callback: Box::new(callback), + } + } +} + +type WebviewLabel = String; +type EventName = String; + /// Holds event handlers and pending event handlers, along with the salts associating them. -struct InnerListeners { - handlers: Mutex>>>, - pending: Mutex>>, +struct InnerListeners { + pending: Mutex>, + handlers: Mutex>>, + js_event_listeners: Mutex>>>, function_name: &'static str, listeners_object_name: &'static str, next_event_id: Arc, } /// A self-contained event manager. -pub struct Listeners { - inner: Arc>, +#[derive(Clone)] +pub struct Listeners { + inner: Arc, } -impl Default for Listeners { +impl Default for Listeners { fn default() -> Self { Self { inner: Arc::new(InnerListeners { - handlers: Mutex::default(), pending: Mutex::default(), + handlers: Mutex::default(), + js_event_listeners: Mutex::default(), function_name: "__internal_unstable_listeners_function_id__", listeners_object_name: "__internal_unstable_listeners_object_id__", next_event_id: Default::default(), @@ -57,15 +82,7 @@ impl Default for Listeners { } } -impl Clone for Listeners { - fn clone(&self) -> Self { - Self { - inner: self.inner.clone(), - } - } -} - -impl Listeners { +impl Listeners { pub(crate) fn next_event_id(&self) -> EventId { self.inner.next_event_id.fetch_add(1, Ordering::Relaxed) } @@ -81,7 +98,7 @@ impl Listeners { } /// Insert a pending event action to the queue. - fn insert_pending(&self, action: Pending) { + fn insert_pending(&self, action: Pending) { self .inner .pending @@ -104,9 +121,9 @@ impl Listeners { for action in pending { match action { Pending::Unlisten(id) => self.unlisten(id), - Pending::Listen(id, event, handler) => self.listen_with_id(id, event, handler), + Pending::Listen { id, event, handler } => self.listen_with_id(id, event, handler), Pending::Emit(args) => { - self.emit(&args)?; + self.emit(args)?; } } } @@ -114,9 +131,9 @@ impl Listeners { Ok(()) } - fn listen_with_id(&self, id: EventId, event: String, handler: Handler) { + fn listen_with_id(&self, id: EventId, event: String, handler: Handler) { match self.inner.handlers.try_lock() { - Err(_) => self.insert_pending(Pending::Listen(id, event, handler)), + Err(_) => self.insert_pending(Pending::Listen { id, event, handler }), Ok(mut lock) => { lock.entry(event).or_default().insert(id, handler); } @@ -127,17 +144,12 @@ impl Listeners { pub(crate) fn listen( &self, event: String, - webview: Option>, + target: EventTarget, handler: F, ) -> EventId { let id = self.next_event_id(); - let handler = Handler { - webview, - callback: Box::new(handler), - }; - + let handler = Handler::new(target, handler); self.listen_with_id(id, event, handler); - id } @@ -145,18 +157,19 @@ impl Listeners { pub(crate) fn once( &self, event: String, - webview: Option>, + target: EventTarget, handler: F, ) { let self_ = self.clone(); let handler = Cell::new(Some(handler)); - self.listen(event, webview, move |event| { - self_.unlisten(event.id); + self.listen(event, target, move |event| { + let id = event.id; let handler = handler .take() .expect("attempted to call handler more than once"); - handler(event) + handler(event); + self_.unlisten(id); }); } @@ -171,42 +184,27 @@ impl Listeners { } /// Emits the given event with its payload based on a filter. - pub(crate) fn emit_filter(&self, emit_args: &EmitArgs, filter: Option) -> crate::Result<()> + pub(crate) fn emit_filter(&self, emit_args: EmitArgs, filter: Option) -> crate::Result<()> where - F: Fn(&Webview) -> bool, + F: Fn(&EventTarget) -> bool, { let mut maybe_pending = false; match self.inner.handlers.try_lock() { Err(_) => self.insert_pending(Pending::Emit(emit_args.clone())), Ok(lock) => { if let Some(handlers) = lock.get(&emit_args.event_name) { - let handlers = if let Some(filter) = filter { - handlers + let handlers: Vec<_> = match filter { + Some(filter) => handlers .iter() - .filter(|h| { - h.1 - .webview - .as_ref() - .map(|w| { - // clippy sees this as redundant closure but - // fixing it will result in a compiler error - #[allow(clippy::redundant_closure)] - filter(w) - }) - .unwrap_or(false) - }) - .collect::>() - } else { - handlers.iter().collect::>() + .filter(|(_, Handler { target, .. })| *target == EventTarget::Any || filter(target)) + .collect(), + None => handlers.iter().collect(), }; if !handlers.is_empty() { - for (&id, handler) in handlers { - maybe_pending = true; - (handler.callback)(self::Event { - id, - data: emit_args.payload.clone(), - }) + maybe_pending = true; + for (&id, Handler { callback, .. }) in handlers { + (callback)(Event::new(id, emit_args.payload.clone())) } } } @@ -221,15 +219,100 @@ impl Listeners { } /// Emits the given event with its payload. - pub(crate) fn emit(&self, emit_args: &EmitArgs) -> crate::Result<()> { - self.emit_filter(emit_args, None::<&dyn Fn(&Webview) -> bool>) + pub(crate) fn emit(&self, emit_args: EmitArgs) -> crate::Result<()> { + self.emit_filter(emit_args, None::<&dyn Fn(&EventTarget) -> bool>) + } + + pub(crate) fn listen_js( + &self, + event: &str, + source_webview_label: &str, + target: EventTarget, + id: EventId, + ) { + let mut listeners = self.inner.js_event_listeners.lock().unwrap(); + listeners + .entry(source_webview_label.to_string()) + .or_default() + .entry(event.to_string()) + .or_default() + .insert(JsHandler { id, target }); + } + + pub(crate) fn unlisten_js(&self, id: EventId) { + let mut listeners = self.inner.js_event_listeners.lock().unwrap(); + + let mut empty = None; + let listeners = listeners.values_mut(); + 'outer: for listeners in listeners { + for (key, handlers) in listeners.iter_mut() { + let mut found = false; + + handlers.retain(|h| { + let keep = h.id != id; + if !found { + found = !keep + } + keep + }); + + if handlers.is_empty() { + empty.replace(key.clone()); + } + + if found { + break 'outer; + } + } + + if let Some(key) = &empty { + listeners.remove(key); + } + } + } + + pub(crate) fn has_js_listener bool>( + &self, + event: &str, + filter: F, + ) -> bool { + let listeners = self.inner.js_event_listeners.lock().unwrap(); + listeners.values().any(|events| { + events + .get(event) + .map(|handlers| handlers.iter().any(|h| filter(&h.target))) + .unwrap_or(false) + }) + } + + pub(crate) fn try_for_each_js<'a, R, I, F>( + &self, + event: &str, + mut webviews: I, + callback: F, + ) -> crate::Result<()> + where + R: Runtime, + I: Iterator>, + F: Fn(&Webview, &EventTarget) -> crate::Result<()>, + { + let listeners = self.inner.js_event_listeners.lock().unwrap(); + webviews.try_for_each(|webview| { + if let Some(handlers) = listeners.get(webview.label()).and_then(|s| s.get(event)) { + for JsHandler { target, .. } in handlers { + callback(webview, target)?; + } + } + + Ok(()) + }) } } #[cfg(test)] mod test { use super::*; - use crate::{event::EventSource, test::MockRuntime}; + use crate::event::EventTarget; use proptest::prelude::*; // dummy event handler function @@ -243,11 +326,11 @@ mod test { // check to see if listen() is properly passing keys into the LISTENERS map #[test] fn listeners_check_key(e in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // clone e as the key let key = e.clone(); // pass e and an dummy func into listen - listeners.listen(e, None, event_fn); + listeners.listen(e, EventTarget::Any, event_fn); // lock mutex let l = listeners.inner.handlers.lock().unwrap(); @@ -259,11 +342,11 @@ mod test { // check to see if listen inputs a handler function properly into the LISTENERS map. #[test] fn listeners_check_fn(e in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // clone e as the key let key = e.clone(); // pass e and an dummy func into listen - listeners.listen(e, None, event_fn); + listeners.listen(e, EventTarget::Any, event_fn); // lock mutex let mut l = listeners.inner.handlers.lock().unwrap(); @@ -285,14 +368,13 @@ mod test { // check to see if on_event properly grabs the stored function from listen. #[test] fn check_on_event(key in "[a-z]+", d in "[a-z]+") { - let listeners: Listeners = Default::default(); + let listeners: Listeners = Default::default(); // call listen with key and the event_fn dummy func - listeners.listen(key.clone(), None, event_fn); + listeners.listen(key.clone(), EventTarget::Any, event_fn); // call on event with key and d. - listeners.emit(&EmitArgs { + listeners.emit(EmitArgs { event_name: key.clone(), event: serde_json::to_string(&key).unwrap(), - source: serde_json::to_string(&EventSource::Global).unwrap(), payload: serde_json::to_string(&d).unwrap() })?; diff --git a/core/tauri/src/event/mod.rs b/core/tauri/src/event/mod.rs index 31ef08bf108f..d165581c4c63 100644 --- a/core/tauri/src/event/mod.rs +++ b/core/tauri/src/event/mod.rs @@ -4,6 +4,8 @@ mod listener; pub(crate) mod plugin; +use std::{convert::Infallible, str::FromStr}; + pub(crate) use listener::Listeners; use serde::{Deserialize, Serialize}; @@ -24,13 +26,98 @@ pub fn assert_event_name_is_valid(event: &str) { /// Unique id of an event. pub type EventId = u32; -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// Event Target +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)] #[serde(tag = "kind")] -#[serde(rename_all = "camelCase")] -pub enum EventSource { - Global, - Window { label: String }, - Webview { label: String }, +#[non_exhaustive] +pub enum EventTarget { + /// Any and all event targets. + Any, + + /// Any [`Window`](crate::Window), [`Webview`](crate::Webview) or [`WebviewWindow`](crate::WebviewWindow) that have this label. + AnyLabel { + /// Target label. + label: String, + }, + + /// [`App`](crate::App) and [`AppHandle`](crate::AppHandle) targets. + App, + + /// [`Window`](crate::Window) target. + Window { + /// window label. + label: String, + }, + + /// [`Webview`](crate::Webview) target. + Webview { + /// webview label. + label: String, + }, + + /// [`WebviewWindow`](crate::WebviewWindow) target. + WebviewWindow { + /// webview window label. + label: String, + }, +} + +impl EventTarget { + /// [`Self::Any`] target. + pub fn any() -> Self { + Self::Any + } + + /// [`Self::App`] target. + pub fn app() -> Self { + Self::App + } + + /// [`Self::AnyLabel`] target. + pub fn labeled(label: impl Into) -> Self { + Self::AnyLabel { + label: label.into(), + } + } + + /// [`Self::Window`] target. + pub fn window(label: impl Into) -> Self { + Self::Window { + label: label.into(), + } + } + + /// [`Self::Webview`] target. + pub fn webview(label: impl Into) -> Self { + Self::Webview { + label: label.into(), + } + } + + /// [`Self::WebviewWindow`] target. + pub fn webview_window(label: impl Into) -> Self { + Self::WebviewWindow { + label: label.into(), + } + } +} + +impl> From for EventTarget { + fn from(value: T) -> Self { + Self::AnyLabel { + label: value.as_ref().to_string(), + } + } +} + +impl FromStr for EventTarget { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + Ok(Self::AnyLabel { + label: s.to_string(), + }) + } } /// Serialized emit arguments. @@ -40,20 +127,17 @@ pub struct EmitArgs { pub event_name: String, /// Serialized event name. pub event: String, - /// Serialized [`EventSource`]. - pub source: String, /// Serialized payload. pub payload: String, } impl EmitArgs { - pub fn from(event: &str, source: &EventSource, payload: S) -> crate::Result { + pub fn new(event: &str, payload: S) -> crate::Result { #[cfg(feature = "tracing")] let _span = tracing::debug_span!("window::emit::serialize").entered(); Ok(EmitArgs { event_name: event.into(), event: serde_json::to_string(event)?, - source: serde_json::to_string(source)?, payload: serde_json::to_string(&payload)?, }) } @@ -67,6 +151,10 @@ pub struct Event { } impl Event { + fn new(id: EventId, data: String) -> Self { + Self { id, data } + } + /// The [`EventId`] of the handler that was triggered. pub fn id(&self) -> EventId { self.id @@ -78,11 +166,11 @@ impl Event { } } -pub fn listen_js( +pub fn listen_js_script( listeners_object_name: &str, + serialized_target: &str, event: &str, event_id: EventId, - serialized_source: &str, handler: &str, ) -> String { format!( @@ -91,34 +179,42 @@ pub fn listen_js( if (window['{listeners}'] === void 0) {{ Object.defineProperty(window, '{listeners}', {{ value: Object.create(null) }}); }} - if (window['{listeners}'][{event}] === void 0) {{ - Object.defineProperty(window['{listeners}'], {event}, {{ value: [] }}); + if (window['{listeners}']['{event}'] === void 0) {{ + Object.defineProperty(window['{listeners}'], '{event}', {{ value: [] }}); }} - const eventListeners = window['{listeners}'][{event}] + const eventListeners = window['{listeners}']['{event}'] const listener = {{ id: {event_id}, - source: {source}, + target: {target}, handler: {handler} }}; eventListeners.push(listener); }})() ", listeners = listeners_object_name, - source = serialized_source, + target = serialized_target, ) } -pub fn emit_js(event_emit_function_name: &str, emit_args: &EmitArgs) -> crate::Result { +pub fn emit_js_script( + event_emit_function_name: &str, + emit_args: &EmitArgs, + serialized_target: &str, +) -> crate::Result { Ok(format!( - "(function () {{ const fn = window['{}']; fn && fn({{event: {}, source: {}, payload: {}}}) }})()", + "(function () {{ const fn = window['{}']; fn && fn({{event: {}, payload: {}}}, {target}) }})()", event_emit_function_name, emit_args.event, - emit_args.source, - emit_args.payload + emit_args.payload, + target = serialized_target, )) } -pub fn unlisten_js(listeners_object_name: &str, event_name: &str, event_id: EventId) -> String { +pub fn unlisten_js_script( + listeners_object_name: &str, + event_name: &str, + event_id: EventId, +) -> String { format!( " (function () {{ @@ -138,12 +234,11 @@ pub fn event_initialization_script(function: &str, listeners: &str) -> String { format!( " Object.defineProperty(window, '{function}', {{ - value: function (eventData) {{ + value: function (eventData, target) {{ const listeners = (window['{listeners}'] && window['{listeners}'][eventData.event]) || [] - for (let i = listeners.length - 1; i >= 0; i--) {{ const listener = listeners[i] - if (listener.source.kind === 'global' || eventData.source.kind === 'global' || listener.source.kind === 'window' || eventData.source.kind === 'window' || listener.source.label === eventData.source.label) {{ + if ((listener.target.kind === 'Global' && target.kind === 'Global') || (listener.target.kind === target.kind && listener.target.label === target.label)) {{ eventData.id = listener.id listener.handler(eventData) }} diff --git a/core/tauri/src/event/plugin.rs b/core/tauri/src/event/plugin.rs index 8eb0259f8279..9eebca3bcd34 100644 --- a/core/tauri/src/event/plugin.rs +++ b/core/tauri/src/event/plugin.rs @@ -2,21 +2,24 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use std::ops::Deref; + use serde::{Deserialize, Deserializer}; use serde_json::Value as JsonValue; use tauri_runtime::window::is_label_valid; use crate::plugin::{Builder, TauriPlugin}; -use crate::sealed::ManagerBase; use crate::{command, ipc::CallbackFn, EventId, Manager, Result, Runtime}; use crate::{AppHandle, Webview}; -use super::{is_event_name_valid, EventSource}; +use super::{is_event_name_valid, EventTarget}; pub struct EventName(String); -impl AsRef for EventName { - fn as_ref(&self) -> &str { +impl Deref for EventName { + type Target = str; + + fn deref(&self) -> &Self::Target { &self.0 } } @@ -63,21 +66,12 @@ impl<'de> Deserialize<'de> for WebviewLabel { #[command(root = "crate")] pub fn listen( - app: AppHandle, webview: Webview, event: EventName, - webview_label: Option, + target: EventTarget, handler: CallbackFn, ) -> Result { - if let Some(l) = webview_label { - app - .manager() - .get_webview(&l.0) - .ok_or(crate::Error::WebviewNotFound)? - .listen_js(EventSource::Webview { label: l.0 }, event.0, handler) - } else { - webview.listen_js(EventSource::Global, event.0, handler) - } + webview.listen_js(&event, target, handler) } #[command(root = "crate")] @@ -86,28 +80,31 @@ pub fn unlisten( event: EventName, event_id: EventId, ) -> Result<()> { - webview.unlisten_js(event.as_ref(), event_id) + webview.unlisten_js(&event, event_id) } #[command(root = "crate")] pub fn emit( app: AppHandle, - webview: Webview, event: EventName, - target: Option, payload: Option, ) -> Result<()> { - let target = target.unwrap_or(EventSource::Global); - match target { - EventSource::Global => app.emit(&event.0, payload), - EventSource::Webview { label } => webview.emit_to(&label, &event.0, payload), - EventSource::Window { label } => webview.window().emit_to(&label, &event.0, payload), - } + app.emit(&event, payload) +} + +#[command(root = "crate")] +pub fn emit_to( + app: AppHandle, + target: EventTarget, + event: EventName, + payload: Option, +) -> Result<()> { + app.emit_to(target, &event, payload) } /// Initializes the event plugin. pub(crate) fn init() -> TauriPlugin { Builder::new("event") - .invoke_handler(crate::generate_handler![listen, unlisten, emit,]) + .invoke_handler(crate::generate_handler![listen, unlisten, emit, emit_to]) .build() } diff --git a/core/tauri/src/lib.rs b/core/tauri/src/lib.rs index 572f8357f01d..e07541d085d6 100644 --- a/core/tauri/src/lib.rs +++ b/core/tauri/src/lib.rs @@ -67,7 +67,6 @@ pub use cocoa; #[doc(hidden)] pub use embed_plist; pub use error::{Error, Result}; -use event::EventSource; pub use resources::{Resource, ResourceId, ResourceTable}; #[cfg(target_os = "ios")] #[doc(hidden)] @@ -203,7 +202,7 @@ pub use runtime::ActivationPolicy; #[cfg(target_os = "macos")] pub use self::utils::TitleBarStyle; -pub use self::event::{Event, EventId}; +pub use self::event::{Event, EventId, EventTarget}; pub use { self::app::{App, AppHandle, AssetResolver, Builder, CloseRequestApi, RunEvent, WindowEvent}, self::manager::Asset, @@ -589,7 +588,7 @@ pub trait Manager: sealed::ManagerBase { self.manager().package_info() } - /// Listen to an event emitted on any window. + /// Listen to an emitted event to any [target](EventTarget). /// /// # Examples /// ``` @@ -603,18 +602,20 @@ pub trait Manager: sealed::ManagerBase { /// /// tauri::Builder::default() /// .setup(|app| { - /// app.listen_global("synchronized", |event| { + /// app.listen_any("synchronized", |event| { /// println!("app is in sync"); /// }); /// Ok(()) /// }) /// .invoke_handler(tauri::generate_handler![synchronize]); /// ``` - fn listen_global(&self, event: impl Into, handler: F) -> EventId + fn listen_any(&self, event: impl Into, handler: F) -> EventId where F: Fn(Event) + Send + 'static, { - self.manager().listen(event.into(), None, handler) + self + .manager() + .listen(event.into(), EventTarget::Any, handler) } /// Remove an event listener. @@ -626,7 +627,7 @@ pub trait Manager: sealed::ManagerBase { /// tauri::Builder::default() /// .setup(|app| { /// let handle = app.handle().clone(); - /// let handler = app.listen_global("ready", move |event| { + /// let handler = app.listen_any("ready", move |event| { /// println!("app is ready"); /// /// // we no longer need to listen to the event @@ -645,19 +646,17 @@ pub trait Manager: sealed::ManagerBase { self.manager().unlisten(id) } - /// Listen to a global event only once. + /// Listens once to an emitted event to any [target](EventTarget) . /// - /// See [`Self::listen_global`] for more information. - fn once_global(&self, event: impl Into, handler: F) + /// See [`Self::listen_any`] for more information. + fn once_any(&self, event: impl Into, handler: F) where F: FnOnce(Event) + Send + 'static, { - self.manager().once(event.into(), None, handler) + self.manager().once(event.into(), EventTarget::Any, handler) } - /// Emits an event to all webviews. - /// - /// If using [`Window`] to emit the event, it will be used as the source. + /// Emits an event to all [targets](EventTarget). /// /// # Examples /// ``` @@ -674,50 +673,76 @@ pub trait Manager: sealed::ManagerBase { tracing::instrument("app::emit", skip(self, payload)) )] fn emit(&self, event: &str, payload: S) -> Result<()> { - self.manager().emit(event, EventSource::Global, payload) + self.manager().emit(event, payload) } - /// Emits an event to the webview with the specified label. - /// - /// If using [`Window`] to emit the event, it will be used as the source. + /// Emits an event to all [targets](EventTarget) matching the given target. /// /// # Examples /// ``` - /// use tauri::Manager; + /// use tauri::{Manager, EventTarget}; /// /// #[tauri::command] /// fn download(app: tauri::AppHandle) { /// for i in 1..100 { /// std::thread::sleep(std::time::Duration::from_millis(150)); - /// // emit a download progress event to the updater window - /// app.emit_to("updater", "download-progress", i); + /// // emit a download progress event to all listeners + /// app.emit_to(EventTarget::any(), "download-progress", i); + /// // emit an event to listeners that used App::listen or AppHandle::listen + /// app.emit_to(EventTarget::app(), "download-progress", i); + /// // emit an event to any webview/window/webviewWindow matching the given label + /// app.emit_to("updater", "download-progress", i); // similar to using EventTarget::labeled + /// app.emit_to(EventTarget::labeled("updater"), "download-progress", i); + /// // emit an event to listeners that used WebviewWindow::listen + /// app.emit_to(EventTarget::webview_window("updater"), "download-progress", i); /// } /// } /// ``` #[cfg_attr( feature = "tracing", - tracing::instrument("app::emit::to", skip(self, payload)) + tracing::instrument("app::emit::to", skip(self, target, payload), fields(target)) )] - fn emit_to(&self, label: &str, event: &str, payload: S) -> Result<()> { - self - .manager() - .emit_filter(event, EventSource::Global, payload, |w| label == w.label()) + fn emit_to(&self, target: I, event: &str, payload: S) -> Result<()> + where + I: Into, + S: Serialize + Clone, + { + let target = target.into(); + #[cfg(feature = "tracing")] + tracing::Span::current().record("target", format!("{target:?}")); + + self.manager().emit_filter(event, payload, |s| match s { + t @ EventTarget::Window { label } + | t @ EventTarget::Webview { label } + | t @ EventTarget::WebviewWindow { label } => { + if let EventTarget::AnyLabel { + label: target_label, + } = &target + { + label == target_label + } else { + t == &target + } + } + t => t == &target, + }) } - /// Emits an event to specific webviews based on a filter. - /// - /// If using [`Window`] to emit the event, it will be used as the source. + /// Emits an event to all [targets](EventTarget) based on the given filter. /// /// # Examples /// ``` - /// use tauri::Manager; + /// use tauri::{Manager, EventTarget}; /// /// #[tauri::command] /// fn download(app: tauri::AppHandle) { /// for i in 1..100 { /// std::thread::sleep(std::time::Duration::from_millis(150)); /// // emit a download progress event to the updater window - /// app.emit_filter("download-progress", i, |w| w.label() == "main" ); + /// app.emit_filter("download-progress", i, |t| match t { + /// EventTarget::WebviewWindow { label } => label == "main", + /// _ => false, + /// }); /// } /// } /// ``` @@ -728,11 +753,9 @@ pub trait Manager: sealed::ManagerBase { fn emit_filter(&self, event: &str, payload: S, filter: F) -> Result<()> where S: Serialize + Clone, - F: Fn(&Webview) -> bool, + F: Fn(&EventTarget) -> bool, { - self - .manager() - .emit_filter(event, EventSource::Global, payload, filter) + self.manager().emit_filter(event, payload, filter) } /// Fetch a single window from the manager. diff --git a/core/tauri/src/manager/mod.rs b/core/tauri/src/manager/mod.rs index 84c635891088..b7e389d79b7e 100644 --- a/core/tauri/src/manager/mod.rs +++ b/core/tauri/src/manager/mod.rs @@ -22,7 +22,7 @@ use tauri_utils::{ use crate::{ app::{AppHandle, GlobalWindowEventListener, OnPageLoad}, - event::{assert_event_name_is_valid, Event, EventId, EventSource, Listeners}, + event::{assert_event_name_is_valid, Event, EventId, EventTarget, Listeners}, ipc::{Invoke, InvokeHandler, InvokeResponder, RuntimeAuthority}, plugin::PluginStore, utils::{ @@ -188,7 +188,7 @@ pub struct AppManager { pub menu: menu::MenuManager, pub(crate) plugins: Mutex>, - pub listeners: Listeners, + pub listeners: Listeners, pub state: Arc, pub config: Config, pub assets: Box, @@ -418,7 +418,7 @@ impl AppManager { } } - pub(crate) fn listeners(&self) -> &Listeners { + pub(crate) fn listeners(&self) -> &Listeners { &self.listeners } @@ -453,11 +453,11 @@ impl AppManager { pub fn listen( &self, event: String, - window: Option>, + target: EventTarget, handler: F, ) -> EventId { assert_event_name_is_valid(&event); - self.listeners().listen(event, window, handler) + self.listeners().listen(event, target, handler) } pub fn unlisten(&self, id: EventId) { @@ -467,65 +467,59 @@ impl AppManager { pub fn once( &self, event: String, - webview: Option, + target: EventTarget, handler: F, ) { assert_event_name_is_valid(&event); - self - .listeners() - .once(event, webview.and_then(|w| self.get_webview(&w)), handler) + self.listeners().once(event, target, handler) } - pub fn emit_filter( - &self, - event: &str, - source: EventSource, - payload: S, - filter: F, - ) -> crate::Result<()> + pub fn emit_filter(&self, event: &str, payload: S, filter: F) -> crate::Result<()> where S: Serialize + Clone, - F: Fn(&Webview) -> bool, + F: Fn(&EventTarget) -> bool, { assert_event_name_is_valid(event); #[cfg(feature = "tracing")] let _span = tracing::debug_span!("emit::run").entered(); - let emit_args = EmitArgs::from(event, &source, payload)?; + let emit_args = EmitArgs::new(event, payload)?; - self - .webview - .webviews_lock() - .values() - .filter(|w| w.has_js_listener(&source, event)) - .filter(|w| filter(w)) - .try_for_each(|webview| webview.emit_js(&emit_args))?; + let listeners = self.listeners(); + + listeners.try_for_each_js( + event, + self.webview.webviews_lock().values(), + |webview, target| { + if filter(target) { + webview.emit_js(&emit_args, target) + } else { + Ok(()) + } + }, + )?; - self.listeners().emit_filter(&emit_args, Some(filter))?; + listeners.emit_filter(emit_args, Some(filter))?; Ok(()) } - pub fn emit( - &self, - event: &str, - source: EventSource, - payload: S, - ) -> crate::Result<()> { + pub fn emit(&self, event: &str, payload: S) -> crate::Result<()> { assert_event_name_is_valid(event); #[cfg(feature = "tracing")] let _span = tracing::debug_span!("emit::run").entered(); - let emit_args = EmitArgs::from(event, &source, payload)?; + let emit_args = EmitArgs::new(event, payload)?; - self - .webview - .webviews_lock() - .values() - .filter(|w| w.has_js_listener(&source, event)) - .try_for_each(|window| window.emit_js(&emit_args))?; + let listeners = self.listeners(); + + listeners.try_for_each_js( + event, + self.webview.webviews_lock().values(), + |webview, target| webview.emit_js(&emit_args, target), + )?; - self.listeners().emit(&emit_args)?; + listeners.emit(emit_args)?; Ok(()) } @@ -618,17 +612,25 @@ mod test { }; use crate::{ + event::EventTarget, generate_context, plugin::PluginStore, test::{mock_app, MockRuntime}, - App, Manager, StateManager, WebviewWindow, WebviewWindowBuilder, Wry, + webview::WebviewBuilder, + window::WindowBuilder, + App, Manager, StateManager, Webview, WebviewWindow, WebviewWindowBuilder, Window, Wry, }; use super::AppManager; + const APP_LISTEN_ID: &str = "App::listen"; + const APP_LISTEN_ANY_ID: &str = "App::listen_any"; const WINDOW_LISTEN_ID: &str = "Window::listen"; - const WINDOW_LISTEN_GLOBAL_ID: &str = "Window::listen_global"; - const APP_LISTEN_GLOBAL_ID: &str = "App::listen_global"; + const WINDOW_LISTEN_ANY_ID: &str = "Window::listen_any"; + const WEBVIEW_LISTEN_ID: &str = "Webview::listen"; + const WEBVIEW_LISTEN_ANY_ID: &str = "Webview::listen_any"; + const WEBVIEW_WINDOW_LISTEN_ID: &str = "WebviewWindow::listen"; + const WEBVIEW_WINDOW_LISTEN_ANY_ID: &str = "WebviewWindow::listen_any"; const TEST_EVENT_NAME: &str = "event"; #[test] @@ -664,147 +666,215 @@ mod test { struct EventSetup { app: App, - webview: WebviewWindow, + window: Window, + webview: Webview, + webview_window: WebviewWindow, tx: Sender<(&'static str, String)>, rx: Receiver<(&'static str, String)>, } - fn setup_events() -> EventSetup { + fn setup_events(setup_any: bool) -> EventSetup { let app = mock_app(); - let webview = WebviewWindowBuilder::new(&app, "main", Default::default()) + + let window = WindowBuilder::new(&app, "main-window").build().unwrap(); + + let webview = window + .add_child( + WebviewBuilder::new("main-webview", Default::default()), + crate::LogicalPosition::new(0, 0), + window.inner_size().unwrap(), + ) + .unwrap(); + + let webview_window = WebviewWindowBuilder::new(&app, "main-webview-window", Default::default()) .build() .unwrap(); let (tx, rx) = channel(); - let tx_ = tx.clone(); - webview.listen(TEST_EVENT_NAME, move |evt| { - tx_ - .send(( - WINDOW_LISTEN_ID, - serde_json::from_str::(evt.payload()).unwrap(), - )) - .unwrap(); - }); - - let tx_ = tx.clone(); - webview.listen_global(TEST_EVENT_NAME, move |evt| { - tx_ - .send(( - WINDOW_LISTEN_GLOBAL_ID, - serde_json::from_str::(evt.payload()).unwrap(), - )) - .unwrap(); - }); + macro_rules! setup_listener { + ($type:ident, $id:ident, $any_id:ident) => { + let tx_ = tx.clone(); + $type.listen(TEST_EVENT_NAME, move |evt| { + tx_ + .send(($id, serde_json::from_str::(evt.payload()).unwrap())) + .unwrap(); + }); + + if setup_any { + let tx_ = tx.clone(); + $type.listen_any(TEST_EVENT_NAME, move |evt| { + tx_ + .send(( + $any_id, + serde_json::from_str::(evt.payload()).unwrap(), + )) + .unwrap(); + }); + } + }; + } - let tx_ = tx.clone(); - app.listen_global(TEST_EVENT_NAME, move |evt| { - tx_ - .send(( - APP_LISTEN_GLOBAL_ID, - serde_json::from_str::(evt.payload()).unwrap(), - )) - .unwrap(); - }); + setup_listener!(app, APP_LISTEN_ID, APP_LISTEN_ANY_ID); + setup_listener!(window, WINDOW_LISTEN_ID, WINDOW_LISTEN_ANY_ID); + setup_listener!(webview, WEBVIEW_LISTEN_ID, WEBVIEW_LISTEN_ANY_ID); + setup_listener!( + webview_window, + WEBVIEW_WINDOW_LISTEN_ID, + WEBVIEW_WINDOW_LISTEN_ANY_ID + ); EventSetup { app, + window, webview, + webview_window, tx, rx, } } - fn assert_events(received: &[&str], expected: &[&str]) { + fn assert_events(kind: &str, received: &[&str], expected: &[&str]) { for e in expected { - assert!(received.contains(e), "{e} did not receive global event"); + assert!(received.contains(e), "{e} did not receive `{kind}` event"); } assert_eq!( received.len(), expected.len(), - "received {:?} events but expected {:?}", + "received {:?} `{kind}` events but expected {:?}", received, expected ); } #[test] - fn app_global_events() { + fn emit() { let EventSetup { app, - webview: _, + window, + webview, + webview_window, tx: _, rx, - } = setup_events(); + } = setup_events(true); - let mut received = Vec::new(); - let payload = "global-payload"; - app.emit(TEST_EVENT_NAME, payload).unwrap(); - while let Ok((source, p)) = rx.recv_timeout(Duration::from_secs(1)) { - assert_eq!(p, payload); - received.push(source); - } - assert_events( - &received, - &[ - WINDOW_LISTEN_ID, - WINDOW_LISTEN_GLOBAL_ID, - APP_LISTEN_GLOBAL_ID, - ], - ); + run_emit_test("emit (app)", app, &rx); + run_emit_test("emit (window)", window, &rx); + run_emit_test("emit (webview)", webview, &rx); + run_emit_test("emit (webview_window)", webview_window, &rx); } - #[test] - fn window_global_events() { - let EventSetup { - app: _, - webview, - tx: _, - rx, - } = setup_events(); - + fn run_emit_test>(kind: &str, m: M, rx: &Receiver<(&str, String)>) { let mut received = Vec::new(); let payload = "global-payload"; - webview.emit(TEST_EVENT_NAME, payload).unwrap(); + m.emit(TEST_EVENT_NAME, payload).unwrap(); while let Ok((source, p)) = rx.recv_timeout(Duration::from_secs(1)) { assert_eq!(p, payload); received.push(source); } assert_events( + kind, &received, &[ + APP_LISTEN_ID, + APP_LISTEN_ANY_ID, WINDOW_LISTEN_ID, - WINDOW_LISTEN_GLOBAL_ID, - APP_LISTEN_GLOBAL_ID, + WINDOW_LISTEN_ANY_ID, + WEBVIEW_LISTEN_ID, + WEBVIEW_LISTEN_ANY_ID, + WEBVIEW_WINDOW_LISTEN_ID, + WEBVIEW_WINDOW_LISTEN_ANY_ID, ], ); } #[test] - fn window_local_events() { + fn emit_to() { let EventSetup { app, + window, webview, + webview_window, tx, rx, - } = setup_events(); + } = setup_events(false); + + run_emit_to_test( + "emit_to (App)", + &app, + &window, + &webview, + &webview_window, + tx.clone(), + &rx, + ); + run_emit_to_test( + "emit_to (window)", + &window, + &window, + &webview, + &webview_window, + tx.clone(), + &rx, + ); + run_emit_to_test( + "emit_to (webview)", + &webview, + &window, + &webview, + &webview_window, + tx.clone(), + &rx, + ); + run_emit_to_test( + "emit_to (webview_window)", + &webview_window, + &window, + &webview, + &webview_window, + tx.clone(), + &rx, + ); + } + fn run_emit_to_test>( + kind: &str, + m: &M, + window: &Window, + webview: &Webview, + webview_window: &WebviewWindow, + tx: Sender<(&'static str, String)>, + rx: &Receiver<(&'static str, String)>, + ) { let mut received = Vec::new(); let payload = "global-payload"; - webview - .emit_to(webview.label(), TEST_EVENT_NAME, payload) - .unwrap(); - while let Ok((source, p)) = rx.recv_timeout(Duration::from_secs(1)) { - assert_eq!(p, payload); - received.push(source); + + macro_rules! test_target { + ($target:expr, $id:ident) => { + m.emit_to($target, TEST_EVENT_NAME, payload).unwrap(); + while let Ok((source, p)) = rx.recv_timeout(Duration::from_secs(1)) { + assert_eq!(p, payload); + received.push(source); + } + assert_events(kind, &received, &[$id]); + + received.clear(); + }; } - assert_events(&received, &[WINDOW_LISTEN_ID]); - received.clear(); + test_target!(EventTarget::App, APP_LISTEN_ID); + test_target!(window.label(), WINDOW_LISTEN_ID); + test_target!(webview.label(), WEBVIEW_LISTEN_ID); + test_target!(webview_window.label(), WEBVIEW_WINDOW_LISTEN_ID); + let other_webview_listen_id = "OtherWebview::listen"; - let other_webview = WebviewWindowBuilder::new(&app, "other", Default::default()) - .build() - .unwrap(); + let other_webview = WebviewWindowBuilder::new( + window, + kind.replace(['(', ')', ' '], ""), + Default::default(), + ) + .build() + .unwrap(); other_webview.listen(TEST_EVENT_NAME, move |evt| { tx.send(( @@ -813,13 +883,12 @@ mod test { )) .unwrap(); }); - webview - .emit_to(other_webview.label(), TEST_EVENT_NAME, payload) + m.emit_to(other_webview.label(), TEST_EVENT_NAME, payload) .unwrap(); while let Ok((source, p)) = rx.recv_timeout(Duration::from_secs(1)) { assert_eq!(p, payload); received.push(source); } - assert_events(&received, &[other_webview_listen_id]); + assert_events("emit_to", &received, &[other_webview_listen_id]); } } diff --git a/core/tauri/src/manager/webview.rs b/core/tauri/src/manager/webview.rs index 7edd12b741d0..241ab5f34859 100644 --- a/core/tauri/src/manager/webview.rs +++ b/core/tauri/src/manager/webview.rs @@ -59,6 +59,7 @@ pub struct UriSchemeProtocol { } #[derive(Clone, Serialize)] +#[serde(rename_all = "camelCase")] pub struct WebviewLabelDef { pub window_label: String, pub label: String, @@ -168,7 +169,7 @@ impl WebviewManager { Object.defineProperty(window.__TAURI_INTERNALS__, 'metadata', {{ value: {{ windows: {window_labels_array}.map(function (label) {{ return {{ label: label }} }}), - webviews: {webview_labels_array}.map(function (label) {{ return {{ label: label }} }}), + webviews: {webview_labels_array}, currentWindow: {{ label: {current_window_label} }}, currentWebview: {{ label: {current_webview_label} }} }} diff --git a/core/tauri/src/manager/window.rs b/core/tauri/src/manager/window.rs index 2ae3f863d94f..e22d333821c8 100644 --- a/core/tauri/src/manager/window.rs +++ b/core/tauri/src/manager/window.rs @@ -19,8 +19,8 @@ use tauri_runtime::{ }; use crate::{ - app::GlobalWindowEventListener, event::EventSource, AppHandle, EventLoopMessage, Icon, Manager, - Runtime, Scopes, Window, WindowEvent, + app::GlobalWindowEventListener, sealed::ManagerBase, AppHandle, EventLoopMessage, EventTarget, + Icon, Manager, Runtime, Scopes, Window, WindowEvent, }; use super::AppManager; @@ -145,14 +145,15 @@ fn on_window_event( WindowEvent::Resized(size) => window.emit(WINDOW_RESIZED_EVENT, size)?, WindowEvent::Moved(position) => window.emit(WINDOW_MOVED_EVENT, position)?, WindowEvent::CloseRequested { api } => { - if window.webviews().iter().any(|w| { - w.has_js_listener( - &EventSource::Window { - label: window.label().into(), - }, - WINDOW_CLOSE_REQUESTED_EVENT, - ) - }) { + let listeners = window.manager().listeners(); + let has_js_listener = + listeners.has_js_listener(WINDOW_CLOSE_REQUESTED_EVENT, |target| match target { + EventTarget::Window { label } | EventTarget::WebviewWindow { label } => { + label == window.label() + } + _ => false, + }); + if has_js_listener { api.prevent_close(); } window.emit(WINDOW_CLOSE_REQUESTED_EVENT, ())?; diff --git a/core/tauri/src/webview/mod.rs b/core/tauri/src/webview/mod.rs index 9a5c9dd47b74..1ef73f356e66 100644 --- a/core/tauri/src/webview/mod.rs +++ b/core/tauri/src/webview/mod.rs @@ -27,7 +27,7 @@ pub use url::Url; use crate::{ app::UriSchemeResponder, - event::{EmitArgs, EventSource}, + event::{EmitArgs, EventTarget}, ipc::{ CallbackFn, CommandArg, CommandItem, Invoke, InvokeBody, InvokeError, InvokeMessage, InvokeResolver, Origin, OwnedInvokeResponder, @@ -39,7 +39,6 @@ use crate::{ use std::{ borrow::Cow, - collections::{HashMap, HashSet}, hash::{Hash, Hasher}, path::PathBuf, sync::{Arc, Mutex}, @@ -110,34 +109,6 @@ impl<'a> PageLoadPayload<'a> { } } -/// Key for a JS event listener. -#[derive(Debug, Clone, PartialEq, Eq)] -struct JsEventListenerKey { - /// The source. - pub source: EventSource, - /// The event name. - pub event: String, -} - -impl Hash for JsEventListenerKey { - fn hash(&self, state: &mut H) { - self.event.hash(state); - match &self.source { - EventSource::Global => { - "global".hash(state); - } - EventSource::Webview { label } => { - "webview".hash(state); - label.hash(state); - } - EventSource::Window { label } => { - "window".hash(state); - label.hash(state); - } - } - } -} - /// The IPC invoke request. #[derive(Debug)] pub struct InvokeRequest { @@ -236,12 +207,12 @@ impl PlatformWebview { macro_rules! unstable_struct { (#[doc = $doc:expr] $($tokens:tt)*) => { - #[cfg(feature = "unstable")] + #[cfg(any(test, feature = "unstable"))] #[cfg_attr(docsrs, doc(cfg(feature = "unstable")))] #[doc = $doc] pub $($tokens)* - #[cfg(not(feature = "unstable"))] + #[cfg(not(any(test, feature = "unstable")))] pub(crate) $($tokens)* } } @@ -660,11 +631,13 @@ tauri::Builder::default() app_manager.emit_filter( "tauri://webview-created", - EventSource::Global, Some(CreatedEvent { label: webview.label().into(), }), - |w| w != &webview, + |s| match s { + EventTarget::Webview { label } => label == webview.label(), + _ => false, + }, )?; Ok(webview) @@ -811,7 +784,6 @@ pub struct Webview { pub(crate) window: Window, /// The webview created by the runtime. pub(crate) webview: DetachedWebview, - js_event_listeners: Arc>>>, } impl std::fmt::Debug for Webview { @@ -819,7 +791,6 @@ impl std::fmt::Debug for Webview { f.debug_struct("Window") .field("window", &self.window) .field("webview", &self.webview) - .field("js_event_listeners", &self.js_event_listeners) .finish() } } @@ -829,7 +800,6 @@ impl Clone for Webview { Self { window: self.window.clone(), webview: self.webview.clone(), - js_event_listeners: self.js_event_listeners.clone(), } } } @@ -853,11 +823,7 @@ impl PartialEq for Webview { impl Webview { /// Create a new webview that is attached to the window. pub(crate) fn new(window: Window, webview: DetachedWebview) -> Self { - Self { - window, - webview, - js_event_listeners: Default::default(), - } + Self { window, webview } } /// Initializes a webview builder with the given window label and URL to load on the webview. @@ -1236,107 +1202,51 @@ fn main() { /// Register a JS event listener and return its identifier. pub(crate) fn listen_js( &self, - source: EventSource, - event: String, + event: &str, + target: EventTarget, handler: CallbackFn, ) -> crate::Result { - let event_id = self.manager().listeners().next_event_id(); + let listeners = self.manager().listeners(); + + let id = listeners.next_event_id(); - self.eval(&crate::event::listen_js( - self.manager().listeners().listeners_object_name(), - &format!("'{}'", event), - event_id, - &serde_json::to_string(&source)?, + self.eval(&crate::event::listen_js_script( + listeners.listeners_object_name(), + &serde_json::to_string(&target)?, + event, + id, &format!("window['_{}']", handler.0), ))?; - self - .js_event_listeners - .lock() - .unwrap() - .entry(JsEventListenerKey { source, event }) - .or_default() - .insert(event_id); + listeners.listen_js(event, self.label(), target, id); - Ok(event_id) + Ok(id) } /// Unregister a JS event listener. pub(crate) fn unlisten_js(&self, event: &str, id: EventId) -> crate::Result<()> { - self.eval(&crate::event::unlisten_js( - self.manager().listeners().listeners_object_name(), + let listeners = self.manager().listeners(); + + self.eval(&crate::event::unlisten_js_script( + listeners.listeners_object_name(), event, id, ))?; - let mut empty = None; - let mut js_listeners = self.js_event_listeners.lock().unwrap(); - let iter = js_listeners.iter_mut(); - for (key, ids) in iter { - if ids.contains(&id) { - ids.remove(&id); - if ids.is_empty() { - empty.replace(key.clone()); - } - break; - } - } - - if let Some(key) = empty { - js_listeners.remove(&key); - } + listeners.unlisten_js(id); Ok(()) } - pub(crate) fn emit_js(&self, emit_args: &EmitArgs) -> crate::Result<()> { - self.eval(&crate::event::emit_js( + pub(crate) fn emit_js(&self, emit_args: &EmitArgs, target: &EventTarget) -> crate::Result<()> { + self.eval(&crate::event::emit_js_script( self.manager().listeners().function_name(), emit_args, + &serde_json::to_string(target)?, )?)?; Ok(()) } - /// Whether this webview registered a listener to an event from the given source and event name. - pub(crate) fn has_js_listener(&self, source: &EventSource, event: &str) -> bool { - let listeners = self.js_event_listeners.lock().unwrap(); - - match source { - // for global events, any listener is triggered - EventSource::Global => listeners.keys().any(|k| k.event == event), - // if the window matches this webview's window, - // the event is delivered as long as it listens to the event name - EventSource::Window { label } if label == self.window.label() => { - let event = event.to_string(); - // webview-specific event is also triggered on global events, so we check that - listeners.contains_key(&JsEventListenerKey { - source: source.clone(), - event: event.clone(), - }) || listeners.contains_key(&JsEventListenerKey { - source: EventSource::Webview { - label: label.clone(), - }, - event: event.clone(), - }) || listeners.contains_key(&JsEventListenerKey { - source: EventSource::Global, - event, - }) - } - _ => { - let event = event.to_string(); - - // webview-specific event is also triggered on global events, so we check that - listeners.contains_key(&JsEventListenerKey { - source: source.clone(), - event: event.clone(), - }) || listeners.contains_key(&JsEventListenerKey { - source: EventSource::Global, - event, - }) - } - } - } - /// Opens the developer tools window (Web Inspector). /// The devtools is only enabled on debug builds or with the `devtools` feature flag. /// @@ -1473,13 +1383,16 @@ tauri::Builder::default() where F: Fn(Event) + Send + 'static, { - self - .window - .manager - .listen(event.into(), Some(self.clone()), handler) + self.window.manager.listen( + event.into(), + EventTarget::Webview { + label: self.label().to_string(), + }, + handler, + ) } - /// Unlisten to an event on this window. + /// Unlisten to an event on this webview. /// /// # Examples #[cfg_attr( @@ -1519,55 +1432,18 @@ tauri::Builder::default() where F: FnOnce(Event) + Send + 'static, { - let label = self.webview.label.clone(); - self.window.manager.once(event.into(), Some(label), handler) - } -} - -impl Manager for Webview { - fn emit(&self, event: &str, payload: S) -> crate::Result<()> { - self.manager().emit( - event, - EventSource::Webview { - label: self.label().to_string(), - }, - payload, - )?; - Ok(()) - } - - fn emit_to( - &self, - label: &str, - event: &str, - payload: S, - ) -> crate::Result<()> { - self.manager().emit_filter( - event, - EventSource::Webview { - label: self.label().to_string(), - }, - payload, - |w| label == w.label(), - ) - } - - fn emit_filter(&self, event: &str, payload: S, filter: F) -> crate::Result<()> - where - S: Serialize + Clone, - F: Fn(&Webview) -> bool, - { - self.manager().emit_filter( - event, - EventSource::Webview { + self.window.manager.once( + event.into(), + EventTarget::Webview { label: self.label().to_string(), }, - payload, - filter, + handler, ) } } +impl Manager for Webview {} + impl ManagerBase for Webview { fn manager(&self) -> &AppManager { &self.window.manager diff --git a/core/tauri/src/webview/webview_window.rs b/core/tauri/src/webview/webview_window.rs index 9088fe6c6b47..99ed739814ec 100644 --- a/core/tauri/src/webview/webview_window.rs +++ b/core/tauri/src/webview/webview_window.rs @@ -6,6 +6,11 @@ use std::{borrow::Cow, path::PathBuf, sync::Arc}; +use crate::{ + event::EventTarget, + runtime::window::dpi::{PhysicalPosition, PhysicalSize}, + window::Monitor, +}; #[cfg(desktop)] use crate::{ menu::{ContextMenu, Menu}, @@ -18,11 +23,6 @@ use crate::{ }, Icon, }; -use crate::{ - runtime::window::dpi::{PhysicalPosition, PhysicalSize}, - window::Monitor, -}; -use serde::Serialize; use tauri_utils::config::{WebviewUrl, WindowConfig}; use url::Url; @@ -861,24 +861,6 @@ unsafe impl raw_window_handle::HasRawWindowHandle for WebviewWindow< } } -impl ManagerBase for WebviewWindow { - fn manager(&self) -> &AppManager { - self.webview.manager() - } - - fn manager_owned(&self) -> Arc> { - self.webview.manager_owned() - } - - fn runtime(&self) -> RuntimeOrDispatch<'_, R> { - self.webview.runtime() - } - - fn managed_app_handle(&self) -> &AppHandle { - self.webview.managed_app_handle() - } -} - impl<'de, R: Runtime> CommandArg<'de, R> for WebviewWindow { /// Grabs the [`Window`] from the [`CommandItem`]. This will never fail. fn from_command(command: CommandItem<'de, R>) -> Result { @@ -1702,7 +1684,7 @@ tauri::Builder::default() /// Event system APIs. impl WebviewWindow { - /// Listen to an event on this webview. + /// Listen to an event on this webview window. /// /// # Examples /// @@ -1728,10 +1710,16 @@ tauri::Builder::default() where F: Fn(Event) + Send + 'static, { - self.webview.listen(event, handler) + self.manager().listen( + event.into(), + EventTarget::WebviewWindow { + label: self.label().to_string(), + }, + handler, + ) } - /// Unlisten to an event on this window. + /// Unlisten to an event on this webview window. /// /// # Examples #[cfg_attr( @@ -1761,39 +1749,42 @@ tauri::Builder::default() "#### )] pub fn unlisten(&self, id: EventId) { - self.webview.unlisten(id) + self.manager().unlisten(id) } - /// Listen to an event on this webview only once. + /// Listen to an event on this window webview only once. /// /// See [`Self::listen`] for more information. pub fn once(&self, event: impl Into, handler: F) where F: FnOnce(Event) + Send + 'static, { - self.webview.once(event, handler) + self.manager().once( + event.into(), + EventTarget::WebviewWindow { + label: self.label().to_string(), + }, + handler, + ) } } -impl Manager for WebviewWindow { - fn emit(&self, event: &str, payload: S) -> crate::Result<()> { - self.webview.emit(event, payload) +impl Manager for WebviewWindow {} + +impl ManagerBase for WebviewWindow { + fn manager(&self) -> &AppManager { + self.webview.manager() } - fn emit_to( - &self, - label: &str, - event: &str, - payload: S, - ) -> crate::Result<()> { - self.webview.emit_to(label, event, payload) + fn manager_owned(&self) -> Arc> { + self.webview.manager_owned() } - fn emit_filter(&self, event: &str, payload: S, filter: F) -> crate::Result<()> - where - S: Serialize + Clone, - F: Fn(&Webview) -> bool, - { - self.webview.emit_filter(event, payload, filter) + fn runtime(&self) -> RuntimeOrDispatch<'_, R> { + self.webview.runtime() + } + + fn managed_app_handle(&self) -> &AppHandle { + self.webview.managed_app_handle() } } diff --git a/core/tauri/src/window/mod.rs b/core/tauri/src/window/mod.rs index 73f283ad6021..52384191a6e5 100644 --- a/core/tauri/src/window/mod.rs +++ b/core/tauri/src/window/mod.rs @@ -14,7 +14,7 @@ pub use tauri_utils::{config::Color, WindowEffect as Effect, WindowEffectState a use crate::{ app::AppHandle, - event::{Event, EventId, EventSource}, + event::{Event, EventId, EventTarget}, ipc::{CommandArg, CommandItem, InvokeError}, manager::{webview::WebviewLabelDef, AppManager}, runtime::{ @@ -911,60 +911,7 @@ impl PartialEq for Window { } } -impl Manager for Window { - #[cfg_attr( - feature = "tracing", - tracing::instrument("window::emit", skip(self, payload)) - )] - fn emit(&self, event: &str, payload: S) -> crate::Result<()> { - // store the webviews before emit_filter() to prevent a deadlock - let webviews = self.webviews(); - self.manager().emit_filter( - event, - EventSource::Window { - label: self.label().to_string(), - }, - payload, - |w| webviews.contains(w), - )?; - Ok(()) - } - - fn emit_to( - &self, - label: &str, - event: &str, - payload: S, - ) -> crate::Result<()> { - self.manager().emit_filter( - event, - EventSource::Window { - label: self.label().to_string(), - }, - payload, - |w| label == w.label(), - ) - } - - #[cfg_attr( - feature = "tracing", - tracing::instrument("window::emit::filter", skip(self, payload, filter)) - )] - fn emit_filter(&self, event: &str, payload: S, filter: F) -> crate::Result<()> - where - S: Serialize + Clone, - F: Fn(&Webview) -> bool, - { - self.manager().emit_filter( - event, - EventSource::Window { - label: self.label().to_string(), - }, - payload, - filter, - ) - } -} +impl Manager for Window {} impl ManagerBase for Window { fn manager(&self) -> &AppManager { @@ -1021,7 +968,7 @@ impl Window { } /// Adds a new webview as a child of this window. - #[cfg(all(desktop, feature = "unstable"))] + #[cfg(any(test, all(desktop, feature = "unstable")))] #[cfg_attr(docsrs, doc(cfg(all(desktop, feature = "unstable"))))] pub fn add_child, S: Into>( &self, @@ -1993,8 +1940,13 @@ tauri::Builder::default() where F: Fn(Event) + Send + 'static, { - // TODO: listen on all webviews - self.manager.listen(event.into(), None, handler) + self.manager.listen( + event.into(), + EventTarget::Window { + label: self.label().to_string(), + }, + handler, + ) } /// Unlisten to an event on this window. @@ -2037,8 +1989,13 @@ tauri::Builder::default() where F: FnOnce(Event) + Send + 'static, { - // TODO: listen on all webviews - self.manager.once(event.into(), None, handler) + self.manager.once( + event.into(), + EventTarget::Window { + label: self.label().to_string(), + }, + handler, + ) } } diff --git a/core/tests/acl/src/lib.rs b/core/tests/acl/src/lib.rs index bfb0b7d0b771..f2d2aaed4d6f 100644 --- a/core/tests/acl/src/lib.rs +++ b/core/tests/acl/src/lib.rs @@ -46,7 +46,7 @@ mod tests { 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") { + 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 fixture_plugins_str = read_to_string(fixture_entry.path().join("required-plugins.json")) .expect("failed to read fixture required-plugins.json file"); diff --git a/examples/multiwindow/index.html b/examples/multiwindow/index.html index 8b65a78d0c4e..c0f8187398cc 100644 --- a/examples/multiwindow/index.html +++ b/examples/multiwindow/index.html @@ -24,11 +24,10 @@ const container = document.getElementById('container') function createWindowMessageBtn(label) { - const webview = WebviewWindow.getByLabel(label) const button = document.createElement('button') button.innerText = 'Send message to ' + label button.addEventListener('click', function () { - webview.emit('clicked', 'message from ' + windowLabel) + appWindow.emitTo(label, 'clicked', 'message from ' + windowLabel) }) container.appendChild(button) } @@ -67,7 +66,7 @@ globalMessageButton.innerHTML = 'Send global message' globalMessageButton.addEventListener('click', function () { // emit to all windows - window.__TAURI__.event.emit('clicked', 'message from ' + windowLabel) + appWindow.emit('clicked', 'message from ' + windowLabel) }) container.appendChild(globalMessageButton) @@ -82,4 +81,4 @@ - \ No newline at end of file + diff --git a/examples/multiwindow/main.rs b/examples/multiwindow/main.rs index 07c296f4d9f4..648565865f2e 100644 --- a/examples/multiwindow/main.rs +++ b/examples/multiwindow/main.rs @@ -5,8 +5,30 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use tauri::{webview::PageLoadEvent, WebviewWindowBuilder}; +use tauri_utils::acl::{ + resolved::{CommandKey, ResolvedCommand}, + ExecutionContext, +}; fn main() { + let mut context = tauri::generate_context!("../../examples/multiwindow/tauri.conf.json"); + for cmd in [ + "plugin:event|listen", + "plugin:event|emit", + "plugin:event|emit_to", + ] { + context.resolved_acl().allowed_commands.insert( + CommandKey { + name: cmd.into(), + context: ExecutionContext::Local, + }, + ResolvedCommand { + windows: vec!["*".parse().unwrap()], + ..Default::default() + }, + ); + } + tauri::Builder::default() .on_page_load(|webview, payload| { if payload.event() == PageLoadEvent::Finished { @@ -28,8 +50,6 @@ fn main() { Ok(()) }) - .run(tauri::generate_context!( - "../../examples/multiwindow/tauri.conf.json" - )) + .run(context) .expect("failed to run tauri application"); } diff --git a/tooling/api/src/event.ts b/tooling/api/src/event.ts index edf06067da6f..b456342cf5e6 100644 --- a/tooling/api/src/event.ts +++ b/tooling/api/src/event.ts @@ -11,24 +11,17 @@ import { invoke, transformCallback } from './core' -type EventSource = - | { - kind: 'global' - } - | { - kind: 'window' - label: string - } - | { - kind: 'webview' - label: string - } +type EventTarget = + | { kind: 'Any' } + | { kind: 'AnyLabel'; label: string } + | { kind: 'App' } + | { kind: 'Window'; label: string } + | { kind: 'Webview'; label: string } + | { kind: 'WebviewWindow'; label: string } interface Event { /** Event name */ event: EventName - /** The source of the event. Can be a global event, an event from a window or an event from another webview. */ - source: EventSource /** Event identifier used to unlisten */ id: number /** Event payload */ @@ -43,16 +36,11 @@ type EventName = `${TauriEvent}` | (string & Record) interface Options { /** - * Window or webview the function targets. + * The event target to listen to, defaults to `{ kind: 'Any' }`, see {@link EventTarget}. * - * When listening to events and using this value, - * only events triggered by the window with the given label are received. - * - * When emitting events, only the window with the given label will receive it. + * If a string is provided, {@link EventTarget.AnyLabel} is used. */ - target?: - | { kind: 'window'; label: string } - | { kind: 'webview'; label: string } + target?: string | EventTarget } /** @@ -89,14 +77,13 @@ async function _unlisten(event: string, eventId: number): Promise { } /** - * Listen to an event. The event can be either global or window-specific. - * See {@link Event.source} to check the event source. + * Listen to an emitted event to any {@link EventTarget|target}. * * @example * ```typescript * import { listen } from '@tauri-apps/api/event'; * const unlisten = await listen('error', (event) => { - * console.log(`Got error in window ${event.source}, payload: ${event.payload}`); + * console.log(`Got error, payload: ${event.payload}`); * }); * * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted @@ -105,6 +92,7 @@ async function _unlisten(event: string, eventId: number): Promise { * * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. * @param handler Event handler callback. + * @param options Event listening options. * @returns A promise resolving to a function to unlisten to the event. * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. * @@ -115,9 +103,13 @@ async function listen( handler: EventCallback, options?: Options ): Promise { + const target: EventTarget = + typeof options?.target === 'string' + ? { kind: 'AnyLabel', label: options.target } + : options?.target ?? { kind: 'Any' } return invoke('plugin:event|listen', { event, - target: options?.target, + target, handler: transformCallback(handler) }).then((eventId) => { return async () => _unlisten(event, eventId) @@ -125,7 +117,7 @@ async function listen( } /** - * Listen to an one-off event. See {@link listen} for more information. + * Listens once to an emitted event to any {@link EventTarget|target}. * * @example * ```typescript @@ -143,6 +135,8 @@ async function listen( * ``` * * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param handler Event handler callback. + * @param options Event listening options. * @returns A promise resolving to a function to unlisten to the event. * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. * @@ -164,7 +158,8 @@ async function once( } /** - * Emits an event to the backend and all Tauri windows. + * Emits an event to all {@link EventTarget|targets}. + * * @example * ```typescript * import { emit } from '@tauri-apps/api/event'; @@ -172,28 +167,53 @@ async function once( * ``` * * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param payload Event payload. * * @since 1.0.0 */ -async function emit( +async function emit(event: string, payload?: unknown): Promise { + await invoke('plugin:event|emit', { + event, + payload + }) +} + +/** + * Emits an event to all {@link EventTarget|targets} matching the given target. + * + * @example + * ```typescript + * import { emit } from '@tauri-apps/api/event'; + * await emit('frontend-loaded', { loggedIn: true, token: 'authToken' }); + * ``` + * + * @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object. + * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param payload Event payload. + * + * @since 1.0.0 + */ +async function emitTo( + target: EventTarget | string, event: string, - payload?: unknown, - options?: Options + payload?: unknown ): Promise { - await invoke('plugin:event|emit', { + const eventTarget: EventTarget = + typeof target === 'string' ? { kind: 'AnyLabel', label: target } : target + await invoke('plugin:event|emit_to', { + target: eventTarget, event, - target: options?.target, payload }) } export type { - EventSource, Event, + EventTarget, EventCallback, UnlistenFn, EventName, Options } -export { listen, once, emit, TauriEvent } +export { listen, once, emit, emitTo, TauriEvent } diff --git a/tooling/api/src/webview.ts b/tooling/api/src/webview.ts index 0d5a58989f35..2b68bcbb4b79 100644 --- a/tooling/api/src/webview.ts +++ b/tooling/api/src/webview.ts @@ -19,7 +19,16 @@ import { PhysicalPosition, PhysicalSize } from './dpi' import type { LogicalPosition, LogicalSize } from './dpi' import type { EventName, EventCallback, UnlistenFn } from './event' -import { TauriEvent, emit, listen, once } from './event' +import { + TauriEvent, + // imported for documentation purposes + // eslint-disable-next-line + type EventTarget, + emit, + emitTo, + listen, + once +} from './event' import { invoke } from './core' import { Window, getCurrent as getCurrentWindow } from './window' import type { WindowOptions } from './window' @@ -190,7 +199,7 @@ class Webview { } /** - * Listen to an event emitted by the backend that is tied to the webview. + * Listen to an emitted event on this webview. * * @example * ```typescript @@ -220,12 +229,12 @@ class Webview { }) } return listen(event, handler, { - target: { kind: 'webview', label: this.label } + target: { kind: 'Webview', label: this.label } }) } /** - * Listen to an one-off event emitted by the backend that is tied to the webview. + * Listen to an emitted event on this webview only once. * * @example * ```typescript @@ -252,12 +261,13 @@ class Webview { }) } return once(event, handler, { - target: { kind: 'webview', label: this.label } + target: { kind: 'Webview', label: this.label } }) } /** - * Emits an event to the backend, tied to the webview. + * Emits an event to all {@link EventTarget|targets}. + * * @example * ```typescript * import { getCurrent } from '@tauri-apps/api/webview'; @@ -274,15 +284,44 @@ class Webview { handler({ event, id: -1, - source: { kind: 'webview', label: this.label }, payload }) } return Promise.resolve() } - return emit(event, payload, { - target: { kind: 'webview', label: this.label } - }) + return emit(event, payload) + } + + /** + * Emits an event to all {@link EventTarget|targets} matching the given target. + * + * @example + * ```typescript + * import { getCurrent } from '@tauri-apps/api/webview'; + * await getCurrent().emit('webview-loaded', { loggedIn: true, token: 'authToken' }); + * ``` + * + * @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object. + * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param payload Event payload. + */ + async emitTo( + target: string, + event: string, + payload?: unknown + ): Promise { + if (localTauriEvents.includes(event)) { + // eslint-disable-next-line + for (const handler of this.listeners[event] || []) { + handler({ + event, + id: -1, + payload + }) + } + return Promise.resolve() + } + return emitTo(target, event, payload) } /** @ignore */ @@ -604,12 +643,79 @@ class WebviewWindow { // @ts-expect-error `skip` is not defined in the public API but it is handled by the constructor return getAll().map((w) => new WebviewWindow(w.label, { skip: true })) } + + /** + * Listen to an emitted event on this webivew window. + * + * @example + * ```typescript + * import { WebviewWindow } from '@tauri-apps/api/webview'; + * const unlisten = await WebviewWindow.getCurrent().listen('state-changed', (event) => { + * console.log(`Got error: ${payload}`); + * }); + * + * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted + * unlisten(); + * ``` + * + * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param handler Event handler. + * @returns A promise resolving to a function to unlisten to the event. + * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. + */ + async listen( + event: EventName, + handler: EventCallback + ): Promise { + if (this._handleTauriEvent(event, handler)) { + return Promise.resolve(() => { + // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, security/detect-object-injection + const listeners = this.listeners[event] + listeners.splice(listeners.indexOf(handler), 1) + }) + } + return listen(event, handler, { + target: { kind: 'WebviewWindow', label: this.label } + }) + } + + /** + * Listen to an emitted event on this webivew window only once. + * + * @example + * ```typescript + * import { WebviewWindow } from '@tauri-apps/api/webview'; + * const unlisten = await WebviewWindow.getCurrent().once('initialized', (event) => { + * console.log(`Webview initialized!`); + * }); + * + * // you need to call unlisten if your handler goes out of scope e.g. the component is unmounted + * unlisten(); + * ``` + * + * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param handler Event handler. + * @returns A promise resolving to a function to unlisten to the event. + * Note that removing the listener is required if your listener goes out of scope e.g. the component is unmounted. + */ + async once(event: string, handler: EventCallback): Promise { + if (this._handleTauriEvent(event, handler)) { + return Promise.resolve(() => { + // eslint-disable-next-line security/detect-object-injection + const listeners = this.listeners[event] + listeners.splice(listeners.indexOf(handler), 1) + }) + } + return once(event, handler, { + target: { kind: 'WebviewWindow', label: this.label } + }) + } } -// order matters, we use window APIs by default -applyMixins(WebviewWindow, [Webview, Window]) +// Order matters, we use window APIs by default +applyMixins(WebviewWindow, [Window, Webview]) -/** Extends a base class by other specifed classes */ +/** Extends a base class by other specifed classes, wihtout overriding existing properties */ function applyMixins( baseClass: { prototype: unknown }, extendedClasses: unknown @@ -619,6 +725,12 @@ function applyMixins( : [extendedClasses] ).forEach((extendedClass: { prototype: unknown }) => { Object.getOwnPropertyNames(extendedClass.prototype).forEach((name) => { + if ( + typeof baseClass.prototype === 'object' && + baseClass.prototype && + name in baseClass.prototype + ) + return Object.defineProperty( baseClass.prototype, name, diff --git a/tooling/api/src/window.ts b/tooling/api/src/window.ts index af1634979734..543933ae4937 100644 --- a/tooling/api/src/window.ts +++ b/tooling/api/src/window.ts @@ -22,14 +22,17 @@ import { PhysicalPosition, PhysicalSize } from './dpi' -import type { - Event, - EventName, - EventCallback, - UnlistenFn, - EventSource +import type { Event, EventName, EventCallback, UnlistenFn } from './event' +import { + TauriEvent, + // imported for documentation purposes + // eslint-disable-next-line + type EventTarget, + emit, + emitTo, + listen, + once } from './event' -import { TauriEvent, emit, listen, once } from './event' import { invoke } from './core' import { WebviewWindow } from './webview' @@ -97,15 +100,12 @@ enum UserAttentionType { class CloseRequestedEvent { /** Event name */ event: EventName - /** The source of the event. */ - source: EventSource /** Event identifier used to unlisten */ id: number private _preventDefault = false constructor(event: Event) { this.event = event.event - this.source = event.source this.id = event.id } @@ -360,7 +360,7 @@ class Window { } /** - * Listen to an event emitted by the backend that is tied to the window. + * Listen to an emitted event on this window. * * @example * ```typescript @@ -390,12 +390,12 @@ class Window { }) } return listen(event, handler, { - target: { kind: 'window', label: this.label } + target: { kind: 'Window', label: this.label } }) } /** - * Listen to an one-off event emitted by the backend that is tied to the window. + * Listen to an emitted event on this window only once. * * @example * ```typescript @@ -422,12 +422,12 @@ class Window { }) } return once(event, handler, { - target: { kind: 'window', label: this.label } + target: { kind: 'Window', label: this.label } }) } /** - * Emits an event to the backend, tied to the window. + * Emits an event to all {@link EventTarget|targets}. * @example * ```typescript * import { getCurrent } from '@tauri-apps/api/window'; @@ -444,15 +444,43 @@ class Window { handler({ event, id: -1, - source: { kind: 'window', label: this.label }, payload }) } return Promise.resolve() } - return emit(event, payload, { - target: { kind: 'window', label: this.label } - }) + return emit(event, payload) + } + + /** + * Emits an event to all {@link EventTarget|targets} matching the given target. + * + * @example + * ```typescript + * import { getCurrent } from '@tauri-apps/api/window'; + * await getCurrent().emit('window-loaded', { loggedIn: true, token: 'authToken' }); + * ``` + * @param target Label of the target Window/Webview/WebviewWindow or raw {@link EventTarget} object. + * @param event Event name. Must include only alphanumeric characters, `-`, `/`, `:` and `_`. + * @param payload Event payload. + */ + async emitTo( + target: string | EventTarget, + event: string, + payload?: unknown + ): Promise { + if (localTauriEvents.includes(event)) { + // eslint-disable-next-line + for (const handler of this.listeners[event] || []) { + handler({ + event, + id: -1, + payload + }) + } + return Promise.resolve() + } + return emitTo(target, event, payload) } /** @ignore */