File
Blob: src/shared/entitlements/page-ai.ts
| 1 | import { |
| 2 | isWorkspaceWriterRole, |
| 3 | type EntitlementSurface, |
| 4 | type PageAccessLevel, |
| 5 | type ResolvedWorkspaceRole, |
| 6 | } from "@/shared/entitlements/common"; |
| 7 | |
| 8 | export interface PageAiEntitlements { |
| 9 | useAiRewrite: boolean; |
| 10 | useAiGenerate: boolean; |
| 11 | summarizePage: boolean; |
| 12 | askPage: boolean; |
| 13 | } |
| 14 | |
| 15 | const ALL_DENY: PageAiEntitlements = { |
| 16 | useAiRewrite: false, |
| 17 | useAiGenerate: false, |
| 18 | summarizePage: false, |
| 19 | askPage: false, |
| 20 | }; |
| 21 | |
| 22 | const CANONICAL_WRITER_TABLE: Record<PageAccessLevel, PageAiEntitlements> = { |
| 23 | none: ALL_DENY, |
| 24 | view: { |
| 25 | useAiRewrite: false, |
| 26 | useAiGenerate: false, |
| 27 | summarizePage: true, |
| 28 | askPage: true, |
| 29 | }, |
| 30 | edit: { |
| 31 | useAiRewrite: true, |
| 32 | useAiGenerate: true, |
| 33 | summarizePage: true, |
| 34 | askPage: true, |
| 35 | }, |
| 36 | }; |
| 37 | |
| 38 | // AI is member-only by product policy. The role axis denies guests and |
| 39 | // non-members on the canonical surface even if they hold a page_share grant; |
| 40 | // the shared surface (`/s/:token` / `?share=`) is link-scoped and denies all |
| 41 | // AI regardless of role. |
| 42 | export function getPageAiEntitlements( |
| 43 | surface: EntitlementSurface, |
| 44 | pageAccess: PageAccessLevel, |
| 45 | workspaceRole: ResolvedWorkspaceRole, |
| 46 | ): PageAiEntitlements { |
| 47 | if (surface === "shared") return ALL_DENY; |
| 48 | if (!isWorkspaceWriterRole(workspaceRole)) return ALL_DENY; |
| 49 | return CANONICAL_WRITER_TABLE[pageAccess]; |
| 50 | } |