import { getPreferenceValues, showToast, Toast } from "@raycast/api" export interface Project { id: string name: string containerTag: string description?: string } export interface Memory { id: string content: string title?: string url?: string containerTag?: string createdAt: string } export interface SearchResult { documentId: string chunks: unknown[] title?: string metadata: Record score?: number createdAt: string updatedAt: string type: string } export interface AddMemoryRequest { content: string containerTags?: string[] title?: string url?: string metadata?: Record } interface AddProjectRequest { name: string } export interface SearchRequest { q: string containerTags?: string[] limit?: number } export interface SearchResponse { results: SearchResult[] timing: number total: number } const API_BASE_URL = "https://api.supermemory.ai" class SupermemoryAPIError extends Error { constructor( message: string, public status?: number, ) { super(message) this.name = "SupermemoryAPIError" } } class AuthenticationError extends Error { constructor(message: string) { super(message) this.name = "AuthenticationError" } } function getApiKey(): string { const { apiKey } = getPreferenceValues() return apiKey } async function makeAuthenticatedRequest( endpoint: string, options: RequestInit = {}, ): Promise { const apiKey = getApiKey() const url = `${API_BASE_URL}${endpoint}` try { const response = await fetch(url, { ...options, headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json", ...options.headers, }, }) if (!response.ok) { if (response.status === 401) { throw new AuthenticationError( "Invalid API key. Please check your API key in preferences. Get a new one from https://supermemory.link/raycast", ) } let errorMessage = `API request failed: ${response.statusText}` try { const errorBody = (await response.json()) as { message?: string } if (errorBody.message) { errorMessage = errorBody.message } } catch { // Ignore JSON parsing errors, use default message } throw new SupermemoryAPIError(errorMessage, response.status) } if (!response.headers.get("content-type")?.includes("application/json")) { throw new SupermemoryAPIError("Invalid response format from API") } const data = (await response.json()) as T return data } catch (err) { if ( err instanceof AuthenticationError || err instanceof SupermemoryAPIError ) { throw err } // Handle network errors or other fetch errors throw new SupermemoryAPIError( `Network error: ${err instanceof Error ? err.message : "Unknown error"}`, ) } } export async function fetchProjects(): Promise { try { const response = await makeAuthenticatedRequest<{ projects: Project[] }>( "/v3/projects", ) return response.projects || [] } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Failed to fetch projects", message: error instanceof Error ? error.message : "Unknown error occurred", }) throw error } } export async function addProject(request: AddProjectRequest): Promise { const response = await makeAuthenticatedRequest("/v3/projects", { method: "POST", body: JSON.stringify(request), }) await showToast({ style: Toast.Style.Success, title: "Project Added", message: "Successfully added project to Supermemory", }) return response } export async function addMemory(request: AddMemoryRequest): Promise { try { const response = await makeAuthenticatedRequest("/v3/documents", { method: "POST", body: JSON.stringify(request), }) await showToast({ style: Toast.Style.Success, title: "Memory Added", message: "Successfully added memory to Supermemory", }) return response } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Failed to add memory", message: error instanceof Error ? error.message : "Unknown error occurred", }) throw error } } export async function searchMemories( request: SearchRequest, ): Promise { try { const response = await makeAuthenticatedRequest( "/v3/search", { method: "POST", body: JSON.stringify(request), }, ) return response.results || [] } catch (error) { await showToast({ style: Toast.Style.Failure, title: "Failed to search memories", message: error instanceof Error ? error.message : "Unknown error occurred", }) throw error } } // Helper function to check if API key is configured and valid export async function fetchSettings(): Promise { const response = await makeAuthenticatedRequest("/v3/settings") return response }