/** * Knowledge API Client * Handles knowledge entry-related API requests */ import type { KnowledgeEntryWithTags, KnowledgeTag, KnowledgeEntryVersionWithAuthor, PaginatedResponse, } from "@mosaic/shared"; import { EntryStatus, Visibility } from "@mosaic/shared"; import { apiGet, apiPost, apiPatch, apiDelete, type ApiResponse } from "./client"; export interface EntryFilters { status?: EntryStatus; visibility?: Visibility; tag?: string; tags?: string[]; page?: number; limit?: number; search?: string; sortBy?: "updatedAt" | "createdAt" | "title"; sortOrder?: "asc" | "desc"; } export interface EntriesResponse { data: KnowledgeEntryWithTags[]; meta?: { total?: number; page?: number; limit?: number; }; } export interface CreateEntryData { title: string; content: string; summary?: string; status?: EntryStatus; visibility?: Visibility; tags?: string[]; } export interface UpdateEntryData { title?: string; content?: string; summary?: string; status?: EntryStatus; visibility?: Visibility; tags?: string[]; changeNote?: string; } export interface RestoreVersionData { changeNote?: string; } /** * Fetch knowledge entries with optional filters */ export async function fetchEntries(filters?: EntryFilters): Promise { const params = new URLSearchParams(); if (filters?.status) { params.append("status", filters.status); } if (filters?.visibility) { params.append("visibility", filters.visibility); } if (filters?.tag) { params.append("tag", filters.tag); } if (filters?.tags && filters.tags.length > 0) { filters.tags.forEach((tag) => params.append("tags", tag)); } if (filters?.page) { params.append("page", filters.page.toString()); } if (filters?.limit) { params.append("limit", filters.limit.toString()); } if (filters?.search) { params.append("search", filters.search); } if (filters?.sortBy) { params.append("sortBy", filters.sortBy); } if (filters?.sortOrder) { params.append("sortOrder", filters.sortOrder); } const queryString = params.toString(); const endpoint = queryString ? `/api/knowledge/entries?${queryString}` : "/api/knowledge/entries"; const response = await apiGet(endpoint); return response; } /** * Fetch a single knowledge entry by slug */ export async function fetchEntry(slug: string): Promise { return apiGet(`/api/knowledge/entries/${slug}`); } /** * Create a new knowledge entry */ export async function createEntry(data: CreateEntryData): Promise { return apiPost("/api/knowledge/entries", data); } /** * Update an existing knowledge entry */ export async function updateEntry( slug: string, data: UpdateEntryData ): Promise { return apiPatch(`/api/knowledge/entries/${slug}`, data); } /** * Delete (archive) a knowledge entry */ export async function deleteEntry(slug: string): Promise { await apiDelete(`/api/knowledge/entries/${slug}`); } /** * Fetch all knowledge tags */ export async function fetchTags(): Promise { const response = await apiGet>("/api/knowledge/tags"); return response.data; } /** * Fetch version history for an entry */ export async function fetchVersions( slug: string, page: number = 1, limit: number = 20 ): Promise> { const params = new URLSearchParams(); params.append("page", page.toString()); params.append("limit", limit.toString()); return apiGet>( `/api/knowledge/entries/${slug}/versions?${params.toString()}` ); } /** * Fetch a specific version of an entry */ export async function fetchVersion( slug: string, version: number ): Promise { return apiGet( `/api/knowledge/entries/${slug}/versions/${version}` ); } /** * Restore a previous version of an entry */ export async function restoreVersion( slug: string, version: number, data?: RestoreVersionData ): Promise { return apiPost( `/api/knowledge/entries/${slug}/restore/${version}`, data || {} ); } /** * Fetch backlinks for an entry (entries that link to this entry) */ export async function fetchBacklinks(slug: string): Promise<{ entry: { id: string; slug: string; title: string }; backlinks: Array<{ id: string; sourceId: string; targetId: string; linkText: string; displayText: string; positionStart: number; positionEnd: number; resolved: boolean; context: string | null; createdAt: Date; source: { id: string; title: string; slug: string; summary?: string | null; }; }>; count: number; }> { return apiGet<{ entry: { id: string; slug: string; title: string }; backlinks: Array<{ id: string; sourceId: string; targetId: string; linkText: string; displayText: string; positionStart: number; positionEnd: number; resolved: boolean; context: string | null; createdAt: Date; source: { id: string; title: string; slug: string; summary?: string | null; }; }>; count: number; }>(`/api/knowledge/entries/${slug}/backlinks`); } /** * Fetch knowledge base statistics */ export async function fetchKnowledgeStats(): Promise<{ overview: { totalEntries: number; totalTags: number; totalLinks: number; publishedEntries: number; draftEntries: number; archivedEntries: number; }; mostConnected: Array<{ id: string; slug: string; title: string; incomingLinks: number; outgoingLinks: number; totalConnections: number; }>; recentActivity: Array<{ id: string; slug: string; title: string; updatedAt: string; status: string; }>; tagDistribution: Array<{ id: string; name: string; slug: string; color: string | null; entryCount: number; }>; }> { return apiGet(`/api/knowledge/stats`); } /** * Fetch entry graph (network of connected entries) */ export async function fetchEntryGraph( slug: string, depth: number = 1 ): Promise<{ centerNode: { id: string; slug: string; title: string; summary: string | null; tags: Array<{ id: string; name: string; slug: string; color: string | null; }>; depth: number; }; nodes: Array<{ id: string; slug: string; title: string; summary: string | null; tags: Array<{ id: string; name: string; slug: string; color: string | null; }>; depth: number; }>; edges: Array<{ id: string; sourceId: string; targetId: string; linkText: string; }>; stats: { totalNodes: number; totalEdges: number; maxDepth: number; }; }> { const params = new URLSearchParams(); params.append("depth", depth.toString()); return apiGet(`/api/knowledge/entries/${slug}/graph?${params.toString()}`); } /** * Mock entries for development (until backend endpoints are ready) */ export const mockEntries: KnowledgeEntryWithTags[] = [ { id: "entry-1", workspaceId: "workspace-1", slug: "getting-started", title: "Getting Started with Mosaic Stack", content: "# Getting Started\n\nWelcome to Mosaic Stack...", contentHtml: "

Getting Started

Welcome to Mosaic Stack...

", summary: "A comprehensive guide to getting started with the Mosaic Stack platform.", status: EntryStatus.PUBLISHED, visibility: Visibility.PUBLIC, createdBy: "user-1", updatedBy: "user-1", createdAt: new Date("2026-01-20"), updatedAt: new Date("2026-01-28"), tags: [ { id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-2", workspaceId: "workspace-1", name: "Onboarding", slug: "onboarding", color: "#10B981", createdAt: new Date(), updatedAt: new Date(), }, ], }, { id: "entry-2", workspaceId: "workspace-1", slug: "architecture-overview", title: "Architecture Overview", content: "# Architecture\n\nThe Mosaic Stack architecture...", contentHtml: "

Architecture

The Mosaic Stack architecture...

", summary: "Overview of the system architecture and design patterns used in Mosaic Stack.", status: EntryStatus.PUBLISHED, visibility: Visibility.WORKSPACE, createdBy: "user-1", updatedBy: "user-1", createdAt: new Date("2026-01-15"), updatedAt: new Date("2026-01-27"), tags: [ { id: "tag-3", workspaceId: "workspace-1", name: "Architecture", slug: "architecture", color: "#8B5CF6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date(), }, ], }, { id: "entry-3", workspaceId: "workspace-1", slug: "api-documentation-draft", title: "API Documentation (Draft)", content: "# API Docs\n\nWork in progress...", contentHtml: "

API Docs

Work in progress...

", summary: "Comprehensive API documentation for developers.", status: EntryStatus.DRAFT, visibility: Visibility.PRIVATE, createdBy: "user-1", updatedBy: "user-1", createdAt: new Date("2026-01-29"), updatedAt: new Date("2026-01-29"), tags: [ { id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-5", workspaceId: "workspace-1", name: "API", slug: "api", color: "#EF4444", createdAt: new Date(), updatedAt: new Date(), }, ], }, { id: "entry-4", workspaceId: "workspace-1", slug: "deployment-guide", title: "Deployment Guide", content: "# Deployment\n\nHow to deploy Mosaic Stack...", contentHtml: "

Deployment

How to deploy Mosaic Stack...

", summary: "Step-by-step guide for deploying Mosaic Stack to production.", status: EntryStatus.PUBLISHED, visibility: Visibility.WORKSPACE, createdBy: "user-1", updatedBy: "user-1", createdAt: new Date("2026-01-18"), updatedAt: new Date("2026-01-25"), tags: [ { id: "tag-6", workspaceId: "workspace-1", name: "DevOps", slug: "devops", color: "#14B8A6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date(), }, ], }, { id: "entry-5", workspaceId: "workspace-1", slug: "old-meeting-notes", title: "Q4 2025 Meeting Notes", content: "# Meeting Notes\n\nOld archived notes...", contentHtml: "

Meeting Notes

Old archived notes...

", summary: "Meeting notes from Q4 2025 - archived for reference.", status: EntryStatus.ARCHIVED, visibility: Visibility.PRIVATE, createdBy: "user-1", updatedBy: "user-1", createdAt: new Date("2025-12-15"), updatedAt: new Date("2026-01-05"), tags: [ { id: "tag-7", workspaceId: "workspace-1", name: "Meetings", slug: "meetings", color: "#6B7280", createdAt: new Date(), updatedAt: new Date(), }, ], }, ]; export const mockTags: KnowledgeTag[] = [ { id: "tag-1", workspaceId: "workspace-1", name: "Tutorial", slug: "tutorial", color: "#3B82F6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-2", workspaceId: "workspace-1", name: "Onboarding", slug: "onboarding", color: "#10B981", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-3", workspaceId: "workspace-1", name: "Architecture", slug: "architecture", color: "#8B5CF6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-4", workspaceId: "workspace-1", name: "Technical", slug: "technical", color: "#F59E0B", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-5", workspaceId: "workspace-1", name: "API", slug: "api", color: "#EF4444", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-6", workspaceId: "workspace-1", name: "DevOps", slug: "devops", color: "#14B8A6", createdAt: new Date(), updatedAt: new Date(), }, { id: "tag-7", workspaceId: "workspace-1", name: "Meetings", slug: "meetings", color: "#6B7280", createdAt: new Date(), updatedAt: new Date(), }, ];