import React, { useMemo } from 'react'; import { BookOpenText, ExternalLink, FileText } from 'lucide-react'; import { Link, useParams } from 'react-router-dom'; import Markdown from 'react-markdown'; import type { Components } from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { Footer } from '../components/Footer'; import { defaultMarkdownComponents } from '../utils/markdownComponents'; import { extractTitleFromMarkdown, fallbackTitleFromPath, stripFrontmatter, } from '../utils/markdownHelpers.mjs'; import { isWikiIndexSlug, toWikiLlmsPath, toWikiRoute, } from '../utils/wikiPathHelpers.mjs'; interface WikiDoc { filePath: string; slug: string; title: string; content: string; } const normalizePath = (path: string): string => { const clean = path.replace(/\\/g, '/'); const parts: string[] = []; for (const part of clean.split('/')) { if (!part || part === '.') continue; if (part === '..') { if (parts.length > 0) parts.pop(); continue; } parts.push(part); } return parts.join('/'); }; const dirname = (path: string): string => { const idx = path.lastIndexOf('/'); return idx === -1 ? '' : path.slice(0, idx); }; const resolveFromFile = (currentFilePath: string, targetPath: string): string => { if (!targetPath) return currentFilePath; if (targetPath.startsWith('/')) return normalizePath(targetPath.slice(1)); const baseDir = dirname(currentFilePath); const joined = baseDir ? `${baseDir}/${targetPath}` : targetPath; return normalizePath(joined); }; const splitHash = (href: string): { path: string; hash: string } => { const idx = href.indexOf('#'); if (idx === -1) return { path: href, hash: '' }; return { path: href.slice(0, idx), hash: href.slice(idx) }; }; const toWikiRelativePath = (globPath: string): string => globPath.replace(/^\.\.\/wiki\//, '').replace(/\\/g, '/'); const isExternalHref = (href: string): boolean => /^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(href) || href.startsWith('//'); const ALLOWED_LINK_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']); const ALLOWED_IMAGE_SCHEMES = new Set(['http:', 'https:']); const sanitizeHref = (href: string): string | null => { const trimmed = href.trim(); if (!trimmed) return null; if (trimmed.startsWith('//')) return null; const schemeMatch = trimmed.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:)/); if (!schemeMatch) return trimmed; return ALLOWED_LINK_SCHEMES.has(schemeMatch[1].toLowerCase()) ? trimmed : null; }; const sanitizeImageSrc = (src: string): string | null => { const trimmed = src.trim(); if (!trimmed) return null; if (trimmed.startsWith('//')) return null; const schemeMatch = trimmed.match(/^([a-zA-Z][a-zA-Z0-9+.-]*:)/); if (!schemeMatch) return trimmed; return ALLOWED_IMAGE_SCHEMES.has(schemeMatch[1].toLowerCase()) ? trimmed : null; }; const markdownModules = import.meta.glob('../wiki/**/*.md', { eager: true, query: '?raw', import: 'default', }) as Record; const assetModules = import.meta.glob('../wiki/**/*.{png,jpg,jpeg,gif,svg,webp,avif}', { eager: true, import: 'default', }) as Record; const wikiDocs: WikiDoc[] = Object.entries(markdownModules) .map(([globPath, content]) => { const filePath = toWikiRelativePath(globPath); return { filePath, slug: filePath.replace(/\.md$/i, ''), title: extractTitleFromMarkdown(content, filePath), content: stripFrontmatter(content).trim(), }; }) .sort((a, b) => { const aIndex = a.slug.toLowerCase() === 'index'; const bIndex = b.slug.toLowerCase() === 'index'; if (aIndex && !bIndex) return -1; if (!aIndex && bIndex) return 1; const aModule = a.filePath.startsWith('modules/'); const bModule = b.filePath.startsWith('modules/'); if (aModule !== bModule) return aModule ? 1 : -1; return a.title.localeCompare(b.title, 'en', { sensitivity: 'base' }); }); const wikiDocBySlug = new Map( wikiDocs.map((doc) => [doc.slug.toLowerCase(), doc]), ); const wikiDocByFilePath = new Map( wikiDocs.map((doc) => [doc.filePath.toLowerCase(), doc]), ); const wikiAssetByPath = new Map( Object.entries(assetModules).map(([globPath, assetUrl]) => [ toWikiRelativePath(globPath).toLowerCase(), assetUrl, ]), ); const defaultDoc = wikiDocBySlug.get('index') ?? wikiDocs[0] ?? null; const languageLabelByCode: Record = { en: 'English', es: 'Español', ko: '한국어', fr: 'Français', de: 'Deutsch', ja: '日本語', }; const languageIndexByCode = new Map( wikiDocs .map((doc) => { const match = doc.slug.match(/^([^/]+)\/index$/i); if (!match) return null; const code = match[1].toLowerCase(); return [code, doc] as const; }) .filter((entry): entry is readonly [string, WikiDoc] => entry !== null), ); const toGroupName = (filePath: string): string => { if (!filePath.includes('/')) return 'Core'; if (filePath.startsWith('modules/')) return 'Modules'; const [firstSegment] = filePath.split('/'); return fallbackTitleFromPath(firstSegment); }; export const WikiBrowser: React.FC = () => { const params = useParams<{ '*': string }>(); const wildcard = params['*'] ?? ''; const normalizedWildcard = wildcard.replace(/^\/+|\/+$/g, ''); let requested = ''; let decodeFailed = false; try { requested = decodeURIComponent(normalizedWildcard); } catch (error) { decodeFailed = normalizedWildcard.length > 0; console.warn('Failed to decode wiki route segment', { wildcard, error }); requested = ''; } const requestedSlug = requested || 'INDEX'; const requestedSlugLower = requestedSlug.toLowerCase(); const languageIndexFallback = languageIndexByCode.get(requestedSlugLower); const selectedDoc = wikiDocBySlug.get(requestedSlugLower) ?? languageIndexFallback ?? defaultDoc; const notFound = (decodeFailed && normalizedWildcard.length > 0) || (requested.length > 0 && !wikiDocBySlug.has(requestedSlugLower) && !languageIndexFallback); const groupedDocs = useMemo(() => { const map = new Map(); for (const doc of wikiDocs) { const group = toGroupName(doc.filePath); const existing = map.get(group) ?? []; existing.push(doc); map.set(group, existing); } const preferredOrder = ['Core', 'Modules']; return Array.from(map.entries()) .sort(([a], [b]) => { const idxA = preferredOrder.indexOf(a); const idxB = preferredOrder.indexOf(b); if (idxA !== -1 || idxB !== -1) { if (idxA === -1) return 1; if (idxB === -1) return -1; return idxA - idxB; } return a.localeCompare(b, 'en', { sensitivity: 'base' }); }) .map(([name, docs]) => ({ name, docs: docs.sort((a, b) => a.title.localeCompare(b.title, 'en', { sensitivity: 'base' }), ), })); }, []); if (!selectedDoc) { return (

Wiki unavailable

No markdown files were found in the wiki source.

); } const activeSlug = selectedDoc.slug.toLowerCase(); const pageLlmsPath = toWikiLlmsPath(activeSlug); const showWikiLlmsIndexLink = !isWikiIndexSlug(activeSlug); const localizedPrefix = Array.from(languageIndexByCode.keys()).find((code) => activeSlug.startsWith(`${code}/`), ); const currentLanguageCode = localizedPrefix ?? 'en'; const activeBaseSlug = localizedPrefix ? activeSlug.slice(localizedPrefix.length + 1) : activeSlug; const languageOptions = [ { code: 'en', label: languageLabelByCode.en ?? 'English' }, ...Array.from(languageIndexByCode.keys()) .sort((a, b) => a.localeCompare(b, 'en', { sensitivity: 'base' })) .map((code) => ({ code, label: languageLabelByCode[code] ?? code.toUpperCase(), })), ].map((option) => { const targetSlug = option.code === 'en' ? activeBaseSlug : `${option.code}/${activeBaseSlug}`; const fallbackSlug = option.code === 'en' ? 'index' : `${option.code}/index`; const resolvedSlug = wikiDocBySlug.has(targetSlug) ? targetSlug : fallbackSlug; const translated = wikiDocBySlug.has(targetSlug); return { ...option, route: toWikiRoute(resolvedSlug), translated, }; }); const resolveWikiRouteFromHref = (href: string): string | null => { if (!href || isExternalHref(href) || href.startsWith('mailto:') || href.startsWith('tel:')) { return null; } const { path, hash } = splitHash(href); if (!path || !path.toLowerCase().endsWith('.md')) return null; const resolvedFilePath = resolveFromFile(selectedDoc.filePath, path).toLowerCase(); const targetDoc = wikiDocByFilePath.get(resolvedFilePath); if (!targetDoc) return null; return `${toWikiRoute(targetDoc.slug)}${hash}`; }; const resolveAssetUrl = (srcOrHref: string): string | null => { if (!srcOrHref || isExternalHref(srcOrHref) || srcOrHref.startsWith('/')) return null; const { path } = splitHash(srcOrHref); if (!path) return null; const resolvedAssetPath = resolveFromFile(selectedDoc.filePath, path).toLowerCase(); return wikiAssetByPath.get(resolvedAssetPath) ?? null; }; const wikiMarkdownComponents: Components = { ...defaultMarkdownComponents, a: ({ href, children }) => { if (!href) return {children}; const wikiRoute = resolveWikiRouteFromHref(href); if (wikiRoute) { return ( {children} ); } const assetHref = resolveAssetUrl(href); const finalHref = assetHref ?? href; const safeHref = sanitizeHref(finalHref); if (!safeHref) { return {children}; } const external = isExternalHref(safeHref); return ( {children} ); }, img: ({ src, alt }) => { const resolvedSrc = src ? resolveAssetUrl(src) : null; const finalSrc = resolvedSrc ?? (src ? sanitizeImageSrc(src) : null); if (!finalSrc) { return [image blocked]; } return ( {alt ); }, }; return (

Wiki

Full repository wiki rendered from markdown in wiki/. This is the same source synced to GitHub Wiki.

Language: {languageOptions.map((option) => { const isActiveLanguage = option.code === currentLanguageCode; return isActiveLanguage ? ( {option.label} ) : ( {option.label} {option.translated ? ( · translated ) : ( · index fallback )} ); })}
{notFound && (
Wiki page not found for {requested}. Showing {selectedDoc.title} instead.
)} {selectedDoc.content}
); };