/** * Snapshot endpoint — exports a portable database snapshot for preview mode. * * Security: * - Authenticated users: requires content:read + schema:read permissions * - Builds and previews: the frontend service account's API token (Bearer), same permissions * - Excludes auth/user/session/token tables */ import type { User } from "@premium-cms/auth"; import type { APIRoute } from "astro"; import { requirePerm } from "#api/authorize.js"; import { apiError, apiSuccess, handleError } from "#api/error.js"; import { generateSnapshot } from "#api/handlers/snapshot.js"; import { getPublicOrigin } from "#api/public-url.js"; import { resolveSessionUser } from "../../session-user.js"; export const prerender = false; export const GET: APIRoute = async ({ request, locals, url, session }) => { const { emdash } = locals; // Auth middleware resolves sessions and Bearer tokens; the manual session // resolution below only covers callers the middleware left unresolved. let user: User | undefined = (locals as { user?: User }).user; if (!user && session && emdash?.db) { try { const { createKyselyAdapter } = await import("@premium-cms/auth/adapters/kysely"); const sessionUser = await resolveSessionUser(session); if (sessionUser?.id) { const adapter = createKyselyAdapter(emdash.db); const resolved = await adapter.getUserById(sessionUser.id); if (resolved && !resolved.disabled) { user = resolved; } } } catch { // Session resolution failed; the permission checks below answer 401 } } if (!emdash?.db) { return apiError("NOT_CONFIGURED", "EmDash is not initialized", 500); } // A session (an admin) or an API token — the frontend service account's, or anyone's with the grants. const contentDenied = requirePerm(user, "content:read"); if (contentDenied) return contentDenied; const schemaDenied = requirePerm(user, "schema:read"); if (schemaDenied) return schemaDenied; try { const includeDrafts = url.searchParams.get("drafts") === "true"; const snapshot = await generateSnapshot(emdash.db, { includeDrafts, origin: getPublicOrigin(url, emdash.config), }); return apiSuccess(snapshot); } catch (error) { return handleError(error, "Failed to generate snapshot", "SNAPSHOT_ERROR"); } };