From 0d4059e51876ab3caf0fb35ab6e77d1b17ebfbec Mon Sep 17 00:00:00 2001 From: haex Date: Mon, 10 Nov 2025 02:31:32 +0100 Subject: [PATCH] Add TypeScript types for ExtensionError and improve error handling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add SerializedExtensionError TypeScript bindings from Rust - Add ExtensionErrorCode enum export with ts-rs - Create useExtensionError composable with type guards and error message extraction - Fix developer page toast messages to show proper error messages instead of [object Object] - Add getErrorMessage helper function for robust error handling across different error types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src-tauri/bindings/ExtensionErrorCode.ts | 6 +++ .../bindings/SerializedExtensionError.ts | 6 +++ src-tauri/src/extension/error.rs | 15 ++++++- src/components/haex/system/developer.vue | 9 ++-- src/composables/useExtensionError.ts | 43 +++++++++++++++++++ 5 files changed, 75 insertions(+), 4 deletions(-) create mode 100644 src-tauri/bindings/ExtensionErrorCode.ts create mode 100644 src-tauri/bindings/SerializedExtensionError.ts create mode 100644 src/composables/useExtensionError.ts diff --git a/src-tauri/bindings/ExtensionErrorCode.ts b/src-tauri/bindings/ExtensionErrorCode.ts new file mode 100644 index 0000000..bf53b73 --- /dev/null +++ b/src-tauri/bindings/ExtensionErrorCode.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Error codes for frontend handling + */ +export type ExtensionErrorCode = "SecurityViolation" | "NotFound" | "PermissionDenied" | "MutexPoisoned" | "Database" | "Filesystem" | "FilesystemWithPath" | "Http" | "Shell" | "Manifest" | "Validation" | "InvalidPublicKey" | "InvalidSignature" | "InvalidActionString" | "SignatureVerificationFailed" | "CalculateHash" | "Installation"; diff --git a/src-tauri/bindings/SerializedExtensionError.ts b/src-tauri/bindings/SerializedExtensionError.ts new file mode 100644 index 0000000..d57b264 --- /dev/null +++ b/src-tauri/bindings/SerializedExtensionError.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. + +/** + * Serialized representation of ExtensionError for TypeScript + */ +export type SerializedExtensionError = { code: number, type: string, message: string, extension_id: string | null, }; diff --git a/src-tauri/src/extension/error.rs b/src-tauri/src/extension/error.rs index 7516049..1943882 100644 --- a/src-tauri/src/extension/error.rs +++ b/src-tauri/src/extension/error.rs @@ -1,10 +1,12 @@ // src-tauri/src/extension/error.rs use thiserror::Error; +use ts_rs::TS; use crate::database::error::DatabaseError; /// Error codes for frontend handling -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, TS)] +#[ts(export)] pub enum ExtensionErrorCode { SecurityViolation = 1000, NotFound = 1001, @@ -25,6 +27,17 @@ pub enum ExtensionErrorCode { Installation = 5000, } +/// Serialized representation of ExtensionError for TypeScript +#[derive(Debug, Clone, serde::Serialize, TS)] +#[ts(export)] +pub struct SerializedExtensionError { + pub code: u16, + #[serde(rename = "type")] + pub error_type: String, + pub message: String, + pub extension_id: Option, +} + impl serde::Serialize for ExtensionErrorCode { fn serialize(&self, serializer: S) -> Result where diff --git a/src/components/haex/system/developer.vue b/src/components/haex/system/developer.vue index 5d2a3dc..30e1ff8 100644 --- a/src/components/haex/system/developer.vue +++ b/src/components/haex/system/developer.vue @@ -163,8 +163,9 @@ const loadDevExtensionAsync = async () => { extensionPath.value = '' } catch (error) { console.error('Failed to load dev extension:', error) + const { getErrorMessage } = useExtensionError() add({ - description: t('add.errors.loadFailed') + error, + description: `${t('add.errors.loadFailed')}: ${getErrorMessage(error)}`, color: 'error', }) } finally { @@ -196,8 +197,9 @@ const reloadDevExtensionAsync = async (extension: ExtensionInfoResponse) => { }) } catch (error) { console.error('Failed to reload dev extension:', error) + const { getErrorMessage } = useExtensionError() add({ - description: t('list.errors.reloadFailed') + error, + description: `${t('list.errors.reloadFailed')}: ${getErrorMessage(error)}`, color: 'error', }) } @@ -223,8 +225,9 @@ const removeDevExtensionAsync = async (extension: ExtensionInfoResponse) => { await loadExtensionsAsync() } catch (error) { console.error('Failed to remove dev extension:', error) + const { getErrorMessage } = useExtensionError() add({ - description: t('list.errors.removeFailed') + error, + description: `${t('list.errors.removeFailed')}: ${getErrorMessage(error)}`, color: 'error', }) } diff --git a/src/composables/useExtensionError.ts b/src/composables/useExtensionError.ts new file mode 100644 index 0000000..b1c05ed --- /dev/null +++ b/src/composables/useExtensionError.ts @@ -0,0 +1,43 @@ +import type { SerializedExtensionError } from '~~/src-tauri/bindings/SerializedExtensionError' + +/** + * Type guard to check if error is a SerializedExtensionError + */ +export function isSerializedExtensionError(error: unknown): error is SerializedExtensionError { + return ( + typeof error === 'object' && + error !== null && + 'code' in error && + 'message' in error && + 'type' in error + ) +} + +/** + * Extract error message from unknown error type + */ +export function getErrorMessage(error: unknown): string { + if (isSerializedExtensionError(error)) { + return error.message + } + + if (error instanceof Error) { + return error.message + } + + if (typeof error === 'string') { + return error + } + + return String(error) +} + +/** + * Composable for handling extension errors + */ +export function useExtensionError() { + return { + isSerializedExtensionError, + getErrorMessage, + } +}