/** * Client for maskinrommet intentions API. * Uses the Vite dev proxy (/api → api.sidelinja.org) in development. * In production, set VITE_API_URL to the maskinrommet URL. */ const BASE_URL = import.meta.env.VITE_API_URL ?? '/api'; export interface CreateNodeRequest { node_kind?: string; title?: string; content?: string; visibility?: string; metadata?: Record; /** Kontekst-node (kommunikasjonsnode). Gir automatisk belongs_to-edge. */ context_id?: string; } export interface CreateNodeResponse { node_id: string; /** Edge-ID for automatisk belongs_to-edge (kun ved context_id). */ belongs_to_edge_id?: string; } export interface CreateEdgeRequest { source_id: string; target_id: string; edge_type: string; metadata?: Record; system?: boolean; } export interface CreateEdgeResponse { edge_id: string; } async function post(accessToken: string, path: string, data: unknown): Promise { const res = await fetch(`${BASE_URL}${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}` }, body: JSON.stringify(data) }); if (!res.ok) { const body = await res.text(); throw new Error(`${path} failed (${res.status}): ${body}`); } return res.json(); } export function createNode( accessToken: string, data: CreateNodeRequest ): Promise { return post(accessToken, '/intentions/create_node', data); } export function createEdge( accessToken: string, data: CreateEdgeRequest ): Promise { return post(accessToken, '/intentions/create_edge', data); } export interface CreateCommunicationRequest { title?: string; participants?: string[]; visibility?: string; metadata?: Record; } export interface CreateCommunicationResponse { node_id: string; edge_ids: string[]; } export function createCommunication( accessToken: string, data: CreateCommunicationRequest ): Promise { return post(accessToken, '/intentions/create_communication', data); } export interface UploadMediaRequest { file: File; source_id?: string; visibility?: string; title?: string; } export interface UploadMediaResponse { media_node_id: string; cas_hash: string; size_bytes: number; already_existed: boolean; has_media_edge_id?: string; } export async function uploadMedia( accessToken: string, data: UploadMediaRequest ): Promise { const form = new FormData(); form.append('file', data.file); if (data.source_id) form.append('source_id', data.source_id); if (data.visibility) form.append('visibility', data.visibility); if (data.title) form.append('title', data.title); const res = await fetch(`${BASE_URL}/intentions/upload_media`, { method: 'POST', headers: { Authorization: `Bearer ${accessToken}` }, body: form }); if (!res.ok) { const body = await res.text(); throw new Error(`upload_media failed (${res.status}): ${body}`); } return res.json(); } /** Build the CAS URL for a given hash. */ export function casUrl(hash: string): string { return `${BASE_URL}/cas/${hash}`; }