import { invoke } from '@tauri-apps/api/core' import { readFile } from '@tauri-apps/plugin-fs' import { getExtensionUrl } from '~/utils/extension' import type { IHaexHubExtension, IHaexHubExtensionManifest, } from '~/types/haexhub' import type { ExtensionPreview } from '@bindings/ExtensionPreview' import type { ExtensionPermissions } from '~~/src-tauri/bindings/ExtensionPermissions' import type { ExtensionInfoResponse } from '~~/src-tauri/bindings/ExtensionInfoResponse' /* const manifestFileName = 'manifest.json' const logoFileName = 'icon.svg' */ export const useExtensionsStore = defineStore('extensionsStore', () => { const availableExtensions = ref([]) const currentRoute = useRouter().currentRoute const currentExtensionId = computed(() => getSingleRouteParam(currentRoute.value.params.extensionId), ) const currentExtension = computed(() => { if (!currentExtensionId.value) return null return ( availableExtensions.value.find( (ext) => ext.id === currentExtensionId.value, ) ?? null ) }) /* const isActive = (id: string) => computed( () => currentRoute.value.name === 'extension' && currentRoute.value.params.extensionId === id, ) */ const extensionEntry = computed(() => { if ( !currentExtension.value?.version || !currentExtension.value?.publicKey || !currentExtension.value?.name ) return null return getExtensionUrl( currentExtension.value.publicKey, currentExtension.value.name, currentExtension.value.version, currentExtension.value.entry ?? 'index.html', currentExtension.value.devServerUrl ?? undefined, ) }) /* const getExtensionPathAsync = async ( extensionId?: string, version?: string, ) => { if (!extensionId || !version) return '' return await join(await appDataDir(), 'extensions', extensionId, version) } */ /* const checkSourceExtensionDirectoryAsync = async ( extensionDirectory: string, ) => { try { const dir = await readDir(extensionDirectory) const manifest = dir.find( (entry) => entry.name === manifestFileName && entry.isFile, ) if (!manifest) throw new Error('Kein Manifest für Erweiterung gefunden') const logo = dir.find((item) => item.isFile && item.name === logoFileName) if (!logo) throw new Error('Logo fehlt') console.log('found icon', logo) return true } catch (error) { console.error(error) addNotificationAsync({ type: 'error', text: JSON.stringify(error) }) //throw error //new Error(`Keine Leseberechtigung für Ordner ${extensionDirectory}`); } } */ const loadExtensionsAsync = async () => { try { const extensions = await invoke('get_all_extensions') console.log('get_all_extensions', extensions) // ExtensionInfoResponse is now directly compatible with IHaexHubExtension availableExtensions.value = extensions } catch (error) { console.error('Fehler beim Laden der Extensions:', error) throw error } } /* const loadExtensionsAsync = async () => { const { currentVault } = storeToRefs(useVaultStore()) const extensions = (await currentVault.value?.drizzle.select().from(haexExtensions)) ?? [] //if (!extensions?.length) return false; const installedExtensions = await filterAsync( extensions, isExtensionInstalledAsync, ) console.log('loadExtensionsAsync installedExtensions', installedExtensions) availableExtensions.value = extensions.map((extension) => ({ id: extension.id, name: extension.name ?? '', icon: extension.icon ?? '', author: extension.author ?? '', version: extension.version ?? '', enabled: extension.enabled ? true : false, installed: installedExtensions.includes(extension), })) ?? [] console.log('loadExtensionsAsync', availableExtensions.value) return true } */ const installAsync = async ( sourcePath: string | null, permissions?: ExtensionPermissions, ) => { if (!sourcePath) throw new Error('Kein Pfad angegeben') try { // Read file as bytes (works with content URIs on Android) const fileBytes = await readFile(sourcePath) const extensionId = await invoke( 'install_extension_with_permissions', { fileBytes: Array.from(fileBytes), customPermissions: permissions, }, ) return extensionId } catch (error) { console.error('Fehler bei Extension-Installation:', error) throw error } } const removeExtensionAsync = async ( publicKey: string, name: string, version: string, ) => { try { await invoke('remove_extension', { publicKey, name, version, }) } catch (error) { console.error('Fehler beim Entfernen der Extension:', error) throw error } } /* const removeExtensionAsync = async (id: string, version: string) => { try { console.log('remove extension', id, version) await removeExtensionFromVaultAsync(id, version) await removeExtensionFilesAsync(id, version) } catch (error) { throw new Error(JSON.stringify(error)) } } */ const isExtensionInstalledAsync = async ({ publicKey, name, version, }: { publicKey: string name: string version: string }) => { try { return await invoke('is_extension_installed', { publicKey, name, extensionVersion: version, }) } catch (error) { console.error('Fehler beim Prüfen der Extension:', error) return false } } const checkManifest = ( manifestFile: unknown, ): manifestFile is IHaexHubExtensionManifest => { const errors = [] if (typeof manifestFile !== 'object' || manifestFile === null) { errors.push('Manifest ist falsch') return false } if (!('id' in manifestFile) || typeof manifestFile.id !== 'string') errors.push('Keine ID vergeben') if (!('name' in manifestFile) || typeof manifestFile.name !== 'string') errors.push('Name fehlt') if (!('entry' in manifestFile) || typeof manifestFile.entry !== 'string') errors.push('Entry fehlerhaft') if (!('author' in manifestFile) || typeof manifestFile.author !== 'string') errors.push('Author fehlt') if (!('url' in manifestFile) || typeof manifestFile.url !== 'string') errors.push('Url fehlt') if ( !('version' in manifestFile) || typeof manifestFile.version !== 'string' ) errors.push('Version fehlt') if ( !('permissions' in manifestFile) || typeof manifestFile.permissions !== 'object' || manifestFile.permissions === null ) { errors.push('Berechtigungen fehlen') } if (errors.length) throw errors /* const permissions = manifestFile.permissions as Partial; if ( ("database" in permissions && (typeof permissions.database !== "object" || permissions.database === null)) || ("filesystem" in permissions && typeof permissions.filesystem !== "object") || permissions.filesystem === null ) { return false; } */ return true } const preview = ref() const previewManifestAsync = async (extensionPath: string) => { // Read file as bytes (works with content URIs on Android) const fileBytes = await readFile(extensionPath) preview.value = await invoke('preview_extension', { fileBytes: Array.from(fileBytes), }) return preview.value } return { availableExtensions, checkManifest, currentExtension, currentExtensionId, extensionEntry, installAsync, //isActive, isExtensionInstalledAsync, loadExtensionsAsync, previewManifestAsync, removeExtensionAsync, } }) /* const getMimeType = (file: string) => { if (file.endsWith('.css')) return 'text/css' if (file.endsWith('.js')) return 'text/javascript' return 'text/plain' } */ /* const removeExtensionFromVaultAsync = async ( id: string | null, version: string | null, ) => { if (!id) throw new Error( 'Erweiterung kann nicht gelöscht werden. Es keine ID angegeben', ) if (!version) throw new Error( 'Erweiterung kann nicht gelöscht werden. Es wurde keine Version angegeben', ) const { currentVault } = useVaultStore() const removedExtensions = await currentVault?.drizzle .delete(haexExtensions) .where(and(eq(haexExtensions.id, id), eq(haexExtensions.version, version))) return removedExtensions } */ /* const removeExtensionFilesAsync = async ( id: string | null, version: string | null, ) => { try { const { getExtensionPathAsync } = useExtensionsStore() if (!id) throw new Error( 'Erweiterung kann nicht gelöscht werden. Es keine ID angegeben', ) if (!version) throw new Error( 'Erweiterung kann nicht gelöscht werden. Es wurde keine Version angegeben', ) const extensionDirectory = await getExtensionPathAsync(id, version) await remove(extensionDirectory, { recursive: true, }) } catch (error) { console.error('ERROR removeExtensionFilesAsync', error) throw new Error(JSON.stringify(error)) } } */