diff --git a/src/composables/extensionMessageHandler.ts b/src/composables/extensionMessageHandler.ts index 0c5e857..e86f1b3 100644 --- a/src/composables/extensionMessageHandler.ts +++ b/src/composables/extensionMessageHandler.ts @@ -7,7 +7,7 @@ import { import { handleDatabaseMethodAsync, handleFilesystemMethodAsync, - handleHttpMethodAsync, + handleWebMethodAsync, handlePermissionsMethodAsync, handleContextMethodAsync, handleStorageMethodAsync, @@ -165,8 +165,8 @@ const registerGlobalMessageHandler = () => { result = await handleDatabaseMethodAsync(request, instance.extension) } else if (request.method.startsWith('haextension.fs.')) { result = await handleFilesystemMethodAsync(request, instance.extension) - } else if (request.method.startsWith('haextension.http.')) { - result = await handleHttpMethodAsync(request, instance.extension) + } else if (request.method.startsWith('haextension.web.')) { + result = await handleWebMethodAsync(request, instance.extension) } else if (request.method.startsWith('haextension.permissions.')) { result = await handlePermissionsMethodAsync(request, instance.extension) } else { diff --git a/src/composables/handlers/http.ts b/src/composables/handlers/http.ts deleted file mode 100644 index b4317f0..0000000 --- a/src/composables/handlers/http.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { IHaexHubExtension } from '~/types/haexhub' -import type { ExtensionRequest } from './types' - -export async function handleHttpMethodAsync( - request: ExtensionRequest, - extension: IHaexHubExtension, -) { - if (!extension || !request) { - throw new Error('Extension not found') - } - - // TODO: Implementiere HTTP Commands im Backend - throw new Error('HTTP methods not yet implemented') -} diff --git a/src/composables/handlers/index.ts b/src/composables/handlers/index.ts index 8a9724b..b2f7f59 100644 --- a/src/composables/handlers/index.ts +++ b/src/composables/handlers/index.ts @@ -1,7 +1,7 @@ // Export all handler functions export { handleDatabaseMethodAsync } from './database' export { handleFilesystemMethodAsync } from './filesystem' -export { handleHttpMethodAsync } from './http' +export { handleWebMethodAsync } from './web' export { handlePermissionsMethodAsync } from './permissions' export { handleContextMethodAsync, setContextGetters } from './context' export { handleStorageMethodAsync } from './storage' diff --git a/src/composables/handlers/web.ts b/src/composables/handlers/web.ts new file mode 100644 index 0000000..59a7b4f --- /dev/null +++ b/src/composables/handlers/web.ts @@ -0,0 +1,92 @@ +import type { IHaexHubExtension } from '~/types/haexhub' +import type { ExtensionRequest } from './types' + +export async function handleWebMethodAsync( + request: ExtensionRequest, + extension: IHaexHubExtension, +) { + if (!extension || !request) { + throw new Error('Extension not found') + } + + // TODO: Add permission check for web requests + // This should verify that the extension has permission to make web requests + // before proceeding with the fetch operation + + const { method, params } = request + + if (method === 'haextension.web.fetch') { + return await handleWebFetchAsync(params) + } + + throw new Error(`Unknown web method: ${method}`) +} + +async function handleWebFetchAsync(params: Record) { + const url = params.url as string + const method = (params.method as string) || 'GET' + const headers = (params.headers as Record) || {} + const body = params.body as string | undefined + const timeout = (params.timeout as number) || 30000 + + if (!url) { + throw new Error('URL is required') + } + + try { + const controller = new AbortController() + const timeoutId = setTimeout(() => controller.abort(), timeout) + + const fetchOptions: RequestInit = { + method, + headers, + signal: controller.signal, + } + + // Convert base64 body back to binary if present + if (body) { + const binaryString = atob(body) + const bytes = new Uint8Array(binaryString.length) + for (let i = 0; i < binaryString.length; i++) { + bytes[i] = binaryString.charCodeAt(i) + } + fetchOptions.body = bytes + } + + const response = await fetch(url, fetchOptions) + clearTimeout(timeoutId) + + // Read response as ArrayBuffer + const responseBody = await response.arrayBuffer() + + // Convert ArrayBuffer to base64 + const bytes = new Uint8Array(responseBody) + let binary = '' + for (let i = 0; i < bytes.byteLength; i++) { + binary += String.fromCharCode(bytes[i]) + } + const base64Body = btoa(binary) + + // Convert headers to plain object + const responseHeaders: Record = {} + response.headers.forEach((value, key) => { + responseHeaders[key] = value + }) + + return { + status: response.status, + statusText: response.statusText, + headers: responseHeaders, + body: base64Body, + url: response.url, + } + } catch (error) { + if (error instanceof Error) { + if (error.name === 'AbortError') { + throw new Error(`Request timeout after ${timeout}ms`) + } + throw new Error(`Fetch failed: ${error.message}`) + } + throw new Error('Fetch failed with unknown error') + } +}