@structcms/api 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/storage/supabase-adapter.ts","../src/utils/sanitize.ts","../src/utils/slug.ts","../src/storage/handlers.ts","../src/media/resolve.ts","../src/delivery/handlers.ts","../src/media/types.ts","../src/media/supabase-adapter.ts","../src/media/handlers.ts","../src/supabase/factory.ts","../src/auth/supabase-adapter.ts","../src/auth/handlers.ts","../src/auth/middleware.ts","../src/export/handlers.ts"],"sourcesContent":["export type {\n Page,\n PageSection,\n PageFilter,\n CreatePageInput,\n UpdatePageInput,\n Navigation,\n NavigationItem,\n CreateNavigationInput,\n UpdateNavigationInput,\n StorageAdapter,\n SupabaseStorageAdapterConfig,\n} from './storage';\n\nexport {\n SupabaseStorageAdapter,\n createStorageAdapter,\n StorageError,\n handleCreatePage,\n handleUpdatePage,\n handleDeletePage,\n handleCreateNavigation,\n handleUpdateNavigation,\n handleDeleteNavigation,\n StorageValidationError,\n} from './storage';\n\nexport { generateSlug, ensureUniqueSlug } from './utils';\n\nexport type {\n PageResponse,\n NavigationResponse,\n ListPagesOptions,\n} from './delivery';\n\nexport {\n handleListPages,\n handleGetPageBySlug,\n handleGetNavigation,\n} from './delivery';\n\nexport type {\n MediaFile,\n MediaAdapter,\n UploadMediaInput,\n MediaFilter,\n AllowedMimeType,\n SupabaseMediaAdapterConfig,\n} from './media';\n\nexport {\n ALLOWED_MIME_TYPES,\n SupabaseMediaAdapter,\n createMediaAdapter,\n MediaError,\n handleUploadMedia,\n handleGetMedia,\n handleListMedia,\n handleDeleteMedia,\n MediaValidationError,\n resolveMediaReferences,\n} from './media';\n\nexport type {\n SupabaseAdapterFactoryStorageConfig,\n SupabaseAdapterFactoryConfig,\n SupabaseAdapters,\n} from './supabase';\n\nexport { createSupabaseAdapters } from './supabase';\n\nexport type {\n PageExportResponse,\n AllPagesExportResponse,\n NavigationExportResponse,\n AllNavigationsExportResponse,\n SiteExportResponse,\n MediaExportEntry,\n} from './export';\n\nexport {\n handleExportPage,\n handleExportAllPages,\n handleExportNavigations,\n handleExportSite,\n} from './export';\n\nexport type {\n AuthUser,\n AuthSession,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n OAuthResponse,\n VerifySessionInput,\n AuthAdapter,\n SupabaseAuthAdapterConfig,\n AuthMiddlewareConfig,\n AuthenticatedRequest,\n} from './auth';\n\nexport {\n SupabaseAuthAdapter,\n createAuthAdapter,\n AuthError,\n handleSignInWithOAuth,\n handleSignInWithPassword,\n handleSignOut,\n handleVerifySession,\n handleRefreshSession,\n handleGetCurrentUser,\n AuthValidationError,\n createAuthMiddleware,\n} from './auth';\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageFilter,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Database row types (snake_case)\n */\ninterface PageRow {\n id: string;\n slug: string;\n page_type: string;\n title: string;\n sections: PageSection[];\n created_at: string;\n updated_at: string;\n}\n\ninterface NavigationRow {\n id: string;\n name: string;\n items: NavigationItem[];\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Maps a database page row to the Page type\n */\nfunction mapPageRowToPage(row: PageRow): Page {\n return {\n id: row.id,\n slug: row.slug,\n pageType: row.page_type,\n title: row.title,\n sections: row.sections,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Maps a database navigation row to the Navigation type\n */\nfunction mapNavigationRowToNavigation(row: NavigationRow): Navigation {\n return {\n id: row.id,\n name: row.name,\n items: row.items,\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Storage adapter error with additional context\n */\nexport class StorageError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'StorageError';\n }\n}\n\n/**\n * Configuration for creating a Supabase storage adapter\n */\nexport interface SupabaseStorageAdapterConfig {\n client: SupabaseClient;\n}\n\n/**\n * Supabase implementation of the StorageAdapter interface\n */\nexport class SupabaseStorageAdapter implements StorageAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseStorageAdapterConfig) {\n this.client = config.client;\n }\n\n async getPage(slug: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('slug', slug).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async getPageById(id: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async createPage(input: CreatePageInput): Promise<Page> {\n const { data, error } = await this.client\n .from('pages')\n .insert({\n slug: input.slug,\n page_type: input.pageType,\n title: input.title,\n sections: input.sections ?? [],\n })\n .select()\n .single();\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async updatePage(input: UpdatePageInput): Promise<Page> {\n const updateData: Record<string, unknown> = {};\n\n if (input.slug !== undefined) {\n updateData.slug = input.slug;\n }\n if (input.pageType !== undefined) {\n updateData.page_type = input.pageType;\n }\n if (input.title !== undefined) {\n updateData.title = input.title;\n }\n if (input.sections !== undefined) {\n updateData.sections = input.sections;\n }\n\n const { data, error } = await this.client\n .from('pages')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Page not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async deletePage(id: string): Promise<void> {\n const { error } = await this.client.from('pages').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listPages(filter?: PageFilter): Promise<Page[]> {\n let query = this.client.from('pages').select('*');\n\n if (filter?.pageType) {\n query = query.eq('page_type', filter.pageType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as PageRow[]).map(mapPageRowToPage);\n }\n\n async getNavigation(name: string): Promise<Navigation | null> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .eq('name', name)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async getNavigationById(id: string): Promise<Navigation | null> {\n const { data, error } = await this.client.from('navigation').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async createNavigation(input: CreateNavigationInput): Promise<Navigation> {\n const { data, error } = await this.client\n .from('navigation')\n .insert({\n name: input.name,\n items: input.items,\n })\n .select()\n .single();\n\n if (error) {\n if (error.code === '23505') {\n throw new StorageError(\n `Navigation with name \"${input.name}\" already exists`,\n 'DUPLICATE_NAME'\n );\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async updateNavigation(input: UpdateNavigationInput): Promise<Navigation> {\n const updateData: Record<string, unknown> = {};\n\n if (input.name !== undefined) {\n updateData.name = input.name;\n }\n if (input.items !== undefined) {\n updateData.items = input.items;\n }\n\n const { data, error } = await this.client\n .from('navigation')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Navigation not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async deleteNavigation(id: string): Promise<void> {\n const { error } = await this.client.from('navigation').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listNavigations(): Promise<Navigation[]> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .order('name', { ascending: true });\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as NavigationRow[]).map(mapNavigationRowToNavigation);\n }\n}\n\n/**\n * Creates a storage adapter using Supabase\n */\nexport function createStorageAdapter(config: SupabaseStorageAdapterConfig): StorageAdapter {\n return new SupabaseStorageAdapter(config);\n}\n","import sanitizeHtml from 'sanitize-html';\nimport type { PageSection } from '../storage/types';\n\n/**\n * Allowed HTML tags for sanitization\n */\nconst ALLOWED_TAGS = [\n 'p',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'a',\n 'strong',\n 'em',\n 'br',\n 'blockquote',\n 'code',\n 'pre',\n 'img',\n];\n\n/**\n * Allowed HTML attributes per tag\n */\nconst ALLOWED_ATTRIBUTES: Record<string, string[]> = {\n a: ['href'],\n img: ['src', 'alt'],\n};\n\n/**\n * Sanitize-html configuration\n */\nconst SANITIZE_OPTIONS: sanitizeHtml.IOptions = {\n allowedTags: ALLOWED_TAGS,\n allowedAttributes: ALLOWED_ATTRIBUTES,\n disallowedTagsMode: 'discard',\n};\n\n/**\n * Sanitize a single string value using the configured allowlist\n */\nexport function sanitizeString(value: string): string {\n return sanitizeHtml(value, SANITIZE_OPTIONS);\n}\n\n/**\n * Recursively sanitize all string values in an unknown data structure\n */\nexport function sanitizeValue(value: unknown): unknown {\n if (typeof value === 'string') {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.map(sanitizeValue);\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = sanitizeValue(val);\n }\n return result;\n }\n\n // number, boolean, null, undefined — pass through\n return value;\n}\n\n/**\n * Sanitize all string values in page sections' data\n * Returns a new array with sanitized sections (does not mutate input)\n */\nexport function sanitizeSectionData(sections: PageSection[]): PageSection[] {\n return sections.map((section) => ({\n ...section,\n data: sanitizeValue(section.data) as Record<string, unknown>,\n }));\n}\n","/**\n * Character replacements for German umlauts and special characters\n */\nconst UMLAUT_MAP: Record<string, string> = {\n ä: 'ae',\n ö: 'oe',\n ü: 'ue',\n Ä: 'Ae',\n Ö: 'Oe',\n Ü: 'Ue',\n ß: 'ss',\n};\n\n/**\n * Generates a URL-safe slug from a title string.\n *\n * @param title - The title to convert to a slug\n * @returns A URL-safe slug\n *\n * @example\n * generateSlug('Hello World') // 'hello-world'\n * generateSlug('Über uns') // 'ueber-uns'\n * generateSlug(' Multiple Spaces ') // 'multiple-spaces'\n */\nexport function generateSlug(title: string): string {\n let slug = title.toLowerCase().trim();\n\n // Replace German umlauts\n for (const [umlaut, replacement] of Object.entries(UMLAUT_MAP)) {\n slug = slug.replace(new RegExp(umlaut, 'g'), replacement.toLowerCase());\n }\n\n // Replace spaces and underscores with hyphens\n slug = slug.replace(/[\\s_]+/g, '-');\n\n // Remove all non-alphanumeric characters except hyphens\n slug = slug.replace(/[^a-z0-9-]/g, '');\n\n // Remove multiple consecutive hyphens\n slug = slug.replace(/-+/g, '-');\n\n // Remove leading and trailing hyphens\n slug = slug.replace(/^-+|-+$/g, '');\n\n return slug;\n}\n\n/**\n * Ensures a slug is unique by appending a numeric suffix if needed.\n *\n * @param slug - The base slug to make unique\n * @param existingSlugs - Array of existing slugs to check against\n * @returns A unique slug\n *\n * @example\n * ensureUniqueSlug('hello', ['hello', 'world']) // 'hello-1'\n * ensureUniqueSlug('hello', ['hello', 'hello-1']) // 'hello-2'\n * ensureUniqueSlug('new', ['hello', 'world']) // 'new'\n */\nexport function ensureUniqueSlug(slug: string, existingSlugs: string[]): string {\n if (!existingSlugs.includes(slug)) {\n return slug;\n }\n\n let counter = 1;\n let uniqueSlug = `${slug}-${counter}`;\n\n while (existingSlugs.includes(uniqueSlug)) {\n counter++;\n uniqueSlug = `${slug}-${counter}`;\n }\n\n return uniqueSlug;\n}\n","import { sanitizeSectionData } from '../utils/sanitize';\nimport { ensureUniqueSlug, generateSlug } from '../utils/slug';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n Page,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Error thrown when storage validation fails\n */\nexport class StorageValidationError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'StorageValidationError';\n }\n}\n\n/**\n * Handler for creating a new page\n * Generates a slug from the title if not provided and ensures uniqueness\n */\nexport async function handleCreatePage(\n adapter: StorageAdapter,\n input: CreatePageInput\n): Promise<Page> {\n if (!input.title.trim()) {\n throw new StorageValidationError('Page title must not be empty', 'EMPTY_TITLE');\n }\n\n const slug = input.slug?.trim() || generateSlug(input.title);\n\n if (!slug) {\n throw new StorageValidationError(\n 'Could not generate a valid slug from the provided title',\n 'INVALID_SLUG'\n );\n }\n\n // Ensure slug uniqueness\n const existingPages = await adapter.listPages();\n const existingSlugs = existingPages.map((p) => p.slug);\n const uniqueSlug = ensureUniqueSlug(slug, existingSlugs);\n\n const sanitizedSections = input.sections ? sanitizeSectionData(input.sections) : undefined;\n\n return adapter.createPage({\n ...input,\n slug: uniqueSlug,\n sections: sanitizedSections,\n });\n}\n\n/**\n * Handler for updating an existing page\n */\nexport async function handleUpdatePage(\n adapter: StorageAdapter,\n input: UpdatePageInput\n): Promise<Page> {\n if (!input.id.trim()) {\n throw new StorageValidationError('Page ID must not be empty', 'EMPTY_ID');\n }\n\n if (input.title !== undefined && !input.title.trim()) {\n throw new StorageValidationError('Page title must not be empty', 'EMPTY_TITLE');\n }\n\n // If slug is being updated, ensure uniqueness\n if (input.slug !== undefined) {\n const slug = input.slug.trim();\n if (!slug) {\n throw new StorageValidationError('Page slug must not be empty', 'EMPTY_SLUG');\n }\n\n const existingPages = await adapter.listPages();\n const existingSlugs = existingPages.filter((p) => p.id !== input.id).map((p) => p.slug);\n\n if (existingSlugs.includes(slug)) {\n throw new StorageValidationError(`Slug \"${slug}\" is already in use`, 'DUPLICATE_SLUG');\n }\n }\n\n const sanitizedInput = input.sections\n ? { ...input, sections: sanitizeSectionData(input.sections) }\n : input;\n\n return adapter.updatePage(sanitizedInput);\n}\n\n/**\n * Handler for deleting a page by ID\n */\nexport async function handleDeletePage(adapter: StorageAdapter, id: string): Promise<void> {\n if (!id.trim()) {\n throw new StorageValidationError('Page ID must not be empty', 'EMPTY_ID');\n }\n\n return adapter.deletePage(id);\n}\n\n/**\n * Handler for creating a new navigation\n * Validates that the name is non-empty and unique\n */\nexport async function handleCreateNavigation(\n adapter: StorageAdapter,\n input: CreateNavigationInput\n): Promise<Navigation> {\n if (!input.name.trim()) {\n throw new StorageValidationError('Navigation name must not be empty', 'EMPTY_NAME');\n }\n\n // Ensure name uniqueness\n const existingNavigations = await adapter.listNavigations();\n const existingNames = existingNavigations.map((n) => n.name);\n\n if (existingNames.includes(input.name.trim())) {\n throw new StorageValidationError(\n `Navigation name \"${input.name.trim()}\" is already in use`,\n 'DUPLICATE_NAME'\n );\n }\n\n return adapter.createNavigation(input);\n}\n\n/**\n * Handler for updating an existing navigation\n */\nexport async function handleUpdateNavigation(\n adapter: StorageAdapter,\n input: UpdateNavigationInput\n): Promise<Navigation> {\n if (!input.id.trim()) {\n throw new StorageValidationError('Navigation ID must not be empty', 'EMPTY_ID');\n }\n\n // If name is being updated, ensure uniqueness\n if (input.name !== undefined) {\n const name = input.name.trim();\n if (!name) {\n throw new StorageValidationError('Navigation name must not be empty', 'EMPTY_NAME');\n }\n\n const existingNavigations = await adapter.listNavigations();\n const existingNames = existingNavigations.filter((n) => n.id !== input.id).map((n) => n.name);\n\n if (existingNames.includes(name)) {\n throw new StorageValidationError(\n `Navigation name \"${name}\" is already in use`,\n 'DUPLICATE_NAME'\n );\n }\n }\n\n return adapter.updateNavigation(input);\n}\n\n/**\n * Handler for deleting a navigation by ID\n */\nexport async function handleDeleteNavigation(adapter: StorageAdapter, id: string): Promise<void> {\n if (!id.trim()) {\n throw new StorageValidationError('Navigation ID must not be empty', 'EMPTY_ID');\n }\n\n return adapter.deleteNavigation(id);\n}\n","import type { PageSection } from '../storage/types';\nimport type { MediaAdapter } from './types';\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Convention: fields ending with these suffixes are treated as media references\n */\nconst MEDIA_FIELD_SUFFIXES = ['_image', '_media', '_photo', '_thumbnail', '_avatar', '_icon'];\n\n/**\n * Checks if a field name is a media reference field by convention\n */\nfunction isMediaField(fieldName: string): boolean {\n const lower = fieldName.toLowerCase();\n if (\n lower === 'image' ||\n lower === 'media' ||\n lower === 'photo' ||\n lower === 'thumbnail' ||\n lower === 'avatar' ||\n lower === 'icon'\n ) {\n return true;\n }\n return MEDIA_FIELD_SUFFIXES.some((suffix) => lower.endsWith(suffix));\n}\n\n/**\n * Checks if a value looks like a media ID (UUID format)\n */\nfunction isMediaId(value: unknown): value is string {\n return typeof value === 'string' && UUID_PATTERN.test(value);\n}\n\n/**\n * Resolves media references in a single data object.\n * Walks all fields and replaces media IDs with public URLs.\n * Returns a new object with resolved references.\n */\nasync function resolveDataObject(\n data: Record<string, unknown>,\n adapter: MediaAdapter\n): Promise<Record<string, unknown>> {\n const resolved: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n if (isMediaField(key) && isMediaId(value)) {\n const media = await adapter.getMedia(value);\n resolved[key] = media ? media.url : null;\n } else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n resolved[key] = await resolveDataObject(value as Record<string, unknown>, adapter);\n } else {\n resolved[key] = value;\n }\n }\n\n return resolved;\n}\n\n/**\n * Resolves media references in page sections.\n * Walks section data fields and replaces media IDs (UUIDs) with public URLs.\n *\n * Convention: Fields named \"image\", \"media\", \"photo\", \"thumbnail\", \"avatar\", \"icon\"\n * or ending with \"_image\", \"_media\", etc. are treated as media references.\n *\n * Missing media is resolved to null.\n */\nexport async function resolveMediaReferences(\n sections: PageSection[],\n adapter: MediaAdapter\n): Promise<PageSection[]> {\n const resolved: PageSection[] = [];\n\n for (const section of sections) {\n const resolvedData = await resolveDataObject(section.data, adapter);\n resolved.push({\n id: section.id,\n type: section.type,\n data: resolvedData,\n });\n }\n\n return resolved;\n}\n","import { resolveMediaReferences } from '../media/resolve';\nimport type { MediaAdapter } from '../media/types';\nimport type { Navigation, Page, StorageAdapter } from '../storage/types';\nimport type { ListPagesOptions, NavigationResponse, PageResponse } from './types';\n\n/**\n * Maps internal Page type to PageResponse for delivery API with resolved media references\n */\nasync function toPageResponse(page: Page, mediaAdapter: MediaAdapter): Promise<PageResponse> {\n const resolvedSections = await resolveMediaReferences(page.sections, mediaAdapter);\n\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: resolvedSections,\n meta: {\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n },\n };\n}\n\n/**\n * Maps internal Navigation type to NavigationResponse for delivery API\n */\nfunction toNavigationResponse(navigation: Navigation): NavigationResponse {\n return {\n id: navigation.id,\n name: navigation.name,\n items: navigation.items,\n meta: {\n updatedAt: navigation.updatedAt.toISOString(),\n },\n };\n}\n\n/**\n * Handler for GET /api/cms/pages\n * Returns all pages with resolved media references, optionally filtered by pageType\n */\nexport async function handleListPages(\n adapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n options?: ListPagesOptions\n): Promise<PageResponse[]> {\n const pages = await adapter.listPages({\n pageType: options?.pageType,\n limit: options?.limit,\n offset: options?.offset,\n });\n\n const results: PageResponse[] = [];\n for (const page of pages) {\n results.push(await toPageResponse(page, mediaAdapter));\n }\n\n return results;\n}\n\n/**\n * Handler for GET /api/cms/pages/:slug\n * Returns a single page by slug with resolved media references, or null if not found\n */\nexport async function handleGetPageBySlug(\n adapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n slug: string\n): Promise<PageResponse | null> {\n const page = await adapter.getPage(slug);\n\n if (!page) {\n return null;\n }\n\n return toPageResponse(page, mediaAdapter);\n}\n\n/**\n * Handler for GET /api/cms/navigation/:name\n * Returns a navigation by name, or null if not found\n */\nexport async function handleGetNavigation(\n adapter: StorageAdapter,\n name: string\n): Promise<NavigationResponse | null> {\n const navigation = await adapter.getNavigation(name);\n\n if (!navigation) {\n return null;\n }\n\n return toNavigationResponse(navigation);\n}\n","/**\n * Allowed MIME types for media uploads\n */\nexport const ALLOWED_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n] as const;\n\nexport type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];\n\n/**\n * Represents a media file stored in the CMS\n */\nexport interface MediaFile {\n id: string;\n filename: string;\n url: string;\n mimeType: string;\n size: number;\n createdAt: Date;\n}\n\n/**\n * Input for uploading a media file\n * data accepts ArrayBuffer for platform-agnostic binary data\n */\nexport interface UploadMediaInput {\n filename: string;\n mimeType: string;\n size: number;\n data: ArrayBuffer | Uint8Array;\n}\n\n/**\n * Filter options for listing media files\n */\nexport interface MediaFilter {\n limit?: number;\n offset?: number;\n mimeType?: string;\n}\n\n/**\n * Media adapter interface for file storage operations.\n * This interface is Supabase-agnostic to allow future portability.\n */\nexport interface MediaAdapter {\n /**\n * Upload a media file\n */\n upload(input: UploadMediaInput): Promise<MediaFile>;\n\n /**\n * Get a media file by ID\n */\n getMedia(id: string): Promise<MediaFile | null>;\n\n /**\n * List media files with optional filtering and pagination\n */\n listMedia(filter?: MediaFilter): Promise<MediaFile[]>;\n\n /**\n * Delete a media file by ID\n */\n deleteMedia(id: string): Promise<void>;\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type { MediaAdapter, MediaFile, MediaFilter, UploadMediaInput } from './types';\n\n/**\n * Database row type for media (snake_case)\n */\ninterface MediaRow {\n id: string;\n filename: string;\n storage_path: string;\n mime_type: string;\n size: number;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Media adapter error with additional context\n */\nexport class MediaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/**\n * Configuration for creating a Supabase media adapter\n */\nexport interface SupabaseMediaAdapterConfig {\n client: SupabaseClient;\n bucketName?: string;\n}\n\n/**\n * Supabase implementation of the MediaAdapter interface\n */\nexport class SupabaseMediaAdapter implements MediaAdapter {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseMediaAdapterConfig) {\n this.client = config.client;\n this.bucketName = config.bucketName ?? 'media';\n }\n\n /**\n * Generates a unique storage path for a file\n */\n private generateStoragePath(filename: string): string {\n const timestamp = Date.now();\n const randomSuffix = Math.random().toString(36).substring(2, 8);\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_');\n return `${timestamp}-${randomSuffix}-${sanitizedFilename}`;\n }\n\n /**\n * Constructs the public URL for a stored file\n */\n private getPublicUrl(storagePath: string): string {\n const { data } = this.client.storage.from(this.bucketName).getPublicUrl(storagePath);\n return data.publicUrl;\n }\n\n /**\n * Maps a database row to MediaFile\n */\n private mapRowToMediaFile(row: MediaRow): MediaFile {\n return {\n id: row.id,\n filename: row.filename,\n url: this.getPublicUrl(row.storage_path),\n mimeType: row.mime_type,\n size: row.size,\n createdAt: new Date(row.created_at),\n };\n }\n\n async upload(input: UploadMediaInput): Promise<MediaFile> {\n const storagePath = this.generateStoragePath(input.filename);\n\n // Upload file to Supabase Storage\n const { error: uploadError } = await this.client.storage\n .from(this.bucketName)\n .upload(storagePath, input.data, {\n contentType: input.mimeType,\n upsert: false,\n });\n\n if (uploadError) {\n throw new MediaError(\n `Failed to upload file: ${uploadError.message}`,\n 'UPLOAD_FAILED',\n uploadError.message\n );\n }\n\n // Create database record\n const { data, error: dbError } = await this.client\n .from('media')\n .insert({\n filename: input.filename,\n storage_path: storagePath,\n mime_type: input.mimeType,\n size: input.size,\n })\n .select()\n .single();\n\n if (dbError) {\n // Cleanup: delete uploaded file if DB insert fails\n await this.client.storage.from(this.bucketName).remove([storagePath]);\n throw new MediaError(\n `Failed to create media record: ${dbError.message}`,\n dbError.code,\n dbError.details\n );\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async getMedia(id: string): Promise<MediaFile | null> {\n const { data, error } = await this.client.from('media').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async listMedia(filter?: MediaFilter): Promise<MediaFile[]> {\n let query = this.client.from('media').select('*');\n\n if (filter?.mimeType) {\n query = query.eq('mime_type', filter.mimeType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return (data as MediaRow[]).map((row) => this.mapRowToMediaFile(row));\n }\n\n async deleteMedia(id: string): Promise<void> {\n // First get the media record to find the storage path\n const { data: mediaRecord, error: fetchError } = await this.client\n .from('media')\n .select('storage_path')\n .eq('id', id)\n .single();\n\n if (fetchError) {\n if (fetchError.code === 'PGRST116') {\n throw new MediaError(`Media not found: ${id}`, 'NOT_FOUND');\n }\n throw new MediaError(fetchError.message, fetchError.code, fetchError.details);\n }\n\n const storagePath = (mediaRecord as { storage_path: string }).storage_path;\n\n // Delete from storage\n const { error: storageError } = await this.client.storage\n .from(this.bucketName)\n .remove([storagePath]);\n\n if (storageError) {\n throw new MediaError(\n `Failed to delete file from storage: ${storageError.message}`,\n 'STORAGE_DELETE_FAILED',\n storageError.message\n );\n }\n\n // Delete database record\n const { error: dbError } = await this.client.from('media').delete().eq('id', id);\n\n if (dbError) {\n throw new MediaError(dbError.message, dbError.code, dbError.details);\n }\n }\n}\n\n/**\n * Creates a media adapter using Supabase\n */\nexport function createMediaAdapter(config: SupabaseMediaAdapterConfig): MediaAdapter {\n return new SupabaseMediaAdapter(config);\n}\n","import type { MediaAdapter, MediaFile, MediaFilter, UploadMediaInput } from './types';\nimport { ALLOWED_MIME_TYPES } from './types';\n\n/**\n * Error thrown when media validation fails\n */\nexport class MediaValidationError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'MediaValidationError';\n }\n}\n\n/**\n * Validates that the MIME type is allowed\n */\nfunction validateMimeType(mimeType: string): void {\n const allowed = ALLOWED_MIME_TYPES as readonly string[];\n if (!allowed.includes(mimeType)) {\n throw new MediaValidationError(\n `Invalid file type: ${mimeType}. Allowed types: ${ALLOWED_MIME_TYPES.join(', ')}`,\n 'INVALID_MIME_TYPE'\n );\n }\n}\n\n/**\n * Handler for uploading a media file\n * Validates the file type and delegates to the adapter\n */\nexport async function handleUploadMedia(\n adapter: MediaAdapter,\n input: UploadMediaInput\n): Promise<MediaFile> {\n validateMimeType(input.mimeType);\n return adapter.upload(input);\n}\n\n/**\n * Handler for retrieving a media file by ID\n */\nexport async function handleGetMedia(adapter: MediaAdapter, id: string): Promise<MediaFile | null> {\n return adapter.getMedia(id);\n}\n\n/**\n * Handler for listing media files with optional filtering\n */\nexport async function handleListMedia(\n adapter: MediaAdapter,\n filter?: MediaFilter\n): Promise<MediaFile[]> {\n return adapter.listMedia(filter);\n}\n\n/**\n * Handler for deleting a media file\n */\nexport async function handleDeleteMedia(adapter: MediaAdapter, id: string): Promise<void> {\n return adapter.deleteMedia(id);\n}\n","import { createClient } from '@supabase/supabase-js';\nimport { createAuthAdapter } from '../auth';\nimport type { AuthAdapter } from '../auth';\nimport { createMediaAdapter } from '../media';\nimport type { MediaAdapter } from '../media';\nimport { createStorageAdapter } from '../storage';\nimport type { StorageAdapter } from '../storage';\n\nexport interface SupabaseAdapterFactoryStorageConfig {\n bucket?: string;\n}\n\nexport interface SupabaseAdapterFactoryConfig {\n url?: string;\n key?: string;\n storage?: SupabaseAdapterFactoryStorageConfig;\n}\n\nexport interface SupabaseAdapters {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n authAdapter: AuthAdapter;\n}\n\ninterface ProcessLike {\n env: Record<string, string | undefined>;\n}\n\nfunction readEnv(name: string): string | undefined {\n const processLike = (globalThis as typeof globalThis & { process?: ProcessLike }).process;\n return processLike?.env[name];\n}\n\nfunction resolveRequiredConfig(\n explicitValue: string | undefined,\n envName: 'SUPABASE_URL' | 'SUPABASE_SECRET_KEY'\n): string {\n const explicit = explicitValue?.trim();\n if (explicit) {\n return explicit;\n }\n\n const fromEnv = readEnv(envName)?.trim();\n if (fromEnv) {\n return fromEnv;\n }\n\n throw new Error(\n `Missing Supabase configuration: provide ${envName} in factory config or environment variable`\n );\n}\n\nfunction resolveBucketName(config: SupabaseAdapterFactoryConfig): string {\n const explicitBucket = config.storage?.bucket?.trim();\n if (explicitBucket) {\n return explicitBucket;\n }\n\n const envBucket = readEnv('SUPABASE_STORAGE_BUCKET')?.trim();\n if (envBucket) {\n return envBucket;\n }\n\n return 'media';\n}\n\nexport function createSupabaseAdapters(\n config: SupabaseAdapterFactoryConfig = {}\n): SupabaseAdapters {\n const url = resolveRequiredConfig(config.url, 'SUPABASE_URL');\n const key = resolveRequiredConfig(config.key, 'SUPABASE_SECRET_KEY');\n const bucketName = resolveBucketName(config);\n\n const client = createClient(url, key);\n\n return {\n storageAdapter: createStorageAdapter({ client }),\n mediaAdapter: createMediaAdapter({ client, bucketName }),\n authAdapter: createAuthAdapter({ client }),\n };\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n AuthAdapter,\n AuthSession,\n AuthUser,\n OAuthResponse,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'AuthError';\n }\n}\n\nexport interface SupabaseAuthAdapterConfig {\n client: SupabaseClient;\n}\n\nexport class SupabaseAuthAdapter implements AuthAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseAuthAdapterConfig) {\n this.client = config.client;\n }\n\n private mapSupabaseUser(user: {\n id: string;\n email?: string;\n user_metadata?: Record<string, unknown>;\n }): AuthUser {\n if (!user.email) {\n throw new AuthError('User email is required', 'INVALID_USER');\n }\n\n return {\n id: user.id,\n email: user.email,\n metadata: user.user_metadata,\n };\n }\n\n async signInWithOAuth(input: SignInWithOAuthInput): Promise<OAuthResponse> {\n const { data, error } = await this.client.auth.signInWithOAuth({\n provider: input.provider,\n options: {\n redirectTo: input.redirectTo,\n },\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.url) {\n throw new AuthError('OAuth URL not provided', 'OAUTH_URL_MISSING');\n }\n\n return {\n url: data.url,\n provider: input.provider,\n };\n }\n\n async signInWithPassword(input: SignInWithPasswordInput): Promise<AuthSession> {\n const { data, error } = await this.client.auth.signInWithPassword({\n email: input.email,\n password: input.password,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session or user not returned', 'AUTH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async signOut(_accessToken: string): Promise<void> {\n const { error } = await this.client.auth.signOut();\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n }\n\n async verifySession(input: VerifySessionInput): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(input.accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n\n async refreshSession(refreshToken: string): Promise<AuthSession> {\n const { data, error } = await this.client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session refresh failed', 'REFRESH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async getCurrentUser(accessToken: string): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n}\n\nexport function createAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter {\n return new SupabaseAuthAdapter(config);\n}\n","import type {\n AuthAdapter,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AuthValidationError';\n }\n}\n\nexport async function handleSignInWithOAuth(adapter: AuthAdapter, input: SignInWithOAuthInput) {\n if (!input.provider) {\n throw new AuthValidationError('Provider is required');\n }\n\n const validProviders = ['google', 'github', 'gitlab', 'azure', 'bitbucket'];\n if (!validProviders.includes(input.provider)) {\n throw new AuthValidationError(`Invalid provider. Must be one of: ${validProviders.join(', ')}`);\n }\n\n return await adapter.signInWithOAuth(input);\n}\n\n/**\n * Validate password strength\n * Requirements:\n * - Minimum 8 characters\n * - At least 3 of: uppercase, lowercase, numbers, special characters\n * - Not a common password\n */\nfunction validatePassword(password: string): void {\n if (password.length < 8) {\n throw new AuthValidationError('Password must be at least 8 characters');\n }\n\n const hasUpperCase = /[A-Z]/.test(password);\n const hasLowerCase = /[a-z]/.test(password);\n const hasNumbers = /\\d/.test(password);\n const hasSpecialChar = /[!@#$%^&*(),.?\":{}|<>_\\-+=\\[\\]\\\\/'`~]/.test(password);\n\n const complexityCount = [hasUpperCase, hasLowerCase, hasNumbers, hasSpecialChar].filter(\n Boolean\n ).length;\n\n if (complexityCount < 3) {\n throw new AuthValidationError(\n 'Password must contain at least 3 of: uppercase letters, lowercase letters, numbers, special characters'\n );\n }\n\n // Check against common passwords\n const commonPasswords = [\n 'password',\n 'password1',\n 'password123',\n '12345678',\n '123456789',\n 'qwerty',\n 'abc123',\n 'monkey',\n '1234567890',\n 'letmein',\n 'trustno1',\n 'dragon',\n 'baseball',\n 'iloveyou',\n 'master',\n 'sunshine',\n 'ashley',\n 'bailey',\n 'shadow',\n '123123',\n ];\n\n if (commonPasswords.includes(password.toLowerCase())) {\n throw new AuthValidationError('Password is too common. Please choose a stronger password.');\n }\n}\n\nexport async function handleSignInWithPassword(\n adapter: AuthAdapter,\n input: SignInWithPasswordInput\n) {\n if (!input.email || !input.password) {\n throw new AuthValidationError('Email and password are required');\n }\n\n if (!input.email.includes('@')) {\n throw new AuthValidationError('Invalid email format');\n }\n\n // Strengthen password policy (Fix #5)\n validatePassword(input.password);\n\n return await adapter.signInWithPassword(input);\n}\n\nexport async function handleSignOut(adapter: AuthAdapter, accessToken: string) {\n if (!accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n return await adapter.signOut(accessToken);\n}\n\nexport async function handleVerifySession(adapter: AuthAdapter, input: VerifySessionInput) {\n if (!input.accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n // Enforce token expiration (Fix #7)\n if (input.expiresAt) {\n const now = new Date();\n const expiresAt = input.expiresAt instanceof Date ? input.expiresAt : new Date(input.expiresAt);\n \n if (now > expiresAt) {\n throw new AuthValidationError('Token has expired');\n }\n }\n\n const user = await adapter.verifySession(input);\n\n if (!user) {\n throw new AuthValidationError('Invalid or expired token');\n }\n\n return user;\n}\n\nexport async function handleRefreshSession(adapter: AuthAdapter, refreshToken: string) {\n if (!refreshToken) {\n throw new AuthValidationError('Refresh token is required');\n }\n\n return await adapter.refreshSession(refreshToken);\n}\n\nexport async function handleGetCurrentUser(adapter: AuthAdapter, accessToken: string) {\n if (!accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n return await adapter.getCurrentUser(accessToken);\n}\n","import type { AuthAdapter, AuthUser } from './types';\n\nexport interface AuthenticatedRequest {\n user: AuthUser;\n accessToken: string;\n}\n\nexport interface AuthMiddlewareConfig {\n adapter: AuthAdapter;\n extractToken?: (headers: Record<string, string | undefined>) => string | null;\n}\n\nexport function createAuthMiddleware(config: AuthMiddlewareConfig) {\n const extractToken =\n config.extractToken ||\n ((headers: Record<string, string | undefined>) => {\n const authHeader = headers.authorization || headers.Authorization;\n if (!authHeader) return null;\n\n const parts = authHeader.split(' ');\n if (parts.length !== 2 || parts[0] !== 'Bearer') return null;\n\n return parts[1];\n });\n\n return async function authenticate(\n headers: Record<string, string | undefined>\n ): Promise<AuthenticatedRequest> {\n const token = extractToken(headers);\n\n if (!token) {\n throw new Error('No authentication token provided');\n }\n\n const user = await config.adapter.verifySession({ accessToken: token });\n\n if (!user) {\n throw new Error('Invalid or expired token');\n }\n\n return {\n user,\n accessToken: token,\n };\n };\n}\n","import { resolveMediaReferences } from '../media/resolve';\nimport type { MediaAdapter } from '../media/types';\nimport type { Navigation, Page, StorageAdapter } from '../storage/types';\nimport type {\n AllNavigationsExportResponse,\n AllPagesExportResponse,\n MediaExportEntry,\n NavigationExportResponse,\n PageExportResponse,\n SiteExportResponse,\n} from './types';\n\n/**\n * Generates a Content-Disposition header value for file download\n */\nfunction contentDisposition(filename: string): string {\n return `attachment; filename=\"${filename}\"`;\n}\n\n/**\n * Converts a Page to a PageExportResponse with resolved media references\n */\nasync function toPageExport(page: Page, mediaAdapter: MediaAdapter): Promise<PageExportResponse> {\n const resolvedSections = await resolveMediaReferences(page.sections, mediaAdapter);\n\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: resolvedSections,\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/pages/:slug\n * Returns complete page JSON with resolved media URLs\n */\nexport async function handleExportPage(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n slug: string\n): Promise<{ data: PageExportResponse; contentDisposition: string } | null> {\n const page = await storageAdapter.getPage(slug);\n\n if (!page) {\n return null;\n }\n\n const data = await toPageExport(page, mediaAdapter);\n\n return {\n data,\n contentDisposition: contentDisposition(`${page.slug}.json`),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/pages\n * Returns all pages as JSON array with resolved media URLs\n */\nexport async function handleExportAllPages(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter\n): Promise<{ data: AllPagesExportResponse; contentDisposition: string }> {\n const pages = await storageAdapter.listPages();\n\n const exportedPages: PageExportResponse[] = [];\n for (const page of pages) {\n exportedPages.push(await toPageExport(page, mediaAdapter));\n }\n\n const data: AllPagesExportResponse = {\n pages: exportedPages,\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('pages-export.json'),\n };\n}\n\n/**\n * Converts a Navigation to a NavigationExportResponse\n */\nfunction toNavigationExport(nav: Navigation): NavigationExportResponse {\n return {\n id: nav.id,\n name: nav.name,\n items: nav.items,\n updatedAt: nav.updatedAt.toISOString(),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/navigation\n * Returns all navigation structures as JSON\n */\nexport async function handleExportNavigations(\n storageAdapter: StorageAdapter\n): Promise<{ data: AllNavigationsExportResponse; contentDisposition: string }> {\n const navigations = await storageAdapter.listNavigations();\n\n const data: AllNavigationsExportResponse = {\n navigations: navigations.map(toNavigationExport),\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('navigation-export.json'),\n };\n}\n\n/**\n * Handler for GET /api/cms/export\n * Returns complete site content (pages, navigation, media metadata) as JSON\n */\nexport async function handleExportSite(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter\n): Promise<{ data: SiteExportResponse; contentDisposition: string }> {\n // Export pages with resolved media\n const pages = await storageAdapter.listPages();\n const exportedPages: PageExportResponse[] = [];\n for (const page of pages) {\n exportedPages.push(await toPageExport(page, mediaAdapter));\n }\n\n // Export navigations\n const navigations = await storageAdapter.listNavigations();\n const exportedNavigations = navigations.map(toNavigationExport);\n\n // Export media metadata\n const mediaFiles = await mediaAdapter.listMedia();\n const exportedMedia: MediaExportEntry[] = mediaFiles.map((file) => ({\n id: file.id,\n filename: file.filename,\n url: file.url,\n mimeType: file.mimeType,\n size: file.size,\n createdAt: file.createdAt.toISOString(),\n }));\n\n const data: SiteExportResponse = {\n pages: exportedPages,\n navigations: exportedNavigations,\n media: exportedMedia,\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('site-export.json'),\n };\n}\n"],"mappings":"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","names":["sanitizeHtml"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/storage/supabase-adapter.ts","../src/utils/sanitize.ts","../src/utils/slug.ts","../src/storage/handlers.ts","../src/validation/schemas.ts","../src/media/resolve.ts","../src/delivery/handlers.ts","../src/media/types.ts","../src/media/supabase-adapter.ts","../src/media/handlers.ts","../src/supabase/factory.ts","../src/auth/supabase-adapter.ts","../src/auth/handlers.ts","../src/auth/middleware.ts","../src/auth/csrf.ts","../src/auth/rate-limiter.ts","../src/export/handlers.ts","../src/audit/logger.ts"],"sourcesContent":["export type {\n Page,\n PageSection,\n PageFilter,\n CreatePageInput,\n UpdatePageInput,\n Navigation,\n NavigationItem,\n CreateNavigationInput,\n UpdateNavigationInput,\n StorageAdapter,\n SupabaseStorageAdapterConfig,\n} from './storage';\n\nexport {\n SupabaseStorageAdapter,\n createStorageAdapter,\n StorageError,\n handleCreatePage,\n handleUpdatePage,\n handleDeletePage,\n handleCreateNavigation,\n handleUpdateNavigation,\n handleDeleteNavigation,\n StorageValidationError,\n} from './storage';\n\nexport { generateSlug, ensureUniqueSlug, stripTags } from './utils';\n\nexport type {\n CreatePageInput as CreatePageSchemaType,\n UpdatePageInput as UpdatePageSchemaType,\n CreateNavigationInput as CreateNavigationSchemaType,\n UpdateNavigationInput as UpdateNavigationSchemaType,\n SignInInput,\n MediaUploadInput as MediaUploadSchemaType,\n} from './validation';\n\nexport {\n CreatePageSchema,\n UpdatePageSchema,\n CreateNavigationSchema,\n UpdateNavigationSchema,\n SignInSchema,\n MediaUploadSchema,\n} from './validation';\n\nexport type {\n PageResponse,\n NavigationResponse,\n ListPagesOptions,\n} from './delivery';\n\nexport {\n handleListPages,\n handleGetPageBySlug,\n handleGetNavigation,\n} from './delivery';\n\nexport type {\n MediaFile,\n MediaAdapter,\n UploadMediaInput,\n MediaFilter,\n AllowedMimeType,\n AllowedDocumentMimeType,\n MediaCategory,\n SupabaseMediaAdapterConfig,\n} from './media';\n\nexport {\n ALLOWED_MIME_TYPES,\n ALLOWED_DOCUMENT_MIME_TYPES,\n ALL_ALLOWED_MIME_TYPES,\n MAX_FILE_SIZE,\n SupabaseMediaAdapter,\n createMediaAdapter,\n MediaError,\n handleUploadMedia,\n handleGetMedia,\n handleListMedia,\n handleDeleteMedia,\n MediaValidationError,\n resolveMediaReferences,\n} from './media';\n\nexport type {\n SupabaseAdapterFactoryStorageConfig,\n SupabaseAdapterFactoryConfig,\n SupabaseAdapters,\n} from './supabase';\n\nexport { createSupabaseAdapters } from './supabase';\n\nexport type {\n PageExportResponse,\n AllPagesExportResponse,\n NavigationExportResponse,\n AllNavigationsExportResponse,\n SiteExportResponse,\n MediaExportEntry,\n} from './export';\n\nexport {\n handleExportPage,\n handleExportAllPages,\n handleExportNavigations,\n handleExportSite,\n} from './export';\n\nexport type {\n AuthUser,\n AuthSession,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n OAuthResponse,\n VerifySessionInput,\n AuthAdapter,\n SupabaseAuthAdapterConfig,\n AuthMiddlewareConfig,\n AuthenticatedRequest,\n RateLimiter,\n RateLimiterConfig,\n RateLimitResult,\n} from './auth';\n\nexport {\n SupabaseAuthAdapter,\n createAuthAdapter,\n AuthError,\n handleSignInWithOAuth,\n handleSignInWithPassword,\n handleSignOut,\n handleVerifySession,\n handleRefreshSession,\n handleGetCurrentUser,\n AuthValidationError,\n createAuthMiddleware,\n generateCsrfToken,\n validateCsrfToken,\n createRateLimiter,\n} from './auth';\n\nexport type { AuditEntry } from './audit';\n\nexport { createAuditLogger, withAuditLog } from './audit';\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageFilter,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Database row types (snake_case)\n */\ninterface PageRow {\n id: string;\n slug: string;\n page_type: string;\n title: string;\n sections: PageSection[];\n created_at: string;\n updated_at: string;\n}\n\ninterface NavigationRow {\n id: string;\n name: string;\n items: NavigationItem[];\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Maps a database page row to the Page type\n */\nfunction mapPageRowToPage(row: PageRow): Page {\n return {\n id: row.id,\n slug: row.slug,\n pageType: row.page_type,\n title: row.title,\n sections: row.sections,\n createdAt: new Date(row.created_at),\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Maps a database navigation row to the Navigation type\n */\nfunction mapNavigationRowToNavigation(row: NavigationRow): Navigation {\n return {\n id: row.id,\n name: row.name,\n items: row.items,\n updatedAt: new Date(row.updated_at),\n };\n}\n\n/**\n * Storage adapter error with additional context\n */\nexport class StorageError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'StorageError';\n }\n}\n\n/**\n * Configuration for creating a Supabase storage adapter\n */\nexport interface SupabaseStorageAdapterConfig {\n client: SupabaseClient;\n}\n\n/**\n * Supabase implementation of the StorageAdapter interface\n */\nexport class SupabaseStorageAdapter implements StorageAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseStorageAdapterConfig) {\n this.client = config.client;\n }\n\n async getPage(slug: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('slug', slug).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async getPageById(id: string): Promise<Page | null> {\n const { data, error } = await this.client.from('pages').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async createPage(input: CreatePageInput): Promise<Page> {\n const { data, error } = await this.client\n .from('pages')\n .insert({\n slug: input.slug,\n page_type: input.pageType,\n title: input.title,\n sections: input.sections ?? [],\n })\n .select()\n .single();\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async updatePage(input: UpdatePageInput): Promise<Page> {\n const updateData: Record<string, unknown> = {};\n\n if (input.slug !== undefined) {\n updateData.slug = input.slug;\n }\n if (input.pageType !== undefined) {\n updateData.page_type = input.pageType;\n }\n if (input.title !== undefined) {\n updateData.title = input.title;\n }\n if (input.sections !== undefined) {\n updateData.sections = input.sections;\n }\n\n const { data, error } = await this.client\n .from('pages')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Page not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapPageRowToPage(data as PageRow);\n }\n\n async deletePage(id: string): Promise<void> {\n const { error } = await this.client.from('pages').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listPages(filter?: PageFilter): Promise<Page[]> {\n let query = this.client.from('pages').select('*');\n\n if (filter?.pageType) {\n query = query.eq('page_type', filter.pageType);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as PageRow[]).map(mapPageRowToPage);\n }\n\n async getNavigation(name: string): Promise<Navigation | null> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .eq('name', name)\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async getNavigationById(id: string): Promise<Navigation | null> {\n const { data, error } = await this.client.from('navigation').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async createNavigation(input: CreateNavigationInput): Promise<Navigation> {\n const { data, error } = await this.client\n .from('navigation')\n .insert({\n name: input.name,\n items: input.items,\n })\n .select()\n .single();\n\n if (error) {\n if (error.code === '23505') {\n throw new StorageError(\n `Navigation with name \"${input.name}\" already exists`,\n 'DUPLICATE_NAME'\n );\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async updateNavigation(input: UpdateNavigationInput): Promise<Navigation> {\n const updateData: Record<string, unknown> = {};\n\n if (input.name !== undefined) {\n updateData.name = input.name;\n }\n if (input.items !== undefined) {\n updateData.items = input.items;\n }\n\n const { data, error } = await this.client\n .from('navigation')\n .update(updateData)\n .eq('id', input.id)\n .select()\n .single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n throw new StorageError(`Navigation not found: ${input.id}`, 'NOT_FOUND');\n }\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return mapNavigationRowToNavigation(data as NavigationRow);\n }\n\n async deleteNavigation(id: string): Promise<void> {\n const { error } = await this.client.from('navigation').delete().eq('id', id);\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n }\n\n async listNavigations(): Promise<Navigation[]> {\n const { data, error } = await this.client\n .from('navigation')\n .select('*')\n .order('name', { ascending: true });\n\n if (error) {\n throw new StorageError(error.message, error.code, error.details);\n }\n\n return (data as NavigationRow[]).map(mapNavigationRowToNavigation);\n }\n}\n\n/**\n * Creates a storage adapter using Supabase\n */\nexport function createStorageAdapter(config: SupabaseStorageAdapterConfig): StorageAdapter {\n return new SupabaseStorageAdapter(config);\n}\n","import sanitizeHtml from 'sanitize-html';\nimport type { PageSection } from '../storage/types';\n\n/**\n * Allowed HTML tags for sanitization\n */\nconst ALLOWED_TAGS = [\n 'p',\n 'h1',\n 'h2',\n 'h3',\n 'h4',\n 'h5',\n 'h6',\n 'ul',\n 'ol',\n 'li',\n 'a',\n 'strong',\n 'em',\n 'br',\n 'blockquote',\n 'code',\n 'pre',\n 'img',\n];\n\n/**\n * Allowed HTML attributes per tag\n */\nconst ALLOWED_ATTRIBUTES: Record<string, string[]> = {\n a: ['href'],\n img: ['src', 'alt'],\n};\n\n/**\n * Sanitize-html configuration\n */\nconst SANITIZE_OPTIONS: sanitizeHtml.IOptions = {\n allowedTags: ALLOWED_TAGS,\n allowedAttributes: ALLOWED_ATTRIBUTES,\n disallowedTagsMode: 'discard',\n};\n\n/**\n * Sanitize a single string value using the configured allowlist\n */\nexport function sanitizeString(value: string): string {\n return sanitizeHtml(value, SANITIZE_OPTIONS);\n}\n\n/**\n * Strip all HTML tags from a string (for plain text fields like titles, names)\n */\nexport function stripTags(value: string): string {\n return sanitizeHtml(value, {\n allowedTags: [],\n allowedAttributes: {},\n });\n}\n\n/**\n * Recursively sanitize all string values in an unknown data structure\n */\nexport function sanitizeValue(value: unknown): unknown {\n if (typeof value === 'string') {\n return sanitizeString(value);\n }\n\n if (Array.isArray(value)) {\n return value.map(sanitizeValue);\n }\n\n if (value !== null && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value as Record<string, unknown>)) {\n result[key] = sanitizeValue(val);\n }\n return result;\n }\n\n // number, boolean, null, undefined — pass through\n return value;\n}\n\n/**\n * Sanitize all string values in page sections' data\n * Returns a new array with sanitized sections (does not mutate input)\n */\nexport function sanitizeSectionData(sections: PageSection[]): PageSection[] {\n return sections.map((section) => ({\n ...section,\n data: sanitizeValue(section.data) as Record<string, unknown>,\n }));\n}\n","/**\n * Character replacements for German umlauts and special characters\n */\nconst UMLAUT_MAP: Record<string, string> = {\n ä: 'ae',\n ö: 'oe',\n ü: 'ue',\n Ä: 'Ae',\n Ö: 'Oe',\n Ü: 'Ue',\n ß: 'ss',\n};\n\n/**\n * Generates a URL-safe slug from a title string.\n *\n * @param title - The title to convert to a slug\n * @returns A URL-safe slug\n *\n * @example\n * generateSlug('Hello World') // 'hello-world'\n * generateSlug('Über uns') // 'ueber-uns'\n * generateSlug(' Multiple Spaces ') // 'multiple-spaces'\n */\nexport function generateSlug(title: string): string {\n let slug = title.toLowerCase().trim();\n\n // Replace German umlauts\n for (const [umlaut, replacement] of Object.entries(UMLAUT_MAP)) {\n slug = slug.replace(new RegExp(umlaut, 'g'), replacement.toLowerCase());\n }\n\n // Replace spaces and underscores with hyphens\n slug = slug.replace(/[\\s_]+/g, '-');\n\n // Remove all non-alphanumeric characters except hyphens\n slug = slug.replace(/[^a-z0-9-]/g, '');\n\n // Remove multiple consecutive hyphens\n slug = slug.replace(/-+/g, '-');\n\n // Remove leading and trailing hyphens\n slug = slug.replace(/^-+|-+$/g, '');\n\n return slug;\n}\n\n/**\n * Ensures a slug is unique by appending a numeric suffix if needed.\n *\n * @param slug - The base slug to make unique\n * @param existingSlugs - Array of existing slugs to check against\n * @returns A unique slug\n *\n * @example\n * ensureUniqueSlug('hello', ['hello', 'world']) // 'hello-1'\n * ensureUniqueSlug('hello', ['hello', 'hello-1']) // 'hello-2'\n * ensureUniqueSlug('new', ['hello', 'world']) // 'new'\n */\nexport function ensureUniqueSlug(slug: string, existingSlugs: string[]): string {\n if (!existingSlugs.includes(slug)) {\n return slug;\n }\n\n let counter = 1;\n let uniqueSlug = `${slug}-${counter}`;\n\n while (existingSlugs.includes(uniqueSlug)) {\n counter++;\n uniqueSlug = `${slug}-${counter}`;\n }\n\n return uniqueSlug;\n}\n","import { sanitizeSectionData, stripTags } from '../utils/sanitize';\nimport { ensureUniqueSlug, generateSlug } from '../utils/slug';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n Page,\n StorageAdapter,\n UpdateNavigationInput,\n UpdatePageInput,\n} from './types';\n\n/**\n * Error thrown when storage validation fails\n */\nexport class StorageValidationError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'StorageValidationError';\n }\n}\n\n/**\n * Handler for creating a new page\n * Generates a slug from the title if not provided and ensures uniqueness\n */\nexport async function handleCreatePage(\n adapter: StorageAdapter,\n input: CreatePageInput\n): Promise<Page> {\n // Sanitize title to remove any HTML tags\n const sanitizedTitle = stripTags(input.title).trim();\n\n if (!sanitizedTitle) {\n throw new StorageValidationError('Page title must not be empty', 'EMPTY_TITLE');\n }\n\n const slug = input.slug?.trim() || generateSlug(sanitizedTitle);\n\n if (!slug) {\n throw new StorageValidationError(\n 'Could not generate a valid slug from the provided title',\n 'INVALID_SLUG'\n );\n }\n\n // Ensure slug uniqueness\n const existingPages = await adapter.listPages();\n const existingSlugs = existingPages.map((p) => p.slug);\n const uniqueSlug = ensureUniqueSlug(slug, existingSlugs);\n\n const sanitizedSections = input.sections ? sanitizeSectionData(input.sections) : undefined;\n\n return adapter.createPage({\n ...input,\n title: sanitizedTitle,\n slug: uniqueSlug,\n sections: sanitizedSections,\n });\n}\n\n/**\n * Handler for updating an existing page\n */\nexport async function handleUpdatePage(\n adapter: StorageAdapter,\n input: UpdatePageInput\n): Promise<Page> {\n if (!input.id.trim()) {\n throw new StorageValidationError('Page ID must not be empty', 'EMPTY_ID');\n }\n\n // Sanitize title if provided\n let sanitizedTitle: string | undefined;\n if (input.title !== undefined) {\n sanitizedTitle = stripTags(input.title).trim();\n if (!sanitizedTitle) {\n throw new StorageValidationError('Page title must not be empty', 'EMPTY_TITLE');\n }\n }\n\n // If slug is being updated, ensure uniqueness\n if (input.slug !== undefined) {\n const slug = input.slug.trim();\n if (!slug) {\n throw new StorageValidationError('Page slug must not be empty', 'EMPTY_SLUG');\n }\n\n const existingPages = await adapter.listPages();\n const existingSlugs = existingPages.filter((p) => p.id !== input.id).map((p) => p.slug);\n\n if (existingSlugs.includes(slug)) {\n throw new StorageValidationError(`Slug \"${slug}\" is already in use`, 'DUPLICATE_SLUG');\n }\n }\n\n const sanitizedInput = {\n ...input,\n ...(sanitizedTitle !== undefined && { title: sanitizedTitle }),\n ...(input.sections && { sections: sanitizeSectionData(input.sections) }),\n };\n\n return adapter.updatePage(sanitizedInput);\n}\n\n/**\n * Handler for deleting a page by ID\n */\nexport async function handleDeletePage(adapter: StorageAdapter, id: string): Promise<void> {\n if (!id.trim()) {\n throw new StorageValidationError('Page ID must not be empty', 'EMPTY_ID');\n }\n\n return adapter.deletePage(id);\n}\n\n/**\n * Handler for creating a new navigation\n * Validates that the name is non-empty and unique\n */\nexport async function handleCreateNavigation(\n adapter: StorageAdapter,\n input: CreateNavigationInput\n): Promise<Navigation> {\n // Sanitize name to remove any HTML tags\n const sanitizedName = stripTags(input.name).trim();\n\n if (!sanitizedName) {\n throw new StorageValidationError('Navigation name must not be empty', 'EMPTY_NAME');\n }\n\n // Ensure name uniqueness\n const existingNavigations = await adapter.listNavigations();\n const existingNames = existingNavigations.map((n) => n.name);\n\n if (existingNames.includes(sanitizedName)) {\n throw new StorageValidationError(\n `Navigation name \"${sanitizedName}\" is already in use`,\n 'DUPLICATE_NAME'\n );\n }\n\n return adapter.createNavigation({\n ...input,\n name: sanitizedName,\n });\n}\n\n/**\n * Handler for updating an existing navigation\n */\nexport async function handleUpdateNavigation(\n adapter: StorageAdapter,\n input: UpdateNavigationInput\n): Promise<Navigation> {\n if (!input.id.trim()) {\n throw new StorageValidationError('Navigation ID must not be empty', 'EMPTY_ID');\n }\n\n // If name is being updated, ensure uniqueness\n let sanitizedName: string | undefined;\n if (input.name !== undefined) {\n sanitizedName = stripTags(input.name).trim();\n if (!sanitizedName) {\n throw new StorageValidationError('Navigation name must not be empty', 'EMPTY_NAME');\n }\n\n const existingNavigations = await adapter.listNavigations();\n const existingNames = existingNavigations.filter((n) => n.id !== input.id).map((n) => n.name);\n\n if (existingNames.includes(sanitizedName)) {\n throw new StorageValidationError(\n `Navigation name \"${sanitizedName}\" is already in use`,\n 'DUPLICATE_NAME'\n );\n }\n }\n\n return adapter.updateNavigation({\n ...input,\n ...(sanitizedName !== undefined && { name: sanitizedName }),\n });\n}\n\n/**\n * Handler for deleting a navigation by ID\n */\nexport async function handleDeleteNavigation(adapter: StorageAdapter, id: string): Promise<void> {\n if (!id.trim()) {\n throw new StorageValidationError('Navigation ID must not be empty', 'EMPTY_ID');\n }\n\n return adapter.deleteNavigation(id);\n}\n","import { z } from 'zod';\n\n/**\n * Maximum file size: 50MB\n */\nexport const MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Schema for page sections\n */\nconst PageSectionSchema = z.object({\n id: z.string().optional(),\n type: z.string(),\n data: z.record(z.unknown()),\n});\n\n/**\n * Schema for creating a new page\n */\nexport const CreatePageSchema = z.object({\n title: z.string().max(200, 'Title must not exceed 200 characters'),\n pageType: z.string(),\n slug: z.string().max(200, 'Slug must not exceed 200 characters').optional(),\n sections: z.array(PageSectionSchema).optional(),\n});\n\n/**\n * Schema for updating an existing page\n */\nexport const UpdatePageSchema = CreatePageSchema.partial();\n\n/**\n * Schema for navigation items (recursive)\n */\nconst NavigationItemSchema: z.ZodType = z.lazy(() =>\n z.object({\n label: z.string(),\n href: z.string(),\n children: z.array(NavigationItemSchema).optional(),\n })\n);\n\n/**\n * Schema for creating a new navigation\n */\nexport const CreateNavigationSchema = z.object({\n name: z.string().max(100, 'Name must not exceed 100 characters'),\n items: z.array(NavigationItemSchema),\n});\n\n/**\n * Schema for updating an existing navigation\n */\nexport const UpdateNavigationSchema = CreateNavigationSchema.partial();\n\n/**\n * Schema for sign in\n */\nexport const SignInSchema = z.object({\n email: z.string().email('Invalid email address'),\n password: z.string().min(1, 'Password is required'),\n});\n\n/**\n * Schema for media upload\n */\nexport const MediaUploadSchema = z.object({\n filename: z.string().max(255, 'Filename must not exceed 255 characters'),\n mimeType: z.string(),\n size: z.number().max(MAX_FILE_SIZE, `File size must not exceed ${MAX_FILE_SIZE / 1024 / 1024}MB`),\n data: z.instanceof(ArrayBuffer),\n});\n\n/**\n * Type exports for TypeScript\n */\nexport type CreatePageInput = z.infer<typeof CreatePageSchema>;\nexport type UpdatePageInput = z.infer<typeof UpdatePageSchema>;\nexport type CreateNavigationInput = z.infer<typeof CreateNavigationSchema>;\nexport type UpdateNavigationInput = z.infer<typeof UpdateNavigationSchema>;\nexport type SignInInput = z.infer<typeof SignInSchema>;\nexport type MediaUploadInput = z.infer<typeof MediaUploadSchema>;\n","import type { PageSection } from '../storage/types';\nimport type { MediaAdapter } from './types';\n\nconst UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n\n/**\n * Convention: fields ending with these suffixes are treated as media references\n */\nconst MEDIA_FIELD_SUFFIXES = [\n '_image',\n '_media',\n '_photo',\n '_thumbnail',\n '_avatar',\n '_icon',\n '_file',\n '_document',\n '_attachment',\n '_download',\n];\n\n/**\n * Checks if a field name is a media reference field by convention\n */\nfunction isMediaField(fieldName: string): boolean {\n const lower = fieldName.toLowerCase();\n if (\n lower === 'image' ||\n lower === 'media' ||\n lower === 'photo' ||\n lower === 'thumbnail' ||\n lower === 'avatar' ||\n lower === 'icon' ||\n lower === 'file' ||\n lower === 'document' ||\n lower === 'attachment' ||\n lower === 'download'\n ) {\n return true;\n }\n return MEDIA_FIELD_SUFFIXES.some((suffix) => lower.endsWith(suffix));\n}\n\n/**\n * Checks if a value looks like a media ID (UUID format)\n */\nfunction isMediaId(value: unknown): value is string {\n return typeof value === 'string' && UUID_PATTERN.test(value);\n}\n\n/**\n * Resolves media references in a single data object.\n * Walks all fields and replaces media IDs with public URLs.\n * Returns a new object with resolved references.\n */\nasync function resolveDataObject(\n data: Record<string, unknown>,\n adapter: MediaAdapter\n): Promise<Record<string, unknown>> {\n const resolved: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(data)) {\n if (isMediaField(key) && isMediaId(value)) {\n const media = await adapter.getMedia(value);\n resolved[key] = media ? media.url : null;\n } else if (value !== null && typeof value === 'object' && !Array.isArray(value)) {\n resolved[key] = await resolveDataObject(value as Record<string, unknown>, adapter);\n } else {\n resolved[key] = value;\n }\n }\n\n return resolved;\n}\n\n/**\n * Resolves media references in page sections.\n * Walks section data fields and replaces media IDs (UUIDs) with public URLs.\n *\n * Convention: Fields named \"image\", \"media\", \"photo\", \"thumbnail\", \"avatar\", \"icon\"\n * or ending with \"_image\", \"_media\", etc. are treated as media references.\n *\n * Missing media is resolved to null.\n */\nexport async function resolveMediaReferences(\n sections: PageSection[],\n adapter: MediaAdapter\n): Promise<PageSection[]> {\n const resolved: PageSection[] = [];\n\n for (const section of sections) {\n const resolvedData = await resolveDataObject(section.data, adapter);\n resolved.push({\n id: section.id,\n type: section.type,\n data: resolvedData,\n });\n }\n\n return resolved;\n}\n","import { resolveMediaReferences } from '../media/resolve';\nimport type { MediaAdapter } from '../media/types';\nimport type { Navigation, Page, StorageAdapter } from '../storage/types';\nimport type { ListPagesOptions, NavigationResponse, PageResponse } from './types';\n\n/**\n * Maps internal Page type to PageResponse for delivery API with resolved media references\n */\nasync function toPageResponse(page: Page, mediaAdapter: MediaAdapter): Promise<PageResponse> {\n const resolvedSections = await resolveMediaReferences(page.sections, mediaAdapter);\n\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: resolvedSections,\n meta: {\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n },\n };\n}\n\n/**\n * Maps internal Navigation type to NavigationResponse for delivery API\n */\nfunction toNavigationResponse(navigation: Navigation): NavigationResponse {\n return {\n id: navigation.id,\n name: navigation.name,\n items: navigation.items,\n meta: {\n updatedAt: navigation.updatedAt.toISOString(),\n },\n };\n}\n\n/**\n * Handler for GET /api/cms/pages\n * Returns all pages with resolved media references, optionally filtered by pageType\n */\nexport async function handleListPages(\n adapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n options?: ListPagesOptions\n): Promise<PageResponse[]> {\n const pages = await adapter.listPages({\n pageType: options?.pageType,\n limit: options?.limit,\n offset: options?.offset,\n });\n\n const results: PageResponse[] = [];\n for (const page of pages) {\n results.push(await toPageResponse(page, mediaAdapter));\n }\n\n return results;\n}\n\n/**\n * Handler for GET /api/cms/pages/:slug\n * Returns a single page by slug with resolved media references, or null if not found\n */\nexport async function handleGetPageBySlug(\n adapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n slug: string\n): Promise<PageResponse | null> {\n const page = await adapter.getPage(slug);\n\n if (!page) {\n return null;\n }\n\n return toPageResponse(page, mediaAdapter);\n}\n\n/**\n * Handler for GET /api/cms/navigation/:name\n * Returns a navigation by name, or null if not found\n */\nexport async function handleGetNavigation(\n adapter: StorageAdapter,\n name: string\n): Promise<NavigationResponse | null> {\n const navigation = await adapter.getNavigation(name);\n\n if (!navigation) {\n return null;\n }\n\n return toNavigationResponse(navigation);\n}\n","/**\n * Maximum file size: 50MB\n */\nexport const MAX_FILE_SIZE = 50 * 1024 * 1024;\n\n/**\n * Allowed MIME types for image uploads\n */\nexport const ALLOWED_MIME_TYPES = [\n 'image/jpeg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/svg+xml',\n] as const;\n\nexport type AllowedMimeType = (typeof ALLOWED_MIME_TYPES)[number];\n\n/**\n * Allowed MIME types for document uploads\n */\nexport const ALLOWED_DOCUMENT_MIME_TYPES = [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n 'application/vnd.ms-excel',\n 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n 'application/vnd.ms-powerpoint',\n 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n 'text/plain',\n 'text/csv',\n 'application/zip',\n 'application/gzip',\n] as const;\n\nexport type AllowedDocumentMimeType = (typeof ALLOWED_DOCUMENT_MIME_TYPES)[number];\n\n/**\n * All allowed MIME types (images + documents)\n */\nexport const ALL_ALLOWED_MIME_TYPES = [\n ...ALLOWED_MIME_TYPES,\n ...ALLOWED_DOCUMENT_MIME_TYPES,\n] as const;\n\n/**\n * Media category discriminator\n */\nexport type MediaCategory = 'image' | 'document';\n\n/**\n * Represents a media file stored in the CMS\n */\nexport interface MediaFile {\n id: string;\n filename: string;\n url: string;\n mimeType: string;\n size: number;\n category: MediaCategory;\n createdAt: Date;\n}\n\n/**\n * Input for uploading a media file\n * data accepts ArrayBuffer for platform-agnostic binary data\n */\nexport interface UploadMediaInput {\n filename: string;\n mimeType: string;\n size: number;\n data: ArrayBuffer | Uint8Array;\n}\n\n/**\n * Filter options for listing media files\n */\nexport interface MediaFilter {\n limit?: number;\n offset?: number;\n mimeType?: string;\n category?: MediaCategory;\n}\n\n/**\n * Media adapter interface for file storage operations.\n * This interface is Supabase-agnostic to allow future portability.\n */\nexport interface MediaAdapter {\n /**\n * Upload a media file\n */\n upload(input: UploadMediaInput): Promise<MediaFile>;\n\n /**\n * Get a media file by ID\n */\n getMedia(id: string): Promise<MediaFile | null>;\n\n /**\n * List media files with optional filtering and pagination\n */\n listMedia(filter?: MediaFilter): Promise<MediaFile[]>;\n\n /**\n * Delete a media file by ID\n */\n deleteMedia(id: string): Promise<void>;\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n MediaAdapter,\n MediaCategory,\n MediaFile,\n MediaFilter,\n UploadMediaInput,\n} from './types';\nimport { ALLOWED_MIME_TYPES } from './types';\n\n/**\n * Database row type for media (snake_case)\n */\ninterface MediaRow {\n id: string;\n filename: string;\n storage_path: string;\n mime_type: string;\n size: number;\n category: string;\n created_at: string;\n updated_at: string;\n}\n\n/**\n * Derives the media category from a MIME type.\n * Image MIME types map to 'image', everything else to 'document'.\n */\nfunction deriveCategory(mimeType: string): MediaCategory {\n const imageMimes = ALLOWED_MIME_TYPES as readonly string[];\n return imageMimes.includes(mimeType) ? 'image' : 'document';\n}\n\n/**\n * Media adapter error with additional context\n */\nexport class MediaError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'MediaError';\n }\n}\n\n/**\n * Configuration for creating a Supabase media adapter\n */\nexport interface SupabaseMediaAdapterConfig {\n client: SupabaseClient;\n bucketName?: string;\n}\n\n/**\n * Supabase implementation of the MediaAdapter interface\n */\nexport class SupabaseMediaAdapter implements MediaAdapter {\n private client: SupabaseClient;\n private bucketName: string;\n\n constructor(config: SupabaseMediaAdapterConfig) {\n this.client = config.client;\n this.bucketName = config.bucketName ?? 'media';\n }\n\n /**\n * Generates a unique storage path for a file\n */\n private generateStoragePath(filename: string): string {\n const timestamp = Date.now();\n const randomSuffix = Math.random().toString(36).substring(2, 8);\n const sanitizedFilename = filename.replace(/[^a-zA-Z0-9.-]/g, '_');\n return `${timestamp}-${randomSuffix}-${sanitizedFilename}`;\n }\n\n /**\n * Constructs the public URL for a stored file\n */\n private getPublicUrl(storagePath: string): string {\n const { data } = this.client.storage.from(this.bucketName).getPublicUrl(storagePath);\n return data.publicUrl;\n }\n\n /**\n * Maps a database row to MediaFile\n */\n private mapRowToMediaFile(row: MediaRow): MediaFile {\n return {\n id: row.id,\n filename: row.filename,\n url: this.getPublicUrl(row.storage_path),\n mimeType: row.mime_type,\n size: row.size,\n category: row.category as MediaCategory,\n createdAt: new Date(row.created_at),\n };\n }\n\n async upload(input: UploadMediaInput): Promise<MediaFile> {\n const storagePath = this.generateStoragePath(input.filename);\n\n // Upload file to Supabase Storage\n const { error: uploadError } = await this.client.storage\n .from(this.bucketName)\n .upload(storagePath, input.data, {\n contentType: input.mimeType,\n upsert: false,\n });\n\n if (uploadError) {\n throw new MediaError(\n `Failed to upload file: ${uploadError.message}`,\n 'UPLOAD_FAILED',\n uploadError.message\n );\n }\n\n // Create database record\n const { data, error: dbError } = await this.client\n .from('media')\n .insert({\n filename: input.filename,\n storage_path: storagePath,\n mime_type: input.mimeType,\n size: input.size,\n category: deriveCategory(input.mimeType),\n })\n .select()\n .single();\n\n if (dbError) {\n // Cleanup: delete uploaded file if DB insert fails\n await this.client.storage.from(this.bucketName).remove([storagePath]);\n throw new MediaError(\n `Failed to create media record: ${dbError.message}`,\n dbError.code,\n dbError.details\n );\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async getMedia(id: string): Promise<MediaFile | null> {\n const { data, error } = await this.client.from('media').select('*').eq('id', id).single();\n\n if (error) {\n if (error.code === 'PGRST116') {\n return null; // Not found\n }\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return this.mapRowToMediaFile(data as MediaRow);\n }\n\n async listMedia(filter?: MediaFilter): Promise<MediaFile[]> {\n let query = this.client.from('media').select('*');\n\n if (filter?.mimeType) {\n query = query.eq('mime_type', filter.mimeType);\n }\n\n if (filter?.category) {\n query = query.eq('category', filter.category);\n }\n\n query = query.order('created_at', { ascending: false });\n\n if (filter?.limit) {\n query = query.limit(filter.limit);\n }\n\n if (filter?.offset) {\n query = query.range(filter.offset, filter.offset + (filter.limit ?? 100) - 1);\n }\n\n const { data, error } = await query;\n\n if (error) {\n throw new MediaError(error.message, error.code, error.details);\n }\n\n return (data as MediaRow[]).map((row) => this.mapRowToMediaFile(row));\n }\n\n async deleteMedia(id: string): Promise<void> {\n // First get the media record to find the storage path\n const { data: mediaRecord, error: fetchError } = await this.client\n .from('media')\n .select('storage_path')\n .eq('id', id)\n .single();\n\n if (fetchError) {\n if (fetchError.code === 'PGRST116') {\n throw new MediaError(`Media not found: ${id}`, 'NOT_FOUND');\n }\n throw new MediaError(fetchError.message, fetchError.code, fetchError.details);\n }\n\n const storagePath = (mediaRecord as { storage_path: string }).storage_path;\n\n // Delete from storage\n const { error: storageError } = await this.client.storage\n .from(this.bucketName)\n .remove([storagePath]);\n\n if (storageError) {\n throw new MediaError(\n `Failed to delete file from storage: ${storageError.message}`,\n 'STORAGE_DELETE_FAILED',\n storageError.message\n );\n }\n\n // Delete database record\n const { error: dbError } = await this.client.from('media').delete().eq('id', id);\n\n if (dbError) {\n throw new MediaError(dbError.message, dbError.code, dbError.details);\n }\n }\n}\n\n/**\n * Creates a media adapter using Supabase\n */\nexport function createMediaAdapter(config: SupabaseMediaAdapterConfig): MediaAdapter {\n return new SupabaseMediaAdapter(config);\n}\n","import type { MediaAdapter, MediaFile, MediaFilter, UploadMediaInput } from './types';\nimport { ALL_ALLOWED_MIME_TYPES, MAX_FILE_SIZE } from './types';\n\n/**\n * Error thrown when media validation fails\n */\nexport class MediaValidationError extends Error {\n constructor(\n message: string,\n public readonly code: string\n ) {\n super(message);\n this.name = 'MediaValidationError';\n }\n}\n\n/**\n * Validates that the MIME type is allowed\n */\nfunction validateMimeType(mimeType: string): void {\n const allowed = ALL_ALLOWED_MIME_TYPES as readonly string[];\n if (!allowed.includes(mimeType)) {\n throw new MediaValidationError(\n `Invalid file type: ${mimeType}. Allowed types: ${ALL_ALLOWED_MIME_TYPES.join(', ')}`,\n 'INVALID_MIME_TYPE'\n );\n }\n}\n\n/**\n * Validates that the file size is within the allowed limit\n */\nfunction validateFileSize(size: number): void {\n if (size > MAX_FILE_SIZE) {\n throw new MediaValidationError(\n `File size exceeds maximum allowed size of ${MAX_FILE_SIZE / 1024 / 1024}MB`,\n 'FILE_TOO_LARGE'\n );\n }\n}\n\n/**\n * Handler for uploading a media file\n * Validates the file type, size, and delegates to the adapter\n */\nexport async function handleUploadMedia(\n adapter: MediaAdapter,\n input: UploadMediaInput\n): Promise<MediaFile> {\n validateMimeType(input.mimeType);\n validateFileSize(input.size);\n return adapter.upload(input);\n}\n\n/**\n * Handler for retrieving a media file by ID\n */\nexport async function handleGetMedia(adapter: MediaAdapter, id: string): Promise<MediaFile | null> {\n return adapter.getMedia(id);\n}\n\n/**\n * Handler for listing media files with optional filtering\n */\nexport async function handleListMedia(\n adapter: MediaAdapter,\n filter?: MediaFilter\n): Promise<MediaFile[]> {\n return adapter.listMedia(filter);\n}\n\n/**\n * Handler for deleting a media file\n */\nexport async function handleDeleteMedia(adapter: MediaAdapter, id: string): Promise<void> {\n return adapter.deleteMedia(id);\n}\n","import { createClient } from '@supabase/supabase-js';\nimport { createAuthAdapter } from '../auth';\nimport type { AuthAdapter } from '../auth';\nimport { createMediaAdapter } from '../media';\nimport type { MediaAdapter } from '../media';\nimport { createStorageAdapter } from '../storage';\nimport type { StorageAdapter } from '../storage';\n\nexport interface SupabaseAdapterFactoryStorageConfig {\n bucket?: string;\n}\n\nexport interface SupabaseAdapterFactoryConfig {\n url?: string;\n key?: string;\n storage?: SupabaseAdapterFactoryStorageConfig;\n}\n\nexport interface SupabaseAdapters {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n authAdapter: AuthAdapter;\n}\n\ninterface ProcessLike {\n env: Record<string, string | undefined>;\n}\n\nfunction readEnv(name: string): string | undefined {\n const processLike = (globalThis as typeof globalThis & { process?: ProcessLike }).process;\n return processLike?.env[name];\n}\n\nfunction resolveRequiredConfig(\n explicitValue: string | undefined,\n envName: 'SUPABASE_URL' | 'SUPABASE_SECRET_KEY'\n): string {\n const explicit = explicitValue?.trim();\n if (explicit) {\n return explicit;\n }\n\n const fromEnv = readEnv(envName)?.trim();\n if (fromEnv) {\n return fromEnv;\n }\n\n throw new Error(\n `Missing Supabase configuration: provide ${envName} in factory config or environment variable`\n );\n}\n\nfunction resolveBucketName(config: SupabaseAdapterFactoryConfig): string {\n const explicitBucket = config.storage?.bucket?.trim();\n if (explicitBucket) {\n return explicitBucket;\n }\n\n const envBucket = readEnv('SUPABASE_STORAGE_BUCKET')?.trim();\n if (envBucket) {\n return envBucket;\n }\n\n return 'media';\n}\n\nexport function createSupabaseAdapters(\n config: SupabaseAdapterFactoryConfig = {}\n): SupabaseAdapters {\n const url = resolveRequiredConfig(config.url, 'SUPABASE_URL');\n const key = resolveRequiredConfig(config.key, 'SUPABASE_SECRET_KEY');\n const bucketName = resolveBucketName(config);\n\n const client = createClient(url, key);\n\n return {\n storageAdapter: createStorageAdapter({ client }),\n mediaAdapter: createMediaAdapter({ client, bucketName }),\n authAdapter: createAuthAdapter({ client }),\n };\n}\n","import type { SupabaseClient } from '@supabase/supabase-js';\nimport type {\n AuthAdapter,\n AuthSession,\n AuthUser,\n OAuthResponse,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthError extends Error {\n constructor(\n message: string,\n public readonly code?: string,\n public readonly details?: string\n ) {\n super(message);\n this.name = 'AuthError';\n }\n}\n\nexport interface SupabaseAuthAdapterConfig {\n client: SupabaseClient;\n}\n\nexport class SupabaseAuthAdapter implements AuthAdapter {\n private client: SupabaseClient;\n\n constructor(config: SupabaseAuthAdapterConfig) {\n this.client = config.client;\n }\n\n private mapSupabaseUser(user: {\n id: string;\n email?: string;\n user_metadata?: Record<string, unknown>;\n }): AuthUser {\n if (!user.email) {\n throw new AuthError('User email is required', 'INVALID_USER');\n }\n\n return {\n id: user.id,\n email: user.email,\n metadata: user.user_metadata,\n };\n }\n\n async signInWithOAuth(input: SignInWithOAuthInput): Promise<OAuthResponse> {\n const { data, error } = await this.client.auth.signInWithOAuth({\n provider: input.provider,\n options: {\n redirectTo: input.redirectTo,\n },\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.url) {\n throw new AuthError('OAuth URL not provided', 'OAUTH_URL_MISSING');\n }\n\n return {\n url: data.url,\n provider: input.provider,\n };\n }\n\n async signInWithPassword(input: SignInWithPasswordInput): Promise<AuthSession> {\n const { data, error } = await this.client.auth.signInWithPassword({\n email: input.email,\n password: input.password,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session or user not returned', 'AUTH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async signOut(_accessToken: string): Promise<void> {\n const { error } = await this.client.auth.signOut();\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n }\n\n async verifySession(input: VerifySessionInput): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(input.accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n\n async refreshSession(refreshToken: string): Promise<AuthSession> {\n const { data, error } = await this.client.auth.refreshSession({\n refresh_token: refreshToken,\n });\n\n if (error) {\n throw new AuthError(error.message, error.status?.toString(), error.message);\n }\n\n if (!data.session || !data.user) {\n throw new AuthError('Session refresh failed', 'REFRESH_FAILED');\n }\n\n return {\n accessToken: data.session.access_token,\n refreshToken: data.session.refresh_token,\n expiresAt: data.session.expires_at ? new Date(data.session.expires_at * 1000) : undefined,\n user: this.mapSupabaseUser(data.user),\n };\n }\n\n async getCurrentUser(accessToken: string): Promise<AuthUser | null> {\n const { data, error } = await this.client.auth.getUser(accessToken);\n\n if (error) {\n return null;\n }\n\n if (!data.user) {\n return null;\n }\n\n return this.mapSupabaseUser(data.user);\n }\n}\n\nexport function createAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter {\n return new SupabaseAuthAdapter(config);\n}\n","import type {\n AuthAdapter,\n SignInWithOAuthInput,\n SignInWithPasswordInput,\n VerifySessionInput,\n} from './types';\n\nexport class AuthValidationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AuthValidationError';\n }\n}\n\nexport async function handleSignInWithOAuth(adapter: AuthAdapter, input: SignInWithOAuthInput) {\n if (!input.provider) {\n throw new AuthValidationError('Provider is required');\n }\n\n const validProviders = ['google', 'github', 'gitlab', 'azure', 'bitbucket'];\n if (!validProviders.includes(input.provider)) {\n throw new AuthValidationError(`Invalid provider. Must be one of: ${validProviders.join(', ')}`);\n }\n\n return await adapter.signInWithOAuth(input);\n}\n\n/**\n * Validate password strength\n * Requirements:\n * - Minimum 8 characters\n * - At least 3 of: uppercase, lowercase, numbers, special characters\n * - Not a common password\n */\nfunction validatePassword(password: string): void {\n if (password.length < 8) {\n throw new AuthValidationError('Password must be at least 8 characters');\n }\n\n const hasUpperCase = /[A-Z]/.test(password);\n const hasLowerCase = /[a-z]/.test(password);\n const hasNumbers = /\\d/.test(password);\n const hasSpecialChar = /[!@#$%^&*(),.?\":{}|<>_\\-+=\\[\\]\\\\/'`~]/.test(password);\n\n const complexityCount = [hasUpperCase, hasLowerCase, hasNumbers, hasSpecialChar].filter(\n Boolean\n ).length;\n\n if (complexityCount < 3) {\n throw new AuthValidationError(\n 'Password must contain at least 3 of: uppercase letters, lowercase letters, numbers, special characters'\n );\n }\n\n // Check against common passwords\n const commonPasswords = [\n 'password',\n 'password1',\n 'password123',\n '12345678',\n '123456789',\n 'qwerty',\n 'abc123',\n 'monkey',\n '1234567890',\n 'letmein',\n 'trustno1',\n 'dragon',\n 'baseball',\n 'iloveyou',\n 'master',\n 'sunshine',\n 'ashley',\n 'bailey',\n 'shadow',\n '123123',\n ];\n\n if (commonPasswords.includes(password.toLowerCase())) {\n throw new AuthValidationError('Password is too common. Please choose a stronger password.');\n }\n}\n\nexport async function handleSignInWithPassword(\n adapter: AuthAdapter,\n input: SignInWithPasswordInput\n) {\n if (!input.email || !input.password) {\n throw new AuthValidationError('Email and password are required');\n }\n\n if (!input.email.includes('@')) {\n throw new AuthValidationError('Invalid email format');\n }\n\n // Strengthen password policy (Fix #5)\n validatePassword(input.password);\n\n return await adapter.signInWithPassword(input);\n}\n\nexport async function handleSignOut(adapter: AuthAdapter, accessToken: string) {\n if (!accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n return await adapter.signOut(accessToken);\n}\n\nexport async function handleVerifySession(adapter: AuthAdapter, input: VerifySessionInput) {\n if (!input.accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n // Enforce token expiration (Fix #7)\n if (input.expiresAt) {\n const now = new Date();\n const expiresAt = input.expiresAt instanceof Date ? input.expiresAt : new Date(input.expiresAt);\n\n if (now > expiresAt) {\n throw new AuthValidationError('Token has expired');\n }\n }\n\n const user = await adapter.verifySession(input);\n\n if (!user) {\n throw new AuthValidationError('Invalid or expired token');\n }\n\n return user;\n}\n\nexport async function handleRefreshSession(adapter: AuthAdapter, refreshToken: string) {\n if (!refreshToken) {\n throw new AuthValidationError('Refresh token is required');\n }\n\n return await adapter.refreshSession(refreshToken);\n}\n\nexport async function handleGetCurrentUser(adapter: AuthAdapter, accessToken: string) {\n if (!accessToken) {\n throw new AuthValidationError('Access token is required');\n }\n\n return await adapter.getCurrentUser(accessToken);\n}\n","import type { AuthAdapter, AuthUser } from './types';\n\nexport interface AuthenticatedRequest {\n user: AuthUser;\n accessToken: string;\n}\n\nexport interface AuthMiddlewareConfig {\n adapter: AuthAdapter;\n extractToken?: (headers: Record<string, string | undefined>) => string | null;\n}\n\nexport function createAuthMiddleware(config: AuthMiddlewareConfig) {\n const extractToken =\n config.extractToken ||\n ((headers: Record<string, string | undefined>) => {\n const authHeader = headers.authorization || headers.Authorization;\n if (!authHeader) return null;\n\n const parts = authHeader.split(' ');\n if (parts.length !== 2 || parts[0] !== 'Bearer') return null;\n\n return parts[1];\n });\n\n return async function authenticate(\n headers: Record<string, string | undefined>\n ): Promise<AuthenticatedRequest> {\n const token = extractToken(headers);\n\n if (!token) {\n throw new Error('No authentication token provided');\n }\n\n const user = await config.adapter.verifySession({ accessToken: token });\n\n if (!user) {\n throw new Error('Invalid or expired token');\n }\n\n return {\n user,\n accessToken: token,\n };\n };\n}\n","/**\n * Generates a cryptographically secure random CSRF token\n * @returns A hex-encoded random token (32 bytes = 64 hex characters)\n */\nexport function generateCsrfToken(): string {\n const bytes = new Uint8Array(32);\n crypto.getRandomValues(bytes);\n return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Validates CSRF tokens using double-submit cookie pattern\n * Compares the token from the cookie with the token from the request header\n *\n * @param cookieToken - Token from the cookie\n * @param headerToken - Token from the X-CSRF-Token header\n * @returns true if tokens match and are valid, false otherwise\n */\nexport function validateCsrfToken(\n cookieToken: string | undefined,\n headerToken: string | undefined\n): boolean {\n // Both tokens must be present\n if (!cookieToken || !headerToken) {\n return false;\n }\n\n // Both tokens must be non-empty strings\n if (cookieToken.trim() === '' || headerToken.trim() === '') {\n return false;\n }\n\n // Tokens must match exactly\n return cookieToken === headerToken;\n}\n","/**\n * Configuration for rate limiter\n */\nexport interface RateLimiterConfig {\n /** Time window in milliseconds */\n windowMs: number;\n /** Maximum number of requests allowed in the time window */\n maxRequests: number;\n}\n\n/**\n * Result of rate limit check\n */\nexport interface RateLimitResult {\n /** Whether the request is allowed */\n allowed: boolean;\n /** Number of seconds to wait before retrying (only set if not allowed) */\n retryAfter?: number;\n}\n\n/**\n * Entry in the rate limiter tracking map\n */\ninterface RateLimitEntry {\n /** Timestamps of requests in the current window */\n timestamps: number[];\n /** Timeout ID for auto-cleanup */\n timeoutId?: number;\n}\n\n/**\n * Rate limiter using sliding window algorithm with in-memory storage\n */\nexport interface RateLimiter {\n /**\n * Check if a request from the given key is allowed\n * @param key - Unique identifier for the requester (e.g., IP address, user ID)\n * @returns Result indicating if request is allowed and retry time if not\n */\n check(key: string): RateLimitResult;\n\n /**\n * Reset the rate limit for a specific key\n * @param key - The key to reset\n */\n reset(key: string): void;\n}\n\n/**\n * Creates a new rate limiter instance\n * @param config - Configuration for the rate limiter\n * @returns A new RateLimiter instance\n */\nexport function createRateLimiter(config: RateLimiterConfig): RateLimiter {\n const { windowMs, maxRequests } = config;\n const entries = new Map<string, RateLimitEntry>();\n\n /**\n * Clean up old timestamps from an entry\n */\n function cleanupEntry(entry: RateLimitEntry, now: number): void {\n const windowStart = now - windowMs;\n entry.timestamps = entry.timestamps.filter((ts) => ts > windowStart);\n }\n\n /**\n * Schedule auto-cleanup for an entry\n */\n function scheduleCleanup(key: string): void {\n const entry = entries.get(key);\n if (!entry) return;\n\n // Clear existing timeout\n if (entry.timeoutId) {\n clearTimeout(entry.timeoutId);\n }\n\n // Schedule cleanup after window expires\n entry.timeoutId = setTimeout(() => {\n const currentEntry = entries.get(key);\n if (currentEntry) {\n cleanupEntry(currentEntry, Date.now());\n\n // Remove entry if no more timestamps\n if (currentEntry.timestamps.length === 0) {\n entries.delete(key);\n } else {\n // Reschedule if still has timestamps\n scheduleCleanup(key);\n }\n }\n }, windowMs);\n }\n\n return {\n check(key: string): RateLimitResult {\n const now = Date.now();\n let entry = entries.get(key);\n\n if (!entry) {\n entry = { timestamps: [] };\n entries.set(key, entry);\n }\n\n // Clean up old timestamps\n cleanupEntry(entry, now);\n\n // Check if limit exceeded\n if (entry.timestamps.length >= maxRequests) {\n const oldestTimestamp = entry.timestamps[0] ?? now;\n const retryAfterMs = oldestTimestamp + windowMs - now;\n const retryAfterSeconds = Math.ceil(retryAfterMs / 1000);\n\n return {\n allowed: false,\n retryAfter: retryAfterSeconds,\n };\n }\n\n // Allow request and track timestamp\n entry.timestamps.push(now);\n scheduleCleanup(key);\n\n return {\n allowed: true,\n };\n },\n\n reset(key: string): void {\n const entry = entries.get(key);\n if (entry?.timeoutId) {\n clearTimeout(entry.timeoutId);\n }\n entries.delete(key);\n },\n };\n}\n","import { resolveMediaReferences } from '../media/resolve';\nimport type { MediaAdapter } from '../media/types';\nimport type { Navigation, Page, StorageAdapter } from '../storage/types';\nimport type {\n AllNavigationsExportResponse,\n AllPagesExportResponse,\n MediaExportEntry,\n NavigationExportResponse,\n PageExportResponse,\n SiteExportResponse,\n} from './types';\n\n/**\n * Generates a Content-Disposition header value for file download\n */\nfunction contentDisposition(filename: string): string {\n return `attachment; filename=\"${filename}\"`;\n}\n\n/**\n * Converts a Page to a PageExportResponse with resolved media references\n */\nasync function toPageExport(page: Page, mediaAdapter: MediaAdapter): Promise<PageExportResponse> {\n const resolvedSections = await resolveMediaReferences(page.sections, mediaAdapter);\n\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: resolvedSections,\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/pages/:slug\n * Returns complete page JSON with resolved media URLs\n */\nexport async function handleExportPage(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter,\n slug: string\n): Promise<{ data: PageExportResponse; contentDisposition: string } | null> {\n const page = await storageAdapter.getPage(slug);\n\n if (!page) {\n return null;\n }\n\n const data = await toPageExport(page, mediaAdapter);\n\n return {\n data,\n contentDisposition: contentDisposition(`${page.slug}.json`),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/pages\n * Returns all pages as JSON array with resolved media URLs\n */\nexport async function handleExportAllPages(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter\n): Promise<{ data: AllPagesExportResponse; contentDisposition: string }> {\n const pages = await storageAdapter.listPages();\n\n const exportedPages: PageExportResponse[] = [];\n for (const page of pages) {\n exportedPages.push(await toPageExport(page, mediaAdapter));\n }\n\n const data: AllPagesExportResponse = {\n pages: exportedPages,\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('pages-export.json'),\n };\n}\n\n/**\n * Converts a Navigation to a NavigationExportResponse\n */\nfunction toNavigationExport(nav: Navigation): NavigationExportResponse {\n return {\n id: nav.id,\n name: nav.name,\n items: nav.items,\n updatedAt: nav.updatedAt.toISOString(),\n };\n}\n\n/**\n * Handler for GET /api/cms/export/navigation\n * Returns all navigation structures as JSON\n */\nexport async function handleExportNavigations(\n storageAdapter: StorageAdapter\n): Promise<{ data: AllNavigationsExportResponse; contentDisposition: string }> {\n const navigations = await storageAdapter.listNavigations();\n\n const data: AllNavigationsExportResponse = {\n navigations: navigations.map(toNavigationExport),\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('navigation-export.json'),\n };\n}\n\n/**\n * Handler for GET /api/cms/export\n * Returns complete site content (pages, navigation, media metadata) as JSON\n */\nexport async function handleExportSite(\n storageAdapter: StorageAdapter,\n mediaAdapter: MediaAdapter\n): Promise<{ data: SiteExportResponse; contentDisposition: string }> {\n // Export pages with resolved media\n const pages = await storageAdapter.listPages();\n const exportedPages: PageExportResponse[] = [];\n for (const page of pages) {\n exportedPages.push(await toPageExport(page, mediaAdapter));\n }\n\n // Export navigations\n const navigations = await storageAdapter.listNavigations();\n const exportedNavigations = navigations.map(toNavigationExport);\n\n // Export media metadata\n const mediaFiles = await mediaAdapter.listMedia();\n const exportedMedia: MediaExportEntry[] = mediaFiles.map((file) => ({\n id: file.id,\n filename: file.filename,\n url: file.url,\n mimeType: file.mimeType,\n size: file.size,\n createdAt: file.createdAt.toISOString(),\n }));\n\n const data: SiteExportResponse = {\n pages: exportedPages,\n navigations: exportedNavigations,\n media: exportedMedia,\n exportedAt: new Date().toISOString(),\n };\n\n return {\n data,\n contentDisposition: contentDisposition('site-export.json'),\n };\n}\n","export interface AuditEntry {\n action: string;\n entity: string;\n entityId: string;\n userId?: string;\n timestamp: Date;\n metadata?: Record<string, unknown>;\n}\n\ntype AuditSink = (entry: AuditEntry) => void | Promise<void>;\n\nconst defaultSink: AuditSink = (entry) => {\n const output = JSON.stringify(entry, null, 2);\n // Use globalThis to access console in both Node.js and browser environments\n // biome-ignore lint/suspicious/noExplicitAny: console may not be in type definitions\n (globalThis as any).console?.log?.(output);\n};\n\nexport function createAuditLogger(sink: AuditSink = defaultSink) {\n return {\n log: async (entry: Omit<AuditEntry, 'timestamp'>) => {\n await sink({\n ...entry,\n timestamp: new Date(),\n });\n },\n };\n}\n\nexport interface WithAuditLogOptions {\n action: string;\n entity: string;\n extractEntityId: (args: unknown[]) => string;\n extractUserId?: (args: unknown[]) => string | undefined;\n metadata?: (args: unknown[]) => Record<string, unknown> | undefined;\n}\n\n// biome-ignore lint/suspicious/noExplicitAny: generic wrapper for any handler signature\nexport function withAuditLog<T extends (...args: any[]) => any>(\n handler: T,\n options: WithAuditLogOptions,\n sink?: AuditSink\n): T {\n const logger = createAuditLogger(sink);\n\n return (async (...args: Parameters<T>): Promise<ReturnType<T>> => {\n const result = await handler(...args);\n\n await logger.log({\n action: options.action,\n entity: options.entity,\n entityId: options.extractEntityId(args),\n userId: options.extractUserId?.(args),\n metadata: options.metadata?.(args),\n });\n\n return result;\n }) as T;\n}\n"],"mappings":"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","names":["MAX_FILE_SIZE","sanitizeHtml","MAX_FILE_SIZE","MAX_FILE_SIZE"]}