From 74c3e992ee5b966963a29070cdf7eb3cf44526d9 Mon Sep 17 00:00:00 2001 From: pythoninthegrass <4097471+pythoninthegrass@users.noreply.github.com> Date: Mon, 13 Apr 2026 11:45:16 -0500 Subject: [PATCH] feat(events): backend mutation reconciliation replacing frontend optimistic updates Add LibraryReconcileEvent with authoritative stats (total_tracks, total_duration, revision) emitted after every library mutation. Replace LibraryUpdatedEvent::deleted calls in delete, purge, dedup, scan, favorite, and watcher flows. Frontend applies backend-provided totals instead of computing them locally, eliminating count divergence and phantom tracks. - Add LibraryReconcileEvent struct with delete/scan_complete/dedup/favorite factory methods and emit_library_reconcile on EventEmitter trait - Modify library_delete_track(s), library_delete_all, library_purge_missing, run_backfill_and_dedup to emit reconcile events with DB stats + revision - Modify scan_paths_to_library and watcher to emit reconcile on completion - Modify favorites_add/remove to emit reconcile with affected_sections - Add _removeFromView to library store (filters view without recomputing totals) - Add handleLibraryReconcile handler in events.js with queue cleanup - Remove deleted-action branch from createLibraryUpdatedHandler - Remove fetchTracks from handleScanComplete (reconcile handles it) - Update context-menu-actions to use _removeFromView for optimistic UI - Add 7 Rust unit tests and 13 Vitest tests for reconcile event handling Co-Authored-By: Claude Opus 4.6 --- .../__tests__/reconcile-events.test.js | 346 ++++++++++++++++++ app/frontend/js/events.js | 157 +++++--- .../js/mixins/context-menu-actions.js | 203 +++++----- app/frontend/js/stores/library.js | 199 ++++++---- .../mt-tauri/gen/schemas/acl-manifests.json | 2 +- .../mt-tauri/gen/schemas/desktop-schema.json | 162 ++++++++ crates/mt-tauri/gen/schemas/macOS-schema.json | 162 ++++++++ crates/mt-tauri/src/commands/favorites.rs | 26 +- crates/mt-tauri/src/db/models.rs | 2 +- crates/mt-tauri/src/events.rs | 173 +++++++++ crates/mt-tauri/src/library/commands.rs | 69 +++- crates/mt-tauri/src/scanner/commands.rs | 20 +- crates/mt-tauri/src/watcher.rs | 18 +- 13 files changed, 1294 insertions(+), 245 deletions(-) create mode 100644 app/frontend/__tests__/reconcile-events.test.js diff --git a/app/frontend/__tests__/reconcile-events.test.js b/app/frontend/__tests__/reconcile-events.test.js new file mode 100644 index 00000000..665ced43 --- /dev/null +++ b/app/frontend/__tests__/reconcile-events.test.js @@ -0,0 +1,346 @@ +/** + * Tests for library:reconcile event handling + * + * Verifies that the frontend correctly applies backend reconciliation + * events instead of computing local state. + */ + +import { beforeEach, describe, expect, it, vi } from "vitest"; + +// Minimal library store stub for testing reconcile behavior +function createTestLibraryStore(initialTracks = []) { + const _sectionTracks = [...initialTracks]; + const _trackPages = {}; + let _dataVersion = 0; + let _cacheCleared = false; + + return { + totalTracks: initialTracks.length, + totalDuration: initialTracks.reduce((sum, t) => sum + (t.duration || 0), 0), + currentSection: "all", + _lastRevision: 0, + _sectionTracks, + _trackPages, + _dataVersion, + + get filteredTracks() { + return this._sectionTracks; + }, + + _setSectionTracks(tracks) { + this._sectionTracks.length = 0; + this._sectionTracks.push(...tracks); + }, + + _clearCache() { + _cacheCleared = true; + }, + + get cacheCleared() { + return _cacheCleared; + }, + + _removeFromView(idSet) { + if (this._sectionTracks.length > 0) { + const newTracks = this._sectionTracks.filter((t) => !idSet.has(t.id)); + this._setSectionTracks(newTracks); + this._dataVersion++; + } else { + for (const [pageIdx, page] of Object.entries(this._trackPages)) { + this._trackPages[pageIdx] = page.filter((t) => !idSet.has(t.id)); + } + this._dataVersion++; + } + this._clearCache(); + }, + + fetchTracks: vi.fn(), + }; +} + +function createTestQueueStore(initialItems = []) { + return { + items: [...initialItems], + _originalOrder: [...initialItems], + _initializing: false, + _updating: false, + currentIndex: 0, + load: vi.fn(), + }; +} + +// Simulate the reconcile handler from events.js +function handleLibraryReconcile(library, queue, payload) { + const { + mutation, + affected_sections, + removed_ids, + total_tracks, + total_duration, + revision, + } = payload; + + library.totalTracks = total_tracks; + library.totalDuration = total_duration; + library._lastRevision = revision; + + if ( + (mutation === "delete" || mutation === "dedup") && + removed_ids.length > 0 + ) { + const idSet = new Set(removed_ids); + library._removeFromView(idSet); + // Simplified queue cleanup for testing + queue.items = queue.items.filter((t) => !idSet.has(t.id)); + } else if ( + mutation === "scan_complete" || + mutation === "delete" || + mutation === "dedup" + ) { + library.fetchTracks(); + } + + if ( + affected_sections.includes("liked") && + library.currentSection === "liked" + ) { + library.fetchTracks(); + } +} + +describe("Library Reconcile Event Handler", () => { + let library; + let queue; + + const sampleTracks = [ + { id: 1, title: "Track 1", duration: 180000 }, + { id: 2, title: "Track 2", duration: 240000 }, + { id: 3, title: "Track 3", duration: 200000 }, + { id: 4, title: "Track 4", duration: 300000 }, + ]; + + beforeEach(() => { + library = createTestLibraryStore(sampleTracks); + queue = createTestQueueStore(sampleTracks); + }); + + describe("delete mutation with specific IDs", () => { + it("applies authoritative totals from backend", () => { + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [2, 3], + added_ids: [], + total_tracks: 2, + total_duration: 480000, + revision: 5, + }); + + expect(library.totalTracks).toBe(2); + expect(library.totalDuration).toBe(480000); + expect(library._lastRevision).toBe(5); + }); + + it("removes specified tracks from view", () => { + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [2, 3], + added_ids: [], + total_tracks: 2, + total_duration: 480000, + revision: 5, + }); + + const remainingIds = library.filteredTracks.map((t) => t.id); + expect(remainingIds).toEqual([1, 4]); + expect(remainingIds).not.toContain(2); + expect(remainingIds).not.toContain(3); + }); + + it("removes deleted tracks from queue", () => { + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [1, 3], + added_ids: [], + total_tracks: 2, + total_duration: 540000, + revision: 6, + }); + + const queueIds = queue.items.map((t) => t.id); + expect(queueIds).toEqual([2, 4]); + }); + + it("does not call fetchTracks for targeted deletes", () => { + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [2], + added_ids: [], + total_tracks: 3, + total_duration: 680000, + revision: 7, + }); + + expect(library.fetchTracks).not.toHaveBeenCalled(); + }); + }); + + describe("delete mutation without IDs (bulk)", () => { + it("triggers full refetch", () => { + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [], + added_ids: [], + total_tracks: 0, + total_duration: 0, + revision: 8, + }); + + expect(library.fetchTracks).toHaveBeenCalled(); + expect(library.totalTracks).toBe(0); + }); + }); + + describe("scan_complete mutation", () => { + it("triggers full refetch with authoritative totals", () => { + handleLibraryReconcile(library, queue, { + mutation: "scan_complete", + affected_sections: ["all", "added"], + removed_ids: [], + added_ids: [], + total_tracks: 150, + total_duration: 45000000, + revision: 10, + }); + + expect(library.fetchTracks).toHaveBeenCalled(); + expect(library.totalTracks).toBe(150); + expect(library.totalDuration).toBe(45000000); + expect(library._lastRevision).toBe(10); + }); + }); + + describe("dedup mutation", () => { + it("removes deduplicated tracks and updates totals", () => { + handleLibraryReconcile(library, queue, { + mutation: "dedup", + affected_sections: ["all"], + removed_ids: [3, 4], + added_ids: [], + total_tracks: 2, + total_duration: 420000, + revision: 12, + }); + + const remainingIds = library.filteredTracks.map((t) => t.id); + expect(remainingIds).toEqual([1, 2]); + expect(library.totalTracks).toBe(2); + expect(library.totalDuration).toBe(420000); + }); + }); + + describe("favorite mutation", () => { + it("refreshes liked section when viewing it", () => { + library.currentSection = "liked"; + + handleLibraryReconcile(library, queue, { + mutation: "favorite_add", + affected_sections: ["liked"], + removed_ids: [], + added_ids: [], + total_tracks: 4, + total_duration: 920000, + revision: 15, + }); + + expect(library.fetchTracks).toHaveBeenCalled(); + }); + + it("does not refetch when not viewing liked section", () => { + library.currentSection = "all"; + + handleLibraryReconcile(library, queue, { + mutation: "favorite_add", + affected_sections: ["liked"], + removed_ids: [], + added_ids: [], + total_tracks: 4, + total_duration: 920000, + revision: 15, + }); + + expect(library.fetchTracks).not.toHaveBeenCalled(); + }); + }); + + describe("authoritative totals override local state", () => { + it("overrides even when local and backend disagree", () => { + library.totalTracks = 999; + library.totalDuration = 9999999; + + handleLibraryReconcile(library, queue, { + mutation: "delete", + affected_sections: ["all"], + removed_ids: [1], + added_ids: [], + total_tracks: 3, + total_duration: 740000, + revision: 20, + }); + + expect(library.totalTracks).toBe(3); + expect(library.totalDuration).toBe(740000); + }); + }); +}); + +describe("_removeFromView", () => { + it("filters section tracks without touching totals", () => { + const store = createTestLibraryStore([ + { id: 1, title: "A", duration: 100 }, + { id: 2, title: "B", duration: 200 }, + { id: 3, title: "C", duration: 300 }, + ]); + + const originalTotal = store.totalTracks; + const originalDuration = store.totalDuration; + + store._removeFromView(new Set([2])); + + expect(store.filteredTracks.map((t) => t.id)).toEqual([1, 3]); + // Totals are NOT recomputed by _removeFromView + expect(store.totalTracks).toBe(originalTotal); + expect(store.totalDuration).toBe(originalDuration); + }); + + it("filters paginated tracks", () => { + const store = createTestLibraryStore([]); + store._sectionTracks.length = 0; // Clear section tracks + store._trackPages[0] = [ + { id: 1, title: "A" }, + { id: 2, title: "B" }, + ]; + store._trackPages[1] = [ + { id: 3, title: "C" }, + { id: 4, title: "D" }, + ]; + + store._removeFromView(new Set([2, 3])); + + expect(store._trackPages[0].map((t) => t.id)).toEqual([1]); + expect(store._trackPages[1].map((t) => t.id)).toEqual([4]); + }); + + it("clears cache after removal", () => { + const store = createTestLibraryStore([ + { id: 1, title: "A", duration: 100 }, + ]); + + store._removeFromView(new Set([1])); + expect(store.cacheCleared).toBe(true); + }); +}); diff --git a/app/frontend/js/events.js b/app/frontend/js/events.js index a17b81da..72263979 100644 --- a/app/frontend/js/events.js +++ b/app/frontend/js/events.js @@ -8,7 +8,11 @@ * Event naming convention: `domain:action` (e.g., `library:updated`) */ -const { listen } = window.__TAURI__?.event ?? { listen: () => Promise.resolve(() => {}) }; +import { removeFromQueue } from "./utils/library-operations.js"; + +const { listen } = window.__TAURI__?.event ?? { + listen: () => Promise.resolve(() => {}), +}; // Store unlisten functions for cleanup const listeners = []; @@ -18,23 +22,24 @@ const listeners = []; */ export const Events = { // Library events - LIBRARY_UPDATED: 'library:updated', - SCAN_PROGRESS: 'library:scan-progress', - SCAN_COMPLETE: 'library:scan-complete', + LIBRARY_UPDATED: "library:updated", + LIBRARY_RECONCILE: "library:reconcile", + SCAN_PROGRESS: "library:scan-progress", + SCAN_COMPLETE: "library:scan-complete", // Queue events - QUEUE_UPDATED: 'queue:updated', - QUEUE_STATE_CHANGED: 'queue:state-changed', + QUEUE_UPDATED: "queue:updated", + QUEUE_STATE_CHANGED: "queue:state-changed", // Favorites events - FAVORITES_UPDATED: 'favorites:updated', + FAVORITES_UPDATED: "favorites:updated", // Playlist events - PLAYLISTS_UPDATED: 'playlists:updated', + PLAYLISTS_UPDATED: "playlists:updated", // Settings events (Tauri Store) - SETTINGS_CHANGED: 'settings://changed', - SETTINGS_RESET: 'settings://reset', + SETTINGS_CHANGED: "settings://changed", + SETTINGS_RESET: "settings://reset", }; /** @@ -66,16 +71,15 @@ function createLibraryUpdatedHandler(Alpine) { return (payload) => { const { action, track_ids } = payload; - const library = Alpine.store('library'); + const library = Alpine.store("library"); console.log( `[events] Library ${action}:`, - track_ids.length ? `${track_ids.length} tracks` : 'bulk update', + track_ids.length ? `${track_ids.length} tracks` : "bulk update", ); - if (action === 'deleted' && track_ids.length > 0) { - library.removeTracksLocally(track_ids); - } else if (action === 'added' || action === 'modified' || action === 'deleted') { + // Deletions are handled by library:reconcile event with authoritative stats + if (action === "added" || action === "modified") { debouncedFetchTracks(library); } }; @@ -83,7 +87,7 @@ function createLibraryUpdatedHandler(Alpine) { function handleScanProgress(Alpine, payload) { const { job_id, status, scanned, found, errors, current_path } = payload; - const library = Alpine.store('library'); + const library = Alpine.store("library"); if (library.setScanProgress) { library.setScanProgress({ @@ -99,7 +103,7 @@ function handleScanProgress(Alpine, payload) { function handleScanComplete(Alpine, payload) { const { added, skipped, errors, duration_ms } = payload; - const library = Alpine.store('library'); + const library = Alpine.store("library"); console.log( `[events] Scan complete: ${added} added, ${skipped} skipped, ${errors} errors (${duration_ms}ms)`, @@ -108,20 +112,20 @@ function handleScanComplete(Alpine, payload) { if (library.clearScanProgress) { library.clearScanProgress(); } - library.fetchTracks(); + // Track refresh is handled by library:reconcile event with authoritative stats } function createQueueUpdatedHandler(Alpine) { let queueReloadDebounce = null; return (payload) => { - console.log('[events] queue:updated', payload); + console.log("[events] queue:updated", payload); - const queue = Alpine.store('queue'); + const queue = Alpine.store("queue"); if (queue?._initializing || queue?._updating) { console.log( - '[events] Skipping queue reload during', - queue._initializing ? 'initialization' : 'active update', + "[events] Skipping queue reload during", + queue._initializing ? "initialization" : "active update", ); return; } @@ -131,7 +135,7 @@ function createQueueUpdatedHandler(Alpine) { } queueReloadDebounce = setTimeout(() => { - const queue = Alpine.store('queue'); + const queue = Alpine.store("queue"); if (queue && queue.load && !queue._initializing && !queue._updating) { queue.load(); } @@ -140,25 +144,73 @@ function createQueueUpdatedHandler(Alpine) { } function handleQueueStateChanged(Alpine, payload) { - console.log('[events] queue:state-changed', payload); + console.log("[events] queue:state-changed", payload); - const queue = Alpine.store('queue'); + const queue = Alpine.store("queue"); if (queue && !queue._initializing && !queue._updating) { queue.currentIndex = payload.current_index; queue.shuffle = payload.shuffle_enabled; queue.loop = payload.loop_mode; } else if (queue?._initializing || queue?._updating) { console.log( - '[events] Skipping queue state update during', - queue._initializing ? 'initialization' : 'active update', + "[events] Skipping queue state update during", + queue._initializing ? "initialization" : "active update", ); } } +function handleLibraryReconcile(Alpine, payload) { + const { + mutation, + affected_sections, + removed_ids, + total_tracks, + total_duration, + revision, + } = payload; + const library = Alpine.store("library"); + + console.log( + `[events] Library reconcile (${mutation}): total=${total_tracks}, removed=${removed_ids.length}`, + ); + + // Apply authoritative totals from backend + window.Alpine.disableEffectScheduling(() => { + library.totalTracks = total_tracks; + library.totalDuration = total_duration; + }); + library._lastRevision = revision; + + if ( + (mutation === "delete" || mutation === "dedup") && + removed_ids.length > 0 + ) { + // Targeted removal: filter IDs from local view, queue cleanup + const idSet = new Set(removed_ids); + library._removeFromView(idSet); + removeFromQueue(Alpine, idSet); + } else if ( + mutation === "scan_complete" || + mutation === "delete" || + mutation === "dedup" + ) { + // Bulk change: full refetch + library.fetchTracks(); + } + + // Refresh if currently viewing an affected section + if ( + affected_sections.includes("liked") && + library.currentSection === "liked" + ) { + library.fetchTracks(); + } +} + function handleFavoritesUpdated(Alpine, payload) { const { action, track_id } = payload; - const library = Alpine.store('library'); - const player = Alpine.store('player'); + const library = Alpine.store("library"); + const player = Alpine.store("player"); console.log(`[events] Favorites ${action}: track ${track_id}`); @@ -167,13 +219,13 @@ function handleFavoritesUpdated(Alpine, payload) { } if (player.currentTrack?.id === track_id) { - player.isFavorite = action === 'added'; + player.isFavorite = action === "added"; } } function handlePlaylistsUpdated(Alpine, payload) { const { action, playlist_id } = payload; - const library = Alpine.store('library'); + const library = Alpine.store("library"); console.log(`[events] Playlists ${action}: playlist ${playlist_id}`); @@ -195,23 +247,23 @@ function handleSettingsChanged(Alpine, payload) { console.log(`[events] Settings changed: ${key} =`, value); - const ui = Alpine.store('ui'); - const player = Alpine.store('player'); + const ui = Alpine.store("ui"); + const player = Alpine.store("player"); switch (key) { - case 'volume': - if (player && typeof value === 'number') { + case "volume": + if (player && typeof value === "number") { player.volume = value; } break; - case 'theme': - if (ui && typeof value === 'string') { + case "theme": + if (ui && typeof value === "string") { ui.theme = value; ui.applyTheme(); } break; - case 'sidebar_width': - if (ui && typeof value === 'number') { + case "sidebar_width": + if (ui && typeof value === "number") { ui.sidebarWidth = value; } break; @@ -227,21 +279,32 @@ function handleSettingsChanged(Alpine, payload) { * @param {object} Alpine - Alpine.js instance */ export async function initEventListeners(Alpine) { - console.log('[events] Initializing Tauri event listeners...'); + console.log("[events] Initializing Tauri event listeners..."); await subscribe(Events.LIBRARY_UPDATED, createLibraryUpdatedHandler(Alpine)); + await subscribe(Events.LIBRARY_RECONCILE, (p) => + handleLibraryReconcile(Alpine, p), + ); await subscribe(Events.SCAN_PROGRESS, (p) => handleScanProgress(Alpine, p)); await subscribe(Events.SCAN_COMPLETE, (p) => handleScanComplete(Alpine, p)); await subscribe(Events.QUEUE_UPDATED, createQueueUpdatedHandler(Alpine)); - await subscribe(Events.QUEUE_STATE_CHANGED, (p) => handleQueueStateChanged(Alpine, p)); - await subscribe(Events.FAVORITES_UPDATED, (p) => handleFavoritesUpdated(Alpine, p)); - await subscribe(Events.PLAYLISTS_UPDATED, (p) => handlePlaylistsUpdated(Alpine, p)); - await subscribe(Events.SETTINGS_CHANGED, (p) => handleSettingsChanged(Alpine, p)); + await subscribe(Events.QUEUE_STATE_CHANGED, (p) => + handleQueueStateChanged(Alpine, p), + ); + await subscribe(Events.FAVORITES_UPDATED, (p) => + handleFavoritesUpdated(Alpine, p), + ); + await subscribe(Events.PLAYLISTS_UPDATED, (p) => + handlePlaylistsUpdated(Alpine, p), + ); + await subscribe(Events.SETTINGS_CHANGED, (p) => + handleSettingsChanged(Alpine, p), + ); await subscribe(Events.SETTINGS_RESET, () => { - console.log('[events] Settings reset to defaults'); + console.log("[events] Settings reset to defaults"); }); - console.log('[events] Tauri event listeners initialized'); + console.log("[events] Tauri event listeners initialized"); } /** @@ -249,7 +312,7 @@ export async function initEventListeners(Alpine) { * Call this when the app is closing */ export function cleanupEventListeners() { - console.log('[events] Cleaning up event listeners...'); + console.log("[events] Cleaning up event listeners..."); listeners.forEach((unlisten) => unlisten()); listeners.length = 0; } diff --git a/app/frontend/js/mixins/context-menu-actions.js b/app/frontend/js/mixins/context-menu-actions.js index 71cd945c..fbd69f0a 100644 --- a/app/frontend/js/mixins/context-menu-actions.js +++ b/app/frontend/js/mixins/context-menu-actions.js @@ -1,5 +1,5 @@ -import { favorites } from '../api/favorites.js'; -import { playlists } from '../api/playlists.js'; +import { favorites } from "../api/favorites.js"; +import { playlists } from "../api/playlists.js"; /** * Context menu and playback actions mixin for library browser. @@ -22,22 +22,22 @@ export function contextMenuActionsMixin() { // Store track IDs globally for Tauri drop handler workaround window._mtDraggedTrackIds = trackIds; - console.log('[drag-drop]', 'dragstart', { + console.log("[drag-drop]", "dragstart", { trackCount: trackIds.length, trackIds, dataTransferData: trackIdsJson, }); - event.dataTransfer.setData('application/json', trackIdsJson); - event.dataTransfer.effectAllowed = 'all'; + event.dataTransfer.setData("application/json", trackIdsJson); + event.dataTransfer.effectAllowed = "all"; const count = trackIds.length; - const dragEl = document.createElement('div'); + const dragEl = document.createElement("div"); dragEl.className = - 'fixed bg-primary text-primary-foreground px-3 py-1.5 rounded-md text-sm font-medium shadow-lg pointer-events-none'; - dragEl.textContent = count === 1 ? '1 track' : `${count} tracks`; - dragEl.style.position = 'absolute'; - dragEl.style.top = '-1000px'; + "fixed bg-primary text-primary-foreground px-3 py-1.5 rounded-md text-sm font-medium shadow-lg pointer-events-none"; + dragEl.textContent = count === 1 ? "1 track" : `${count} tracks`; + dragEl.style.position = "absolute"; + dragEl.style.top = "-1000px"; document.body.appendChild(dragEl); event.dataTransfer.setDragImage(dragEl, 0, 0); setTimeout(() => dragEl.remove(), 0); @@ -49,10 +49,10 @@ export function contextMenuActionsMixin() { setTimeout(() => { window._mtDragJustEnded = false; window._mtDraggedTrackIds = null; - console.log('[drag-drop]', 'dragJustEnded cleared'); + console.log("[drag-drop]", "dragJustEnded cleared"); }, 1000); - console.log('[drag-drop]', 'dragend', { + console.log("[drag-drop]", "dragend", { dropEffect: event.dataTransfer?.dropEffect, }); }, @@ -74,42 +74,43 @@ export function contextMenuActionsMixin() { } const selectedCount = this.selectedTracks.size; - const trackLabel = selectedCount === 1 ? 'track' : `${selectedCount} tracks`; + const trackLabel = + selectedCount === 1 ? "track" : `${selectedCount} tracks`; const isInPlaylist = this.currentPlaylistId !== null; const menuItems = [ { - label: 'Play Now', + label: "Play Now", action: () => this.playSelected(), }, { label: `Add ${trackLabel} to Queue`, action: () => this.addSelectedToQueue(), }, - { type: 'separator' }, + { type: "separator" }, { - label: 'Play Next', + label: "Play Next", action: () => this.playSelectedNext(), }, { - label: 'Add to Playlist', + label: "Add to Playlist", hasSubmenu: true, action: () => { this.showPlaylistSubmenu = !this.showPlaylistSubmenu; }, }, { - label: 'Add to Liked Songs', + label: "Add to Liked Songs", action: () => this.toggleFavoriteFromMenu(track), }, { - label: 'Go to Artist', + label: "Go to Artist", action: () => this.goToArtist(track), disabled: selectedCount > 1 || (!track.artist && !track.album_artist), }, { - label: 'Go to Album', + label: "Go to Album", action: () => this.goToAlbum(track), disabled: selectedCount > 1 || !track.album, }, @@ -121,37 +122,40 @@ export function contextMenuActionsMixin() { .then((result) => { if (!this.contextMenu) return; const favoriteItem = this.contextMenu.items.find( - (i) => i.label === 'Add to Liked Songs' || i.label === 'Remove from Liked Songs', + (i) => + i.label === "Add to Liked Songs" || + i.label === "Remove from Liked Songs", ); if (favoriteItem) { favoriteItem.label = result.is_favorite - ? 'Remove from Liked Songs' - : 'Add to Liked Songs'; + ? "Remove from Liked Songs" + : "Add to Liked Songs"; } }) .catch(() => {}); if (isInPlaylist) { - menuItems.push({ type: 'separator' }); + menuItems.push({ type: "separator" }); menuItems.push({ label: `Remove ${trackLabel} from Playlist`, action: () => this.removeFromPlaylist(), }); } - menuItems.push({ type: 'separator' }); + menuItems.push({ type: "separator" }); menuItems.push({ - label: 'Show in Finder', + label: "Show in Finder", action: () => this.showInFinder(track), disabled: selectedCount > 1, }); menuItems.push({ - label: selectedCount > 1 - ? `Edit Metadata (${selectedCount} tracks)...` - : 'Edit Metadata...', + label: + selectedCount > 1 + ? `Edit Metadata (${selectedCount} tracks)...` + : "Edit Metadata...", action: () => this.editMetadata(track), }); - menuItems.push({ type: 'separator' }); + menuItems.push({ type: "separator" }); menuItems.push({ label: `Remove ${trackLabel} from Library`, action: () => this.removeSelected(), @@ -178,11 +182,14 @@ export function contextMenuActionsMixin() { items: menuItems, }; this.showPlaylistSubmenu = false; - this.submenuOnLeft = x + menuWidth + 45 + submenuWidth > window.innerWidth; + this.submenuOnLeft = + x + menuWidth + 45 + submenuWidth > window.innerWidth; }, getSelectedTracks() { - return this.library.filteredTracks.filter((t) => this.selectedTracks.has(t.id)); + return this.library.filteredTracks.filter((t) => + this.selectedTracks.has(t.id), + ); }, async playSelected() { @@ -198,15 +205,15 @@ export function contextMenuActionsMixin() { async addSelectedToQueue() { const tracks = this.getSelectedTracks(); if (tracks.length > 0) { - console.log('[context-menu]', 'add_to_queue', { + console.log("[context-menu]", "add_to_queue", { trackCount: tracks.length, trackIds: tracks.map((t) => t.id), }); await this.queue.addTracks(tracks); this.$store.ui.toast( - `Added ${tracks.length} track${tracks.length > 1 ? 's' : ''} to queue`, - 'success', + `Added ${tracks.length} track${tracks.length > 1 ? "s" : ""} to queue`, + "success", ); } this.contextMenu = null; @@ -215,15 +222,15 @@ export function contextMenuActionsMixin() { async playSelectedNext() { const tracks = this.getSelectedTracks(); if (tracks.length > 0) { - console.log('[context-menu]', 'play_next', { + console.log("[context-menu]", "play_next", { trackCount: tracks.length, trackIds: tracks.map((t) => t.id), }); await this.queue.playNextTracks(tracks); this.$store.ui.toast( - `Playing ${tracks.length} track${tracks.length > 1 ? 's' : ''} next`, - 'success', + `Playing ${tracks.length} track${tracks.length > 1 ? "s" : ""} next`, + "success", ); } this.contextMenu = null; @@ -233,7 +240,7 @@ export function contextMenuActionsMixin() { const tracks = this.getSelectedTracks(); if (tracks.length === 0) return; - console.log('[context-menu]', 'add_to_playlist', { + console.log("[context-menu]", "add_to_playlist", { playlistId, trackCount: tracks.length, trackIds: tracks.map((t) => t.id), @@ -243,27 +250,27 @@ export function contextMenuActionsMixin() { const trackIds = tracks.map((t) => t.id); const result = await playlists.addTracks(playlistId, trackIds); const playlist = this.playlists.find((p) => p.id === playlistId); - const playlistName = playlist?.name || 'playlist'; + const playlistName = playlist?.name || "playlist"; if (result.added > 0) { this.$store.ui.toast( - `Added ${result.added} track${result.added > 1 ? 's' : ''} to "${playlistName}"`, - 'success', + `Added ${result.added} track${result.added > 1 ? "s" : ""} to "${playlistName}"`, + "success", ); } else { this.$store.ui.toast( - `Track${tracks.length > 1 ? 's' : ''} already in "${playlistName}"`, - 'info', + `Track${tracks.length > 1 ? "s" : ""} already in "${playlistName}"`, + "info", ); } - window.dispatchEvent(new CustomEvent('mt:playlists-updated')); + window.dispatchEvent(new CustomEvent("mt:playlists-updated")); } catch (error) { - console.error('[context-menu]', 'add_to_playlist_error', { + console.error("[context-menu]", "add_to_playlist_error", { playlistId, error: error.message, }); - this.$store.ui.toast('Failed to add to playlist', 'error'); + this.$store.ui.toast("Failed to add to playlist", "error"); } this.contextMenu = null; @@ -285,11 +292,11 @@ export function contextMenuActionsMixin() { } this.library.refreshIfLikedSongs(); } catch (error) { - console.error('[context-menu]', 'toggle_favorite_error', { + console.error("[context-menu]", "toggle_favorite_error", { trackId: track.id, error: error.message, }); - this.$store.ui.toast('Failed to update liked songs', 'error'); + this.$store.ui.toast("Failed to update liked songs", "error"); } }, @@ -299,7 +306,7 @@ export function contextMenuActionsMixin() { // Dispatch event - albums-browser handles view switch and album opening window.dispatchEvent( - new CustomEvent('mt:navigate-to-album', { + new CustomEvent("mt:navigate-to-album", { detail: { album: track.album, albumArtist: track.album_artist || track.artist, @@ -315,7 +322,7 @@ export function contextMenuActionsMixin() { // Dispatch event - artists-browser handles view switch and artist selection window.dispatchEvent( - new CustomEvent('mt:navigate-to-artist', { + new CustomEvent("mt:navigate-to-artist", { detail: { artist }, }), ); @@ -329,7 +336,9 @@ export function contextMenuActionsMixin() { const trackIds = tracks.map((t) => t.id); window.dispatchEvent( - new CustomEvent('mt:create-playlist-with-tracks', { detail: { trackIds } }), + new CustomEvent("mt:create-playlist-with-tracks", { + detail: { trackIds }, + }), ); }, @@ -342,7 +351,9 @@ export function contextMenuActionsMixin() { try { const positions = []; for (const track of tracks) { - const index = this.library.filteredTracks.findIndex((t) => t.id === track.id); + const index = this.library.filteredTracks.findIndex( + (t) => t.id === track.id, + ); if (index >= 0) positions.push(index); } @@ -353,22 +364,25 @@ export function contextMenuActionsMixin() { } this.$store.ui.toast( - `Removed ${tracks.length} track${tracks.length > 1 ? 's' : ''} from playlist`, - 'success', + `Removed ${tracks.length} track${tracks.length > 1 ? "s" : ""} from playlist`, + "success", ); const playlist = await playlists.get(this.currentPlaylistId); const newTracks = (playlist.tracks || []).map((item) => item.track); this.library.tracks = newTracks; this.library.totalTracks = newTracks.length; - this.library.totalDuration = newTracks.reduce((sum, t) => sum + (t.duration || 0), 0); + this.library.totalDuration = newTracks.reduce( + (sum, t) => sum + (t.duration || 0), + 0, + ); this.library.applyFilters(); this.clearSelection(); - window.dispatchEvent(new CustomEvent('mt:playlists-updated')); + window.dispatchEvent(new CustomEvent("mt:playlists-updated")); } catch (error) { - console.error('Failed to remove from playlist:', error); - this.$store.ui.toast('Failed to remove from playlist', 'error'); + console.error("Failed to remove from playlist:", error); + this.$store.ui.toast("Failed to remove from playlist", "error"); } this.contextMenu = null; @@ -377,13 +391,16 @@ export function contextMenuActionsMixin() { async showInFinder(track) { const trackPath = track?.filepath || track?.path; if (!trackPath) { - console.error('Cannot show in folder: track has no filepath/path', track); - this.$store.ui.toast('Cannot locate file', 'error'); + console.error( + "Cannot show in folder: track has no filepath/path", + track, + ); + this.$store.ui.toast("Cannot locate file", "error"); this.contextMenu = null; return; } - console.log('[context-menu]', 'show_in_finder', { + console.log("[context-menu]", "show_in_finder", { trackId: track.id, trackTitle: track.title, trackPath, @@ -391,17 +408,17 @@ export function contextMenuActionsMixin() { try { if (window.__TAURI__) { - const { revealItemInDir } = await import('@tauri-apps/plugin-opener'); + const { revealItemInDir } = await import("@tauri-apps/plugin-opener"); await revealItemInDir(trackPath); } else { - console.log('Show in folder (browser mode):', trackPath); + console.log("Show in folder (browser mode):", trackPath); } } catch (error) { - console.error('[context-menu]', 'show_in_finder_error', { + console.error("[context-menu]", "show_in_finder_error", { trackId: track.id, error: error.message, }); - this.$store.ui.toast('Failed to open folder', 'error'); + this.$store.ui.toast("Failed to open folder", "error"); } this.contextMenu = null; }, @@ -412,14 +429,14 @@ export function contextMenuActionsMixin() { tracks.push(track); } - console.log('[context-menu]', 'edit_metadata', { + console.log("[context-menu]", "edit_metadata", { trackCount: tracks.length, trackIds: tracks.map((t) => t.id), anchorTrackId: track.id, }); this.contextMenu = null; - this.$store.ui.openModal('editMetadata', { + this.$store.ui.openModal("editMetadata", { tracks, library: this.library, anchorTrackId: track.id, @@ -430,32 +447,36 @@ export function contextMenuActionsMixin() { const tracks = this.getSelectedTracks(); if (tracks.length === 0) return; - console.log('[context-menu]', 'remove_from_library', { + console.log("[context-menu]", "remove_from_library", { trackCount: tracks.length, trackIds: tracks.map((t) => t.id), }); - const confirmMsg = tracks.length === 1 - ? `Remove "${tracks[0].title}" from library?` - : `Remove ${tracks.length} tracks from library?`; + const confirmMsg = + tracks.length === 1 + ? `Remove "${tracks[0].title}" from library?` + : `Remove ${tracks.length} tracks from library?`; this.contextMenu = null; - const confirmed = (await window.__TAURI__?.dialog?.confirm(confirmMsg, { - title: 'Remove from Library', - kind: 'warning', - })) ?? window.confirm(confirmMsg); + const confirmed = + (await window.__TAURI__?.dialog?.confirm(confirmMsg, { + title: "Remove from Library", + kind: "warning", + })) ?? window.confirm(confirmMsg); if (confirmed) { const trackIds = tracks.map((t) => t.id); const isDeletingAll = trackIds.length === this.library.allTracks.length; - // Optimistic UI: remove from local state immediately - this.library.removeTracksLocally(trackIds); + // Optimistic UI: remove from view (totals come from backend reconcile event) + const idSet = new Set(trackIds); + this.library._removeFromView(idSet); + this.library._removeFromQueue(idSet); this.selectedTracks.clear(); this.$store.ui.toast( - `Removed ${tracks.length} track${tracks.length > 1 ? 's' : ''}`, - 'success', + `Removed ${tracks.length} track${tracks.length > 1 ? "s" : ""}`, + "success", ); const { invoke } = window.__TAURI__.core; @@ -463,20 +484,28 @@ export function contextMenuActionsMixin() { try { if (isDeletingAll) { // Remove watched folders first so watcher can't re-add tracks - const folders = await invoke('watched_folders_list'); + const folders = await invoke("watched_folders_list"); await Promise.allSettled( - (folders || []).map((f) => invoke('watched_folders_remove', { id: f.id })), + (folders || []).map((f) => + invoke("watched_folders_remove", { id: f.id }), + ), ); // Single SQL wipe of library, favorites, playlist_items - await invoke('library_delete_all'); - console.log('[library-browser] Deleted all tracks and removed watched folders'); + await invoke("library_delete_all"); + console.log( + "[library-browser] Deleted all tracks and removed watched folders", + ); } else { // Batch delete by IDs in a single IPC call - await invoke('library_delete_tracks', { trackIds }); - console.log('[library-browser] Batch deleted', trackIds.length, 'tracks'); + await invoke("library_delete_tracks", { trackIds }); + console.log( + "[library-browser] Batch deleted", + trackIds.length, + "tracks", + ); } } catch (err) { - console.error('[library-browser] Delete failed:', err); + console.error("[library-browser] Delete failed:", err); this.library.fetchTracks(); } } diff --git a/app/frontend/js/stores/library.js b/app/frontend/js/stores/library.js index 9cf7cdc2..1c1d7038 100644 --- a/app/frontend/js/stores/library.js +++ b/app/frontend/js/stores/library.js @@ -9,12 +9,12 @@ * recent, playlists) load all tracks in a single fetch. */ -import { library as libraryApi } from '../api/library.js'; +import { library as libraryApi } from "../api/library.js"; import { buildCacheEntry, createCacheSaver, loadCacheFromSettings, -} from '../utils/library-cache.js'; +} from "../utils/library-cache.js"; import { applySectionData, backgroundRefreshLibrary, @@ -26,19 +26,21 @@ import { removeFromQueue, removeTracksLocallyOp, scanPaths, -} from '../utils/library-operations.js'; +} from "../utils/library-operations.js"; -const { listen } = window.__TAURI__?.event ?? { listen: () => Promise.resolve(() => {}) }; +const { listen } = window.__TAURI__?.event ?? { + listen: () => Promise.resolve(() => {}), +}; // Re-export for use in library-operations.js (they call store._updateCache etc.) export { applySectionData }; export function createLibraryStore(Alpine) { - Alpine.store('library', { + Alpine.store("library", { // Search and filter state - searchQuery: '', - sortBy: 'default', - sortOrder: 'asc', + searchQuery: "", + sortBy: "default", + sortOrder: "asc", currentSection: getInitialSection(), // Loading state @@ -75,7 +77,9 @@ export function createLibraryStore(Alpine) { async init() { this._saveCache = createCacheSaver(window.settings); - const { cache, loaded: hasCachedData } = loadCacheFromSettings(window.settings); + const { cache, loaded: hasCachedData } = loadCacheFromSettings( + window.settings, + ); if (hasCachedData) { this._sectionCache = cache; @@ -84,7 +88,7 @@ export function createLibraryStore(Alpine) { this.totalTracks = cached.totalTracks; this.totalDuration = cached.totalDuration; this._lastLoadedSection = this.currentSection; - console.log('[library] showing cached summary on init:', { + console.log("[library] showing cached summary on init:", { section: this.currentSection, totalTracks: cached.totalTracks, }); @@ -96,16 +100,25 @@ export function createLibraryStore(Alpine) { }, async _setupWatchedFolderListener() { - this._watchedFolderListener = await listen('watched-folder:results', (event) => { - const { added, updated, deleted } = event.payload || {}; - console.log('[library] watched-folder:results', { added, updated, deleted }); - - if (added > 0 || updated > 0 || deleted > 0) { - console.log('[library] Reloading library after watched folder scan'); - this._clearCache(); - this.load({ forceReload: true }); - } - }); + this._watchedFolderListener = await listen( + "watched-folder:results", + (event) => { + const { added, updated, deleted } = event.payload || {}; + console.log("[library] watched-folder:results", { + added, + updated, + deleted, + }); + + if (added > 0 || updated > 0 || deleted > 0) { + console.log( + "[library] Reloading library after watched folder scan", + ); + this._clearCache(); + this.load({ forceReload: true }); + } + }, + ); }, _updateCache(section, data) { @@ -137,10 +150,10 @@ export function createLibraryStore(Alpine) { _clearCache(section = null) { if (section) { delete this._sectionCache[section]; - console.log('[library] cache cleared for section:', section); + console.log("[library] cache cleared for section:", section); } else { this._sectionCache = {}; - console.log('[library] cache cleared (all sections)'); + console.log("[library] cache cleared (all sections)"); } this._persistCache(); }, @@ -175,19 +188,21 @@ export function createLibraryStore(Alpine) { try { const sortKeyMap = { - default: 'artist', - index: 'track_number', - dateAdded: 'added_date', - lastPlayed: 'last_played', - playCount: 'play_count', - year: 'date', - genre: 'genre', - trackTotal: 'track_total', - discNumber: 'disc_number', + default: "artist", + index: "track_number", + dateAdded: "added_date", + lastPlayed: "last_played", + playCount: "play_count", + year: "date", + genre: "genre", + trackTotal: "track_total", + discNumber: "disc_number", }; - const uiStore = Alpine.store('ui'); - const ignoreWords = uiStore.sortIgnoreWords ? uiStore.sortIgnoreWordsList : null; + const uiStore = Alpine.store("ui"); + const ignoreWords = uiStore.sortIgnoreWords + ? uiStore.sortIgnoreWordsList + : null; const data = await libraryApi.getTracks({ search: this.searchQuery.trim() || null, @@ -211,13 +226,16 @@ export function createLibraryStore(Alpine) { // Trigger Alpine reactivity by incrementing version this._dataVersion++; - console.log('[library] page loaded:', { + console.log("[library] page loaded:", { pageIndex, trackCount: tracks.length, totalPages: Math.ceil(this.totalTracks / this._pageSize), }); } catch (error) { - console.error('[library] page fetch failed:', { pageIndex, error: error.message }); + console.error("[library] page fetch failed:", { + pageIndex, + error: error.message, + }); } finally { if (this._loadGeneration === gen) { delete this._loadingPages[pageIndex]; @@ -308,22 +326,24 @@ export function createLibraryStore(Alpine) { _getSortParams() { const sortKeyMap = { - default: 'artist', - index: 'track_number', - dateAdded: 'added_date', - lastPlayed: 'last_played', - playCount: 'play_count', - year: 'date', - genre: 'genre', - trackTotal: 'track_total', - discNumber: 'disc_number', + default: "artist", + index: "track_number", + dateAdded: "added_date", + lastPlayed: "last_played", + playCount: "play_count", + year: "date", + genre: "genre", + trackTotal: "track_total", + discNumber: "disc_number", }; - const uiStore = Alpine.store('ui'); + const uiStore = Alpine.store("ui"); return { search: this.searchQuery.trim() || null, sort: sortKeyMap[this.sortBy] || this.sortBy, order: this.sortOrder, - ignoreWords: uiStore.sortIgnoreWords ? uiStore.sortIgnoreWordsList : null, + ignoreWords: uiStore.sortIgnoreWords + ? uiStore.sortIgnoreWordsList + : null, }; }, @@ -363,40 +383,41 @@ export function createLibraryStore(Alpine) { }, loadFavorites() { - return this._loadSection('liked', null); + return this._loadSection("liked", null); }, _backgroundRefreshFavorites() { // Preserve original matching: currentSection === 'liked' OR _lastLoadedSection === 'liked' - const section = (this.currentSection === 'liked' || this._lastLoadedSection === 'liked') - ? 'liked' - : null; + const section = + this.currentSection === "liked" || this._lastLoadedSection === "liked" + ? "liked" + : null; if (!section) return; - return this._backgroundRefreshSection('liked', null); + return this._backgroundRefreshSection("liked", null); }, loadRecentlyPlayed(days = 14) { - return this._loadSection('recent', null, { days }); + return this._loadSection("recent", null, { days }); }, _backgroundRefreshRecentlyPlayed(days = 14) { - return this._backgroundRefreshSection('recent', null, { days }); + return this._backgroundRefreshSection("recent", null, { days }); }, loadRecentlyAdded(days = 14) { - return this._loadSection('added', null, { days }); + return this._loadSection("added", null, { days }); }, _backgroundRefreshRecentlyAdded(days = 14) { - return this._backgroundRefreshSection('added', null, { days }); + return this._backgroundRefreshSection("added", null, { days }); }, loadTop25() { - return this._loadSection('top25', null); + return this._loadSection("top25", null); }, _backgroundRefreshTop25() { - return this._backgroundRefreshSection('top25', null); + return this._backgroundRefreshSection("top25", null); }, loadPlaylist(playlistId) { @@ -411,19 +432,19 @@ export function createLibraryStore(Alpine) { }; this._persistCache(); - console.log('[navigation]', 'load_playlist_complete', { + console.log("[navigation]", "load_playlist_complete", { playlistId, trackCount: this.filteredTracks.length, }); return data; }; - console.log('[navigation]', 'load_playlist', { playlistId }); + console.log("[navigation]", "load_playlist", { playlistId }); // The unified endpoint returns flat Track objects for playlists return this._loadSection(section, null, { onSuccess: cachePlaylist, - logTag: 'navigation', + logTag: "navigation", }); }, @@ -448,17 +469,19 @@ export function createLibraryStore(Alpine) { // ----------------------------------------------------------------------- setSection(section) { - console.log('[navigation]', 'switch_section', { + console.log("[navigation]", "switch_section", { previousSection: this.currentSection, newSection: section, }); this.currentSection = section; - window.dispatchEvent(new CustomEvent('mt:section-change', { detail: { section } })); + window.dispatchEvent( + new CustomEvent("mt:section-change", { detail: { section } }), + ); }, refreshIfLikedSongs() { - if (this.currentSection === 'liked') { + if (this.currentSection === "liked") { this.loadFavorites(); } }, @@ -482,13 +505,13 @@ export function createLibraryStore(Alpine) { }, setSortBy(field) { - console.log('[library]', 'setSortBy', { field }); + console.log("[library]", "setSortBy", { field }); if (this.sortBy === field) { - this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc'; + this.sortOrder = this.sortOrder === "asc" ? "desc" : "asc"; } else { this.sortBy = field; - this.sortOrder = 'asc'; + this.sortOrder = "asc"; } this.load({ forceReload: true }); @@ -518,12 +541,34 @@ export function createLibraryStore(Alpine) { return removeFromQueue(Alpine, idSet); }, + // Filter track IDs from the current view without recomputing totals. + // Authoritative totals come from the backend reconcile event. + _removeFromView(idSet) { + if (this._sectionTracks) { + const newTracks = this._sectionTracks.filter((t) => !idSet.has(t.id)); + window.Alpine.disableEffectScheduling(() => { + this._setSectionTracks(newTracks); + this._dataVersion++; + }); + } else { + for (const [pageIdx, page] of Object.entries(this._trackPages)) { + this._trackPages[pageIdx] = page.filter((t) => !idSet.has(t.id)); + } + this._dataVersion++; + } + this._clearCache(); + }, + async remove(trackId) { try { + // Optimistic visual removal; reconcile event will provide authoritative totals + this._removeFromView(new Set([trackId])); + this._removeFromQueue(new Set([trackId])); await libraryApi.deleteTrack(trackId); - this.removeTracksLocally([trackId]); } catch (error) { - console.error('Failed to remove track:', error); + console.error("Failed to remove track:", error); + // Rollback: re-fetch from backend + this.fetchTracks(); throw error; } }, @@ -546,7 +591,7 @@ export function createLibraryStore(Alpine) { try { return await libraryApi.getTrack(trackId); } catch (error) { - console.error('[library] getTrackAsync failed:', error); + console.error("[library] getTrackAsync failed:", error); return null; } }, @@ -570,7 +615,7 @@ export function createLibraryStore(Alpine) { return offset; } catch (error) { - console.error('[library] _jumpToPrefix failed:', error); + console.error("[library] _jumpToPrefix failed:", error); return null; } }, @@ -580,7 +625,7 @@ export function createLibraryStore(Alpine) { // ----------------------------------------------------------------------- async addToQueue(track, playNow = false) { - await Alpine.store('queue').add(track, playNow); + await Alpine.store("queue").add(track, playNow); }, async addAllToQueue(playNow = false) { @@ -588,11 +633,11 @@ export function createLibraryStore(Alpine) { if (this._isPaginated() && !this._allPagesLoaded) { await this._loadAllPages(); } - await Alpine.store('queue').add(this.filteredTracks, playNow); + await Alpine.store("queue").add(this.filteredTracks, playNow); }, async playNow(track) { - const queue = Alpine.store('queue'); + const queue = Alpine.store("queue"); await queue.clear(); await queue.add(track, true); }, @@ -633,7 +678,9 @@ export function createLibraryStore(Alpine) { if (updatedTrack) { // Update track in the appropriate storage if (this._sectionTracks) { - const index = this._sectionTracks.findIndex((t) => t.id === trackId); + const index = this._sectionTracks.findIndex( + (t) => t.id === trackId, + ); if (index >= 0) { this._sectionTracks[index] = updatedTrack; this._dataVersion++; @@ -650,7 +697,7 @@ export function createLibraryStore(Alpine) { } } } catch (error) { - console.error('[library] Failed to rescan track:', error); + console.error("[library] Failed to rescan track:", error); } }, @@ -665,7 +712,7 @@ export function createLibraryStore(Alpine) { this.scanProgress = Math.min(99, scanned); } - console.log('[library] scan progress:', { + console.log("[library] scan progress:", { jobId, status, scanned, diff --git a/crates/mt-tauri/gen/schemas/acl-manifests.json b/crates/mt-tauri/gen/schemas/acl-manifests.json index 78de997e..e4c13932 100644 --- a/crates/mt-tauri/gen/schemas/acl-manifests.json +++ b/crates/mt-tauri/gen/schemas/acl-manifests.json @@ -1 +1 @@ -{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"global-shortcut":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n","permissions":[]},"permissions":{"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-register-all":{"identifier":"allow-register-all","description":"Enables the register_all command without any pre-configured scope.","commands":{"allow":["register_all"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"allow-unregister-all":{"identifier":"allow-unregister-all","description":"Enables the unregister_all command without any pre-configured scope.","commands":{"allow":["unregister_all"],"deny":[]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-register-all":{"identifier":"deny-register-all","description":"Denies the register_all command without any pre-configured scope.","commands":{"allow":[],"deny":["register_all"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}},"deny-unregister-all":{"identifier":"deny-unregister-all","description":"Denies the unregister_all command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister_all"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-load","allow-get-store","allow-set","allow-get","allow-has","allow-delete","allow-clear","allow-reset","allow-keys","allow-values","allow-entries","allow-length","allow-reload","allow-save"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-get-store":{"identifier":"allow-get-store","description":"Enables the get_store command without any pre-configured scope.","commands":{"allow":["get_store"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reload":{"identifier":"allow-reload","description":"Enables the reload command without any pre-configured scope.","commands":{"allow":["reload"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-get-store":{"identifier":"deny-get-store","description":"Denies the get_store command without any pre-configured scope.","commands":{"allow":[],"deny":["get_store"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reload":{"identifier":"deny-reload","description":"Denies the reload command without any pre-configured scope.","commands":{"allow":[],"deny":["reload"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"dialog":{"default_permission":{"identifier":"default","description":"This permission set configures the types of dialogs\navailable from the dialog plugin.\n\n#### Granted Permissions\n\nAll dialog types are enabled.\n\n\n","permissions":["allow-ask","allow-confirm","allow-message","allow-save","allow-open"]},"permissions":{"allow-ask":{"identifier":"allow-ask","description":"Enables the ask command without any pre-configured scope.","commands":{"allow":["ask"],"deny":[]}},"allow-confirm":{"identifier":"allow-confirm","description":"Enables the confirm command without any pre-configured scope.","commands":{"allow":["confirm"],"deny":[]}},"allow-message":{"identifier":"allow-message","description":"Enables the message command without any pre-configured scope.","commands":{"allow":["message"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"deny-ask":{"identifier":"deny-ask","description":"Denies the ask command without any pre-configured scope.","commands":{"allow":[],"deny":["ask"]}},"deny-confirm":{"identifier":"deny-confirm","description":"Denies the confirm command without any pre-configured scope.","commands":{"allow":[],"deny":["confirm"]}},"deny-message":{"identifier":"deny-message","description":"Denies the message command without any pre-configured scope.","commands":{"allow":[],"deny":["message"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}}},"permission_sets":{},"global_scope_schema":null},"global-shortcut":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n","permissions":[]},"permissions":{"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-register-all":{"identifier":"allow-register-all","description":"Enables the register_all command without any pre-configured scope.","commands":{"allow":["register_all"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"allow-unregister-all":{"identifier":"allow-unregister-all","description":"Enables the unregister_all command without any pre-configured scope.","commands":{"allow":["unregister_all"],"deny":[]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-register-all":{"identifier":"deny-register-all","description":"Denies the register_all command without any pre-configured scope.","commands":{"allow":[],"deny":["register_all"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}},"deny-unregister-all":{"identifier":"deny-unregister-all","description":"Denies the unregister_all command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister_all"]}}},"permission_sets":{},"global_scope_schema":null},"mcp-bridge":{"default_permission":{"identifier":"default","description":"Default permissions for MCP Bridge plugin","permissions":["allow-capture-native-screenshot","allow-emit-event","allow-execute-command","allow-execute-js","allow-get-backend-state","allow-get-ipc-events","allow-get-window-info","allow-list-windows","allow-report-ipc-event","allow-request-script-injection","allow-script-result","allow-start-ipc-monitor","allow-stop-ipc-monitor"]},"permissions":{"allow-capture-native-screenshot":{"identifier":"allow-capture-native-screenshot","description":"Enables the capture_native_screenshot command without any pre-configured scope.","commands":{"allow":["capture_native_screenshot"],"deny":[]}},"allow-emit-event":{"identifier":"allow-emit-event","description":"Enables the emit_event command without any pre-configured scope.","commands":{"allow":["emit_event"],"deny":[]}},"allow-execute-command":{"identifier":"allow-execute-command","description":"Enables the execute_command command without any pre-configured scope.","commands":{"allow":["execute_command"],"deny":[]}},"allow-execute-js":{"identifier":"allow-execute-js","description":"Enables the execute_js command without any pre-configured scope.","commands":{"allow":["execute_js"],"deny":[]}},"allow-get-backend-state":{"identifier":"allow-get-backend-state","description":"Enables the get_backend_state command without any pre-configured scope.","commands":{"allow":["get_backend_state"],"deny":[]}},"allow-get-ipc-events":{"identifier":"allow-get-ipc-events","description":"Enables the get_ipc_events command without any pre-configured scope.","commands":{"allow":["get_ipc_events"],"deny":[]}},"allow-get-window-info":{"identifier":"allow-get-window-info","description":"Enables the get_window_info command without any pre-configured scope.","commands":{"allow":["get_window_info"],"deny":[]}},"allow-list-windows":{"identifier":"allow-list-windows","description":"Enables the list_windows command without any pre-configured scope.","commands":{"allow":["list_windows"],"deny":[]}},"allow-report-ipc-event":{"identifier":"allow-report-ipc-event","description":"Enables the report_ipc_event command without any pre-configured scope.","commands":{"allow":["report_ipc_event"],"deny":[]}},"allow-request-script-injection":{"identifier":"allow-request-script-injection","description":"Enables the request_script_injection command without any pre-configured scope.","commands":{"allow":["request_script_injection"],"deny":[]}},"allow-script-result":{"identifier":"allow-script-result","description":"Enables the script_result command without any pre-configured scope.","commands":{"allow":["script_result"],"deny":[]}},"allow-start-ipc-monitor":{"identifier":"allow-start-ipc-monitor","description":"Enables the start_ipc_monitor command without any pre-configured scope.","commands":{"allow":["start_ipc_monitor"],"deny":[]}},"allow-stop-ipc-monitor":{"identifier":"allow-stop-ipc-monitor","description":"Enables the stop_ipc_monitor command without any pre-configured scope.","commands":{"allow":["stop_ipc_monitor"],"deny":[]}},"deny-capture-native-screenshot":{"identifier":"deny-capture-native-screenshot","description":"Denies the capture_native_screenshot command without any pre-configured scope.","commands":{"allow":[],"deny":["capture_native_screenshot"]}},"deny-emit-event":{"identifier":"deny-emit-event","description":"Denies the emit_event command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_event"]}},"deny-execute-command":{"identifier":"deny-execute-command","description":"Denies the execute_command command without any pre-configured scope.","commands":{"allow":[],"deny":["execute_command"]}},"deny-execute-js":{"identifier":"deny-execute-js","description":"Denies the execute_js command without any pre-configured scope.","commands":{"allow":[],"deny":["execute_js"]}},"deny-get-backend-state":{"identifier":"deny-get-backend-state","description":"Denies the get_backend_state command without any pre-configured scope.","commands":{"allow":[],"deny":["get_backend_state"]}},"deny-get-ipc-events":{"identifier":"deny-get-ipc-events","description":"Denies the get_ipc_events command without any pre-configured scope.","commands":{"allow":[],"deny":["get_ipc_events"]}},"deny-get-window-info":{"identifier":"deny-get-window-info","description":"Denies the get_window_info command without any pre-configured scope.","commands":{"allow":[],"deny":["get_window_info"]}},"deny-list-windows":{"identifier":"deny-list-windows","description":"Denies the list_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["list_windows"]}},"deny-report-ipc-event":{"identifier":"deny-report-ipc-event","description":"Denies the report_ipc_event command without any pre-configured scope.","commands":{"allow":[],"deny":["report_ipc_event"]}},"deny-request-script-injection":{"identifier":"deny-request-script-injection","description":"Denies the request_script_injection command without any pre-configured scope.","commands":{"allow":[],"deny":["request_script_injection"]}},"deny-script-result":{"identifier":"deny-script-result","description":"Denies the script_result command without any pre-configured scope.","commands":{"allow":[],"deny":["script_result"]}},"deny-start-ipc-monitor":{"identifier":"deny-start-ipc-monitor","description":"Denies the start_ipc_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["start_ipc_monitor"]}},"deny-stop-ipc-monitor":{"identifier":"deny-stop-ipc-monitor","description":"Denies the stop_ipc_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["stop_ipc_monitor"]}}},"permission_sets":{},"global_scope_schema":null},"opener":{"default_permission":{"identifier":"default","description":"This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer","permissions":["allow-open-url","allow-reveal-item-in-dir","allow-default-urls"]},"permissions":{"allow-default-urls":{"identifier":"allow-default-urls","description":"This enables opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application.","commands":{"allow":[],"deny":[]},"scope":{"allow":[{"url":"mailto:*"},{"url":"tel:*"},{"url":"http://*"},{"url":"https://*"}]}},"allow-open-path":{"identifier":"allow-open-path","description":"Enables the open_path command without any pre-configured scope.","commands":{"allow":["open_path"],"deny":[]}},"allow-open-url":{"identifier":"allow-open-url","description":"Enables the open_url command without any pre-configured scope.","commands":{"allow":["open_url"],"deny":[]}},"allow-reveal-item-in-dir":{"identifier":"allow-reveal-item-in-dir","description":"Enables the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":["reveal_item_in_dir"],"deny":[]}},"deny-open-path":{"identifier":"deny-open-path","description":"Denies the open_path command without any pre-configured scope.","commands":{"allow":[],"deny":["open_path"]}},"deny-open-url":{"identifier":"deny-open-url","description":"Denies the open_url command without any pre-configured scope.","commands":{"allow":[],"deny":["open_url"]}},"deny-reveal-item-in-dir":{"identifier":"deny-reveal-item-in-dir","description":"Denies the reveal_item_in_dir command without any pre-configured scope.","commands":{"allow":[],"deny":["reveal_item_in_dir"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this url with, for example: firefox."},"url":{"description":"A URL that can be opened by the webview when using the Opener APIs.\n\nWildcards can be used following the UNIX glob pattern.\n\nExamples:\n\n- \"https://*\" : allows all HTTPS origin\n\n- \"https://*.github.com/tauri-apps/tauri\": allows any subdomain of \"github.com\" with the \"tauri-apps/api\" path\n\n- \"https://myapi.service.com/users/*\": allows access to any URLs that begins with \"https://myapi.service.com/users/\"","type":"string"}},"required":["url"],"type":"object"},{"properties":{"app":{"allOf":[{"$ref":"#/definitions/Application"}],"description":"An application to open this path with, for example: xdg-open."},"path":{"description":"A path that can be opened by the webview when using the Opener APIs.\n\nThe pattern can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"}},"required":["path"],"type":"object"}],"definitions":{"Application":{"anyOf":[{"description":"Open in default application.","type":"null"},{"description":"If true, allow open with any application.","type":"boolean"},{"description":"Allow specific application to open with.","type":"string"}],"description":"Opener scope application."}},"description":"Opener scope entry.","title":"OpenerScopeEntry"}},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}},"store":{"default_permission":{"identifier":"default","description":"This permission set configures what kind of\noperations are available from the store plugin.\n\n#### Granted Permissions\n\nAll operations are enabled by default.\n\n","permissions":["allow-load","allow-get-store","allow-set","allow-get","allow-has","allow-delete","allow-clear","allow-reset","allow-keys","allow-values","allow-entries","allow-length","allow-reload","allow-save"]},"permissions":{"allow-clear":{"identifier":"allow-clear","description":"Enables the clear command without any pre-configured scope.","commands":{"allow":["clear"],"deny":[]}},"allow-delete":{"identifier":"allow-delete","description":"Enables the delete command without any pre-configured scope.","commands":{"allow":["delete"],"deny":[]}},"allow-entries":{"identifier":"allow-entries","description":"Enables the entries command without any pre-configured scope.","commands":{"allow":["entries"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-get-store":{"identifier":"allow-get-store","description":"Enables the get_store command without any pre-configured scope.","commands":{"allow":["get_store"],"deny":[]}},"allow-has":{"identifier":"allow-has","description":"Enables the has command without any pre-configured scope.","commands":{"allow":["has"],"deny":[]}},"allow-keys":{"identifier":"allow-keys","description":"Enables the keys command without any pre-configured scope.","commands":{"allow":["keys"],"deny":[]}},"allow-length":{"identifier":"allow-length","description":"Enables the length command without any pre-configured scope.","commands":{"allow":["length"],"deny":[]}},"allow-load":{"identifier":"allow-load","description":"Enables the load command without any pre-configured scope.","commands":{"allow":["load"],"deny":[]}},"allow-reload":{"identifier":"allow-reload","description":"Enables the reload command without any pre-configured scope.","commands":{"allow":["reload"],"deny":[]}},"allow-reset":{"identifier":"allow-reset","description":"Enables the reset command without any pre-configured scope.","commands":{"allow":["reset"],"deny":[]}},"allow-save":{"identifier":"allow-save","description":"Enables the save command without any pre-configured scope.","commands":{"allow":["save"],"deny":[]}},"allow-set":{"identifier":"allow-set","description":"Enables the set command without any pre-configured scope.","commands":{"allow":["set"],"deny":[]}},"allow-values":{"identifier":"allow-values","description":"Enables the values command without any pre-configured scope.","commands":{"allow":["values"],"deny":[]}},"deny-clear":{"identifier":"deny-clear","description":"Denies the clear command without any pre-configured scope.","commands":{"allow":[],"deny":["clear"]}},"deny-delete":{"identifier":"deny-delete","description":"Denies the delete command without any pre-configured scope.","commands":{"allow":[],"deny":["delete"]}},"deny-entries":{"identifier":"deny-entries","description":"Denies the entries command without any pre-configured scope.","commands":{"allow":[],"deny":["entries"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-get-store":{"identifier":"deny-get-store","description":"Denies the get_store command without any pre-configured scope.","commands":{"allow":[],"deny":["get_store"]}},"deny-has":{"identifier":"deny-has","description":"Denies the has command without any pre-configured scope.","commands":{"allow":[],"deny":["has"]}},"deny-keys":{"identifier":"deny-keys","description":"Denies the keys command without any pre-configured scope.","commands":{"allow":[],"deny":["keys"]}},"deny-length":{"identifier":"deny-length","description":"Denies the length command without any pre-configured scope.","commands":{"allow":[],"deny":["length"]}},"deny-load":{"identifier":"deny-load","description":"Denies the load command without any pre-configured scope.","commands":{"allow":[],"deny":["load"]}},"deny-reload":{"identifier":"deny-reload","description":"Denies the reload command without any pre-configured scope.","commands":{"allow":[],"deny":["reload"]}},"deny-reset":{"identifier":"deny-reset","description":"Denies the reset command without any pre-configured scope.","commands":{"allow":[],"deny":["reset"]}},"deny-save":{"identifier":"deny-save","description":"Denies the save command without any pre-configured scope.","commands":{"allow":[],"deny":["save"]}},"deny-set":{"identifier":"deny-set","description":"Denies the set command without any pre-configured scope.","commands":{"allow":[],"deny":["set"]}},"deny-values":{"identifier":"deny-values","description":"Denies the values command without any pre-configured scope.","commands":{"allow":[],"deny":["values"]}}},"permission_sets":{},"global_scope_schema":null}} \ No newline at end of file diff --git a/crates/mt-tauri/gen/schemas/desktop-schema.json b/crates/mt-tauri/gen/schemas/desktop-schema.json index e7f11fbb..780e054c 100644 --- a/crates/mt-tauri/gen/schemas/desktop-schema.json +++ b/crates/mt-tauri/gen/schemas/desktop-schema.json @@ -2654,6 +2654,168 @@ "const": "global-shortcut:deny-unregister-all", "markdownDescription": "Denies the unregister_all command without any pre-configured scope." }, + { + "description": "Default permissions for MCP Bridge plugin\n#### This default permission set includes:\n\n- `allow-capture-native-screenshot`\n- `allow-emit-event`\n- `allow-execute-command`\n- `allow-execute-js`\n- `allow-get-backend-state`\n- `allow-get-ipc-events`\n- `allow-get-window-info`\n- `allow-list-windows`\n- `allow-report-ipc-event`\n- `allow-request-script-injection`\n- `allow-script-result`\n- `allow-start-ipc-monitor`\n- `allow-stop-ipc-monitor`", + "type": "string", + "const": "mcp-bridge:default", + "markdownDescription": "Default permissions for MCP Bridge plugin\n#### This default permission set includes:\n\n- `allow-capture-native-screenshot`\n- `allow-emit-event`\n- `allow-execute-command`\n- `allow-execute-js`\n- `allow-get-backend-state`\n- `allow-get-ipc-events`\n- `allow-get-window-info`\n- `allow-list-windows`\n- `allow-report-ipc-event`\n- `allow-request-script-injection`\n- `allow-script-result`\n- `allow-start-ipc-monitor`\n- `allow-stop-ipc-monitor`" + }, + { + "description": "Enables the capture_native_screenshot command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-capture-native-screenshot", + "markdownDescription": "Enables the capture_native_screenshot command without any pre-configured scope." + }, + { + "description": "Enables the emit_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-emit-event", + "markdownDescription": "Enables the emit_event command without any pre-configured scope." + }, + { + "description": "Enables the execute_command command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-execute-command", + "markdownDescription": "Enables the execute_command command without any pre-configured scope." + }, + { + "description": "Enables the execute_js command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-execute-js", + "markdownDescription": "Enables the execute_js command without any pre-configured scope." + }, + { + "description": "Enables the get_backend_state command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-backend-state", + "markdownDescription": "Enables the get_backend_state command without any pre-configured scope." + }, + { + "description": "Enables the get_ipc_events command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-ipc-events", + "markdownDescription": "Enables the get_ipc_events command without any pre-configured scope." + }, + { + "description": "Enables the get_window_info command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-window-info", + "markdownDescription": "Enables the get_window_info command without any pre-configured scope." + }, + { + "description": "Enables the list_windows command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-list-windows", + "markdownDescription": "Enables the list_windows command without any pre-configured scope." + }, + { + "description": "Enables the report_ipc_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-report-ipc-event", + "markdownDescription": "Enables the report_ipc_event command without any pre-configured scope." + }, + { + "description": "Enables the request_script_injection command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-request-script-injection", + "markdownDescription": "Enables the request_script_injection command without any pre-configured scope." + }, + { + "description": "Enables the script_result command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-script-result", + "markdownDescription": "Enables the script_result command without any pre-configured scope." + }, + { + "description": "Enables the start_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-start-ipc-monitor", + "markdownDescription": "Enables the start_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Enables the stop_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-stop-ipc-monitor", + "markdownDescription": "Enables the stop_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Denies the capture_native_screenshot command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-capture-native-screenshot", + "markdownDescription": "Denies the capture_native_screenshot command without any pre-configured scope." + }, + { + "description": "Denies the emit_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-emit-event", + "markdownDescription": "Denies the emit_event command without any pre-configured scope." + }, + { + "description": "Denies the execute_command command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-execute-command", + "markdownDescription": "Denies the execute_command command without any pre-configured scope." + }, + { + "description": "Denies the execute_js command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-execute-js", + "markdownDescription": "Denies the execute_js command without any pre-configured scope." + }, + { + "description": "Denies the get_backend_state command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-backend-state", + "markdownDescription": "Denies the get_backend_state command without any pre-configured scope." + }, + { + "description": "Denies the get_ipc_events command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-ipc-events", + "markdownDescription": "Denies the get_ipc_events command without any pre-configured scope." + }, + { + "description": "Denies the get_window_info command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-window-info", + "markdownDescription": "Denies the get_window_info command without any pre-configured scope." + }, + { + "description": "Denies the list_windows command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-list-windows", + "markdownDescription": "Denies the list_windows command without any pre-configured scope." + }, + { + "description": "Denies the report_ipc_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-report-ipc-event", + "markdownDescription": "Denies the report_ipc_event command without any pre-configured scope." + }, + { + "description": "Denies the request_script_injection command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-request-script-injection", + "markdownDescription": "Denies the request_script_injection command without any pre-configured scope." + }, + { + "description": "Denies the script_result command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-script-result", + "markdownDescription": "Denies the script_result command without any pre-configured scope." + }, + { + "description": "Denies the start_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-start-ipc-monitor", + "markdownDescription": "Denies the start_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Denies the stop_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-stop-ipc-monitor", + "markdownDescription": "Denies the stop_ipc_monitor command without any pre-configured scope." + }, { "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", "type": "string", diff --git a/crates/mt-tauri/gen/schemas/macOS-schema.json b/crates/mt-tauri/gen/schemas/macOS-schema.json index e7f11fbb..780e054c 100644 --- a/crates/mt-tauri/gen/schemas/macOS-schema.json +++ b/crates/mt-tauri/gen/schemas/macOS-schema.json @@ -2654,6 +2654,168 @@ "const": "global-shortcut:deny-unregister-all", "markdownDescription": "Denies the unregister_all command without any pre-configured scope." }, + { + "description": "Default permissions for MCP Bridge plugin\n#### This default permission set includes:\n\n- `allow-capture-native-screenshot`\n- `allow-emit-event`\n- `allow-execute-command`\n- `allow-execute-js`\n- `allow-get-backend-state`\n- `allow-get-ipc-events`\n- `allow-get-window-info`\n- `allow-list-windows`\n- `allow-report-ipc-event`\n- `allow-request-script-injection`\n- `allow-script-result`\n- `allow-start-ipc-monitor`\n- `allow-stop-ipc-monitor`", + "type": "string", + "const": "mcp-bridge:default", + "markdownDescription": "Default permissions for MCP Bridge plugin\n#### This default permission set includes:\n\n- `allow-capture-native-screenshot`\n- `allow-emit-event`\n- `allow-execute-command`\n- `allow-execute-js`\n- `allow-get-backend-state`\n- `allow-get-ipc-events`\n- `allow-get-window-info`\n- `allow-list-windows`\n- `allow-report-ipc-event`\n- `allow-request-script-injection`\n- `allow-script-result`\n- `allow-start-ipc-monitor`\n- `allow-stop-ipc-monitor`" + }, + { + "description": "Enables the capture_native_screenshot command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-capture-native-screenshot", + "markdownDescription": "Enables the capture_native_screenshot command without any pre-configured scope." + }, + { + "description": "Enables the emit_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-emit-event", + "markdownDescription": "Enables the emit_event command without any pre-configured scope." + }, + { + "description": "Enables the execute_command command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-execute-command", + "markdownDescription": "Enables the execute_command command without any pre-configured scope." + }, + { + "description": "Enables the execute_js command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-execute-js", + "markdownDescription": "Enables the execute_js command without any pre-configured scope." + }, + { + "description": "Enables the get_backend_state command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-backend-state", + "markdownDescription": "Enables the get_backend_state command without any pre-configured scope." + }, + { + "description": "Enables the get_ipc_events command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-ipc-events", + "markdownDescription": "Enables the get_ipc_events command without any pre-configured scope." + }, + { + "description": "Enables the get_window_info command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-get-window-info", + "markdownDescription": "Enables the get_window_info command without any pre-configured scope." + }, + { + "description": "Enables the list_windows command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-list-windows", + "markdownDescription": "Enables the list_windows command without any pre-configured scope." + }, + { + "description": "Enables the report_ipc_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-report-ipc-event", + "markdownDescription": "Enables the report_ipc_event command without any pre-configured scope." + }, + { + "description": "Enables the request_script_injection command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-request-script-injection", + "markdownDescription": "Enables the request_script_injection command without any pre-configured scope." + }, + { + "description": "Enables the script_result command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-script-result", + "markdownDescription": "Enables the script_result command without any pre-configured scope." + }, + { + "description": "Enables the start_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-start-ipc-monitor", + "markdownDescription": "Enables the start_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Enables the stop_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:allow-stop-ipc-monitor", + "markdownDescription": "Enables the stop_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Denies the capture_native_screenshot command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-capture-native-screenshot", + "markdownDescription": "Denies the capture_native_screenshot command without any pre-configured scope." + }, + { + "description": "Denies the emit_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-emit-event", + "markdownDescription": "Denies the emit_event command without any pre-configured scope." + }, + { + "description": "Denies the execute_command command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-execute-command", + "markdownDescription": "Denies the execute_command command without any pre-configured scope." + }, + { + "description": "Denies the execute_js command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-execute-js", + "markdownDescription": "Denies the execute_js command without any pre-configured scope." + }, + { + "description": "Denies the get_backend_state command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-backend-state", + "markdownDescription": "Denies the get_backend_state command without any pre-configured scope." + }, + { + "description": "Denies the get_ipc_events command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-ipc-events", + "markdownDescription": "Denies the get_ipc_events command without any pre-configured scope." + }, + { + "description": "Denies the get_window_info command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-get-window-info", + "markdownDescription": "Denies the get_window_info command without any pre-configured scope." + }, + { + "description": "Denies the list_windows command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-list-windows", + "markdownDescription": "Denies the list_windows command without any pre-configured scope." + }, + { + "description": "Denies the report_ipc_event command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-report-ipc-event", + "markdownDescription": "Denies the report_ipc_event command without any pre-configured scope." + }, + { + "description": "Denies the request_script_injection command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-request-script-injection", + "markdownDescription": "Denies the request_script_injection command without any pre-configured scope." + }, + { + "description": "Denies the script_result command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-script-result", + "markdownDescription": "Denies the script_result command without any pre-configured scope." + }, + { + "description": "Denies the start_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-start-ipc-monitor", + "markdownDescription": "Denies the start_ipc_monitor command without any pre-configured scope." + }, + { + "description": "Denies the stop_ipc_monitor command without any pre-configured scope.", + "type": "string", + "const": "mcp-bridge:deny-stop-ipc-monitor", + "markdownDescription": "Denies the stop_ipc_monitor command without any pre-configured scope." + }, { "description": "This permission set allows opening `mailto:`, `tel:`, `https://` and `http://` urls using their default application\nas well as reveal file in directories using default file explorer\n#### This default permission set includes:\n\n- `allow-open-url`\n- `allow-reveal-item-in-dir`\n- `allow-default-urls`", "type": "string", diff --git a/crates/mt-tauri/src/commands/favorites.rs b/crates/mt-tauri/src/commands/favorites.rs index 843fe642..aca9baca 100644 --- a/crates/mt-tauri/src/commands/favorites.rs +++ b/crates/mt-tauri/src/commands/favorites.rs @@ -6,8 +6,10 @@ use tauri::{AppHandle, State}; use tracing::{debug, warn}; -use crate::db::{Database, FavoriteTrack, PaginatedResult, Track, favorites, library, settings}; -use crate::events::{EventEmitter, FavoritesUpdatedEvent}; +use crate::db::{ + Database, FavoriteTrack, PaginatedResult, Track, favorites, library, revision, settings, +}; +use crate::events::{EventEmitter, FavoritesUpdatedEvent, LibraryReconcileEvent}; use crate::lastfm::LastFmClient; /// Response for favorites get operations with pagination @@ -155,8 +157,16 @@ pub(crate) fn favorites_add( return Err("Track is already favorited".to_string()); } - // Emit favorites updated event + // Emit favorites updated event (player UI) and reconcile event (section counts) let _ = app.emit_favorites_updated(FavoritesUpdatedEvent::added(track_id)); + let stats = library::get_library_stats(&conn).map_err(|e| e.to_string())?; + let rev = revision::get_revision(&conn).map_err(|e| e.to_string())?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::favorite( + "add", + stats.total_tracks, + stats.total_duration as f64, + rev, + )); // Sync love to Last.fm if let (Some(artist), Some(title)) = (track.artist.clone(), track.title.clone()) { @@ -188,8 +198,16 @@ pub(crate) fn favorites_remove( return Err(format!("Track with id {} not in favorites", track_id)); } - // Emit favorites updated event + // Emit favorites updated event (player UI) and reconcile event (section counts) let _ = app.emit_favorites_updated(FavoritesUpdatedEvent::removed(track_id)); + let stats = library::get_library_stats(&conn).map_err(|e| e.to_string())?; + let rev = revision::get_revision(&conn).map_err(|e| e.to_string())?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::favorite( + "remove", + stats.total_tracks, + stats.total_duration as f64, + rev, + )); // Sync unlove to Last.fm if let Some(track) = track diff --git a/crates/mt-tauri/src/db/models.rs b/crates/mt-tauri/src/db/models.rs index ae2cd58f..fa155cec 100644 --- a/crates/mt-tauri/src/db/models.rs +++ b/crates/mt-tauri/src/db/models.rs @@ -183,7 +183,7 @@ pub struct LastfmLovedStats { } /// Library statistics -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct LibraryStats { pub total_tracks: i64, pub total_duration: i64, diff --git a/crates/mt-tauri/src/events.rs b/crates/mt-tauri/src/events.rs index 055e8728..3b522f35 100644 --- a/crates/mt-tauri/src/events.rs +++ b/crates/mt-tauri/src/events.rs @@ -23,6 +23,7 @@ pub struct LibraryUpdatedEvent { impl LibraryUpdatedEvent { pub const EVENT_NAME: &'static str = "library:updated"; + #[allow(dead_code)] pub(crate) fn added(track_ids: Vec) -> Self { Self { action: "added".to_string(), @@ -37,6 +38,7 @@ impl LibraryUpdatedEvent { } } + #[allow(dead_code)] pub(crate) fn deleted(track_ids: Vec) -> Self { Self { action: "deleted".to_string(), @@ -444,6 +446,102 @@ impl ReconcileProgressEvent { } } +// ============================================ +// Library Reconcile Events +// ============================================ + +/// Authoritative delta emitted after any library mutation. +/// The frontend applies these instead of computing local state. +#[derive(Clone, Debug, Serialize)] +pub struct LibraryReconcileEvent { + /// What caused this reconcile: "delete", "scan_complete", "dedup", "favorite_add", "favorite_remove" + pub mutation: String, + /// Which frontend sections need refresh: ["all"], ["liked"], ["all", "liked"], etc. + pub affected_sections: Vec, + /// Track IDs removed (empty for scan_complete) + pub removed_ids: Vec, + /// Track IDs added (empty for delete/dedup) + pub added_ids: Vec, + /// Authoritative total track count from DB after mutation + pub total_tracks: i64, + /// Authoritative total duration (seconds) from DB after mutation + pub total_duration: f64, + /// Monotonic revision from library_revision table + pub revision: i64, +} + +impl LibraryReconcileEvent { + pub const EVENT_NAME: &'static str = "library:reconcile"; + + pub(crate) fn delete( + removed_ids: Vec, + total_tracks: i64, + total_duration: f64, + revision: i64, + ) -> Self { + Self { + mutation: "delete".to_string(), + affected_sections: vec!["all".to_string()], + removed_ids, + added_ids: vec![], + total_tracks, + total_duration, + revision, + } + } + + pub(crate) fn scan_complete( + added_ids: Vec, + total_tracks: i64, + total_duration: f64, + revision: i64, + ) -> Self { + Self { + mutation: "scan_complete".to_string(), + affected_sections: vec!["all".to_string(), "added".to_string()], + removed_ids: vec![], + added_ids, + total_tracks, + total_duration, + revision, + } + } + + pub(crate) fn dedup( + removed_ids: Vec, + total_tracks: i64, + total_duration: f64, + revision: i64, + ) -> Self { + Self { + mutation: "dedup".to_string(), + affected_sections: vec!["all".to_string()], + removed_ids, + added_ids: vec![], + total_tracks, + total_duration, + revision, + } + } + + pub(crate) fn favorite( + action: &str, + total_tracks: i64, + total_duration: f64, + revision: i64, + ) -> Self { + Self { + mutation: format!("favorite_{}", action), + affected_sections: vec!["liked".to_string()], + removed_ids: vec![], + added_ids: vec![], + total_tracks, + total_duration, + revision, + } + } +} + // ============================================ // Helper trait for emitting events // ============================================ @@ -460,6 +558,7 @@ pub trait EventEmitter { #[allow(dead_code)] fn emit_settings_updated(&self, event: SettingsUpdatedEvent) -> Result<(), String>; fn emit_reconcile_progress(&self, event: ReconcileProgressEvent) -> Result<(), String>; + fn emit_library_reconcile(&self, event: LibraryReconcileEvent) -> Result<(), String>; } impl EventEmitter for tauri::AppHandle { @@ -516,6 +615,12 @@ impl EventEmitter for tauri::AppHandle { self.emit(ReconcileProgressEvent::EVENT_NAME, event) .map_err(|e| e.to_string()) } + + fn emit_library_reconcile(&self, event: LibraryReconcileEvent) -> Result<(), String> { + use tauri::Emitter; + self.emit(LibraryReconcileEvent::EVENT_NAME, event) + .map_err(|e| e.to_string()) + } } #[cfg(test)] @@ -1075,4 +1180,72 @@ mod tests { let debug = format!("{:?}", FavoritesUpdatedEvent::added(1)); assert!(debug.contains("FavoritesUpdatedEvent")); } + + // ==================== LibraryReconcileEvent Tests ==================== + + #[test] + fn test_library_reconcile_event_serialization() { + let event = LibraryReconcileEvent::delete(vec![1, 2, 3], 100, 5400.5, 42); + let json = serde_json::to_string(&event).unwrap(); + assert!(json.contains("\"mutation\":\"delete\"")); + assert!(json.contains("\"removed_ids\":[1,2,3]")); + assert!(json.contains("\"total_tracks\":100")); + assert!(json.contains("\"revision\":42")); + assert!(json.contains("\"affected_sections\":[\"all\"]")); + } + + #[test] + fn test_library_reconcile_event_delete() { + let event = LibraryReconcileEvent::delete(vec![5, 10], 98, 5000.0, 7); + assert_eq!(event.mutation, "delete"); + assert_eq!(event.removed_ids, vec![5, 10]); + assert!(event.added_ids.is_empty()); + assert_eq!(event.total_tracks, 98); + assert_eq!(event.total_duration, 5000.0); + assert_eq!(event.revision, 7); + assert_eq!(event.affected_sections, vec!["all"]); + } + + #[test] + fn test_library_reconcile_event_scan_complete() { + let event = LibraryReconcileEvent::scan_complete(vec![100, 101], 200, 10000.0, 15); + assert_eq!(event.mutation, "scan_complete"); + assert!(event.removed_ids.is_empty()); + assert_eq!(event.added_ids, vec![100, 101]); + assert_eq!(event.total_tracks, 200); + assert_eq!(event.affected_sections, vec!["all", "added"]); + } + + #[test] + fn test_library_reconcile_event_dedup() { + let event = LibraryReconcileEvent::dedup(vec![3, 7], 48, 2400.0, 20); + assert_eq!(event.mutation, "dedup"); + assert_eq!(event.removed_ids, vec![3, 7]); + assert!(event.added_ids.is_empty()); + assert_eq!(event.total_tracks, 48); + } + + #[test] + fn test_library_reconcile_event_favorite() { + let event = LibraryReconcileEvent::favorite("add", 50, 3000.0, 10); + assert_eq!(event.mutation, "favorite_add"); + assert_eq!(event.affected_sections, vec!["liked"]); + assert!(event.removed_ids.is_empty()); + assert!(event.added_ids.is_empty()); + } + + #[test] + fn test_library_reconcile_event_name() { + assert_eq!(LibraryReconcileEvent::EVENT_NAME, "library:reconcile"); + } + + #[test] + fn test_library_reconcile_event_clone() { + let event = LibraryReconcileEvent::delete(vec![1, 2], 50, 2500.0, 5); + let cloned = event.clone(); + assert_eq!(event.mutation, cloned.mutation); + assert_eq!(event.removed_ids, cloned.removed_ids); + assert_eq!(event.total_tracks, cloned.total_tracks); + assert_eq!(event.revision, cloned.revision); + } } diff --git a/crates/mt-tauri/src/library/commands.rs b/crates/mt-tauri/src/library/commands.rs index bdbb0452..25c36612 100644 --- a/crates/mt-tauri/src/library/commands.rs +++ b/crates/mt-tauri/src/library/commands.rs @@ -11,7 +11,7 @@ use crate::db::{ Database, LibraryStats, SortOrder, Track, TrackMetadata, favorites, library, playlists, removed, revision, }; -use crate::events::{EventEmitter, LibraryUpdatedEvent}; +use crate::events::{EventEmitter, LibraryReconcileEvent, LibraryUpdatedEvent}; use crate::scanner::artwork::Artwork; use crate::scanner::artwork_cache::ArtworkCache; use crate::scanner::fingerprint::{FileFingerprint, compute_content_hash}; @@ -480,6 +480,13 @@ pub(crate) fn library_get_artwork_url( } } +/// Query authoritative stats + revision for reconcile events. +fn get_reconcile_stats(conn: &rusqlite::Connection) -> Result<(i64, f64, i64), String> { + let stats = library::get_library_stats(conn).map_err(|e| e.to_string())?; + let rev = revision::get_revision(conn).map_err(|e| e.to_string())?; + Ok((stats.total_tracks, stats.total_duration as f64, rev)) +} + /// Delete a track from the library and record the removal to prevent re-addition on scan #[tracing::instrument(skip(app, db))] #[tauri::command] @@ -501,7 +508,14 @@ pub(crate) fn library_delete_track( .map_err(|e| e.to_string())?; if deleted { - let _ = app.emit_library_updated(LibraryUpdatedEvent::deleted(vec![track_id])); + let conn = db.conn().map_err(|e| e.to_string())?; + let (total_tracks, total_duration, rev) = get_reconcile_stats(&conn)?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::delete( + vec![track_id], + total_tracks, + total_duration, + rev, + )); } Ok(deleted) @@ -520,7 +534,14 @@ pub(crate) fn library_purge_missing( .map_err(|e| e.to_string())?; if deleted > 0 { info!(count = deleted, "Purged missing tracks from database"); - let _ = app.emit_library_updated(LibraryUpdatedEvent::deleted(vec![])); + let conn = db.conn().map_err(|e| e.to_string())?; + let (total_tracks, total_duration, rev) = get_reconcile_stats(&conn)?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::delete( + vec![], + total_tracks, + total_duration, + rev, + )); } crate::logging::log_slow_command("library_purge_missing", start); Ok(deleted) @@ -552,7 +573,14 @@ pub(crate) fn library_delete_tracks( info!(count = deleted, "Batch deleted tracks"); crate::logging::log_slow_command("library_delete_tracks", start); if deleted > 0 { - let _ = app.emit_library_updated(LibraryUpdatedEvent::deleted(track_ids)); + let conn = db.conn().map_err(|e| e.to_string())?; + let (total_tracks, total_duration, rev) = get_reconcile_stats(&conn)?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::delete( + track_ids, + total_tracks, + total_duration, + rev, + )); } Ok(deleted) } @@ -573,7 +601,7 @@ pub(crate) fn library_delete_all(app: AppHandle, db: State<'_, Database>) -> Res info!(count = deleted, "Deleted all tracks from library"); crate::logging::log_slow_command("library_delete_all", start); if deleted > 0 { - let _ = app.emit_library_updated(LibraryUpdatedEvent::deleted(vec![])); + let _ = app.emit_library_reconcile(LibraryReconcileEvent::delete(vec![], 0, 0.0, 0)); } Ok(deleted) } @@ -723,9 +751,15 @@ pub(crate) fn library_locate_track( // Emit library updated events let _ = app.emit_library_updated(LibraryUpdatedEvent::modified(vec![track_id])); - // If we removed a duplicate, emit deleted event for it + // If we removed a duplicate, emit reconcile event for it if let Some(dup_id) = deleted_duplicate_id { - let _ = app.emit_library_updated(LibraryUpdatedEvent::deleted(vec![dup_id])); + let (total_tracks, total_duration, rev) = get_reconcile_stats(&conn)?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::delete( + vec![dup_id], + total_tracks, + total_duration, + rev, + )); } Ok(updated_track) @@ -945,10 +979,6 @@ pub(crate) fn run_backfill_and_dedup( } } - if !deleted_ids.is_empty() { - let _ = app_handle.emit_library_updated(LibraryUpdatedEvent::deleted(deleted_ids.clone())); - } - // Phase 3: Cross-directory dedup let _ = app_handle.emit_reconcile_progress(ReconcileProgressEvent::cross_directory_dedup(0, 0)); @@ -1102,15 +1132,20 @@ pub(crate) fn run_backfill_and_dedup( } } - // Emit deleted events for cross-directory dedup - if cross_directory_suppressed > 0 { - let _ = app_handle.emit_library_updated(LibraryUpdatedEvent::deleted( - deleted_ids[duplicates_merged as usize..].to_vec(), + let _ = app_handle.emit_reconcile_progress(ReconcileProgressEvent::complete(total)); + + // Emit a single reconcile event with all deleted IDs and authoritative stats + if !deleted_ids.is_empty() { + let stats = library::get_library_stats(conn).map_err(|e| e.to_string())?; + let rev = revision::get_revision(conn).map_err(|e| e.to_string())?; + let _ = app_handle.emit_library_reconcile(LibraryReconcileEvent::dedup( + deleted_ids.clone(), + stats.total_tracks, + stats.total_duration as f64, + rev, )); } - let _ = app_handle.emit_reconcile_progress(ReconcileProgressEvent::complete(total)); - Ok(ReconcileScanResult { backfilled, duplicates_merged, diff --git a/crates/mt-tauri/src/scanner/commands.rs b/crates/mt-tauri/src/scanner/commands.rs index 9d28ad1d..4ffce1d8 100644 --- a/crates/mt-tauri/src/scanner/commands.rs +++ b/crates/mt-tauri/src/scanner/commands.rs @@ -11,8 +11,9 @@ use tracing::{error, info}; use uuid::Uuid; use crate::commands::match_new_tracks_against_loved; +use crate::db::revision; use crate::db::{Database, library, removed}; -use crate::events::{EventEmitter, LibraryUpdatedEvent, ScanCompleteEvent, ScanProgressEvent}; +use crate::events::{EventEmitter, LibraryReconcileEvent, ScanCompleteEvent, ScanProgressEvent}; use crate::scanner::artwork::{Artwork, get_artwork}; use crate::scanner::fingerprint::{FileFingerprint, compute_content_hash}; use crate::scanner::metadata::extract_metadata; @@ -326,12 +327,17 @@ pub(crate) async fn scan_paths_to_library( duration_ms, }); - // Emit library updated events (empty track_ids signals a bulk change - frontend should refresh) - if added_count > 0 || reconciled_count > 0 || recovered_count > 0 { - let _ = app.emit_library_updated(LibraryUpdatedEvent::added(vec![])); - } - if modified_count > 0 { - let _ = app.emit_library_updated(LibraryUpdatedEvent::modified(vec![])); + // Emit reconcile event with authoritative stats + if added_count > 0 || reconciled_count > 0 || recovered_count > 0 || modified_count > 0 { + let conn = db.conn().map_err(|e| e.to_string())?; + let stats = library::get_library_stats(&conn).map_err(|e| e.to_string())?; + let rev = revision::get_revision(&conn).map_err(|e| e.to_string())?; + let _ = app.emit_library_reconcile(LibraryReconcileEvent::scan_complete( + vec![], + stats.total_tracks, + stats.total_duration as f64, + rev, + )); } // Background backfill: compute content_hash for any tracks that are missing diff --git a/crates/mt-tauri/src/watcher.rs b/crates/mt-tauri/src/watcher.rs index ecc28734..534f137a 100644 --- a/crates/mt-tauri/src/watcher.rs +++ b/crates/mt-tauri/src/watcher.rs @@ -17,10 +17,11 @@ use tauri::{AppHandle, Emitter, State}; use tokio::sync::mpsc; use tracing::{debug, error, info, warn}; +use crate::db::revision; use crate::db::{ Database, TrackMetadata, WatchedFolder as DbWatchedFolder, library, removed, watched, }; -use crate::events::{EventEmitter, LibraryUpdatedEvent, ScanCompleteEvent, ScanProgressEvent}; +use crate::events::{EventEmitter, LibraryReconcileEvent, ScanCompleteEvent, ScanProgressEvent}; use crate::scanner::ExtractedMetadata; use crate::scanner::fingerprint::{FileFingerprint, compute_content_hash}; use crate::scanner::scan::{ProgressCallback, scan_2phase}; @@ -684,11 +685,18 @@ impl WatcherManager { }, ); - // Emit a single library:updated event covering all changes. - // Spacedrive pattern: coalesce multiple change types into one event to avoid - // triggering multiple frontend reloads (each event causes a full data refresh). + // Emit a reconcile event with authoritative stats covering all changes. if added > 0 || updated > 0 || deleted > 0 { - let _ = app.emit_library_updated(LibraryUpdatedEvent::added(vec![])); + if let Ok(conn) = db.conn() { + let stats = crate::db::library::get_library_stats(&conn).unwrap_or_default(); + let rev = revision::get_revision(&conn).unwrap_or(0); + let _ = app.emit_library_reconcile(LibraryReconcileEvent::scan_complete( + vec![], + stats.total_tracks, + stats.total_duration as f64, + rev, + )); + } } let _ = app.emit(