Skip to content
File

Blob: src/worker/routes/page-context.ts

typescript48 lines
1import { Hono } from "hono";
2import { eq } from "drizzle-orm";
3 
4import type { AppContext } from "@/worker/app-context";
5import { workspaces } from "@/worker/db/d1/schema";
6import { requireAuth } from "@/worker/middleware/auth";
7import { rateLimit } from "@/worker/middleware/rate-limit";
8import { resolvePageAccessLevels, resolvePrincipal, toResolvedViewerContext } from "@/worker/lib/permissions";
9import { getPage } from "@/worker/lib/page-access";
10 
11const pageContextRouter = new Hono<AppContext>();
12 
13// GET /pages/:id/context - Bootstrap canonical page-route workspace identity
14pageContextRouter.get("/pages/:id/context", requireAuth, rateLimit("RL_API"), async (c) => {
15 const pageId = c.req.param("id");
16 const user = c.get("user")!;
17 const db = c.get("db");
18 
19 const page = await getPage(db, pageId);
20 if (!page) {
21 return c.json({ error: "not_found", message: "Page not found" }, 404);
22 }
23 
24 const workspace = await db.select().from(workspaces).where(eq(workspaces.id, page.workspace_id)).get();
25 if (!workspace) {
26 return c.json({ error: "not_found", message: "Workspace not found" }, 404);
27 }
28 
29 const resolved = await resolvePrincipal(db, user, workspace.id, { surface: "canonical" });
30 if (!resolved) {
31 return c.json({ error: "unauthorized", message: "Authentication required" }, 401);
32 }
33 
34 const accessLevels = await resolvePageAccessLevels(db, resolved.principal, [pageId], workspace.id);
35 const level = accessLevels.get(pageId) ?? "none";
36 
37 if (level === "none") {
38 return c.json({ error: "forbidden", message: "You do not have access to this page" }, 403);
39 }
40 
41 return c.json({
42 workspace,
43 viewer: toResolvedViewerContext(resolved, workspace.slug, "canonical"),
44 });
45});
46 
47export { pageContextRouter };