diff --git a/apps/mana/apps/web/src/lib/modules/kontext/api.ts b/apps/mana/apps/web/src/lib/modules/kontext/api.ts new file mode 100644 index 000000000..6af5b8dba --- /dev/null +++ b/apps/mana/apps/web/src/lib/modules/kontext/api.ts @@ -0,0 +1,44 @@ +/** + * Kontext API client — talks to apps/api `POST /api/v1/context/import-url`. + * + * The server route lives under /context for historical reasons (shared + * crawler + LLM wrapper). Only the kontext singleton consumes it. + */ + +import { authStore } from '$lib/stores/auth.svelte'; +import { getManaApiUrl } from '$lib/api/config'; + +export type CrawlMode = 'single' | 'deep'; + +export interface ImportInput { + url: string; + mode: CrawlMode; + summarize: boolean; +} + +export interface ImportResponse { + title: string; + content: string; + sourceUrl: string; + crawlMode: CrawlMode; + crawledAt: string; + pageCount: number; +} + +export async function crawlUrlViaApi(input: ImportInput): Promise { + const token = await authStore.getValidToken(); + if (!token) throw new Error('not authenticated'); + const res = await fetch(`${getManaApiUrl()}/api/v1/context/import-url`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${token}`, + }, + body: JSON.stringify(input), + }); + if (!res.ok) { + const body = (await res.json().catch(() => ({}))) as { error?: string }; + throw new Error(body.error || `import failed (${res.status})`); + } + return (await res.json()) as ImportResponse; +} diff --git a/apps/mana/apps/web/src/lib/modules/kontext/stores/kontext.svelte.ts b/apps/mana/apps/web/src/lib/modules/kontext/stores/kontext.svelte.ts index 791506e56..712b790c1 100644 --- a/apps/mana/apps/web/src/lib/modules/kontext/stores/kontext.svelte.ts +++ b/apps/mana/apps/web/src/lib/modules/kontext/stores/kontext.svelte.ts @@ -6,7 +6,7 @@ */ import { kontextDocTable } from '../collections'; -import { encryptRecord } from '$lib/data/crypto'; +import { encryptRecord, decryptRecords } from '$lib/data/crypto'; import { KONTEXT_SINGLETON_ID, type LocalKontextDoc } from '../types'; export const kontextStore = { @@ -30,4 +30,13 @@ export const kontextStore = { await encryptRecord('kontextDoc', diff); await kontextDocTable.update(KONTEXT_SINGLETON_ID, diff); }, + + async appendContent(chunk: string): Promise { + await this.ensureDoc(); + const row = await kontextDocTable.get(KONTEXT_SINGLETON_ID); + const [decrypted] = row ? await decryptRecords('kontextDoc', [row]) : []; + const current = decrypted?.content ?? ''; + const separator = current.trim() ? '\n\n---\n\n' : ''; + await this.setContent(`${current}${separator}${chunk}`); + }, };