mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-15 04:21:38 +00:00
feat(raycast-extension): initial version of supermemory extension for raycast chore: update the metadata and ui for app to get api key  
227 lines
5.3 KiB
TypeScript
227 lines
5.3 KiB
TypeScript
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<string, unknown>;
|
|
score?: number;
|
|
createdAt: string;
|
|
updatedAt: string;
|
|
type: string;
|
|
}
|
|
|
|
export interface AddMemoryRequest {
|
|
content: string;
|
|
containerTags?: string[];
|
|
title?: string;
|
|
url?: string;
|
|
metadata?: Record<string, unknown>;
|
|
}
|
|
|
|
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";
|
|
}
|
|
}
|
|
|
|
async function getApiKey(): Promise<string> {
|
|
try {
|
|
const preferences = getPreferenceValues<{ apiKey: string }>();
|
|
const apiKey = preferences.apiKey?.trim();
|
|
|
|
if (!apiKey) {
|
|
throw new AuthenticationError(
|
|
"API key is required. Please add your Supermemory API key in preferences.",
|
|
);
|
|
}
|
|
|
|
return apiKey;
|
|
} catch {
|
|
throw new AuthenticationError("Failed to get API key from preferences.");
|
|
}
|
|
}
|
|
|
|
async function makeAuthenticatedRequest<T>(
|
|
endpoint: string,
|
|
options: RequestInit = {},
|
|
): Promise<T> {
|
|
const apiKey = await 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<Project[]> {
|
|
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 addMemory(request: AddMemoryRequest): Promise<Memory> {
|
|
try {
|
|
const response = await makeAuthenticatedRequest<Memory>("/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<SearchResult[]> {
|
|
try {
|
|
const response = await makeAuthenticatedRequest<SearchResponse>(
|
|
"/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 checkApiConnection(): Promise<boolean> {
|
|
try {
|
|
await fetchProjects();
|
|
return true;
|
|
} catch (error) {
|
|
if (error instanceof AuthenticationError) {
|
|
await showToast({
|
|
style: Toast.Style.Failure,
|
|
title: "API Key Required",
|
|
message:
|
|
"Please configure your Supermemory API key in preferences. Get it from https://supermemory.link/raycast",
|
|
});
|
|
}
|
|
return false;
|
|
}
|
|
}
|