mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-10-07 02:58:11 +00:00
Plugin settings + API client
This commit is contained in:
parent
908f0b6bb9
commit
346670825c
2 changed files with 189 additions and 14 deletions
148
apps/obsidian-connector/src/api.ts
Normal file
148
apps/obsidian-connector/src/api.ts
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
import { Notice, requestUrl } from "obsidian"
|
||||
import type { SupermemorySettings } from "./types"
|
||||
|
||||
export interface PushResponse {
|
||||
accepted: boolean
|
||||
deletedCount: number
|
||||
queuedCount: number
|
||||
}
|
||||
|
||||
export interface ConnectionResponse {
|
||||
id: string
|
||||
}
|
||||
|
||||
export interface NotePayload {
|
||||
path: string
|
||||
content: string
|
||||
title?: string
|
||||
mtime?: number
|
||||
frontmatter?: Record<string, unknown>
|
||||
}
|
||||
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
let _settings: SupermemorySettings | null = null
|
||||
|
||||
export function configure(settings: SupermemorySettings) {
|
||||
_settings = settings
|
||||
}
|
||||
|
||||
function getBaseUrl(): string {
|
||||
if (!_settings) throw new Error("API not configured")
|
||||
return _settings.apiBaseUrl.replace(/\/+$/, "")
|
||||
}
|
||||
|
||||
function getApiKey(): string {
|
||||
if (!_settings?.apiKey) throw new Error("API key not set")
|
||||
return _settings.apiKey
|
||||
}
|
||||
|
||||
async function makeAuthenticatedRequest<T>(
|
||||
endpoint: string,
|
||||
options: { method?: string; body?: unknown } = {},
|
||||
): Promise<T> {
|
||||
const apiKey = getApiKey()
|
||||
const url = `${getBaseUrl()}${endpoint}`
|
||||
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url,
|
||||
method: options.method ?? "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: options.body ? JSON.stringify(options.body) : undefined,
|
||||
})
|
||||
|
||||
if (response.status === 401) {
|
||||
throw new AuthenticationError(
|
||||
"Invalid API key. Check your key in plugin settings.",
|
||||
)
|
||||
}
|
||||
|
||||
if (response.status === 429) {
|
||||
throw new SupermemoryAPIError("Rate limited. Try again in a moment.", 429)
|
||||
}
|
||||
|
||||
if (response.status >= 400) {
|
||||
let errorMessage = `API request failed: ${response.status}`
|
||||
try {
|
||||
const errorBody = response.json as { error?: string }
|
||||
if (errorBody.error) errorMessage = errorBody.error
|
||||
} catch {}
|
||||
throw new SupermemoryAPIError(errorMessage, response.status)
|
||||
}
|
||||
|
||||
return response.json as T
|
||||
} catch (err) {
|
||||
if (err instanceof AuthenticationError) {
|
||||
new Notice("Supermemory: invalid API key. Check plugin settings.")
|
||||
throw err
|
||||
}
|
||||
if (err instanceof SupermemoryAPIError) {
|
||||
if (err.status === 429) {
|
||||
new Notice("Supermemory: rate limited. Try again in a moment.")
|
||||
}
|
||||
throw err
|
||||
}
|
||||
throw new SupermemoryAPIError(
|
||||
`Network error: ${err instanceof Error ? err.message : "Unknown error"}`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export async function createConnection(
|
||||
vaultId: string,
|
||||
vaultName: string,
|
||||
containerTag: string,
|
||||
): Promise<ConnectionResponse> {
|
||||
return makeAuthenticatedRequest<ConnectionResponse>(
|
||||
"/v3/connections/obsidian",
|
||||
{
|
||||
method: "POST",
|
||||
body: { metadata: { vaultId, vaultName }, containerTag },
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export async function pushNotes(
|
||||
connectionId: string,
|
||||
notes: NotePayload[],
|
||||
): Promise<PushResponse> {
|
||||
return makeAuthenticatedRequest<PushResponse>(
|
||||
"/v3/connections/obsidian/push",
|
||||
{
|
||||
method: "POST",
|
||||
body: { connectionId, notes },
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export async function pushDeletions(
|
||||
connectionId: string,
|
||||
deletions: Array<{ path: string }>,
|
||||
): Promise<PushResponse> {
|
||||
return makeAuthenticatedRequest<PushResponse>(
|
||||
"/v3/connections/obsidian/push",
|
||||
{
|
||||
method: "POST",
|
||||
body: { connectionId, deletions },
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import { Notice, Plugin } from "obsidian"
|
||||
import { configure, createConnection } from "./api"
|
||||
import { SupermemorySettingTab } from "./settings"
|
||||
import type { SupermemorySettings } from "./types"
|
||||
|
||||
|
|
@ -17,32 +18,57 @@ export default class SupermemoryPlugin extends Plugin {
|
|||
|
||||
async onload() {
|
||||
await this.loadSettings()
|
||||
configure(this.settings)
|
||||
|
||||
this.addSettingTab(new SupermemorySettingTab(this.app, this))
|
||||
|
||||
this.addRibbonIcon("cloud-upload", "Sync vault to Supermemory", () => {
|
||||
if (!this.settings.apiKey) {
|
||||
new Notice("Set your Supermemory API key in plugin settings first.")
|
||||
return
|
||||
}
|
||||
new Notice("Supermemory sync starting...")
|
||||
this.syncVault()
|
||||
})
|
||||
|
||||
this.addCommand({
|
||||
id: "sync-vault",
|
||||
name: "Sync vault now",
|
||||
callback: () => {
|
||||
if (!this.settings.apiKey) {
|
||||
new Notice(
|
||||
"Set your Supermemory API key in plugin settings first.",
|
||||
)
|
||||
return
|
||||
}
|
||||
new Notice("Supermemory sync starting...")
|
||||
},
|
||||
callback: () => this.syncVault(),
|
||||
})
|
||||
}
|
||||
|
||||
async ensureConnection(): Promise<string | null> {
|
||||
if (!this.settings.apiKey) {
|
||||
new Notice("Set your Supermemory API key in plugin settings first.")
|
||||
return null
|
||||
}
|
||||
|
||||
if (this.settings.connectionId) {
|
||||
return this.settings.connectionId
|
||||
}
|
||||
|
||||
const vaultId = (this.app as unknown as { appId: string }).appId
|
||||
const vaultName = this.settings.vaultName || this.app.vault.getName()
|
||||
|
||||
try {
|
||||
const result = await createConnection(
|
||||
vaultId,
|
||||
vaultName,
|
||||
this.settings.containerTag,
|
||||
)
|
||||
this.settings.connectionId = result.id
|
||||
await this.saveSettings()
|
||||
return result.id
|
||||
} catch (e) {
|
||||
new Notice(
|
||||
`Supermemory: failed to connect — ${e instanceof Error ? e.message : "unknown error"}`,
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
private async syncVault() {
|
||||
const connectionId = await this.ensureConnection()
|
||||
if (!connectionId) return
|
||||
new Notice("Supermemory: sync starting...")
|
||||
}
|
||||
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign(
|
||||
{},
|
||||
|
|
@ -53,5 +79,6 @@ export default class SupermemoryPlugin extends Plugin {
|
|||
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings)
|
||||
configure(this.settings)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue