@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/media/resolve.ts","../../src/delivery/handlers.ts","../../src/media/types.ts","../../src/media/handlers.ts","../../src/utils/sanitize.ts","../../src/utils/slug.ts","../../src/storage/handlers.ts","../../src/next/factories.ts","../../src/auth/handlers.ts","../../src/next/auth-factories.ts"],"sourcesContent":["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 { 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 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 { handleGetPageBySlug, handleListPages } from '../delivery';\nimport {\n MediaValidationError,\n handleDeleteMedia,\n handleGetMedia,\n handleListMedia,\n handleUploadMedia,\n} from '../media';\nimport type { MediaAdapter, UploadMediaInput } from '../media';\nimport {\n StorageValidationError,\n handleCreateNavigation,\n handleCreatePage,\n handleDeleteNavigation,\n handleDeletePage,\n handleUpdateNavigation,\n handleUpdatePage,\n} from '../storage';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n} from '../storage';\n\ntype JsonRecord = Record<string, unknown>;\ntype ParsedPageSection = {\n id?: string;\n type: string;\n data: JsonRecord;\n};\n\ntype ParsedUpdatePagePatch = {\n slug?: string;\n pageType?: string;\n title?: string;\n sections?: ParsedPageSection[];\n};\n\ninterface RequestLike {\n json(): Promise<unknown>;\n formData(): Promise<FormDataLike>;\n}\n\ninterface FormDataLike {\n get(name: string): unknown;\n}\n\ninterface FileLike {\n name: string;\n type: string;\n size: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n}\n\ninterface ResponseLike {\n status: number;\n json(): Promise<unknown>;\n}\n\ninterface ResponseConstructorLike {\n new (body?: string, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n}\n\ninterface RouteContext<TParams extends Record<string, string | string[]>> {\n params: TParams | Promise<TParams>;\n}\n\nexport interface NextPagesRouteConfig {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextPageBySlugRouteConfig {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextPageByIdRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nexport interface NextMediaRouteConfig {\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextMediaByIdRouteConfig {\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextNavigationRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nexport interface NextNavigationByIdRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nfunction getResponseConstructor(): ResponseConstructorLike {\n const responseCtor = (globalThis as typeof globalThis & { Response?: ResponseConstructorLike })\n .Response;\n\n if (!responseCtor) {\n throw new Error('Response constructor is not available in this runtime');\n }\n\n return responseCtor;\n}\n\nfunction jsonResponse(data: unknown, status = 200): ResponseLike {\n const ResponseCtor = getResponseConstructor();\n\n return new ResponseCtor(JSON.stringify(data), {\n status,\n headers: {\n 'content-type': 'application/json',\n },\n });\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return 'Unknown error';\n}\n\nfunction errorResponse(error: unknown, fallbackStatus = 500): ResponseLike {\n if (\n error instanceof StorageValidationError ||\n error instanceof MediaValidationError ||\n error instanceof SyntaxError\n ) {\n return jsonResponse({ error: getErrorMessage(error) }, 400);\n }\n\n return jsonResponse({ error: getErrorMessage(error) }, fallbackStatus);\n}\n\nasync function resolveParams<TParams extends Record<string, string | string[]>>(\n context: RouteContext<TParams>\n): Promise<TParams> {\n return context.params;\n}\n\nfunction normalizeSlug(slug: string | string[]): string {\n return Array.isArray(slug) ? slug.join('/') : slug;\n}\n\nfunction asObject(value: unknown): JsonRecord | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null;\n }\n\n return value as JsonRecord;\n}\n\nfunction isFileLike(value: unknown): value is FileLike {\n if (!value || typeof value !== 'object') {\n return false;\n }\n\n const candidate = value as {\n name?: unknown;\n type?: unknown;\n size?: unknown;\n arrayBuffer?: unknown;\n };\n\n return (\n typeof candidate.name === 'string' &&\n typeof candidate.type === 'string' &&\n typeof candidate.size === 'number' &&\n typeof candidate.arrayBuffer === 'function'\n );\n}\n\nfunction parseStringField(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction parsePageSections(value: unknown): ParsedPageSection[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const sections: ParsedPageSection[] = [];\n\n for (const entry of value) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n return undefined;\n }\n\n const sectionCandidate = entry as {\n id?: unknown;\n type?: unknown;\n data?: unknown;\n };\n\n if (\n (sectionCandidate.id !== undefined && typeof sectionCandidate.id !== 'string') ||\n typeof sectionCandidate.type !== 'string' ||\n !sectionCandidate.data ||\n typeof sectionCandidate.data !== 'object' ||\n Array.isArray(sectionCandidate.data)\n ) {\n return undefined;\n }\n\n sections.push({\n id: sectionCandidate.id,\n type: sectionCandidate.type,\n data: sectionCandidate.data as JsonRecord,\n });\n }\n\n return sections;\n}\n\nfunction normalizePageSections(\n sections: ParsedPageSection[] | undefined,\n existingSections: PageSection[] = []\n): PageSection[] | undefined {\n if (!sections) {\n return undefined;\n }\n\n return sections.map((section, index) => ({\n id: section.id ?? existingSections[index]?.id ?? `${section.type}-${index + 1}`,\n type: section.type,\n data: section.data,\n }));\n}\n\nfunction parseNavigationItems(value: unknown): NavigationItem[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const items: NavigationItem[] = [];\n\n for (const entry of value) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n return undefined;\n }\n\n const itemCandidate = entry as {\n label?: unknown;\n href?: unknown;\n children?: unknown;\n };\n\n if (typeof itemCandidate.label !== 'string' || typeof itemCandidate.href !== 'string') {\n return undefined;\n }\n\n const children =\n itemCandidate.children === undefined\n ? undefined\n : parseNavigationItems(itemCandidate.children);\n\n if (itemCandidate.children !== undefined && !children) {\n return undefined;\n }\n\n items.push({\n label: itemCandidate.label,\n href: itemCandidate.href,\n children,\n });\n }\n\n return items;\n}\n\nfunction parseCreatePageInput(payload: JsonRecord): CreatePageInput | null {\n const pageType = parseStringField(payload.pageType);\n const title = parseStringField(payload.title);\n const slug = parseStringField(payload.slug);\n const sections = normalizePageSections(parsePageSections(payload.sections));\n\n if (!pageType || !title) {\n return null;\n }\n\n if (payload.sections !== undefined && !sections) {\n return null;\n }\n\n return {\n pageType,\n title,\n slug,\n sections,\n };\n}\n\nfunction parseUpdatePagePatch(payload: JsonRecord): ParsedUpdatePagePatch | null {\n const slug = parseStringField(payload.slug);\n const pageType = parseStringField(payload.pageType);\n const title = parseStringField(payload.title);\n const sections = parsePageSections(payload.sections);\n\n if (payload.slug !== undefined && !slug) {\n return null;\n }\n if (payload.pageType !== undefined && !pageType) {\n return null;\n }\n if (payload.title !== undefined && !title) {\n return null;\n }\n if (payload.sections !== undefined && !sections) {\n return null;\n }\n\n return {\n slug,\n pageType,\n title,\n sections,\n };\n}\n\nfunction parseCreateNavigationInput(payload: JsonRecord): CreateNavigationInput | null {\n const name = parseStringField(payload.name);\n const items = parseNavigationItems(payload.items);\n\n if (!name || !items) {\n return null;\n }\n\n return {\n name,\n items,\n };\n}\n\nfunction parseUpdateNavigationPatch(payload: JsonRecord): Omit<UpdateNavigationInput, 'id'> | null {\n const name = parseStringField(payload.name);\n const items = payload.items === undefined ? undefined : parseNavigationItems(payload.items);\n\n if (payload.name !== undefined && !name) {\n return null;\n }\n if (payload.items !== undefined && !items) {\n return null;\n }\n\n return {\n name,\n items,\n };\n}\n\nfunction toPageResponse(page: Page): Record<string, unknown> {\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: page.sections,\n meta: {\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n },\n };\n}\n\nfunction toNavigationResponse(navigation: Navigation): Record<string, unknown> {\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\nexport function createNextPagesRoute(config: NextPagesRouteConfig) {\n return {\n GET: async (_request: RequestLike): Promise<ResponseLike> => {\n try {\n const pages = await handleListPages(config.storageAdapter, config.mediaAdapter);\n return jsonResponse(pages);\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const createInput = parseCreatePageInput(payload);\n if (!createInput) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const page = await handleCreatePage(config.storageAdapter, createInput);\n return jsonResponse(page, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextPageBySlugRoute(config: NextPageBySlugRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const page = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizeSlug(slug)\n );\n\n if (!page) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n return jsonResponse(page);\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const normalizedSlug = normalizeSlug(slug);\n const existingPage = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizedSlug\n );\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const pagePatch = parseUpdatePagePatch(payload);\n if (!pagePatch) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const normalizedSections = normalizePageSections(pagePatch.sections, existingPage.sections);\n\n const page = await handleUpdatePage(config.storageAdapter, {\n ...pagePatch,\n sections: normalizedSections,\n id: existingPage.id,\n });\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const existingPage = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizeSlug(slug)\n );\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n await handleDeletePage(config.storageAdapter, existingPage.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nexport function createNextPageByIdRoute(config: NextPageByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const page = await config.storageAdapter.getPageById(id);\n\n if (!page) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingPage = await config.storageAdapter.getPageById(id);\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const pagePatch = parseUpdatePagePatch(payload);\n if (!pagePatch) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const normalizedSections = normalizePageSections(pagePatch.sections, existingPage.sections);\n\n const page = await handleUpdatePage(config.storageAdapter, {\n ...pagePatch,\n sections: normalizedSections,\n id: existingPage.id,\n });\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingPage = await config.storageAdapter.getPageById(id);\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n await handleDeletePage(config.storageAdapter, existingPage.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nexport function createNextMediaRoute(config: NextMediaRouteConfig) {\n return {\n GET: async (_request: RequestLike): Promise<ResponseLike> => {\n try {\n const media = await handleListMedia(config.mediaAdapter);\n return jsonResponse(media);\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const formData = await request.formData();\n const file = formData.get('file');\n\n if (!isFileLike(file)) {\n return jsonResponse({ error: 'No file provided' }, 400);\n }\n\n const input: UploadMediaInput = {\n filename: file.name,\n mimeType: file.type,\n size: file.size,\n data: await file.arrayBuffer(),\n };\n\n const mediaFile = await handleUploadMedia(config.mediaAdapter, input);\n return jsonResponse(mediaFile, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextMediaByIdRoute(config: NextMediaByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const media = await handleGetMedia(config.mediaAdapter, id);\n\n if (!media) {\n return jsonResponse({ error: 'Media not found' }, 404);\n }\n\n return jsonResponse(media);\n } catch (error) {\n return errorResponse(error);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n await handleDeleteMedia(config.mediaAdapter, id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nexport function createNextNavigationRoute(config: NextNavigationRouteConfig) {\n return {\n GET: async (_request: RequestLike): Promise<ResponseLike> => {\n try {\n const navigations = await config.storageAdapter.listNavigations();\n return jsonResponse(navigations.map(toNavigationResponse));\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const createInput = parseCreateNavigationInput(payload);\n if (!createInput) {\n return jsonResponse({ error: 'Invalid navigation payload' }, 400);\n }\n\n const navigation = await handleCreateNavigation(config.storageAdapter, createInput);\n\n return jsonResponse(navigation, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextNavigationByIdRoute(config: NextNavigationByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const navigation = await config.storageAdapter.getNavigationById(id);\n\n if (!navigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n return jsonResponse(toNavigationResponse(navigation));\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingNavigation = await config.storageAdapter.getNavigationById(id);\n\n if (!existingNavigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const navigationPatch = parseUpdateNavigationPatch(payload);\n if (!navigationPatch) {\n return jsonResponse({ error: 'Invalid navigation payload' }, 400);\n }\n\n const navigation = await handleUpdateNavigation(config.storageAdapter, {\n ...navigationPatch,\n id: existingNavigation.id,\n });\n\n return jsonResponse(navigation);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingNavigation = await config.storageAdapter.getNavigationById(id);\n\n if (!existingNavigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n await handleDeleteNavigation(config.storageAdapter, existingNavigation.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\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 {\n AuthValidationError,\n handleGetCurrentUser,\n handleRefreshSession,\n handleSignInWithOAuth,\n handleSignInWithPassword,\n handleSignOut,\n handleVerifySession,\n} from '../auth';\nimport type { AuthAdapter, SignInWithOAuthInput, SignInWithPasswordInput } from '../auth';\n\ninterface RequestLike {\n json(): Promise<unknown>;\n headers: {\n get(name: string): string | null | undefined;\n };\n}\n\ninterface ResponseLike {\n status: number;\n json(): Promise<unknown>;\n}\n\ninterface ResponseConstructorLike {\n new (body?: string, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n json(data: unknown, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n}\n\nexport interface NextAuthOAuthRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthSignInRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthSignOutRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthVerifyRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthRefreshRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthCurrentUserRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nfunction extractBearerToken(request: RequestLike): string | null {\n const authHeader = request.headers.get('authorization') ?? request.headers.get('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] ?? null;\n}\n\nexport function createNextAuthOAuthRoute(\n config: NextAuthOAuthRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const input = body as SignInWithOAuthInput;\n\n const result = await handleSignInWithOAuth(config.authAdapter, input);\n\n return Response.json({ data: result }, { status: 200 });\n } catch (err) {\n if (err instanceof AuthValidationError) {\n return Response.json(\n { error: { message: err.message, code: 'VALIDATION_ERROR' } },\n { status: 400 }\n );\n }\n\n const message = err instanceof Error ? err.message : 'OAuth initialization failed';\n return Response.json({ error: { message, code: 'OAUTH_ERROR' } }, { status: 500 });\n }\n };\n}\n\nexport function createNextAuthSignInRoute(\n config: NextAuthSignInRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const input = body as SignInWithPasswordInput;\n\n const session = await handleSignInWithPassword(config.authAdapter, input);\n\n return Response.json(session, { status: 200 });\n } catch (err) {\n if (err instanceof AuthValidationError) {\n return Response.json(\n { error: { message: err.message, code: 'VALIDATION_ERROR' } },\n { status: 400 }\n );\n }\n\n const message = err instanceof Error ? err.message : 'Sign in failed';\n return Response.json({ error: { message, code: 'AUTH_ERROR' } }, { status: 401 });\n }\n };\n}\n\nexport function createNextAuthSignOutRoute(\n config: NextAuthSignOutRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n await handleSignOut(config.authAdapter, token);\n\n return Response.json({ message: 'Signed out successfully' }, { status: 200 });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Sign out failed';\n return Response.json({ error: { message, code: 'SIGNOUT_ERROR' } }, { status: 500 });\n }\n };\n}\n\nexport function createNextAuthVerifyRoute(\n config: NextAuthVerifyRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleVerifySession(config.authAdapter, { accessToken: token });\n\n if (!user) {\n return Response.json(\n { error: { message: 'Invalid token', code: 'INVALID_TOKEN' } },\n { status: 401 }\n );\n }\n\n return Response.json(user, { status: 200 });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Verification failed';\n return Response.json({ error: { message, code: 'VERIFY_ERROR' } }, { status: 401 });\n }\n };\n}\n\nexport function createNextAuthRefreshRoute(\n config: NextAuthRefreshRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const { refreshToken } = body as { refreshToken: string };\n\n if (!refreshToken) {\n return Response.json(\n { error: { message: 'Refresh token required', code: 'NO_REFRESH_TOKEN' } },\n { status: 400 }\n );\n }\n\n const session = await handleRefreshSession(config.authAdapter, refreshToken);\n\n return Response.json(session, { status: 200 });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Refresh failed';\n return Response.json({ error: { message, code: 'REFRESH_ERROR' } }, { status: 401 });\n }\n };\n}\n\nexport function createNextAuthCurrentUserRoute(\n config: NextAuthCurrentUserRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function GET(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleGetCurrentUser(config.authAdapter, token);\n\n if (!user) {\n return Response.json(\n { error: { message: 'User not found', code: 'USER_NOT_FOUND' } },\n { status: 401 }\n );\n }\n\n return Response.json(user, { status: 200 });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Failed to get user';\n return Response.json({ error: { message, code: 'GET_USER_ERROR' } }, { status: 500 });\n }\n };\n}\n\nexport function createAuthenticatedRoute<T>(\n authAdapter: AuthAdapter,\n Response: ResponseConstructorLike,\n handler: (request: RequestLike, user: { id: string; email: string }) => Promise<T>\n) {\n return async (request: RequestLike): Promise<T | ResponseLike> => {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'Authentication required', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleVerifySession(authAdapter, { accessToken: token });\n if (!user) {\n return Response.json(\n { error: { message: 'Invalid or expired token', code: 'INVALID_TOKEN' } },\n { status: 401 }\n );\n }\n\n return handler(request, user);\n };\n}\n"],"mappings":"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","names":["toPageResponse"]}
1
+ {"version":3,"sources":["../../src/media/resolve.ts","../../src/delivery/handlers.ts","../../src/media/types.ts","../../src/media/handlers.ts","../../src/utils/sanitize.ts","../../src/utils/slug.ts","../../src/storage/handlers.ts","../../src/next/factories.ts","../../src/auth/handlers.ts","../../src/next/auth-factories.ts"],"sourcesContent":["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 { 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 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 { handleGetPageBySlug, handleListPages } from '../delivery';\nimport {\n MediaValidationError,\n handleDeleteMedia,\n handleGetMedia,\n handleListMedia,\n handleUploadMedia,\n} from '../media';\nimport type { MediaAdapter, MediaCategory, MediaFilter, UploadMediaInput } from '../media';\nimport {\n StorageValidationError,\n handleCreateNavigation,\n handleCreatePage,\n handleDeleteNavigation,\n handleDeletePage,\n handleUpdateNavigation,\n handleUpdatePage,\n} from '../storage';\nimport type {\n CreateNavigationInput,\n CreatePageInput,\n Navigation,\n NavigationItem,\n Page,\n PageSection,\n StorageAdapter,\n UpdateNavigationInput,\n} from '../storage';\n\ntype JsonRecord = Record<string, unknown>;\ntype ParsedPageSection = {\n id?: string;\n type: string;\n data: JsonRecord;\n};\n\ntype ParsedUpdatePagePatch = {\n slug?: string;\n pageType?: string;\n title?: string;\n sections?: ParsedPageSection[];\n};\n\ninterface RequestLike {\n url?: string;\n json(): Promise<unknown>;\n formData(): Promise<FormDataLike>;\n}\n\ninterface FormDataLike {\n get(name: string): unknown;\n}\n\ninterface FileLike {\n name: string;\n type: string;\n size: number;\n arrayBuffer(): Promise<ArrayBuffer>;\n}\n\ninterface ResponseLike {\n status: number;\n json(): Promise<unknown>;\n}\n\ninterface ResponseConstructorLike {\n new (body?: string, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n}\n\ninterface RouteContext<TParams extends Record<string, string | string[]>> {\n params: TParams | Promise<TParams>;\n}\n\nexport interface NextPagesRouteConfig {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextPageBySlugRouteConfig {\n storageAdapter: StorageAdapter;\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextPageByIdRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nexport interface NextMediaRouteConfig {\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextMediaByIdRouteConfig {\n mediaAdapter: MediaAdapter;\n}\n\nexport interface NextNavigationRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nexport interface NextNavigationByIdRouteConfig {\n storageAdapter: StorageAdapter;\n}\n\nfunction getResponseConstructor(): ResponseConstructorLike {\n const responseCtor = (globalThis as typeof globalThis & { Response?: ResponseConstructorLike })\n .Response;\n\n if (!responseCtor) {\n throw new Error('Response constructor is not available in this runtime');\n }\n\n return responseCtor;\n}\n\nfunction jsonResponse(data: unknown, status = 200): ResponseLike {\n const ResponseCtor = getResponseConstructor();\n\n return new ResponseCtor(JSON.stringify(data), {\n status,\n headers: {\n 'content-type': 'application/json',\n },\n });\n}\n\nfunction getErrorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return 'Unknown error';\n}\n\nfunction errorResponse(error: unknown, fallbackStatus = 500): ResponseLike {\n // Only expose error messages for known error types\n if (\n error instanceof StorageValidationError ||\n error instanceof MediaValidationError ||\n error instanceof SyntaxError\n ) {\n return jsonResponse({ error: getErrorMessage(error) }, 400);\n }\n\n // For unknown errors, return a generic message to avoid leaking internal details\n return jsonResponse({ error: 'Internal Server Error' }, fallbackStatus);\n}\n\nasync function resolveParams<TParams extends Record<string, string | string[]>>(\n context: RouteContext<TParams>\n): Promise<TParams> {\n return context.params;\n}\n\nfunction normalizeSlug(slug: string | string[]): string {\n return Array.isArray(slug) ? slug.join('/') : slug;\n}\n\nfunction asObject(value: unknown): JsonRecord | null {\n if (!value || typeof value !== 'object' || Array.isArray(value)) {\n return null;\n }\n\n return value as JsonRecord;\n}\n\nfunction isFileLike(value: unknown): value is FileLike {\n if (!value || typeof value !== 'object') {\n return false;\n }\n\n const candidate = value as {\n name?: unknown;\n type?: unknown;\n size?: unknown;\n arrayBuffer?: unknown;\n };\n\n return (\n typeof candidate.name === 'string' &&\n typeof candidate.type === 'string' &&\n typeof candidate.size === 'number' &&\n typeof candidate.arrayBuffer === 'function'\n );\n}\n\nfunction parseStringField(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction parsePageSections(value: unknown): ParsedPageSection[] | undefined {\n if (value === undefined) {\n return undefined;\n }\n\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const sections: ParsedPageSection[] = [];\n\n for (const entry of value) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n return undefined;\n }\n\n const sectionCandidate = entry as {\n id?: unknown;\n type?: unknown;\n data?: unknown;\n };\n\n if (\n (sectionCandidate.id !== undefined && typeof sectionCandidate.id !== 'string') ||\n typeof sectionCandidate.type !== 'string' ||\n !sectionCandidate.data ||\n typeof sectionCandidate.data !== 'object' ||\n Array.isArray(sectionCandidate.data)\n ) {\n return undefined;\n }\n\n sections.push({\n id: sectionCandidate.id,\n type: sectionCandidate.type,\n data: sectionCandidate.data as JsonRecord,\n });\n }\n\n return sections;\n}\n\nfunction normalizePageSections(\n sections: ParsedPageSection[] | undefined,\n existingSections: PageSection[] = []\n): PageSection[] | undefined {\n if (!sections) {\n return undefined;\n }\n\n return sections.map((section, index) => ({\n id: section.id ?? existingSections[index]?.id ?? `${section.type}-${index + 1}`,\n type: section.type,\n data: section.data,\n }));\n}\n\nfunction parseNavigationItems(value: unknown): NavigationItem[] | undefined {\n if (!Array.isArray(value)) {\n return undefined;\n }\n\n const items: NavigationItem[] = [];\n\n for (const entry of value) {\n if (!entry || typeof entry !== 'object' || Array.isArray(entry)) {\n return undefined;\n }\n\n const itemCandidate = entry as {\n label?: unknown;\n href?: unknown;\n children?: unknown;\n };\n\n if (typeof itemCandidate.label !== 'string' || typeof itemCandidate.href !== 'string') {\n return undefined;\n }\n\n const children =\n itemCandidate.children === undefined\n ? undefined\n : parseNavigationItems(itemCandidate.children);\n\n if (itemCandidate.children !== undefined && !children) {\n return undefined;\n }\n\n items.push({\n label: itemCandidate.label,\n href: itemCandidate.href,\n children,\n });\n }\n\n return items;\n}\n\nfunction parseCreatePageInput(payload: JsonRecord): CreatePageInput | null {\n const pageType = parseStringField(payload.pageType);\n const title = parseStringField(payload.title);\n const slug = parseStringField(payload.slug);\n const sections = normalizePageSections(parsePageSections(payload.sections));\n\n if (!pageType || !title) {\n return null;\n }\n\n if (payload.sections !== undefined && !sections) {\n return null;\n }\n\n return {\n pageType,\n title,\n slug,\n sections,\n };\n}\n\nfunction parseUpdatePagePatch(payload: JsonRecord): ParsedUpdatePagePatch | null {\n const slug = parseStringField(payload.slug);\n const pageType = parseStringField(payload.pageType);\n const title = parseStringField(payload.title);\n const sections = parsePageSections(payload.sections);\n\n if (payload.slug !== undefined && !slug) {\n return null;\n }\n if (payload.pageType !== undefined && !pageType) {\n return null;\n }\n if (payload.title !== undefined && !title) {\n return null;\n }\n if (payload.sections !== undefined && !sections) {\n return null;\n }\n\n return {\n slug,\n pageType,\n title,\n sections,\n };\n}\n\nfunction parseCreateNavigationInput(payload: JsonRecord): CreateNavigationInput | null {\n const name = parseStringField(payload.name);\n const items = parseNavigationItems(payload.items);\n\n if (!name || !items) {\n return null;\n }\n\n return {\n name,\n items,\n };\n}\n\nfunction parseUpdateNavigationPatch(payload: JsonRecord): Omit<UpdateNavigationInput, 'id'> | null {\n const name = parseStringField(payload.name);\n const items = payload.items === undefined ? undefined : parseNavigationItems(payload.items);\n\n if (payload.name !== undefined && !name) {\n return null;\n }\n if (payload.items !== undefined && !items) {\n return null;\n }\n\n return {\n name,\n items,\n };\n}\n\nfunction toPageResponse(page: Page): Record<string, unknown> {\n return {\n id: page.id,\n slug: page.slug,\n pageType: page.pageType,\n title: page.title,\n sections: page.sections,\n meta: {\n createdAt: page.createdAt.toISOString(),\n updatedAt: page.updatedAt.toISOString(),\n },\n };\n}\n\nfunction toNavigationResponse(navigation: Navigation): Record<string, unknown> {\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\nexport function createNextPagesRoute(config: NextPagesRouteConfig) {\n return {\n GET: async (_request: RequestLike): Promise<ResponseLike> => {\n try {\n const pages = await handleListPages(config.storageAdapter, config.mediaAdapter);\n return jsonResponse(pages);\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const createInput = parseCreatePageInput(payload);\n if (!createInput) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const page = await handleCreatePage(config.storageAdapter, createInput);\n return jsonResponse(page, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextPageBySlugRoute(config: NextPageBySlugRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const page = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizeSlug(slug)\n );\n\n if (!page) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n return jsonResponse(page);\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const normalizedSlug = normalizeSlug(slug);\n const existingPage = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizedSlug\n );\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const pagePatch = parseUpdatePagePatch(payload);\n if (!pagePatch) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const normalizedSections = normalizePageSections(pagePatch.sections, existingPage.sections);\n\n const page = await handleUpdatePage(config.storageAdapter, {\n ...pagePatch,\n sections: normalizedSections,\n id: existingPage.id,\n });\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ slug: string | string[] }>\n ): Promise<ResponseLike> => {\n try {\n const { slug } = await resolveParams(context);\n const existingPage = await handleGetPageBySlug(\n config.storageAdapter,\n config.mediaAdapter,\n normalizeSlug(slug)\n );\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n await handleDeletePage(config.storageAdapter, existingPage.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nexport function createNextPageByIdRoute(config: NextPageByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const page = await config.storageAdapter.getPageById(id);\n\n if (!page) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingPage = await config.storageAdapter.getPageById(id);\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const pagePatch = parseUpdatePagePatch(payload);\n if (!pagePatch) {\n return jsonResponse({ error: 'Invalid page payload' }, 400);\n }\n\n const normalizedSections = normalizePageSections(pagePatch.sections, existingPage.sections);\n\n const page = await handleUpdatePage(config.storageAdapter, {\n ...pagePatch,\n sections: normalizedSections,\n id: existingPage.id,\n });\n\n return jsonResponse(toPageResponse(page));\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingPage = await config.storageAdapter.getPageById(id);\n\n if (!existingPage) {\n return jsonResponse({ error: 'Page not found' }, 404);\n }\n\n await handleDeletePage(config.storageAdapter, existingPage.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nfunction getQueryParam(url: string, name: string): string | null {\n const queryStart = url.indexOf('?');\n if (queryStart === -1) return null;\n for (const pair of url.slice(queryStart + 1).split('&')) {\n const eqIndex = pair.indexOf('=');\n const key = decodeURIComponent(eqIndex === -1 ? pair : pair.slice(0, eqIndex));\n if (key === name) return eqIndex === -1 ? '' : decodeURIComponent(pair.slice(eqIndex + 1));\n }\n return null;\n}\n\nfunction parseMediaFilter(request: RequestLike): MediaFilter | undefined {\n if (!request.url) {\n return undefined;\n }\n\n const category = getQueryParam(request.url, 'category');\n const limit = getQueryParam(request.url, 'limit');\n const offset = getQueryParam(request.url, 'offset');\n\n const filter: MediaFilter = {};\n let hasFilter = false;\n\n if (category === 'image' || category === 'document') {\n filter.category = category as MediaCategory;\n hasFilter = true;\n }\n\n if (limit) {\n const parsed = Number.parseInt(limit, 10);\n if (!Number.isNaN(parsed) && parsed > 0) {\n filter.limit = parsed;\n hasFilter = true;\n }\n }\n\n if (offset) {\n const parsed = Number.parseInt(offset, 10);\n if (!Number.isNaN(parsed) && parsed >= 0) {\n filter.offset = parsed;\n hasFilter = true;\n }\n }\n\n return hasFilter ? filter : undefined;\n}\n\nexport function createNextMediaRoute(config: NextMediaRouteConfig) {\n return {\n GET: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const filter = parseMediaFilter(request);\n const media = await handleListMedia(config.mediaAdapter, filter);\n return jsonResponse(media);\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const formData = await request.formData();\n const file = formData.get('file');\n\n if (!isFileLike(file)) {\n return jsonResponse({ error: 'No file provided' }, 400);\n }\n\n const input: UploadMediaInput = {\n filename: file.name,\n mimeType: file.type,\n size: file.size,\n data: await file.arrayBuffer(),\n };\n\n const mediaFile = await handleUploadMedia(config.mediaAdapter, input);\n return jsonResponse(mediaFile, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextMediaByIdRoute(config: NextMediaByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const media = await handleGetMedia(config.mediaAdapter, id);\n\n if (!media) {\n return jsonResponse({ error: 'Media not found' }, 404);\n }\n\n return jsonResponse(media);\n } catch (error) {\n return errorResponse(error);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n await handleDeleteMedia(config.mediaAdapter, id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\n}\n\nexport function createNextNavigationRoute(config: NextNavigationRouteConfig) {\n return {\n GET: async (_request: RequestLike): Promise<ResponseLike> => {\n try {\n const navigations = await config.storageAdapter.listNavigations();\n return jsonResponse(navigations.map(toNavigationResponse));\n } catch (error) {\n return errorResponse(error);\n }\n },\n POST: async (request: RequestLike): Promise<ResponseLike> => {\n try {\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const createInput = parseCreateNavigationInput(payload);\n if (!createInput) {\n return jsonResponse({ error: 'Invalid navigation payload' }, 400);\n }\n\n const navigation = await handleCreateNavigation(config.storageAdapter, createInput);\n\n return jsonResponse(navigation, 201);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n };\n}\n\nexport function createNextNavigationByIdRoute(config: NextNavigationByIdRouteConfig) {\n return {\n GET: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const navigation = await config.storageAdapter.getNavigationById(id);\n\n if (!navigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n return jsonResponse(toNavigationResponse(navigation));\n } catch (error) {\n return errorResponse(error);\n }\n },\n PUT: async (\n request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingNavigation = await config.storageAdapter.getNavigationById(id);\n\n if (!existingNavigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n const payload = asObject(await request.json());\n if (!payload) {\n return jsonResponse({ error: 'Request body must be an object' }, 400);\n }\n\n const navigationPatch = parseUpdateNavigationPatch(payload);\n if (!navigationPatch) {\n return jsonResponse({ error: 'Invalid navigation payload' }, 400);\n }\n\n const navigation = await handleUpdateNavigation(config.storageAdapter, {\n ...navigationPatch,\n id: existingNavigation.id,\n });\n\n return jsonResponse(navigation);\n } catch (error) {\n return errorResponse(error, 400);\n }\n },\n DELETE: async (\n _request: RequestLike,\n context: RouteContext<{ id: string }>\n ): Promise<ResponseLike> => {\n try {\n const { id } = await resolveParams(context);\n const existingNavigation = await config.storageAdapter.getNavigationById(id);\n\n if (!existingNavigation) {\n return jsonResponse({ error: 'Navigation not found' }, 404);\n }\n\n await handleDeleteNavigation(config.storageAdapter, existingNavigation.id);\n return jsonResponse({ success: true });\n } catch (error) {\n return errorResponse(error);\n }\n },\n };\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 {\n AuthValidationError,\n handleGetCurrentUser,\n handleRefreshSession,\n handleSignInWithOAuth,\n handleSignInWithPassword,\n handleSignOut,\n handleVerifySession,\n} from '../auth';\nimport type { AuthAdapter, SignInWithOAuthInput, SignInWithPasswordInput } from '../auth';\n\ninterface RequestLike {\n json(): Promise<unknown>;\n headers: {\n get(name: string): string | null | undefined;\n };\n}\n\ninterface ResponseLike {\n status: number;\n json(): Promise<unknown>;\n}\n\ninterface ResponseConstructorLike {\n new (body?: string, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n json(data: unknown, init?: { status?: number; headers?: Record<string, string> }): ResponseLike;\n}\n\nexport interface NextAuthOAuthRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthSignInRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthSignOutRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthVerifyRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthRefreshRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nexport interface NextAuthCurrentUserRouteConfig {\n authAdapter: AuthAdapter;\n}\n\nfunction extractBearerToken(request: RequestLike): string | null {\n const authHeader = request.headers.get('authorization') ?? request.headers.get('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] ?? null;\n}\n\nexport function createNextAuthOAuthRoute(\n config: NextAuthOAuthRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const input = body as SignInWithOAuthInput;\n\n const result = await handleSignInWithOAuth(config.authAdapter, input);\n\n return Response.json({ data: result }, { status: 200 });\n } catch (err) {\n if (err instanceof AuthValidationError) {\n return Response.json(\n { error: { message: err.message, code: 'VALIDATION_ERROR' } },\n { status: 400 }\n );\n }\n\n // For unknown errors, return a generic message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Internal Server Error', code: 'OAUTH_ERROR' } },\n { status: 500 }\n );\n }\n };\n}\n\nexport function createNextAuthSignInRoute(\n config: NextAuthSignInRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const input = body as SignInWithPasswordInput;\n\n const session = await handleSignInWithPassword(config.authAdapter, input);\n\n return Response.json(session, { status: 200 });\n } catch (err) {\n if (err instanceof AuthValidationError) {\n return Response.json(\n { error: { message: err.message, code: 'VALIDATION_ERROR' } },\n { status: 400 }\n );\n }\n\n // For unknown errors, return a generic message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Invalid credentials', code: 'AUTH_ERROR' } },\n { status: 401 }\n );\n }\n };\n}\n\nexport function createNextAuthSignOutRoute(\n config: NextAuthSignOutRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n await handleSignOut(config.authAdapter, token);\n\n return Response.json({ message: 'Signed out successfully' }, { status: 200 });\n } catch (error) {\n // Return generic error message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Internal Server Error', code: 'SIGNOUT_ERROR' } },\n { status: 500 }\n );\n }\n };\n}\n\nexport function createNextAuthVerifyRoute(\n config: NextAuthVerifyRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleVerifySession(config.authAdapter, { accessToken: token });\n\n if (!user) {\n return Response.json(\n { error: { message: 'Invalid token', code: 'INVALID_TOKEN' } },\n { status: 401 }\n );\n }\n\n return Response.json(user, { status: 200 });\n } catch (error) {\n // Return generic error message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Authentication failed', code: 'VERIFY_ERROR' } },\n { status: 401 }\n );\n }\n };\n}\n\nexport function createNextAuthRefreshRoute(\n config: NextAuthRefreshRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function POST(request: RequestLike): Promise<ResponseLike> {\n try {\n const body = await request.json();\n const { refreshToken } = body as { refreshToken: string };\n\n if (!refreshToken) {\n return Response.json(\n { error: { message: 'Refresh token required', code: 'NO_REFRESH_TOKEN' } },\n { status: 400 }\n );\n }\n\n const session = await handleRefreshSession(config.authAdapter, refreshToken);\n\n return Response.json(session, { status: 200 });\n } catch (error) {\n // Return generic error message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Session refresh failed', code: 'REFRESH_ERROR' } },\n { status: 401 }\n );\n }\n };\n}\n\nexport function createNextAuthCurrentUserRoute(\n config: NextAuthCurrentUserRouteConfig,\n Response: ResponseConstructorLike\n) {\n return async function GET(request: RequestLike): Promise<ResponseLike> {\n try {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'No token provided', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleGetCurrentUser(config.authAdapter, token);\n\n if (!user) {\n return Response.json(\n { error: { message: 'User not found', code: 'USER_NOT_FOUND' } },\n { status: 401 }\n );\n }\n\n return Response.json(user, { status: 200 });\n } catch (error) {\n // Return generic error message to avoid leaking internal details\n return Response.json(\n { error: { message: 'Internal Server Error', code: 'GET_USER_ERROR' } },\n { status: 500 }\n );\n }\n };\n}\n\nexport function createAuthenticatedRoute<T>(\n authAdapter: AuthAdapter,\n Response: ResponseConstructorLike,\n handler: (request: RequestLike, user: { id: string; email: string }) => Promise<T>\n) {\n return async (request: RequestLike): Promise<T | ResponseLike> => {\n const token = extractBearerToken(request);\n if (!token) {\n return Response.json(\n { error: { message: 'Authentication required', code: 'NO_TOKEN' } },\n { status: 401 }\n );\n }\n\n const user = await handleVerifySession(authAdapter, { accessToken: token });\n if (!user) {\n return Response.json(\n { error: { message: 'Invalid or expired token', code: 'INVALID_TOKEN' } },\n { status: 401 }\n );\n }\n\n return handler(request, user);\n };\n}\n"],"mappings":"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","names":["toPageResponse"]}
@@ -135,7 +135,38 @@ function createAuthAdapter(config) {
135
135
  return new SupabaseAuthAdapter(config);
136
136
  }
137
137
 
138
+ // src/media/types.ts
139
+ var MAX_FILE_SIZE = 50 * 1024 * 1024;
140
+ var ALLOWED_MIME_TYPES = [
141
+ "image/jpeg",
142
+ "image/png",
143
+ "image/gif",
144
+ "image/webp",
145
+ "image/svg+xml"
146
+ ];
147
+ var ALLOWED_DOCUMENT_MIME_TYPES = [
148
+ "application/pdf",
149
+ "application/msword",
150
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
151
+ "application/vnd.ms-excel",
152
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
153
+ "application/vnd.ms-powerpoint",
154
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
155
+ "text/plain",
156
+ "text/csv",
157
+ "application/zip",
158
+ "application/gzip"
159
+ ];
160
+ var ALL_ALLOWED_MIME_TYPES = [
161
+ ...ALLOWED_MIME_TYPES,
162
+ ...ALLOWED_DOCUMENT_MIME_TYPES
163
+ ];
164
+
138
165
  // src/media/supabase-adapter.ts
166
+ function deriveCategory(mimeType) {
167
+ const imageMimes = ALLOWED_MIME_TYPES;
168
+ return imageMimes.includes(mimeType) ? "image" : "document";
169
+ }
139
170
  var MediaError = class extends Error {
140
171
  constructor(message, code, details) {
141
172
  super(message);
@@ -177,6 +208,7 @@ var SupabaseMediaAdapter = class {
177
208
  url: this.getPublicUrl(row.storage_path),
178
209
  mimeType: row.mime_type,
179
210
  size: row.size,
211
+ category: row.category,
180
212
  createdAt: new Date(row.created_at)
181
213
  };
182
214
  }
@@ -197,7 +229,8 @@ var SupabaseMediaAdapter = class {
197
229
  filename: input.filename,
198
230
  storage_path: storagePath,
199
231
  mime_type: input.mimeType,
200
- size: input.size
232
+ size: input.size,
233
+ category: deriveCategory(input.mimeType)
201
234
  }).select().single();
202
235
  if (dbError) {
203
236
  await this.client.storage.from(this.bucketName).remove([storagePath]);
@@ -224,6 +257,9 @@ var SupabaseMediaAdapter = class {
224
257
  if (filter?.mimeType) {
225
258
  query = query.eq("mime_type", filter.mimeType);
226
259
  }
260
+ if (filter?.category) {
261
+ query = query.eq("category", filter.category);
262
+ }
227
263
  query = query.order("created_at", { ascending: false });
228
264
  if (filter?.limit) {
229
265
  query = query.limit(filter.limit);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/supabase/index.ts","../../src/supabase/factory.ts","../../src/auth/supabase-adapter.ts","../../src/media/supabase-adapter.ts","../../src/storage/supabase-adapter.ts"],"sourcesContent":["export type {\n SupabaseAdapterFactoryStorageConfig,\n SupabaseAdapterFactoryConfig,\n SupabaseAdapters,\n} from './factory';\n\nexport { createSupabaseAdapters } from './factory';\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 { 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 { 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"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/supabase/index.ts","../../src/supabase/factory.ts","../../src/auth/supabase-adapter.ts","../../src/media/types.ts","../../src/media/supabase-adapter.ts","../../src/storage/supabase-adapter.ts"],"sourcesContent":["export type {\n SupabaseAdapterFactoryStorageConfig,\n SupabaseAdapterFactoryConfig,\n SupabaseAdapters,\n} from './factory';\n\nexport { createSupabaseAdapters } from './factory';\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","/**\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 { 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"],"mappings":"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","names":[]}