const OUTLINE_API_BASE = 'https://wiki.ghostguild.org/api' /** * Strip HTML tags and truncate to 200 characters at a word boundary. * If the stripped text is <= 200 chars, returns it as-is. */ export function extractSummary(text) { if (!text) return '' const stripped = text.replace(/<[^>]*>/g, '').trim() if (stripped.length <= 200) return stripped const truncated = stripped.slice(0, 200) const lastSpace = truncated.lastIndexOf(' ') // If no space found at all, return the full 200 chars (single long word) if (lastSpace <= 0) return truncated return truncated.slice(0, lastSpace) } /** * Fetch all documents from Outline wiki, paginating through all pages. * Throws on any page failure — caller is responsible for abort logic. */ export async function fetchAllDocuments() { const config = useRuntimeConfig() const apiKey = config.outlineApiKey if (!apiKey) { throw createError({ statusCode: 500, statusMessage: 'Outline API key not configured' }) } const documents = [] let path = '/documents.list' while (path) { const response = await fetch(`${OUTLINE_API_BASE}${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` }, body: JSON.stringify({ limit: 25 }) }) if (!response.ok) { const errorText = await response.text() console.error(`[outline] POST ${path} ${response.status} ${errorText}`) throw createError({ statusCode: response.status, statusMessage: 'Outline API error' }) } const data = await response.json() documents.push(...(data.data || [])) path = data.pagination?.nextPath || null } return documents }