Self-hosted knowledge management for SMEs: a split-screen Markdown editor whose sections an LLM refines while you write, and RAG question answering over the documents that result. FastAPI + Postgres/pgvector on the back, SvelteKit on the front, everything OpenAI-compatible and self-hostable. Squashed into a single commit; the development history stays local. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CA43ZJda8Rbp2hKXNy8f6b
43 lines
1.7 KiB
TypeScript
43 lines
1.7 KiB
TypeScript
import { sequence } from '@sveltejs/kit/hooks';
|
|
import type { Handle } from '@sveltejs/kit';
|
|
import { apiFetch } from '$lib/server/api';
|
|
import { rememberRequestLocale } from '$lib/i18n/strategy.server';
|
|
import { paraglideMiddleware } from '$lib/paraglide/server';
|
|
import { getTextDirection } from '$lib/paraglide/runtime';
|
|
|
|
// The only auth logic in the frontend: forward the session cookie to the
|
|
// backend and expose the result as locals.user.
|
|
const auth: Handle = async ({ event, resolve }) => {
|
|
event.locals.user = null;
|
|
if (event.cookies.get('pablan_session')) {
|
|
try {
|
|
const response = await apiFetch(event.fetch, event.cookies, '/api/auth/me');
|
|
if (response.ok) {
|
|
event.locals.user = await response.json();
|
|
}
|
|
} catch {
|
|
// Backend unreachable: treat as logged out instead of failing the page.
|
|
event.locals.user = null;
|
|
}
|
|
}
|
|
// Hand the account's language to the custom locale strategy, which only
|
|
// sees the request. Runs before the i18n handle, hence the order below.
|
|
rememberRequestLocale(event.request, event.locals.user?.locale ?? null);
|
|
return resolve(event);
|
|
};
|
|
|
|
// Resolves the locale through the configured strategy chain and stamps the
|
|
// result into the document, so the very first server-rendered byte already
|
|
// carries the right language.
|
|
const i18n: Handle = ({ event, resolve }) =>
|
|
paraglideMiddleware(event.request, ({ request: localizedRequest, locale }) => {
|
|
event.request = localizedRequest;
|
|
return resolve(event, {
|
|
transformPageChunk: ({ html }) =>
|
|
html.replace('%lang%', locale).replace('%dir%', getTextDirection(locale))
|
|
});
|
|
});
|
|
|
|
// auth first: it is what tells the locale strategy which user is asking.
|
|
export const handle: Handle = sequence(auth, i18n);
|