/** * @fileoverview Tauri IPC bridge. * * Thin wrappers around `window.__TAURI__.core.invoke()` that map each Tauri * command to a named JS function. Organized by domain: sources, items, plugins, * feeds, and OPML import/export. */ (function() { 'use strict'; const invoke = window.__TAURI__.core.invoke; BB.api = { // --- Sources: feed sources aggregated by busser_id --- sources: { /** * List all sources with item/unread counts. * @returns {Promise>} Source objects with id, name, totalCount, unreadCount, health, tags. */ list: () => invoke('list_sources'), }, // --- Items: individual feed entries --- items: { /** * Fetch a paginated, filtered list of items. * @param {Object} [filter] - Filter criteria (source, unread, starred, search, order, page, tag). * @returns {Promise<{items: Array, hasMore: boolean}>} */ list: (filter) => invoke('list_items', { filter: filter || {} }), /** * Get a single item by external_id. * @param {string} id - Item external_id. * @returns {Promise} */ get: (id) => invoke('get_item', { id }), /** * Mark an item as read. * @param {string} id - Item external_id. * @returns {Promise} */ markRead: (id) => invoke('mark_item_read', { id }), /** * Mark an item as unread. * @param {string} id - Item external_id. * @returns {Promise} */ markUnread: (id) => invoke('mark_item_unread', { id }), /** * Star an item. * @param {string} id - Item external_id. * @returns {Promise} */ star: (id) => invoke('star_item', { id }), /** * Unstar an item. * @param {string} id - Item external_id. * @returns {Promise} */ unstar: (id) => invoke('unstar_item', { id }), /** * Get the global unread count. * @returns {Promise} */ unreadCount: () => invoke('get_unread_count'), /** * Mark all unread items as read, optionally for a specific source. * @param {string|null} [sourceId] - Source busser_id, or null for all. * @returns {Promise} Count of items marked read. */ markAllRead: (sourceId) => invoke('mark_all_read', { sourceId: sourceId || null }), }, // --- Plugins: Rhai busser plugins --- plugins: { /** * List all loaded plugins (id, name). * @returns {Promise>} */ list: () => invoke('list_plugins'), /** * Get a plugin's configuration schema (fields for the add-feed form). * @param {string} id - Plugin identifier. * @returns {Promise<{name: string, fields: Array}>} */ schema: (id) => invoke('get_plugin_schema', { id }), }, // --- Feeds: CRUD for subscribed feeds --- feeds: { /** * Get all feeds for a busser (includes config for undo snapshots). * @param {string} busserId - Busser/plugin identifier. * @returns {Promise>} */ getByBusser: (busserId) => invoke('get_feeds_by_busser', { busserId }), /** * Get the first feed for a busser (with decrypted config for editing). * @param {string} busserId - Busser/plugin identifier. * @returns {Promise} */ get: (busserId) => invoke('get_feed', { busserId }), /** * Create a new feed subscription. * @param {Object} input - Feed creation input with busserId, name, config. * @returns {Promise} */ create: (input) => invoke('create_feed', { input }), /** * Update an existing feed's name and config. * @param {string} id - Busser ID. * @param {string} name - New feed name. * @param {Object} config - Updated plugin config values. * @returns {Promise} */ update: (id, name, config) => invoke('update_feed', { id, name, config }), /** * Delete a single feed by UUID. * @param {string} id - Feed UUID. * @returns {Promise} */ delete: (id) => invoke('delete_feed', { id }), /** * Delete all feeds for a busser (source deletion). * @param {string} busserId - Busser/plugin identifier. * @returns {Promise} */ deleteByBusser: (busserId) => invoke('delete_feeds_by_busser', { busserId }), /** * Trigger a fetch across all enabled feeds. * @returns {Promise<{itemsFetched: number, errors: Array}>} */ fetchAll: () => invoke('fetch_all'), /** * Set tags on all feeds for a busser. * @param {string} busserId - Busser/plugin identifier. * @param {Array} tags - Tag names. * @returns {Promise} */ setTags: (busserId, tags) => invoke('set_feed_tags', { busserId, tags }), /** * List all distinct tags across all feeds. * @returns {Promise>} */ listAllTags: () => invoke('list_all_tags'), /** * Reset circuit breaker and retry fetch. * @param {string} busserId - Busser/plugin identifier. * @returns {Promise} */ resetCircuitBreaker: (busserId) => invoke('reset_circuit_breaker', { busserId }), }, // --- OPML: import/export feed subscriptions --- opml: { /** * Export all feeds as OPML XML. * @returns {Promise} OPML XML string. */ export: () => invoke('export_opml'), /** * Import feeds from OPML XML string. * @param {string} content - OPML XML content. * @returns {Promise<{imported: number, skipped: number, errors: Array}>} */ import: (content) => invoke('import_opml', { content }), }, // --- Query Feeds: saved filter rules --- queryFeeds: { /** * List all query feeds with match counts. * @returns {Promise, matchCount: number}>>} */ list: () => invoke('list_query_feeds'), /** * Create a new query feed. * @param {Object} input - Query feed input with name and rules. * @returns {Promise} */ create: (input) => invoke('create_query_feed', { input }), /** * Update a query feed. * @param {string} id - Query feed ID. * @param {string} name - New name. * @param {Array} rules - Updated condition rules. * @returns {Promise} */ update: (id, name, rules) => invoke('update_query_feed', { id, name, rules }), /** * Delete a query feed. * @param {string} id - Query feed ID. * @returns {Promise} */ delete: (id) => invoke('delete_query_feed', { id }), }, // --- Bookmarks: reading list --- bookmarks: { list: (tag) => invoke('list_bookmarks', { tag: tag || null }), create: (input) => invoke('create_bookmark', { input }), createFromItem: (itemId, tags) => invoke('create_bookmark_from_item', { itemId, tags: tags || null }), update: (id, input) => invoke('update_bookmark', { id, input }), delete: (id) => invoke('delete_bookmark', { id }), setTags: (id, tags) => invoke('set_bookmark_tags', { id, tags }), listTags: () => invoke('list_bookmark_tags'), isBookmarked: (url) => invoke('is_bookmarked', { url }), count: () => invoke('get_bookmark_count'), exportHtml: (id) => invoke('export_bookmark_html', { id }), }, // --- Reader: extract article content --- reader: { /** * Extract readable article content from a URL. * @param {string} url - Article URL. * @returns {Promise<{content: string, title?: string}>} */ extract: (url) => invoke('extract_reader_view', { url }), }, // --- Actions: plugin-declared custom actions --- actions: { /** * Download a file to temp dir and open with system default app. * @param {string} url - File URL to download. * @returns {Promise} */ downloadAndOpen: (url) => invoke('download_and_open', { url }), }, // --- Sync: cloud sync via MNW SyncKit --- sync: { /** * Validate an API key against the server. * @param {string} apiKey - API key to validate. * @returns {Promise} App name on success. */ /** * Get current sync status. * @returns {Promise} Status with configured, authenticated, encryptionReady, etc. */ getTiers: () => invoke('sync_get_tiers'), status: () => invoke('sync_status'), /** * Start OAuth2 PKCE auth flow. * @returns {Promise<{authUrl: string, state: string, codeVerifier: string, port: number}>} */ startAuth: () => invoke('sync_start_auth'), /** * Complete auth with authorization code. * @param {Object} input - Auth completion input with code, state, expectedState, codeVerifier, port. * @returns {Promise} */ completeAuth: (input) => invoke('sync_complete_auth', { input }), /** * Disconnect from sync service. * @returns {Promise} */ disconnect: () => invoke('sync_disconnect'), /** * Trigger manual sync. * @returns {Promise<{pushed: number, pulled: number}>} */ now: () => invoke('sync_now'), /** * Set up encryption (first device). * @param {string} password - Encryption password. * @returns {Promise} */ setupEncryptionNew: (password) => invoke('sync_setup_encryption_new', { password }), /** * Set up encryption (joining existing device). * @param {string} password - Encryption password. * @returns {Promise} */ setupEncryptionExisting: (password) => invoke('sync_setup_encryption_existing', { password }), /** * Update auto-sync settings. * @param {Object} input - Settings with autoSyncEnabled, syncIntervalMinutes. * @returns {Promise} */ updateSettings: (input) => invoke('sync_update_settings', { input }), subscriptionStatus: () => invoke('sync_subscription_status'), subscribe: (interval) => invoke('sync_subscribe', { interval }), }, }; })();