@fydemy/cms 1.0.2 → 1.0.3

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/rate-limit.ts","../src/index.ts","../src/content/markdown.ts","../src/content/storage.ts","../src/utils/validation.ts","../src/content/directory.ts","../src/content/collection.ts","../src/content/upload.ts","../src/auth/session.ts","../src/auth/login.ts","../src/api/handlers.ts","../src/api/upload.ts","../src/ui/AdminDashboard.tsx","../src/ui/Login.tsx","../src/middleware/auth.ts","../src/init/setup.ts"],"sourcesContent":["/**\n * Simple in-memory rate limiter for login attempts\n */\n\ninterface RateLimitEntry {\n count: number;\n resetTime: number;\n}\n\nconst rateLimitStore = new Map<string, RateLimitEntry>();\n\n// Configuration\nconst MAX_ATTEMPTS = 5; // Maximum login attempts\nconst WINDOW_MS = 15 * 60 * 1000; // 15 minutes\n\n/**\n * Check if IP/identifier is rate limited\n * @param identifier - IP address or other unique identifier\n * @returns Object with isLimited and remaining attempts\n */\nexport function checkRateLimit(identifier: string): {\n isLimited: boolean;\n remaining: number;\n resetTime: number;\n} {\n const now = Date.now();\n const entry = rateLimitStore.get(identifier);\n\n // No entry or expired entry\n if (!entry || now > entry.resetTime) {\n rateLimitStore.set(identifier, {\n count: 0,\n resetTime: now + WINDOW_MS,\n });\n\n return {\n isLimited: false,\n remaining: MAX_ATTEMPTS,\n resetTime: now + WINDOW_MS,\n };\n }\n\n // Check if limit exceeded\n if (entry.count >= MAX_ATTEMPTS) {\n return {\n isLimited: true,\n remaining: 0,\n resetTime: entry.resetTime,\n };\n }\n\n return {\n isLimited: false,\n remaining: MAX_ATTEMPTS - entry.count,\n resetTime: entry.resetTime,\n };\n}\n\n/**\n * Increment rate limit counter for identifier\n * @param identifier - IP address or other unique identifier\n */\nexport function incrementRateLimit(identifier: string): void {\n const now = Date.now();\n const entry = rateLimitStore.get(identifier);\n\n if (!entry || now > entry.resetTime) {\n rateLimitStore.set(identifier, {\n count: 1,\n resetTime: now + WINDOW_MS,\n });\n } else {\n entry.count++;\n }\n}\n\n/**\n * Reset rate limit for identifier (use after successful login)\n * @param identifier - IP address or other unique identifier\n */\nexport function resetRateLimit(identifier: string): void {\n rateLimitStore.delete(identifier);\n}\n\n/**\n * Clean up expired entries (should be called periodically)\n */\nexport function cleanupRateLimitStore(): void {\n const now = Date.now();\n for (const [identifier, entry] of rateLimitStore.entries()) {\n if (now > entry.resetTime) {\n rateLimitStore.delete(identifier);\n }\n }\n}\n\n// Cleanup expired entries every 5 minutes\nif (typeof setInterval !== \"undefined\") {\n setInterval(cleanupRateLimitStore, 5 * 60 * 1000);\n}\n","// Content management\nexport {\n getMarkdownContent,\n saveMarkdownContent,\n deleteMarkdownContent,\n listMarkdownFiles,\n markdownFileExists,\n parseMarkdown,\n stringifyMarkdown,\n} from \"./content/markdown\";\n\nexport type { MarkdownData } from \"./content/markdown\";\n\nexport { listDirectory } from \"./content/directory\";\n\nexport {\n getCollectionItems,\n getCollectionItem,\n getCollections,\n} from \"./content/collection\";\n\nexport type { CollectionItem } from \"./content/collection\";\n\nexport { uploadFile } from \"./content/upload\";\n\nexport {\n LocalStorage,\n GitHubStorage,\n getStorageProvider,\n} from \"./content/storage\";\n\nexport type { StorageProvider, FileEntry } from \"./content/storage\";\n\n// Authentication\nexport {\n createSession,\n verifySession,\n getSessionFromCookies,\n setSessionCookie,\n clearSessionCookie,\n} from \"./auth/session\";\n\nexport { validateCredentials } from \"./auth/login\";\n\n// API handlers\nexport {\n handleLogin,\n handleLogout,\n handleGetContent,\n handleSaveContent,\n handleDeleteContent,\n handleListFiles,\n createContentApiHandlers,\n createListApiHandlers,\n} from \"./api/handlers\";\n\nexport { handleUpload } from \"./api/upload\";\n\n// UI Components\nexport { AdminDashboard } from \"./ui/AdminDashboard\";\nexport { Login } from \"./ui/Login\";\n\n// Middleware\nexport { createAuthMiddleware } from \"./middleware/auth\";\n\n// Initialize\nexport { initCMS } from \"./init/setup\";\nexport type { InitCMSConfig } from \"./init/setup\";\n\n// Utilities (for advanced usage)\nexport {\n validateFilePath,\n validateUsername,\n validatePassword,\n validateFileSize,\n sanitizeFrontmatter,\n MAX_USERNAME_LENGTH,\n MAX_PASSWORD_LENGTH,\n MAX_FILE_SIZE,\n} from \"./utils/validation\";\n\nexport {\n checkRateLimit,\n incrementRateLimit,\n resetRateLimit,\n} from \"./utils/rate-limit\";\n","import matter from \"gray-matter\";\nimport { getStorageProvider } from \"./storage\";\nimport {\n validateFilePath,\n sanitizeFrontmatter,\n MAX_FILE_SIZE,\n} from \"../utils/validation\";\n\nexport interface MarkdownData {\n content: string;\n data: Record<string, any>;\n}\n\n/**\n * Parse markdown content with frontmatter\n * @param rawContent - Raw markdown content to parse\n * @returns Parsed markdown data with frontmatter and content\n */\nexport function parseMarkdown(rawContent: string): MarkdownData {\n const { data, content } = matter(rawContent);\n return { data, content };\n}\n\n/**\n * Convert data and content back to markdown with frontmatter\n */\nexport function stringifyMarkdown(\n data: Record<string, any>,\n content: string\n): string {\n return matter.stringify(content, data);\n}\n\n/**\n * Read and parse a markdown file\n * @param filePath - Path to the markdown file\n * @returns Parsed markdown data\n * @throws Error if file path is invalid or file is too large\n */\nexport async function getMarkdownContent(\n filePath: string\n): Promise<MarkdownData> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n const rawContent = await storage.readFile(validatedPath);\n\n // Check file size\n const size = Buffer.byteLength(rawContent, \"utf-8\");\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `File size (${size} bytes) exceeds maximum allowed size (${MAX_FILE_SIZE} bytes)`\n );\n }\n\n return parseMarkdown(rawContent);\n}\n\n/**\n * Write markdown file with frontmatter\n * @param filePath - Path to the markdown file\n * @param data - Frontmatter data object\n * @param content - Markdown content\n * @throws Error if file path is invalid or content is too large\n */\nexport async function saveMarkdownContent(\n filePath: string,\n data: Record<string, any>,\n content: string\n): Promise<void> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n // Sanitize frontmatter\n const sanitizedData = sanitizeFrontmatter(data);\n\n const markdown = stringifyMarkdown(sanitizedData, content);\n\n // Check size before writing\n const size = Buffer.byteLength(markdown, \"utf-8\");\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `Content size (${size} bytes) exceeds maximum allowed size (${MAX_FILE_SIZE} bytes)`\n );\n }\n\n const storage = getStorageProvider();\n await storage.writeFile(validatedPath, markdown);\n}\n\n/**\n * Delete a markdown file\n * @param filePath - Path to the markdown file\n * @throws Error if file path is invalid\n */\nexport async function deleteMarkdownContent(filePath: string): Promise<void> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n await storage.deleteFile(validatedPath);\n}\n\n/**\n * List all markdown files in a directory\n * @param directory - Directory path (optional, defaults to root)\n * @returns Array of file paths\n * @throws Error if directory path is invalid\n */\nexport async function listMarkdownFiles(\n directory: string = \"\"\n): Promise<string[]> {\n // Validate directory path if provided\n const validatedDir = directory ? validateFilePath(directory) : \"\";\n\n const storage = getStorageProvider();\n const entries = await storage.listFiles(validatedDir);\n return entries\n .filter((entry) => entry.type === \"file\")\n .map((entry) => entry.path);\n}\n\n/**\n * Check if a markdown file exists\n * @param filePath - Path to the markdown file\n * @returns True if file exists, false otherwise\n * @throws Error if file path is invalid\n */\nexport async function markdownFileExists(filePath: string): Promise<boolean> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n return storage.exists(validatedPath);\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\nimport { Octokit } from \"@octokit/rest\";\n\n/**\n * Represents a file or directory entry\n */\nexport interface FileEntry {\n /** Relative path from base content directory */\n path: string;\n /** File or directory name */\n name: string;\n /** Type of entry */\n type: \"file\" | \"directory\";\n}\n\n/**\n * Interface for file storage operations\n */\nexport interface StorageProvider {\n /** Read file content as string */\n readFile(filePath: string): Promise<string>;\n /** Write content to file, creating parent directories if needed */\n writeFile(filePath: string, content: string): Promise<void>;\n /** Delete a file */\n deleteFile(filePath: string): Promise<void>;\n /** List files in a directory */\n listFiles(directory: string): Promise<FileEntry[]>;\n /** Check if a file exists */\n exists(filePath: string): Promise<boolean>;\n /** Upload a binary file */\n uploadFile(filePath: string, buffer: Buffer): Promise<string>; // Returns public URL\n}\n\n/**\n * Local file system storage (for development)\n */\nexport class LocalStorage implements StorageProvider {\n private baseDir: string;\n\n constructor(baseDir: string = \"public/content\") {\n this.baseDir = baseDir;\n }\n\n private getFullPath(filePath: string): string {\n return path.join(process.cwd(), this.baseDir, filePath);\n }\n\n async readFile(filePath: string): Promise<string> {\n const fullPath = this.getFullPath(filePath);\n return fs.readFile(fullPath, \"utf-8\");\n }\n\n async writeFile(filePath: string, content: string): Promise<void> {\n const fullPath = this.getFullPath(filePath);\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n await fs.writeFile(fullPath, content, \"utf-8\");\n }\n\n async deleteFile(filePath: string): Promise<void> {\n const fullPath = this.getFullPath(filePath);\n await fs.unlink(fullPath);\n }\n\n async listFiles(directory: string): Promise<FileEntry[]> {\n const fullPath = this.getFullPath(directory);\n try {\n const entries = await fs.readdir(fullPath, { withFileTypes: true });\n return entries\n .map((entry) => ({\n path: path.join(directory, entry.name),\n name: entry.name,\n type: entry.isDirectory()\n ? (\"directory\" as const)\n : (\"file\" as const),\n }))\n .filter(\n (entry) => entry.type === \"directory\" || entry.name.endsWith(\".md\")\n );\n } catch (error) {\n return [];\n }\n }\n\n async exists(filePath: string): Promise<boolean> {\n try {\n const fullPath = this.getFullPath(filePath);\n await fs.access(fullPath);\n return true;\n } catch {\n return false;\n }\n }\n\n async uploadFile(filePath: string, buffer: Buffer): Promise<string> {\n // Store uploads in /public/uploads directory\n const uploadPath = path.join(process.cwd(), \"public\", \"uploads\", filePath);\n await fs.mkdir(path.dirname(uploadPath), { recursive: true });\n await fs.writeFile(uploadPath, buffer);\n\n // Return public URL path\n return `/uploads/${filePath}`;\n }\n}\n\n/**\n * GitHub storage (for production)\n */\nexport class GitHubStorage implements StorageProvider {\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n private branch: string;\n private baseDir: string;\n\n constructor() {\n const token = process.env.GITHUB_TOKEN;\n const repoInfo = process.env.GITHUB_REPO;\n\n if (!token || !repoInfo) {\n throw new Error(\n \"GITHUB_TOKEN and GITHUB_REPO must be set for production\"\n );\n }\n\n const [owner, repo] = repoInfo.split(\"/\");\n if (!owner || !repo) {\n throw new Error('GITHUB_REPO must be in format \"owner/repo\"');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n this.branch = process.env.GITHUB_BRANCH || \"main\";\n this.baseDir = \"public/content\";\n }\n\n private getGitHubPath(filePath: string): string {\n return `${this.baseDir}/${filePath}`;\n }\n\n async readFile(filePath: string): Promise<string> {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: this.getGitHubPath(filePath),\n ref: this.branch,\n });\n\n if (\"content\" in data) {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n throw new Error(\"File not found\");\n }\n\n async writeFile(filePath: string, content: string): Promise<void> {\n const githubPath = this.getGitHubPath(filePath);\n let sha: string | undefined;\n\n // Try to get existing file SHA\n try {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n if (\"sha\" in data) {\n sha = data.sha;\n }\n } catch (error) {\n // File doesn't exist, that's ok\n }\n\n await this.octokit.repos.createOrUpdateFileContents({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n message: `Update ${filePath}`,\n content: Buffer.from(content).toString(\"base64\"),\n branch: this.branch,\n sha,\n });\n }\n\n async deleteFile(filePath: string): Promise<void> {\n const githubPath = this.getGitHubPath(filePath);\n\n // Get file SHA\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n\n if (\"sha\" in data) {\n await this.octokit.repos.deleteFile({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n message: `Delete ${filePath}`,\n sha: data.sha,\n branch: this.branch,\n });\n }\n }\n\n async listFiles(directory: string): Promise<FileEntry[]> {\n const githubPath = this.getGitHubPath(directory);\n\n try {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n\n if (Array.isArray(data)) {\n return data\n .map((item) => ({\n path: path.join(directory, item.name),\n name: item.name,\n type:\n item.type === \"dir\" ? (\"directory\" as const) : (\"file\" as const),\n }))\n .filter(\n (entry) => entry.type === \"directory\" || entry.name.endsWith(\".md\")\n );\n }\n } catch (error) {\n // Directory doesn't exist\n }\n\n return [];\n }\n\n async exists(filePath: string): Promise<boolean> {\n try {\n await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: this.getGitHubPath(filePath),\n ref: this.branch,\n });\n return true;\n } catch {\n return false;\n }\n }\n\n async uploadFile(filePath: string, buffer: Buffer): Promise<string> {\n // Store uploads in public/uploads directory in GitHub\n const uploadPath = `public/uploads/${filePath}`;\n\n await this.octokit.repos.createOrUpdateFileContents({\n owner: this.owner,\n repo: this.repo,\n path: uploadPath,\n message: `Upload file: ${filePath}`,\n content: buffer.toString(\"base64\"),\n branch: this.branch,\n });\n\n // Return public URL path\n return `/uploads/${filePath}`;\n }\n}\n\n/**\n * Get the appropriate storage provider based on environment\n */\nexport function getStorageProvider(): StorageProvider {\n if (process.env.NODE_ENV === \"production\" && process.env.GITHUB_TOKEN) {\n return new GitHubStorage();\n }\n return new LocalStorage();\n}\n","import path from \"path\";\n\n/**\n * Maximum username length (prevents DoS)\n */\nexport const MAX_USERNAME_LENGTH = 100;\n\n/**\n * Maximum password length (prevents DoS)\n */\nexport const MAX_PASSWORD_LENGTH = 1000;\n\n/**\n * Maximum file size in bytes (10MB)\n */\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n/**\n * Validate and sanitize file path to prevent directory traversal\n * @param filePath - The file path to validate\n * @returns Sanitized file path\n * @throws Error if path is invalid or attempts directory traversal\n */\nexport function validateFilePath(filePath: string): string {\n if (!filePath || typeof filePath !== \"string\") {\n throw new Error(\"Invalid file path\");\n }\n\n // Remove any null bytes\n if (filePath.includes(\"\\x00\")) {\n throw new Error(\"Invalid file path: null byte detected\");\n }\n\n // Check for directory traversal attempts BEFORE normalization\n if (filePath.includes(\"..\")) {\n throw new Error(\"Invalid file path: directory traversal detected\");\n }\n\n // Normalize the path\n const normalized = path.normalize(filePath).replace(/^(\\.\\.(\\/|\\\\|$))+/, \"\");\n\n // Check if normalized path is different and contains dangerous patterns\n if (normalized.startsWith(\"/\") || normalized.startsWith(\"\\\\\")) {\n throw new Error(\"Invalid file path: directory traversal detected\");\n }\n\n // Ensure path doesn't contain dangerous patterns\n const dangerousPatterns = [\n /\\.\\./,\n /^[/\\\\]/,\n /[<>:\"|?*]/,\n /\\x00/,\n /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i, // Windows reserved names\n ];\n\n for (const pattern of dangerousPatterns) {\n if (pattern.test(normalized)) {\n throw new Error(\"Invalid file path: contains dangerous characters\");\n }\n }\n\n return normalized;\n}\n\n/**\n * Validate username input\n * @param username - The username to validate\n * @returns True if valid\n * @throws Error if invalid\n */\nexport function validateUsername(username: string): boolean {\n if (!username || typeof username !== \"string\") {\n throw new Error(\"Username is required\");\n }\n\n if (username.length > MAX_USERNAME_LENGTH) {\n throw new Error(\n `Username must be ${MAX_USERNAME_LENGTH} characters or less`\n );\n }\n\n // Only allow alphanumeric, underscore, hyphen\n if (!/^[a-zA-Z0-9_-]+$/.test(username)) {\n throw new Error(\n \"Username must contain only letters, numbers, underscores, and hyphens\"\n );\n }\n\n return true;\n}\n\n/**\n * Validate password input\n * @param password - The password to validate\n * @returns True if valid\n * @throws Error if invalid\n */\nexport function validatePassword(password: string): boolean {\n if (!password || typeof password !== \"string\") {\n throw new Error(\"Password is required\");\n }\n\n if (password.length > MAX_PASSWORD_LENGTH) {\n throw new Error(\n `Password must be ${MAX_PASSWORD_LENGTH} characters or less`\n );\n }\n\n return true;\n}\n\n/**\n * Validate file size\n * @param size - File size in bytes\n * @returns True if valid\n * @throws Error if too large\n */\nexport function validateFileSize(size: number): boolean {\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `File size exceeds maximum allowed size of ${\n MAX_FILE_SIZE / 1024 / 1024\n }MB`\n );\n }\n\n return true;\n}\n\n/**\n * Sanitize frontmatter data to prevent injection\n * @param data - The data object to sanitize\n * @returns Sanitized data\n */\nexport function sanitizeFrontmatter(\n data: Record<string, any>\n): Record<string, any> {\n const sanitized: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(data)) {\n // Validate key\n if (!/^[a-zA-Z0-9_-]+$/.test(key)) {\n continue; // Skip invalid keys\n }\n\n // Sanitize value based on type\n if (typeof value === \"string\") {\n // Remove null bytes\n sanitized[key] = value.replace(/\\x00/g, \"\");\n } else if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value === null\n ) {\n sanitized[key] = value;\n } else if (Array.isArray(value)) {\n sanitized[key] = value.map((item) =>\n typeof item === \"string\" ? item.replace(/\\x00/g, \"\") : item\n );\n } else if (typeof value === \"object\") {\n sanitized[key] = sanitizeFrontmatter(value);\n }\n }\n\n return sanitized;\n}\n","import { getStorageProvider, FileEntry } from \"./storage\";\n\n/**\n * List all files and directories in a directory\n * @param directory - Relative path to the directory (default: root)\n * @returns Array of file entries (files and directories)\n */\nexport async function listDirectory(\n directory: string = \"\"\n): Promise<FileEntry[]> {\n const storage = getStorageProvider();\n return storage.listFiles(directory);\n}\n","import { getStorageProvider } from \"./storage\";\nimport { parseMarkdown } from \"./markdown\";\n\n/**\n * Base interface for collection items with flexible frontmatter\n */\nexport interface CollectionItem<T = Record<string, any>> {\n /** The markdown content body */\n content: string;\n /** Frontmatter data with dynamic fields */\n data: T;\n /** File slug (filename without extension) */\n slug: string;\n}\n\n/**\n * Fetch all markdown files from a specific folder/collection\n * @param folderName - The folder name under public/content (e.g., \"blog\", \"pages\")\n * @returns Array of collection items with parsed frontmatter and content\n *\n * @example\n * ```ts\n * // Fetch all blog posts\n * const posts = await getCollectionItems(\"blog\");\n * posts.forEach(post => {\n * console.log(post.data.title); // Access any frontmatter field\n * console.log(post.slug); // Filename without .md\n * });\n *\n * // With type inference for known fields\n * interface BlogPost {\n * title: string;\n * date: string;\n * author?: string;\n * [key: string]: any; // Allow any other fields\n * }\n * const typedPosts = await getCollectionItems<BlogPost>(\"blog\");\n * ```\n */\nexport async function getCollectionItems<T = Record<string, any>>(\n folderName: string\n): Promise<CollectionItem<T>[]> {\n const storage = getStorageProvider();\n\n // List all files in the collection folder\n const entries = await storage.listFiles(folderName);\n\n // Filter for markdown files only\n const mdFiles = entries.filter(\n (entry) => entry.type === \"file\" && entry.path.endsWith(\".md\")\n );\n\n // Read and parse each markdown file\n const items = await Promise.all(\n mdFiles.map(async (file) => {\n const rawContent = await storage.readFile(file.path);\n const { data, content } = parseMarkdown(rawContent);\n\n // Extract slug from filename (remove .md extension)\n const slug = file.path.split(\"/\").pop()!.replace(/\\.md$/, \"\");\n\n return {\n content,\n data: data as T,\n slug,\n };\n })\n );\n\n return items;\n}\n\n/**\n * Fetch a single item from a collection by slug\n * @param folderName - The folder name under public/content\n * @param slug - The filename without .md extension\n * @returns Single collection item or null if not found\n *\n * @example\n * ```ts\n * // Fetch a specific blog post\n * const post = await getCollectionItem(\"blog\", \"my-first-post\");\n * if (post) {\n * console.log(post.data.title);\n * }\n * ```\n */\nexport async function getCollectionItem<T = Record<string, any>>(\n folderName: string,\n slug: string\n): Promise<CollectionItem<T> | null> {\n const storage = getStorageProvider();\n const filePath = `${folderName}/${slug}.md`;\n\n try {\n const exists = await storage.exists(filePath);\n if (!exists) {\n return null;\n }\n\n const rawContent = await storage.readFile(filePath);\n const { data, content } = parseMarkdown(rawContent);\n\n return {\n content,\n data: data as T,\n slug,\n };\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Get all unique folder names (collections) in the content directory\n * @param baseDir - Base directory to scan (default: \"\")\n * @returns Array of folder names\n *\n * @example\n * ```ts\n * const collections = await getCollections();\n * // Returns: [\"blog\", \"pages\", \"docs\", ...]\n * ```\n */\nexport async function getCollections(baseDir: string = \"\"): Promise<string[]> {\n const storage = getStorageProvider();\n const entries = await storage.listFiles(baseDir);\n\n return entries\n .filter((entry) => entry.type === \"directory\")\n .map((entry) => entry.path.split(\"/\").pop()!)\n .filter(Boolean);\n}\n","import { getStorageProvider } from \"./storage\";\n\n/**\n * Upload a file and return its public URL\n * @param fileName - Original filename\n * @param buffer - File content buffer\n * @returns Public URL path to the uploaded file\n */\nexport async function uploadFile(\n fileName: string,\n buffer: Buffer\n): Promise<string> {\n const storage = getStorageProvider();\n\n // Generate unique filename with timestamp to avoid conflicts\n const timestamp = Date.now();\n const ext = fileName.split(\".\").pop();\n const nameWithoutExt = fileName.replace(`.${ext}`, \"\");\n const uniqueFileName = `${nameWithoutExt}-${timestamp}.${ext}`;\n\n return storage.uploadFile(uniqueFileName, buffer);\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { cookies } from \"next/headers\";\n\nconst SESSION_COOKIE_NAME = \"cms-session\";\nconst SESSION_DURATION = 60 * 60 * 24 * 7; // 7 days in seconds\n\n/**\n * Session payload structure for JWT\n */\ninterface SessionPayload {\n /** Username of the authenticated user */\n username: string;\n /** Expiration timestamp (Unix time) */\n exp: number;\n}\n\n/**\n * Get the secret key for JWT signing\n */\nfunction getSecretKey(): Uint8Array {\n const secret = process.env.CMS_SESSION_SECRET;\n if (!secret || secret.length < 32) {\n throw new Error(\"CMS_SESSION_SECRET must be at least 32 characters\");\n }\n return new TextEncoder().encode(secret);\n}\n\n/**\n * Create a new session token for the given username\n * @param username - The username to create a session for\n * @returns Signed JWT string\n */\nexport async function createSession(username: string): Promise<string> {\n const payload: SessionPayload = {\n username,\n exp: Math.floor(Date.now() / 1000) + SESSION_DURATION,\n };\n\n const token = await new SignJWT(payload as any)\n .setProtectedHeader({ alg: \"HS256\" })\n .setExpirationTime(\"7d\")\n .sign(getSecretKey());\n\n return token;\n}\n\n/**\n * Verify and decode a session token\n * @param token - The JWT token to verify\n * @returns Decoded payload if valid, null otherwise\n */\nexport async function verifySession(\n token: string\n): Promise<SessionPayload | null> {\n try {\n const { payload } = await jwtVerify(token, getSecretKey());\n\n // Validate payload structure\n if (\n typeof payload.username === \"string\" &&\n typeof payload.exp === \"number\"\n ) {\n return payload as unknown as SessionPayload;\n }\n\n return null;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Get session from Next.js request cookies\n */\nexport async function getSessionFromCookies(): Promise<SessionPayload | null> {\n const cookieStore = await cookies();\n const token = cookieStore.get(SESSION_COOKIE_NAME)?.value;\n\n if (!token) {\n return null;\n }\n\n return verifySession(token);\n}\n\n/**\n * Set session cookie\n */\nexport async function setSessionCookie(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(SESSION_COOKIE_NAME, token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n maxAge: SESSION_DURATION,\n path: \"/\",\n });\n}\n\n/**\n * Clear session cookie\n */\nexport async function clearSessionCookie(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(SESSION_COOKIE_NAME);\n}\n","import crypto from \"crypto\";\nimport { validateUsername, validatePassword } from \"../utils/validation\";\n\n/**\n * Validate username and password against environment variables using timing-safe comparison\n * @param username - Username to validate\n * @param password - Password to validate\n * @returns True if credentials are valid, false otherwise\n * @throws Error if environment variables are not configured\n */\nexport function validateCredentials(\n username: string,\n password: string\n): boolean {\n // Validate input format first\n try {\n validateUsername(username);\n validatePassword(password);\n } catch (error) {\n // Return false for invalid input format (don't leak validation details)\n return false;\n }\n\n const envUsername = process.env.CMS_ADMIN_USERNAME;\n const envPassword = process.env.CMS_ADMIN_PASSWORD;\n\n if (!envUsername || !envPassword) {\n throw new Error(\n \"CMS_ADMIN_USERNAME and CMS_ADMIN_PASSWORD must be set in environment variables\"\n );\n }\n\n // Use timing-safe comparison to prevent timing attacks\n // Both comparisons must be done to prevent timing analysis\n const usernameMatch = timingSafeEqual(username, envUsername);\n const passwordMatch = timingSafeEqual(password, envPassword);\n\n return usernameMatch && passwordMatch;\n}\n\n/**\n * Timing-safe string comparison using crypto.timingSafeEqual\n * @param a - First string\n * @param b - Second string\n * @returns True if strings match\n */\nfunction timingSafeEqual(a: string, b: string): boolean {\n try {\n // Convert to buffers with consistent encoding\n const bufferA = Buffer.from(a, \"utf-8\");\n const bufferB = Buffer.from(b, \"utf-8\");\n\n // If lengths differ, compare dummy buffers of same length\n // This prevents length-based timing attacks\n if (bufferA.length !== bufferB.length) {\n const dummyBuffer = Buffer.alloc(bufferA.length);\n crypto.timingSafeEqual(bufferA, dummyBuffer);\n return false;\n }\n\n return crypto.timingSafeEqual(bufferA, bufferB);\n } catch {\n return false;\n }\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { validateCredentials } from \"../auth/login\";\nimport { createSession, getSessionFromCookies } from \"../auth/session\";\nimport {\n getMarkdownContent,\n saveMarkdownContent,\n deleteMarkdownContent,\n} from \"../content/markdown\";\nimport { listDirectory } from \"../content/directory\";\n\n/**\n * Login endpoint with rate limiting\n */\nexport async function handleLogin(request: NextRequest) {\n try {\n // Get IP address for rate limiting\n const ip =\n request.headers.get(\"x-forwarded-for\")?.split(\",\")[0] ||\n request.headers.get(\"x-real-ip\") ||\n \"unknown\";\n\n // Check rate limit\n const { checkRateLimit, incrementRateLimit, resetRateLimit } = await import(\n \"../utils/rate-limit\"\n );\n const rateLimit = checkRateLimit(ip);\n\n if (rateLimit.isLimited) {\n const retryAfter = Math.ceil((rateLimit.resetTime - Date.now()) / 1000);\n return NextResponse.json(\n {\n error: \"Too many login attempts. Please try again later.\",\n retryAfter,\n },\n {\n status: 429,\n headers: {\n \"Retry-After\": retryAfter.toString(),\n },\n }\n );\n }\n\n const body = (await request.json()) as {\n username?: string;\n password?: string;\n };\n const { username, password } = body;\n\n if (!username || !password) {\n return NextResponse.json(\n { error: \"Username and password are required\" },\n { status: 400 }\n );\n }\n\n // Validate credentials\n const isValid = validateCredentials(username, password);\n\n if (!isValid) {\n // Increment rate limit on failed attempt\n incrementRateLimit(ip);\n\n // Generic error message to avoid username enumeration\n return NextResponse.json(\n { error: \"Invalid credentials\" },\n { status: 401 }\n );\n }\n\n // Reset rate limit on successful login\n resetRateLimit(ip);\n\n const token = await createSession(username);\n const response = NextResponse.json({ success: true });\n\n // Set cookie in response\n response.cookies.set(\"cms-session\", token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n maxAge: 60 * 60 * 24 * 7, // 7 days\n path: \"/\",\n });\n\n return response;\n } catch (error) {\n console.error(\"Login error:\", error);\n return NextResponse.json(\n { error: \"Authentication service temporarily unavailable\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Logout endpoint\n */\nexport async function handleLogout() {\n const response = NextResponse.json({ success: true });\n response.cookies.delete(\"cms-session\");\n return response;\n}\n\n/**\n * Get content endpoint\n */\nexport async function handleGetContent(\n _request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const content = await getMarkdownContent(filePath);\n return NextResponse.json(content);\n } catch (error) {\n console.error(\"Get content error:\", error);\n return NextResponse.json(\n { error: \"Failed to read content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Save content endpoint\n */\nexport async function handleSaveContent(\n request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const body = (await request.json()) as {\n data?: Record<string, any>;\n content?: string;\n };\n const { data, content } = body;\n\n // Content is optional now - default to empty string\n await saveMarkdownContent(filePath, data || {}, content || \"\");\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error(\"Save content error:\", error);\n return NextResponse.json(\n { error: \"Failed to save content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Delete content endpoint\n */\nexport async function handleDeleteContent(\n _request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n await deleteMarkdownContent(filePath);\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error(\"Delete content error:\", error);\n return NextResponse.json(\n { error: \"Failed to delete content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * List files endpoint\n */\nexport async function handleListFiles(directory: string = \"\") {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const entries = await listDirectory(directory);\n return NextResponse.json({ entries });\n } catch (error) {\n console.error(\"List files error:\", error);\n return NextResponse.json(\n { error: \"Failed to list files\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Create API route handlers for Next.js App Router\n */\nexport function createContentApiHandlers() {\n return {\n async GET(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleGetContent(request, filePath);\n },\n async POST(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleSaveContent(request, filePath);\n },\n async DELETE(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleDeleteContent(request, filePath);\n },\n };\n}\n\n/**\n * Create list API handlers\n */\nexport function createListApiHandlers() {\n return {\n async GET(\n _request: NextRequest,\n { params }: { params: { path?: string[] } }\n ) {\n const directory = params?.path?.join(\"/\") || \"\";\n return handleListFiles(directory);\n },\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionFromCookies } from \"../auth/session\";\nimport { uploadFile } from \"../content/upload\";\n\n/**\n * Handle file upload\n */\nexport async function handleUpload(request: NextRequest) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const formData = await request.formData();\n const file = formData.get(\"file\") as File;\n\n if (!file) {\n return NextResponse.json({ error: \"No file provided\" }, { status: 400 });\n }\n\n // Convert file to buffer\n const bytes = await file.arrayBuffer();\n const buffer = Buffer.from(bytes);\n\n // Upload file\n const publicUrl = await uploadFile(file.name, buffer);\n\n return NextResponse.json({\n success: true,\n url: publicUrl,\n filename: file.name,\n });\n } catch (error) {\n console.error(\"Upload error:\", error);\n return NextResponse.json(\n { error: \"Failed to upload file\" },\n { status: 500 }\n );\n }\n}\n","\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\n\n// Types\ninterface FileEntry {\n path: string;\n name: string;\n type: \"file\" | \"directory\";\n}\n\ntype FieldType = \"text\" | \"date\" | \"number\" | \"markdown\" | \"image\";\n\ninterface FieldMeta {\n type: FieldType;\n value: any;\n}\n\nexport function AdminDashboard() {\n const [entries, setEntries] = useState<FileEntry[]>([]);\n const [currentPath, setCurrentPath] = useState(\"\");\n const [selectedFile, setSelectedFile] = useState<string | null>(null);\n const [fields, setFields] = useState<Record<string, FieldMeta>>({});\n const [loading, setLoading] = useState(false);\n const [message, setMessage] = useState(\"\");\n const [newFileName, setNewFileName] = useState(\"\");\n const [uploading, setUploading] = useState(false);\n\n useEffect(() => {\n loadDirectory(currentPath);\n }, [currentPath]);\n\n const loadDirectory = async (path: string) => {\n try {\n const url = path ? `/api/cms/list/${path}` : \"/api/cms/list\";\n const response = await fetch(url);\n const data = await response.json();\n setEntries(data.entries || []);\n } catch (error) {\n console.error(\"Failed to load directory:\", error);\n }\n };\n\n const loadFile = async (filePath: string) => {\n try {\n const response = await fetch(`/api/cms/content/${filePath}`);\n const data = await response.json();\n setSelectedFile(filePath);\n\n // Convert loaded data to fields format\n const loadedFields: Record<string, FieldMeta> = {};\n\n // Add content as markdown field if exists\n if (data.content !== undefined) {\n loadedFields[\"content\"] = { type: \"markdown\", value: data.content };\n }\n\n // Add frontmatter fields with type detection\n Object.entries(data.data || {}).forEach(([key, value]) => {\n loadedFields[key] = {\n type: detectFieldType(value as any),\n value,\n };\n });\n\n setFields(loadedFields);\n } catch (error) {\n setMessage(\"Failed to load file\");\n }\n };\n\n const detectFieldType = (value: any): FieldType => {\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"string\") {\n if (value.match(/^\\d{4}-\\d{2}-\\d{2}/)) return \"date\";\n if (value.startsWith(\"/uploads/\") || value.startsWith(\"http\"))\n return \"image\";\n if (value.length > 100) return \"markdown\";\n }\n return \"text\";\n };\n\n const saveFile = async () => {\n if (!selectedFile) return;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n // Separate content from frontmatter\n const frontmatter: Record<string, any> = {};\n let content = \"\";\n\n Object.entries(fields).forEach(([key, field]) => {\n if (key === \"content\") {\n content = field.value;\n } else {\n frontmatter[key] = field.value;\n }\n });\n\n const response = await fetch(`/api/cms/content/${selectedFile}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: frontmatter, content }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File saved successfully!\");\n setTimeout(() => setMessage(\"\"), 3000);\n } else {\n const errorData = await response.json().catch(() => ({}));\n setMessage(\n `❌ Failed to save file: ${errorData.error || response.statusText}`\n );\n }\n } catch (error) {\n setMessage(\n `❌ Error saving file: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n } finally {\n setLoading(false);\n }\n };\n\n const createFile = async () => {\n if (!newFileName) return;\n\n const fileName = newFileName.endsWith(\".md\")\n ? newFileName\n : `${newFileName}.md`;\n const fullPath = currentPath ? `${currentPath}/${fileName}` : fileName;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const response = await fetch(`/api/cms/content/${fullPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: {},\n content: \"\",\n }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File created!\");\n setNewFileName(\"\");\n loadDirectory(currentPath);\n loadFile(fullPath);\n } else {\n setMessage(\"❌ Failed to create file\");\n }\n } catch (error) {\n setMessage(\"❌ Error creating file\");\n } finally {\n setLoading(false);\n }\n };\n\n const duplicateFile = async () => {\n if (!selectedFile) return;\n\n const newName = prompt(\"Enter new filename (without .md extension):\");\n if (!newName) return;\n\n const duplicateName = currentPath\n ? `${currentPath}/${newName}.md`\n : `${newName}.md`;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const frontmatter: Record<string, any> = {};\n let content = \"\";\n\n Object.entries(fields).forEach(([key, field]) => {\n if (key === \"content\") {\n content = field.value;\n } else {\n frontmatter[key] = field.value;\n }\n });\n\n const response = await fetch(`/api/cms/content/${duplicateName}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: frontmatter, content }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File duplicated!\");\n loadDirectory(currentPath);\n loadFile(duplicateName);\n } else {\n const errorData = await response.json().catch(() => ({}));\n setMessage(\n `❌ Failed to duplicate file: ${errorData.error || \"Unknown error\"}`\n );\n }\n } catch (error) {\n setMessage(\"❌ Error duplicating file\");\n } finally {\n setLoading(false);\n }\n };\n\n const deleteFile = async (filePath: string) => {\n if (!confirm(`Delete ${filePath}?`)) return;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const response = await fetch(`/api/cms/content/${filePath}`, {\n method: \"DELETE\",\n });\n\n if (response.ok) {\n setMessage(\"✅ File deleted!\");\n if (selectedFile === filePath) {\n setSelectedFile(null);\n setFields({});\n }\n loadDirectory(currentPath);\n } else {\n setMessage(\"❌ Failed to delete file\");\n }\n } catch (error) {\n setMessage(\"❌ Error deleting file\");\n } finally {\n setLoading(false);\n }\n };\n\n const navigateToDir = (dirPath: string) => {\n setCurrentPath(dirPath);\n setSelectedFile(null);\n };\n\n const goUp = () => {\n const parts = currentPath.split(\"/\");\n parts.pop();\n setCurrentPath(parts.join(\"/\"));\n setSelectedFile(null);\n };\n\n const handleLogout = async () => {\n await fetch(\"/api/cms/logout\", { method: \"POST\" });\n window.location.href = \"/admin/login\";\n };\n\n const updateField = (key: string, value: any) => {\n setFields((prev) => ({\n ...prev,\n [key]: { ...prev[key], value },\n }));\n };\n\n const addField = () => {\n const fieldName = prompt(\"Enter field name:\");\n if (!fieldName || fields[fieldName]) return;\n\n const fieldType = prompt(\n \"Enter field type (text/date/number/markdown/image):\",\n \"text\"\n ) as FieldType;\n const validTypes: FieldType[] = [\n \"text\",\n \"date\",\n \"number\",\n \"markdown\",\n \"image\",\n ];\n\n if (!validTypes.includes(fieldType)) {\n alert(\"Invalid field type! Use: text, date, number, markdown, or image\");\n return;\n }\n\n const defaultValue =\n fieldType === \"number\"\n ? 0\n : fieldType === \"date\"\n ? new Date().toISOString().split(\"T\")[0]\n : \"\";\n\n setFields((prev) => ({\n ...prev,\n [fieldName]: { type: fieldType, value: defaultValue },\n }));\n };\n\n const removeField = (key: string) => {\n const newFields = { ...fields };\n delete newFields[key];\n setFields(newFields);\n };\n\n const handleImageUpload = async (\n key: string,\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setUploading(true);\n\n try {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const response = await fetch(\"/api/cms/upload\", {\n method: \"POST\",\n body: formData,\n });\n\n const data = await response.json();\n\n if (response.ok) {\n updateField(key, data.url);\n setMessage(`✅ Image uploaded!`);\n setTimeout(() => setMessage(\"\"), 3000);\n } else {\n setMessage(\"❌ Failed to upload image\");\n }\n } catch (error) {\n setMessage(\"❌ Error uploading image\");\n } finally {\n setUploading(false);\n event.target.value = \"\";\n }\n };\n\n const handleFileUpload = async (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setUploading(true);\n setMessage(\"\");\n\n try {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const response = await fetch(\"/api/cms/upload\", {\n method: \"POST\",\n body: formData,\n });\n\n const data = await response.json();\n\n if (response.ok) {\n setMessage(`✅ File uploaded! Path: ${data.url}`);\n setTimeout(() => setMessage(\"\"), 5000);\n } else {\n setMessage(\"❌ Failed to upload file\");\n }\n } catch (error) {\n setMessage(\"❌ Error uploading file\");\n } finally {\n setUploading(false);\n event.target.value = \"\";\n }\n };\n\n const renderField = (key: string, field: FieldMeta) => {\n switch (field.type) {\n case \"text\":\n return (\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"number\":\n return (\n <input\n id={key}\n type=\"number\"\n value={field.value}\n onChange={(e) => updateField(key, parseFloat(e.target.value) || 0)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"date\":\n return (\n <input\n id={key}\n type=\"date\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"markdown\":\n return (\n <textarea\n id={key}\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n minHeight: key === \"content\" ? \"400px\" : \"150px\",\n fontFamily: \"monospace\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n placeholder={\n key === \"content\"\n ? \"Write your markdown content here...\"\n : \"Markdown text...\"\n }\n />\n );\n case \"image\":\n return (\n <div>\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n placeholder=\"/uploads/image.jpg or https://...\"\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n marginBottom: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={(e) => handleImageUpload(key, e)}\n disabled={uploading}\n style={{ marginBottom: \"0.5rem\" }}\n />\n {field.value && (\n <img\n src={field.value}\n alt={key}\n style={{\n maxWidth: \"200px\",\n display: \"block\",\n marginTop: \"0.5rem\",\n borderRadius: \"4px\",\n border: \"1px solid #ddd\",\n }}\n />\n )}\n </div>\n );\n default:\n return (\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n />\n );\n }\n };\n\n return (\n <div\n className=\"container\"\n style={{ maxWidth: \"1200px\", margin: \"0 auto\", padding: \"2rem\" }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"2rem\",\n }}\n >\n <h1>📝 Admin Dashboard</h1>\n <button\n onClick={handleLogout}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n Logout\n </button>\n </div>\n\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: \"minmax(250px, 300px) 1fr\",\n gap: \"2rem\",\n }}\n >\n {/* Sidebar */}\n <div\n style={{\n background: \"white\",\n padding: \"1.5rem\",\n borderRadius: \"8px\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n }}\n >\n <h2 style={{ marginTop: 0, marginBottom: \"1rem\" }}>Files</h2>\n\n {/* Breadcrumb */}\n <div\n style={{\n marginBottom: \"1rem\",\n fontSize: \"0.875rem\",\n color: \"#666\",\n }}\n >\n <span\n onClick={() => setCurrentPath(\"\")}\n style={{\n cursor: \"pointer\",\n color: \"#0070f3\",\n textDecoration: \"underline\",\n }}\n >\n content\n </span>\n {currentPath && (\n <>\n {\" / \"}\n <span style={{ fontWeight: \"bold\" }}>{currentPath}</span>\n </>\n )}\n </div>\n\n {/* Back button */}\n {currentPath && (\n <button\n onClick={goUp}\n style={{\n width: \"100%\",\n marginBottom: \"1rem\",\n padding: \"0.5rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n ⬆️ Go Up\n </button>\n )}\n\n {/* New file form */}\n <div\n style={{\n marginBottom: \"1.5rem\",\n paddingBottom: \"1.5rem\",\n borderBottom: \"1px solid #eee\",\n }}\n >\n <input\n type=\"text\"\n placeholder=\"new-file.md\"\n value={newFileName}\n onChange={(e) => setNewFileName(e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n marginBottom: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n <button\n onClick={createFile}\n disabled={loading || !newFileName}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n + New File\n </button>\n </div>\n\n {/* File/folder list */}\n <ul style={{ listStyle: \"none\", padding: 0, margin: 0 }}>\n {entries.length === 0 && (\n <li style={{ color: \"#999\", fontStyle: \"italic\" }}>\n Empty directory\n </li>\n )}\n {entries.map((entry) => (\n <li\n key={entry.path}\n style={{\n marginBottom: \"0.5rem\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {entry.type === \"directory\" ? (\n <button\n onClick={() => navigateToDir(entry.path)}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#0070f3\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: \"1rem\",\n padding: \"0.25rem 0\",\n fontWeight: \"bold\",\n }}\n >\n 📁 {entry.name}\n </button>\n ) : (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <button\n onClick={() => loadFile(entry.path)}\n style={{\n background: \"none\",\n border: \"none\",\n color: selectedFile === entry.path ? \"#000\" : \"#444\",\n cursor: \"pointer\",\n textAlign: \"left\",\n padding: \"0.25rem 0\",\n fontWeight:\n selectedFile === entry.path ? \"bold\" : \"normal\",\n textDecoration:\n selectedFile === entry.path ? \"underline\" : \"none\",\n flex: 1,\n }}\n >\n 📄 {entry.name}\n </button>\n <button\n onClick={() => deleteFile(entry.path)}\n disabled={loading}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#d32f2f\",\n cursor: \"pointer\",\n fontSize: \"0.8rem\",\n opacity: 0.7,\n }}\n >\n ✕\n </button>\n </div>\n )}\n </li>\n ))}\n </ul>\n </div>\n\n {/* Editor */}\n <div\n style={{\n background: \"white\",\n padding: \"2rem\",\n borderRadius: \"8px\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n }}\n >\n {selectedFile ? (\n <>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"2rem\",\n paddingBottom: \"1rem\",\n borderBottom: \"1px solid #eee\",\n }}\n >\n <h2 style={{ margin: 0 }}>Edit: {selectedFile}</h2>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <button\n onClick={duplicateFile}\n disabled={loading}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n 📋 Duplicate\n </button>\n <button\n onClick={saveFile}\n disabled={loading}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n {loading ? \"Saving...\" : \"💾 Save Changes\"}\n </button>\n </div>\n </div>\n\n {message && (\n <div\n style={{\n marginBottom: \"1.5rem\",\n padding: \"0.75rem\",\n background: message.includes(\"✅\") ? \"#e6ffe6\" : \"#ffe6e6\",\n borderRadius: \"4px\",\n border: message.includes(\"✅\")\n ? \"1px solid #a5d6a7\"\n : \"1px solid #ef9a9a\",\n }}\n >\n {message}\n </div>\n )}\n\n {/* Dynamic Fields */}\n <div style={{ marginBottom: \"2rem\" }}>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"1rem\",\n }}\n >\n <h3 style={{ fontSize: \"1.1rem\", margin: 0 }}>Fields</h3>\n <button\n onClick={addField}\n style={{\n fontSize: \"0.875rem\",\n padding: \"0.4rem 0.8rem\",\n background: \"#e1f5fe\",\n color: \"#0288d1\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n + Add Field\n </button>\n </div>\n\n {Object.keys(fields).length === 0 ? (\n <div\n style={{\n padding: \"2rem\",\n textAlign: \"center\",\n background: \"#f9f9f9\",\n borderRadius: \"4px\",\n border: \"1px dashed #ccc\",\n }}\n >\n <p\n style={{ color: \"#666\", fontStyle: \"italic\", margin: 0 }}\n >\n No fields yet. Click \"+ Add Field\" to start.\n </p>\n <small\n style={{\n color: \"#999\",\n marginTop: \"0.5rem\",\n display: \"block\",\n }}\n >\n Add 'content' field for the main body\n </small>\n </div>\n ) : (\n Object.entries(fields).map(([key, field]) => (\n <div\n key={key}\n style={{\n marginBottom: \"1.5rem\",\n background: \"#fff\",\n border: \"1px solid #eee\",\n padding: \"1rem\",\n borderRadius: \"6px\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"0.5rem\",\n }}\n >\n <label htmlFor={key} style={{ fontWeight: 500 }}>\n {key}\n <span\n style={{\n marginLeft: \"0.5rem\",\n fontSize: \"0.75rem\",\n color: \"#999\",\n background: \"#f0f0f0\",\n padding: \"0.1rem 0.4rem\",\n borderRadius: \"4px\",\n }}\n >\n {field.type}\n </span>\n </label>\n <button\n onClick={() => removeField(key)}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#e57373\",\n cursor: \"pointer\",\n fontSize: \"0.875rem\",\n }}\n >\n ✕ Remove\n </button>\n </div>\n\n {renderField(key, field)}\n </div>\n ))\n )}\n </div>\n\n {/* General File Upload */}\n <div\n style={{\n marginTop: \"3rem\",\n paddingTop: \"1rem\",\n borderTop: \"1px solid #eee\",\n }}\n >\n <h3\n style={{\n fontSize: \"1rem\",\n marginBottom: \"0.5rem\",\n color: \"#666\",\n }}\n >\n Quick File Upload\n </h3>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <input\n type=\"file\"\n onChange={handleFileUpload}\n disabled={uploading}\n style={{ flex: 1 }}\n />\n {uploading && (\n <span style={{ color: \"#666\" }}>Uploading...</span>\n )}\n </div>\n </div>\n </>\n ) : (\n <div\n style={{\n textAlign: \"center\",\n padding: \"5rem 2rem\",\n color: \"#999\",\n }}\n >\n <div style={{ fontSize: \"3rem\", marginBottom: \"1rem\" }}>👈</div>\n <p style={{ fontSize: \"1.1rem\" }}>\n Select a file from the sidebar to edit\n </p>\n <p>or create a new file to get started</p>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\n\nexport function Login() {\n const [username, setUsername] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n try {\n const response = await fetch(\"/api/cms/login\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username, password }),\n });\n\n const data = (await response.json()) as { error?: string };\n\n if (response.ok) {\n window.location.href = \"/admin\";\n } else {\n setError(data.error || \"Login failed\");\n }\n } catch (err) {\n setError(\"An error occurred. Please try again.\");\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n minHeight: \"100vh\",\n background: \"#f5f5f5\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"400px\",\n padding: \"2rem\",\n background: \"white\",\n borderRadius: \"8px\",\n boxShadow: \"0 4px 6px rgba(0,0,0,0.1)\",\n }}\n >\n <h1 style={{ marginBottom: \"0.5rem\", textAlign: \"center\" }}>\n Admin Login\n </h1>\n <p style={{ color: \"#666\", marginBottom: \"2rem\", textAlign: \"center\" }}>\n Enter your credentials to access the CMS\n </p>\n\n <form onSubmit={handleSubmit}>\n <div style={{ marginBottom: \"1rem\" }}>\n <label\n htmlFor=\"username\"\n style={{\n display: \"block\",\n marginBottom: \"0.5rem\",\n fontWeight: 500,\n }}\n >\n Username\n </label>\n <input\n id=\"username\"\n type=\"text\"\n value={username}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setUsername(e.target.value)\n }\n required\n autoFocus\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n </div>\n\n <div style={{ marginBottom: \"1.5rem\" }}>\n <label\n htmlFor=\"password\"\n style={{\n display: \"block\",\n marginBottom: \"0.5rem\",\n fontWeight: 500,\n }}\n >\n Password\n </label>\n <input\n id=\"password\"\n type=\"password\"\n value={password}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setPassword(e.target.value)\n }\n required\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n </div>\n\n {error && (\n <div\n style={{\n marginBottom: \"1rem\",\n padding: \"0.75rem\",\n background: \"#ffe6e6\",\n color: \"#d32f2f\",\n borderRadius: \"4px\",\n fontSize: \"0.875rem\",\n }}\n >\n {error}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={loading}\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n fontSize: \"1rem\",\n fontWeight: 500,\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n {loading ? \"Logging in...\" : \"Login\"}\n </button>\n </form>\n </div>\n </div>\n );\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionFromCookies } from \"../auth/session\";\n\n/**\n * Create middleware to protect admin routes\n */\nexport function createAuthMiddleware(\n options: {\n loginPath?: string;\n protectedPaths?: string[];\n } = {}\n) {\n const loginPath = options.loginPath || \"/admin/login\";\n const protectedPaths = options.protectedPaths || [\"/admin\"];\n\n return async function middleware(request: NextRequest) {\n const { pathname } = request.nextUrl;\n\n // Skip if not a protected path\n const isProtected = protectedPaths.some((path) =>\n pathname.startsWith(path)\n );\n if (!isProtected) {\n return NextResponse.next();\n }\n\n // Allow login page\n if (pathname === loginPath) {\n return NextResponse.next();\n }\n\n // Check session\n const session = await getSessionFromCookies();\n if (!session) {\n const url = request.nextUrl.clone();\n url.pathname = loginPath;\n url.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(url);\n }\n\n return NextResponse.next();\n };\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n await fs.writeFile(\n path.join(adminDir, \"page.tsx\"),\n `import { AdminDashboard } from '@fydemy/cms';\\n\\nexport default AdminDashboard;\\n`,\n \"utf-8\"\n );\n\n await fs.writeFile(\n path.join(loginDir, \"page.tsx\"),\n `import { Login } from '@fydemy/cms';\\n\\nexport default Login;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created Admin UI pages\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n"],"mappings":"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","names":["path","fs","import_path","path","matter","crypto","checkRateLimit","incrementRateLimit","resetRateLimit","import_server","path","handleLogout","import_react","import_jsx_runtime","import_server","path","import_promises","import_path","path","fs"]}
1
+ {"version":3,"sources":["../src/utils/rate-limit.ts","../src/index.ts","../src/content/markdown.ts","../src/content/storage.ts","../src/utils/validation.ts","../src/content/directory.ts","../src/content/collection.ts","../src/content/upload.ts","../src/auth/session.ts","../src/auth/login.ts","../src/api/handlers.ts","../src/api/upload.ts","../src/ui/AdminDashboard.tsx","../src/ui/Login.tsx","../src/middleware/auth.ts","../src/init/setup.ts"],"sourcesContent":["/**\n * Simple in-memory rate limiter for login attempts\n */\n\ninterface RateLimitEntry {\n count: number;\n resetTime: number;\n}\n\nconst rateLimitStore = new Map<string, RateLimitEntry>();\n\n// Configuration\nconst MAX_ATTEMPTS = 5; // Maximum login attempts\nconst WINDOW_MS = 15 * 60 * 1000; // 15 minutes\n\n/**\n * Check if IP/identifier is rate limited\n * @param identifier - IP address or other unique identifier\n * @returns Object with isLimited and remaining attempts\n */\nexport function checkRateLimit(identifier: string): {\n isLimited: boolean;\n remaining: number;\n resetTime: number;\n} {\n const now = Date.now();\n const entry = rateLimitStore.get(identifier);\n\n // No entry or expired entry\n if (!entry || now > entry.resetTime) {\n rateLimitStore.set(identifier, {\n count: 0,\n resetTime: now + WINDOW_MS,\n });\n\n return {\n isLimited: false,\n remaining: MAX_ATTEMPTS,\n resetTime: now + WINDOW_MS,\n };\n }\n\n // Check if limit exceeded\n if (entry.count >= MAX_ATTEMPTS) {\n return {\n isLimited: true,\n remaining: 0,\n resetTime: entry.resetTime,\n };\n }\n\n return {\n isLimited: false,\n remaining: MAX_ATTEMPTS - entry.count,\n resetTime: entry.resetTime,\n };\n}\n\n/**\n * Increment rate limit counter for identifier\n * @param identifier - IP address or other unique identifier\n */\nexport function incrementRateLimit(identifier: string): void {\n const now = Date.now();\n const entry = rateLimitStore.get(identifier);\n\n if (!entry || now > entry.resetTime) {\n rateLimitStore.set(identifier, {\n count: 1,\n resetTime: now + WINDOW_MS,\n });\n } else {\n entry.count++;\n }\n}\n\n/**\n * Reset rate limit for identifier (use after successful login)\n * @param identifier - IP address or other unique identifier\n */\nexport function resetRateLimit(identifier: string): void {\n rateLimitStore.delete(identifier);\n}\n\n/**\n * Clean up expired entries (should be called periodically)\n */\nexport function cleanupRateLimitStore(): void {\n const now = Date.now();\n for (const [identifier, entry] of rateLimitStore.entries()) {\n if (now > entry.resetTime) {\n rateLimitStore.delete(identifier);\n }\n }\n}\n\n// Cleanup expired entries every 5 minutes\nif (typeof setInterval !== \"undefined\") {\n setInterval(cleanupRateLimitStore, 5 * 60 * 1000);\n}\n","// Content management\nexport {\n getMarkdownContent,\n saveMarkdownContent,\n deleteMarkdownContent,\n listMarkdownFiles,\n markdownFileExists,\n parseMarkdown,\n stringifyMarkdown,\n} from \"./content/markdown\";\n\nexport type { MarkdownData } from \"./content/markdown\";\n\nexport { listDirectory } from \"./content/directory\";\n\nexport {\n getCollectionItems,\n getCollectionItem,\n getCollections,\n} from \"./content/collection\";\n\nexport type { CollectionItem } from \"./content/collection\";\n\nexport { uploadFile } from \"./content/upload\";\n\nexport {\n LocalStorage,\n GitHubStorage,\n getStorageProvider,\n} from \"./content/storage\";\n\nexport type { StorageProvider, FileEntry } from \"./content/storage\";\n\n// Authentication\nexport {\n createSession,\n verifySession,\n getSessionFromCookies,\n setSessionCookie,\n clearSessionCookie,\n} from \"./auth/session\";\n\nexport { validateCredentials } from \"./auth/login\";\n\n// API handlers\nexport {\n handleLogin,\n handleLogout,\n handleGetContent,\n handleSaveContent,\n handleDeleteContent,\n handleListFiles,\n createContentApiHandlers,\n createListApiHandlers,\n} from \"./api/handlers\";\n\nexport { handleUpload } from \"./api/upload\";\n\n// UI Components\nexport { AdminDashboard } from \"./ui/AdminDashboard\";\nexport { Login } from \"./ui/Login\";\n\n// Middleware\nexport { createAuthMiddleware } from \"./middleware/auth\";\n\n// Initialize\nexport { initCMS } from \"./init/setup\";\nexport type { InitCMSConfig } from \"./init/setup\";\n\n// Utilities (for advanced usage)\nexport {\n validateFilePath,\n validateUsername,\n validatePassword,\n validateFileSize,\n sanitizeFrontmatter,\n MAX_USERNAME_LENGTH,\n MAX_PASSWORD_LENGTH,\n MAX_FILE_SIZE,\n} from \"./utils/validation\";\n\nexport {\n checkRateLimit,\n incrementRateLimit,\n resetRateLimit,\n} from \"./utils/rate-limit\";\n","import matter from \"gray-matter\";\nimport { getStorageProvider } from \"./storage\";\nimport {\n validateFilePath,\n sanitizeFrontmatter,\n MAX_FILE_SIZE,\n} from \"../utils/validation\";\n\nexport interface MarkdownData {\n content: string;\n data: Record<string, any>;\n}\n\n/**\n * Parse markdown content with frontmatter\n * @param rawContent - Raw markdown content to parse\n * @returns Parsed markdown data with frontmatter and content\n */\nexport function parseMarkdown(rawContent: string): MarkdownData {\n const { data, content } = matter(rawContent);\n return { data, content };\n}\n\n/**\n * Convert data and content back to markdown with frontmatter\n */\nexport function stringifyMarkdown(\n data: Record<string, any>,\n content: string\n): string {\n return matter.stringify(content, data);\n}\n\n/**\n * Read and parse a markdown file\n * @param filePath - Path to the markdown file\n * @returns Parsed markdown data\n * @throws Error if file path is invalid or file is too large\n */\nexport async function getMarkdownContent(\n filePath: string\n): Promise<MarkdownData> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n const rawContent = await storage.readFile(validatedPath);\n\n // Check file size\n const size = Buffer.byteLength(rawContent, \"utf-8\");\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `File size (${size} bytes) exceeds maximum allowed size (${MAX_FILE_SIZE} bytes)`\n );\n }\n\n return parseMarkdown(rawContent);\n}\n\n/**\n * Write markdown file with frontmatter\n * @param filePath - Path to the markdown file\n * @param data - Frontmatter data object\n * @param content - Markdown content\n * @throws Error if file path is invalid or content is too large\n */\nexport async function saveMarkdownContent(\n filePath: string,\n data: Record<string, any>,\n content: string\n): Promise<void> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n // Sanitize frontmatter\n const sanitizedData = sanitizeFrontmatter(data);\n\n const markdown = stringifyMarkdown(sanitizedData, content);\n\n // Check size before writing\n const size = Buffer.byteLength(markdown, \"utf-8\");\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `Content size (${size} bytes) exceeds maximum allowed size (${MAX_FILE_SIZE} bytes)`\n );\n }\n\n const storage = getStorageProvider();\n await storage.writeFile(validatedPath, markdown);\n}\n\n/**\n * Delete a markdown file\n * @param filePath - Path to the markdown file\n * @throws Error if file path is invalid\n */\nexport async function deleteMarkdownContent(filePath: string): Promise<void> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n await storage.deleteFile(validatedPath);\n}\n\n/**\n * List all markdown files in a directory\n * @param directory - Directory path (optional, defaults to root)\n * @returns Array of file paths\n * @throws Error if directory path is invalid\n */\nexport async function listMarkdownFiles(\n directory: string = \"\"\n): Promise<string[]> {\n // Validate directory path if provided\n const validatedDir = directory ? validateFilePath(directory) : \"\";\n\n const storage = getStorageProvider();\n const entries = await storage.listFiles(validatedDir);\n return entries\n .filter((entry) => entry.type === \"file\")\n .map((entry) => entry.path);\n}\n\n/**\n * Check if a markdown file exists\n * @param filePath - Path to the markdown file\n * @returns True if file exists, false otherwise\n * @throws Error if file path is invalid\n */\nexport async function markdownFileExists(filePath: string): Promise<boolean> {\n // Validate file path\n const validatedPath = validateFilePath(filePath);\n\n const storage = getStorageProvider();\n return storage.exists(validatedPath);\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\nimport { Octokit } from \"@octokit/rest\";\n\n/**\n * Represents a file or directory entry\n */\nexport interface FileEntry {\n /** Relative path from base content directory */\n path: string;\n /** File or directory name */\n name: string;\n /** Type of entry */\n type: \"file\" | \"directory\";\n}\n\n/**\n * Interface for file storage operations\n */\nexport interface StorageProvider {\n /** Read file content as string */\n readFile(filePath: string): Promise<string>;\n /** Write content to file, creating parent directories if needed */\n writeFile(filePath: string, content: string): Promise<void>;\n /** Delete a file */\n deleteFile(filePath: string): Promise<void>;\n /** List files in a directory */\n listFiles(directory: string): Promise<FileEntry[]>;\n /** Check if a file exists */\n exists(filePath: string): Promise<boolean>;\n /** Upload a binary file */\n uploadFile(filePath: string, buffer: Buffer): Promise<string>; // Returns public URL\n}\n\n/**\n * Local file system storage (for development)\n */\nexport class LocalStorage implements StorageProvider {\n private baseDir: string;\n\n constructor(baseDir: string = \"public/content\") {\n this.baseDir = baseDir;\n }\n\n private getFullPath(filePath: string): string {\n return path.join(process.cwd(), this.baseDir, filePath);\n }\n\n async readFile(filePath: string): Promise<string> {\n const fullPath = this.getFullPath(filePath);\n return fs.readFile(fullPath, \"utf-8\");\n }\n\n async writeFile(filePath: string, content: string): Promise<void> {\n const fullPath = this.getFullPath(filePath);\n await fs.mkdir(path.dirname(fullPath), { recursive: true });\n await fs.writeFile(fullPath, content, \"utf-8\");\n }\n\n async deleteFile(filePath: string): Promise<void> {\n const fullPath = this.getFullPath(filePath);\n await fs.unlink(fullPath);\n }\n\n async listFiles(directory: string): Promise<FileEntry[]> {\n const fullPath = this.getFullPath(directory);\n try {\n const entries = await fs.readdir(fullPath, { withFileTypes: true });\n return entries\n .map((entry) => ({\n path: path.join(directory, entry.name),\n name: entry.name,\n type: entry.isDirectory()\n ? (\"directory\" as const)\n : (\"file\" as const),\n }))\n .filter(\n (entry) => entry.type === \"directory\" || entry.name.endsWith(\".md\")\n );\n } catch (error) {\n return [];\n }\n }\n\n async exists(filePath: string): Promise<boolean> {\n try {\n const fullPath = this.getFullPath(filePath);\n await fs.access(fullPath);\n return true;\n } catch {\n return false;\n }\n }\n\n async uploadFile(filePath: string, buffer: Buffer): Promise<string> {\n // Store uploads in /public/uploads directory\n const uploadPath = path.join(process.cwd(), \"public\", \"uploads\", filePath);\n await fs.mkdir(path.dirname(uploadPath), { recursive: true });\n await fs.writeFile(uploadPath, buffer);\n\n // Return public URL path\n return `/uploads/${filePath}`;\n }\n}\n\n/**\n * GitHub storage (for production)\n */\nexport class GitHubStorage implements StorageProvider {\n private octokit: Octokit;\n private owner: string;\n private repo: string;\n private branch: string;\n private baseDir: string;\n\n constructor() {\n const token = process.env.GITHUB_TOKEN;\n const repoInfo = process.env.GITHUB_REPO;\n\n if (!token || !repoInfo) {\n throw new Error(\n \"GITHUB_TOKEN and GITHUB_REPO must be set for production\"\n );\n }\n\n const [owner, repo] = repoInfo.split(\"/\");\n if (!owner || !repo) {\n throw new Error('GITHUB_REPO must be in format \"owner/repo\"');\n }\n\n this.octokit = new Octokit({ auth: token });\n this.owner = owner;\n this.repo = repo;\n this.branch = process.env.GITHUB_BRANCH || \"main\";\n this.baseDir = \"public/content\";\n }\n\n private getGitHubPath(filePath: string): string {\n return `${this.baseDir}/${filePath}`;\n }\n\n async readFile(filePath: string): Promise<string> {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: this.getGitHubPath(filePath),\n ref: this.branch,\n });\n\n if (\"content\" in data) {\n return Buffer.from(data.content, \"base64\").toString(\"utf-8\");\n }\n throw new Error(\"File not found\");\n }\n\n async writeFile(filePath: string, content: string): Promise<void> {\n const githubPath = this.getGitHubPath(filePath);\n let sha: string | undefined;\n\n // Try to get existing file SHA\n try {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n if (\"sha\" in data) {\n sha = data.sha;\n }\n } catch (error) {\n // File doesn't exist, that's ok\n }\n\n await this.octokit.repos.createOrUpdateFileContents({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n message: `Update ${filePath}`,\n content: Buffer.from(content).toString(\"base64\"),\n branch: this.branch,\n sha,\n });\n }\n\n async deleteFile(filePath: string): Promise<void> {\n const githubPath = this.getGitHubPath(filePath);\n\n // Get file SHA\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n\n if (\"sha\" in data) {\n await this.octokit.repos.deleteFile({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n message: `Delete ${filePath}`,\n sha: data.sha,\n branch: this.branch,\n });\n }\n }\n\n async listFiles(directory: string): Promise<FileEntry[]> {\n const githubPath = this.getGitHubPath(directory);\n\n try {\n const { data } = await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: githubPath,\n ref: this.branch,\n });\n\n if (Array.isArray(data)) {\n return data\n .map((item) => ({\n path: path.join(directory, item.name),\n name: item.name,\n type:\n item.type === \"dir\" ? (\"directory\" as const) : (\"file\" as const),\n }))\n .filter(\n (entry) => entry.type === \"directory\" || entry.name.endsWith(\".md\")\n );\n }\n } catch (error) {\n // Directory doesn't exist\n }\n\n return [];\n }\n\n async exists(filePath: string): Promise<boolean> {\n try {\n await this.octokit.repos.getContent({\n owner: this.owner,\n repo: this.repo,\n path: this.getGitHubPath(filePath),\n ref: this.branch,\n });\n return true;\n } catch {\n return false;\n }\n }\n\n async uploadFile(filePath: string, buffer: Buffer): Promise<string> {\n // Store uploads in public/uploads directory in GitHub\n const uploadPath = `public/uploads/${filePath}`;\n\n await this.octokit.repos.createOrUpdateFileContents({\n owner: this.owner,\n repo: this.repo,\n path: uploadPath,\n message: `Upload file: ${filePath}`,\n content: buffer.toString(\"base64\"),\n branch: this.branch,\n });\n\n // Return public URL path\n return `/uploads/${filePath}`;\n }\n}\n\n/**\n * Get the appropriate storage provider based on environment\n */\nexport function getStorageProvider(): StorageProvider {\n if (process.env.NODE_ENV === \"production\" && process.env.GITHUB_TOKEN) {\n return new GitHubStorage();\n }\n return new LocalStorage();\n}\n","import path from \"path\";\n\n/**\n * Maximum username length (prevents DoS)\n */\nexport const MAX_USERNAME_LENGTH = 100;\n\n/**\n * Maximum password length (prevents DoS)\n */\nexport const MAX_PASSWORD_LENGTH = 1000;\n\n/**\n * Maximum file size in bytes (10MB)\n */\nexport const MAX_FILE_SIZE = 10 * 1024 * 1024;\n\n/**\n * Validate and sanitize file path to prevent directory traversal\n * @param filePath - The file path to validate\n * @returns Sanitized file path\n * @throws Error if path is invalid or attempts directory traversal\n */\nexport function validateFilePath(filePath: string): string {\n if (!filePath || typeof filePath !== \"string\") {\n throw new Error(\"Invalid file path\");\n }\n\n // Remove any null bytes\n if (filePath.includes(\"\\x00\")) {\n throw new Error(\"Invalid file path: null byte detected\");\n }\n\n // Check for directory traversal attempts BEFORE normalization\n if (filePath.includes(\"..\")) {\n throw new Error(\"Invalid file path: directory traversal detected\");\n }\n\n // Normalize the path\n const normalized = path.normalize(filePath).replace(/^(\\.\\.(\\/|\\\\|$))+/, \"\");\n\n // Check if normalized path is different and contains dangerous patterns\n if (normalized.startsWith(\"/\") || normalized.startsWith(\"\\\\\")) {\n throw new Error(\"Invalid file path: directory traversal detected\");\n }\n\n // Ensure path doesn't contain dangerous patterns\n const dangerousPatterns = [\n /\\.\\./,\n /^[/\\\\]/,\n /[<>:\"|?*]/,\n /\\x00/,\n /^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$/i, // Windows reserved names\n ];\n\n for (const pattern of dangerousPatterns) {\n if (pattern.test(normalized)) {\n throw new Error(\"Invalid file path: contains dangerous characters\");\n }\n }\n\n return normalized;\n}\n\n/**\n * Validate username input\n * @param username - The username to validate\n * @returns True if valid\n * @throws Error if invalid\n */\nexport function validateUsername(username: string): boolean {\n if (!username || typeof username !== \"string\") {\n throw new Error(\"Username is required\");\n }\n\n if (username.length > MAX_USERNAME_LENGTH) {\n throw new Error(\n `Username must be ${MAX_USERNAME_LENGTH} characters or less`\n );\n }\n\n // Only allow alphanumeric, underscore, hyphen\n if (!/^[a-zA-Z0-9_-]+$/.test(username)) {\n throw new Error(\n \"Username must contain only letters, numbers, underscores, and hyphens\"\n );\n }\n\n return true;\n}\n\n/**\n * Validate password input\n * @param password - The password to validate\n * @returns True if valid\n * @throws Error if invalid\n */\nexport function validatePassword(password: string): boolean {\n if (!password || typeof password !== \"string\") {\n throw new Error(\"Password is required\");\n }\n\n if (password.length > MAX_PASSWORD_LENGTH) {\n throw new Error(\n `Password must be ${MAX_PASSWORD_LENGTH} characters or less`\n );\n }\n\n return true;\n}\n\n/**\n * Validate file size\n * @param size - File size in bytes\n * @returns True if valid\n * @throws Error if too large\n */\nexport function validateFileSize(size: number): boolean {\n if (size > MAX_FILE_SIZE) {\n throw new Error(\n `File size exceeds maximum allowed size of ${\n MAX_FILE_SIZE / 1024 / 1024\n }MB`\n );\n }\n\n return true;\n}\n\n/**\n * Sanitize frontmatter data to prevent injection\n * @param data - The data object to sanitize\n * @returns Sanitized data\n */\nexport function sanitizeFrontmatter(\n data: Record<string, any>\n): Record<string, any> {\n const sanitized: Record<string, any> = {};\n\n for (const [key, value] of Object.entries(data)) {\n // Validate key\n if (!/^[a-zA-Z0-9_-]+$/.test(key)) {\n continue; // Skip invalid keys\n }\n\n // Sanitize value based on type\n if (typeof value === \"string\") {\n // Remove null bytes\n sanitized[key] = value.replace(/\\x00/g, \"\");\n } else if (\n typeof value === \"number\" ||\n typeof value === \"boolean\" ||\n value === null\n ) {\n sanitized[key] = value;\n } else if (Array.isArray(value)) {\n sanitized[key] = value.map((item) =>\n typeof item === \"string\" ? item.replace(/\\x00/g, \"\") : item\n );\n } else if (typeof value === \"object\") {\n sanitized[key] = sanitizeFrontmatter(value);\n }\n }\n\n return sanitized;\n}\n","import { getStorageProvider, FileEntry } from \"./storage\";\n\n/**\n * List all files and directories in a directory\n * @param directory - Relative path to the directory (default: root)\n * @returns Array of file entries (files and directories)\n */\nexport async function listDirectory(\n directory: string = \"\"\n): Promise<FileEntry[]> {\n const storage = getStorageProvider();\n return storage.listFiles(directory);\n}\n","import { getStorageProvider } from \"./storage\";\nimport { parseMarkdown } from \"./markdown\";\n\n/**\n * Base interface for collection items with flexible frontmatter\n */\nexport interface CollectionItem<T = Record<string, any>> {\n /** The markdown content body */\n content: string;\n /** Frontmatter data with dynamic fields */\n data: T;\n /** File slug (filename without extension) */\n slug: string;\n}\n\n/**\n * Fetch all markdown files from a specific folder/collection\n * @param folderName - The folder name under public/content (e.g., \"blog\", \"pages\")\n * @returns Array of collection items with parsed frontmatter and content\n *\n * @example\n * ```ts\n * // Fetch all blog posts\n * const posts = await getCollectionItems(\"blog\");\n * posts.forEach(post => {\n * console.log(post.data.title); // Access any frontmatter field\n * console.log(post.slug); // Filename without .md\n * });\n *\n * // With type inference for known fields\n * interface BlogPost {\n * title: string;\n * date: string;\n * author?: string;\n * [key: string]: any; // Allow any other fields\n * }\n * const typedPosts = await getCollectionItems<BlogPost>(\"blog\");\n * ```\n */\nexport async function getCollectionItems<T = Record<string, any>>(\n folderName: string\n): Promise<CollectionItem<T>[]> {\n const storage = getStorageProvider();\n\n // List all files in the collection folder\n const entries = await storage.listFiles(folderName);\n\n // Filter for markdown files only\n const mdFiles = entries.filter(\n (entry) => entry.type === \"file\" && entry.path.endsWith(\".md\")\n );\n\n // Read and parse each markdown file\n const items = await Promise.all(\n mdFiles.map(async (file) => {\n const rawContent = await storage.readFile(file.path);\n const { data, content } = parseMarkdown(rawContent);\n\n // Extract slug from filename (remove .md extension)\n const slug = file.path.split(\"/\").pop()!.replace(/\\.md$/, \"\");\n\n return {\n content,\n data: data as T,\n slug,\n };\n })\n );\n\n return items;\n}\n\n/**\n * Fetch a single item from a collection by slug\n * @param folderName - The folder name under public/content\n * @param slug - The filename without .md extension\n * @returns Single collection item or null if not found\n *\n * @example\n * ```ts\n * // Fetch a specific blog post\n * const post = await getCollectionItem(\"blog\", \"my-first-post\");\n * if (post) {\n * console.log(post.data.title);\n * }\n * ```\n */\nexport async function getCollectionItem<T = Record<string, any>>(\n folderName: string,\n slug: string\n): Promise<CollectionItem<T> | null> {\n const storage = getStorageProvider();\n const filePath = `${folderName}/${slug}.md`;\n\n try {\n const exists = await storage.exists(filePath);\n if (!exists) {\n return null;\n }\n\n const rawContent = await storage.readFile(filePath);\n const { data, content } = parseMarkdown(rawContent);\n\n return {\n content,\n data: data as T,\n slug,\n };\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Get all unique folder names (collections) in the content directory\n * @param baseDir - Base directory to scan (default: \"\")\n * @returns Array of folder names\n *\n * @example\n * ```ts\n * const collections = await getCollections();\n * // Returns: [\"blog\", \"pages\", \"docs\", ...]\n * ```\n */\nexport async function getCollections(baseDir: string = \"\"): Promise<string[]> {\n const storage = getStorageProvider();\n const entries = await storage.listFiles(baseDir);\n\n return entries\n .filter((entry) => entry.type === \"directory\")\n .map((entry) => entry.path.split(\"/\").pop()!)\n .filter(Boolean);\n}\n","import { getStorageProvider } from \"./storage\";\n\n/**\n * Upload a file and return its public URL\n * @param fileName - Original filename\n * @param buffer - File content buffer\n * @returns Public URL path to the uploaded file\n */\nexport async function uploadFile(\n fileName: string,\n buffer: Buffer\n): Promise<string> {\n const storage = getStorageProvider();\n\n // Generate unique filename with timestamp to avoid conflicts\n const timestamp = Date.now();\n const ext = fileName.split(\".\").pop();\n const nameWithoutExt = fileName.replace(`.${ext}`, \"\");\n const uniqueFileName = `${nameWithoutExt}-${timestamp}.${ext}`;\n\n return storage.uploadFile(uniqueFileName, buffer);\n}\n","import { SignJWT, jwtVerify } from \"jose\";\nimport { cookies } from \"next/headers\";\n\nconst SESSION_COOKIE_NAME = \"cms-session\";\nconst SESSION_DURATION = 60 * 60 * 24 * 7; // 7 days in seconds\n\n/**\n * Session payload structure for JWT\n */\ninterface SessionPayload {\n /** Username of the authenticated user */\n username: string;\n /** Expiration timestamp (Unix time) */\n exp: number;\n}\n\n/**\n * Get the secret key for JWT signing\n */\nfunction getSecretKey(): Uint8Array {\n const secret = process.env.CMS_SESSION_SECRET;\n if (!secret || secret.length < 32) {\n throw new Error(\"CMS_SESSION_SECRET must be at least 32 characters\");\n }\n return new TextEncoder().encode(secret);\n}\n\n/**\n * Create a new session token for the given username\n * @param username - The username to create a session for\n * @returns Signed JWT string\n */\nexport async function createSession(username: string): Promise<string> {\n const payload: SessionPayload = {\n username,\n exp: Math.floor(Date.now() / 1000) + SESSION_DURATION,\n };\n\n const token = await new SignJWT(payload as any)\n .setProtectedHeader({ alg: \"HS256\" })\n .setExpirationTime(\"7d\")\n .sign(getSecretKey());\n\n return token;\n}\n\n/**\n * Verify and decode a session token\n * @param token - The JWT token to verify\n * @returns Decoded payload if valid, null otherwise\n */\nexport async function verifySession(\n token: string\n): Promise<SessionPayload | null> {\n try {\n const { payload } = await jwtVerify(token, getSecretKey());\n\n // Validate payload structure\n if (\n typeof payload.username === \"string\" &&\n typeof payload.exp === \"number\"\n ) {\n return payload as unknown as SessionPayload;\n }\n\n return null;\n } catch (error) {\n return null;\n }\n}\n\n/**\n * Get session from Next.js request cookies\n */\nexport async function getSessionFromCookies(): Promise<SessionPayload | null> {\n const cookieStore = await cookies();\n const token = cookieStore.get(SESSION_COOKIE_NAME)?.value;\n\n if (!token) {\n return null;\n }\n\n return verifySession(token);\n}\n\n/**\n * Set session cookie\n */\nexport async function setSessionCookie(token: string): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.set(SESSION_COOKIE_NAME, token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n maxAge: SESSION_DURATION,\n path: \"/\",\n });\n}\n\n/**\n * Clear session cookie\n */\nexport async function clearSessionCookie(): Promise<void> {\n const cookieStore = await cookies();\n cookieStore.delete(SESSION_COOKIE_NAME);\n}\n","import crypto from \"crypto\";\nimport { validateUsername, validatePassword } from \"../utils/validation\";\n\n/**\n * Validate username and password against environment variables using timing-safe comparison\n * @param username - Username to validate\n * @param password - Password to validate\n * @returns True if credentials are valid, false otherwise\n * @throws Error if environment variables are not configured\n */\nexport function validateCredentials(\n username: string,\n password: string\n): boolean {\n // Validate input format first\n try {\n validateUsername(username);\n validatePassword(password);\n } catch (error) {\n // Return false for invalid input format (don't leak validation details)\n return false;\n }\n\n const envUsername = process.env.CMS_ADMIN_USERNAME;\n const envPassword = process.env.CMS_ADMIN_PASSWORD;\n\n if (!envUsername || !envPassword) {\n throw new Error(\n \"CMS_ADMIN_USERNAME and CMS_ADMIN_PASSWORD must be set in environment variables\"\n );\n }\n\n // Use timing-safe comparison to prevent timing attacks\n // Both comparisons must be done to prevent timing analysis\n const usernameMatch = timingSafeEqual(username, envUsername);\n const passwordMatch = timingSafeEqual(password, envPassword);\n\n return usernameMatch && passwordMatch;\n}\n\n/**\n * Timing-safe string comparison using crypto.timingSafeEqual\n * @param a - First string\n * @param b - Second string\n * @returns True if strings match\n */\nfunction timingSafeEqual(a: string, b: string): boolean {\n try {\n // Convert to buffers with consistent encoding\n const bufferA = Buffer.from(a, \"utf-8\");\n const bufferB = Buffer.from(b, \"utf-8\");\n\n // If lengths differ, compare dummy buffers of same length\n // This prevents length-based timing attacks\n if (bufferA.length !== bufferB.length) {\n const dummyBuffer = Buffer.alloc(bufferA.length);\n crypto.timingSafeEqual(bufferA, dummyBuffer);\n return false;\n }\n\n return crypto.timingSafeEqual(bufferA, bufferB);\n } catch {\n return false;\n }\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { validateCredentials } from \"../auth/login\";\nimport { createSession, getSessionFromCookies } from \"../auth/session\";\nimport {\n getMarkdownContent,\n saveMarkdownContent,\n deleteMarkdownContent,\n} from \"../content/markdown\";\nimport { listDirectory } from \"../content/directory\";\n\n/**\n * Login endpoint with rate limiting\n */\nexport async function handleLogin(request: NextRequest) {\n try {\n // Get IP address for rate limiting\n const ip =\n request.headers.get(\"x-forwarded-for\")?.split(\",\")[0] ||\n request.headers.get(\"x-real-ip\") ||\n \"unknown\";\n\n // Check rate limit\n const { checkRateLimit, incrementRateLimit, resetRateLimit } = await import(\n \"../utils/rate-limit\"\n );\n const rateLimit = checkRateLimit(ip);\n\n if (rateLimit.isLimited) {\n const retryAfter = Math.ceil((rateLimit.resetTime - Date.now()) / 1000);\n return NextResponse.json(\n {\n error: \"Too many login attempts. Please try again later.\",\n retryAfter,\n },\n {\n status: 429,\n headers: {\n \"Retry-After\": retryAfter.toString(),\n },\n }\n );\n }\n\n const body = (await request.json()) as {\n username?: string;\n password?: string;\n };\n const { username, password } = body;\n\n if (!username || !password) {\n return NextResponse.json(\n { error: \"Username and password are required\" },\n { status: 400 }\n );\n }\n\n // Validate credentials\n const isValid = validateCredentials(username, password);\n\n if (!isValid) {\n // Increment rate limit on failed attempt\n incrementRateLimit(ip);\n\n // Generic error message to avoid username enumeration\n return NextResponse.json(\n { error: \"Invalid credentials\" },\n { status: 401 }\n );\n }\n\n // Reset rate limit on successful login\n resetRateLimit(ip);\n\n const token = await createSession(username);\n const response = NextResponse.json({ success: true });\n\n // Set cookie in response\n response.cookies.set(\"cms-session\", token, {\n httpOnly: true,\n secure: process.env.NODE_ENV === \"production\",\n sameSite: \"lax\",\n maxAge: 60 * 60 * 24 * 7, // 7 days\n path: \"/\",\n });\n\n return response;\n } catch (error) {\n console.error(\"Login error:\", error);\n return NextResponse.json(\n { error: \"Authentication service temporarily unavailable\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Logout endpoint\n */\nexport async function handleLogout() {\n const response = NextResponse.json({ success: true });\n response.cookies.delete(\"cms-session\");\n return response;\n}\n\n/**\n * Get content endpoint\n */\nexport async function handleGetContent(\n _request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const content = await getMarkdownContent(filePath);\n return NextResponse.json(content);\n } catch (error) {\n console.error(\"Get content error:\", error);\n return NextResponse.json(\n { error: \"Failed to read content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Save content endpoint\n */\nexport async function handleSaveContent(\n request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const body = (await request.json()) as {\n data?: Record<string, any>;\n content?: string;\n };\n const { data, content } = body;\n\n // Content is optional now - default to empty string\n await saveMarkdownContent(filePath, data || {}, content || \"\");\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error(\"Save content error:\", error);\n return NextResponse.json(\n { error: \"Failed to save content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Delete content endpoint\n */\nexport async function handleDeleteContent(\n _request: NextRequest,\n filePath: string\n) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n await deleteMarkdownContent(filePath);\n return NextResponse.json({ success: true });\n } catch (error) {\n console.error(\"Delete content error:\", error);\n return NextResponse.json(\n { error: \"Failed to delete content\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * List files endpoint\n */\nexport async function handleListFiles(directory: string = \"\") {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const entries = await listDirectory(directory);\n return NextResponse.json({ entries });\n } catch (error) {\n console.error(\"List files error:\", error);\n return NextResponse.json(\n { error: \"Failed to list files\" },\n { status: 500 }\n );\n }\n}\n\n/**\n * Create API route handlers for Next.js App Router\n */\nexport function createContentApiHandlers() {\n return {\n async GET(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleGetContent(request, filePath);\n },\n async POST(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleSaveContent(request, filePath);\n },\n async DELETE(\n request: NextRequest,\n { params }: { params: { path: string[] } }\n ) {\n const filePath = params.path.join(\"/\");\n return handleDeleteContent(request, filePath);\n },\n };\n}\n\n/**\n * Create list API handlers\n */\nexport function createListApiHandlers() {\n return {\n async GET(\n _request: NextRequest,\n { params }: { params: { path?: string[] } }\n ) {\n const directory = params?.path?.join(\"/\") || \"\";\n return handleListFiles(directory);\n },\n };\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionFromCookies } from \"../auth/session\";\nimport { uploadFile } from \"../content/upload\";\n\n/**\n * Handle file upload\n */\nexport async function handleUpload(request: NextRequest) {\n try {\n const session = await getSessionFromCookies();\n if (!session) {\n return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 });\n }\n\n const formData = await request.formData();\n const file = formData.get(\"file\") as File;\n\n if (!file) {\n return NextResponse.json({ error: \"No file provided\" }, { status: 400 });\n }\n\n // Convert file to buffer\n const bytes = await file.arrayBuffer();\n const buffer = Buffer.from(bytes);\n\n // Upload file\n const publicUrl = await uploadFile(file.name, buffer);\n\n return NextResponse.json({\n success: true,\n url: publicUrl,\n filename: file.name,\n });\n } catch (error) {\n console.error(\"Upload error:\", error);\n return NextResponse.json(\n { error: \"Failed to upload file\" },\n { status: 500 }\n );\n }\n}\n","\"use client\";\n\nimport React, { useState, useEffect } from \"react\";\n\n// Types\ninterface FileEntry {\n path: string;\n name: string;\n type: \"file\" | \"directory\";\n}\n\ntype FieldType = \"text\" | \"date\" | \"number\" | \"markdown\" | \"image\";\n\ninterface FieldMeta {\n type: FieldType;\n value: any;\n}\n\nexport function AdminDashboard() {\n const [entries, setEntries] = useState<FileEntry[]>([]);\n const [currentPath, setCurrentPath] = useState(\"\");\n const [selectedFile, setSelectedFile] = useState<string | null>(null);\n const [fields, setFields] = useState<Record<string, FieldMeta>>({});\n const [loading, setLoading] = useState(false);\n const [message, setMessage] = useState(\"\");\n const [newFileName, setNewFileName] = useState(\"\");\n const [uploading, setUploading] = useState(false);\n\n useEffect(() => {\n loadDirectory(currentPath);\n }, [currentPath]);\n\n const loadDirectory = async (path: string) => {\n try {\n const url = path ? `/api/cms/list/${path}` : \"/api/cms/list\";\n const response = await fetch(url);\n const data = await response.json();\n setEntries(data.entries || []);\n } catch (error) {\n console.error(\"Failed to load directory:\", error);\n }\n };\n\n const loadFile = async (filePath: string) => {\n try {\n const response = await fetch(`/api/cms/content/${filePath}`);\n const data = await response.json();\n setSelectedFile(filePath);\n\n // Convert loaded data to fields format\n const loadedFields: Record<string, FieldMeta> = {};\n\n // Add content as markdown field if exists\n if (data.content !== undefined) {\n loadedFields[\"content\"] = { type: \"markdown\", value: data.content };\n }\n\n // Add frontmatter fields with type detection\n Object.entries(data.data || {}).forEach(([key, value]) => {\n loadedFields[key] = {\n type: detectFieldType(value as any),\n value,\n };\n });\n\n setFields(loadedFields);\n } catch (error) {\n setMessage(\"Failed to load file\");\n }\n };\n\n const detectFieldType = (value: any): FieldType => {\n if (typeof value === \"number\") return \"number\";\n if (typeof value === \"string\") {\n if (value.match(/^\\d{4}-\\d{2}-\\d{2}/)) return \"date\";\n if (value.startsWith(\"/uploads/\") || value.startsWith(\"http\"))\n return \"image\";\n if (value.length > 100) return \"markdown\";\n }\n return \"text\";\n };\n\n const saveFile = async () => {\n if (!selectedFile) return;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n // Separate content from frontmatter\n const frontmatter: Record<string, any> = {};\n let content = \"\";\n\n Object.entries(fields).forEach(([key, field]) => {\n if (key === \"content\") {\n content = field.value;\n } else {\n frontmatter[key] = field.value;\n }\n });\n\n const response = await fetch(`/api/cms/content/${selectedFile}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: frontmatter, content }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File saved successfully!\");\n setTimeout(() => setMessage(\"\"), 3000);\n } else {\n const errorData = await response.json().catch(() => ({}));\n setMessage(\n `❌ Failed to save file: ${errorData.error || response.statusText}`\n );\n }\n } catch (error) {\n setMessage(\n `❌ Error saving file: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`\n );\n } finally {\n setLoading(false);\n }\n };\n\n const createFile = async () => {\n if (!newFileName) return;\n\n const fileName = newFileName.endsWith(\".md\")\n ? newFileName\n : `${newFileName}.md`;\n const fullPath = currentPath ? `${currentPath}/${fileName}` : fileName;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const response = await fetch(`/api/cms/content/${fullPath}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n data: {},\n content: \"\",\n }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File created!\");\n setNewFileName(\"\");\n loadDirectory(currentPath);\n loadFile(fullPath);\n } else {\n setMessage(\"❌ Failed to create file\");\n }\n } catch (error) {\n setMessage(\"❌ Error creating file\");\n } finally {\n setLoading(false);\n }\n };\n\n const duplicateFile = async () => {\n if (!selectedFile) return;\n\n const newName = prompt(\"Enter new filename (without .md extension):\");\n if (!newName) return;\n\n const duplicateName = currentPath\n ? `${currentPath}/${newName}.md`\n : `${newName}.md`;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const frontmatter: Record<string, any> = {};\n let content = \"\";\n\n Object.entries(fields).forEach(([key, field]) => {\n if (key === \"content\") {\n content = field.value;\n } else {\n frontmatter[key] = field.value;\n }\n });\n\n const response = await fetch(`/api/cms/content/${duplicateName}`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ data: frontmatter, content }),\n });\n\n if (response.ok) {\n setMessage(\"✅ File duplicated!\");\n loadDirectory(currentPath);\n loadFile(duplicateName);\n } else {\n const errorData = await response.json().catch(() => ({}));\n setMessage(\n `❌ Failed to duplicate file: ${errorData.error || \"Unknown error\"}`\n );\n }\n } catch (error) {\n setMessage(\"❌ Error duplicating file\");\n } finally {\n setLoading(false);\n }\n };\n\n const deleteFile = async (filePath: string) => {\n if (!confirm(`Delete ${filePath}?`)) return;\n\n setLoading(true);\n setMessage(\"\");\n\n try {\n const response = await fetch(`/api/cms/content/${filePath}`, {\n method: \"DELETE\",\n });\n\n if (response.ok) {\n setMessage(\"✅ File deleted!\");\n if (selectedFile === filePath) {\n setSelectedFile(null);\n setFields({});\n }\n loadDirectory(currentPath);\n } else {\n setMessage(\"❌ Failed to delete file\");\n }\n } catch (error) {\n setMessage(\"❌ Error deleting file\");\n } finally {\n setLoading(false);\n }\n };\n\n const navigateToDir = (dirPath: string) => {\n setCurrentPath(dirPath);\n setSelectedFile(null);\n };\n\n const goUp = () => {\n const parts = currentPath.split(\"/\");\n parts.pop();\n setCurrentPath(parts.join(\"/\"));\n setSelectedFile(null);\n };\n\n const handleLogout = async () => {\n await fetch(\"/api/cms/logout\", { method: \"POST\" });\n window.location.href = \"/admin/login\";\n };\n\n const updateField = (key: string, value: any) => {\n setFields((prev) => ({\n ...prev,\n [key]: { ...prev[key], value },\n }));\n };\n\n const addField = () => {\n const fieldName = prompt(\"Enter field name:\");\n if (!fieldName || fields[fieldName]) return;\n\n const fieldType = prompt(\n \"Enter field type (text/date/number/markdown/image):\",\n \"text\"\n ) as FieldType;\n const validTypes: FieldType[] = [\n \"text\",\n \"date\",\n \"number\",\n \"markdown\",\n \"image\",\n ];\n\n if (!validTypes.includes(fieldType)) {\n alert(\"Invalid field type! Use: text, date, number, markdown, or image\");\n return;\n }\n\n const defaultValue =\n fieldType === \"number\"\n ? 0\n : fieldType === \"date\"\n ? new Date().toISOString().split(\"T\")[0]\n : \"\";\n\n setFields((prev) => ({\n ...prev,\n [fieldName]: { type: fieldType, value: defaultValue },\n }));\n };\n\n const removeField = (key: string) => {\n const newFields = { ...fields };\n delete newFields[key];\n setFields(newFields);\n };\n\n const handleImageUpload = async (\n key: string,\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setUploading(true);\n\n try {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const response = await fetch(\"/api/cms/upload\", {\n method: \"POST\",\n body: formData,\n });\n\n const data = await response.json();\n\n if (response.ok) {\n updateField(key, data.url);\n setMessage(`✅ Image uploaded!`);\n setTimeout(() => setMessage(\"\"), 3000);\n } else {\n setMessage(\"❌ Failed to upload image\");\n }\n } catch (error) {\n setMessage(\"❌ Error uploading image\");\n } finally {\n setUploading(false);\n event.target.value = \"\";\n }\n };\n\n const handleFileUpload = async (\n event: React.ChangeEvent<HTMLInputElement>\n ) => {\n const file = event.target.files?.[0];\n if (!file) return;\n\n setUploading(true);\n setMessage(\"\");\n\n try {\n const formData = new FormData();\n formData.append(\"file\", file);\n\n const response = await fetch(\"/api/cms/upload\", {\n method: \"POST\",\n body: formData,\n });\n\n const data = await response.json();\n\n if (response.ok) {\n setMessage(`✅ File uploaded! Path: ${data.url}`);\n setTimeout(() => setMessage(\"\"), 5000);\n } else {\n setMessage(\"❌ Failed to upload file\");\n }\n } catch (error) {\n setMessage(\"❌ Error uploading file\");\n } finally {\n setUploading(false);\n event.target.value = \"\";\n }\n };\n\n const renderField = (key: string, field: FieldMeta) => {\n switch (field.type) {\n case \"text\":\n return (\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"number\":\n return (\n <input\n id={key}\n type=\"number\"\n value={field.value}\n onChange={(e) => updateField(key, parseFloat(e.target.value) || 0)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"date\":\n return (\n <input\n id={key}\n type=\"date\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n );\n case \"markdown\":\n return (\n <textarea\n id={key}\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n style={{\n width: \"100%\",\n minHeight: key === \"content\" ? \"400px\" : \"150px\",\n fontFamily: \"monospace\",\n padding: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n placeholder={\n key === \"content\"\n ? \"Write your markdown content here...\"\n : \"Markdown text...\"\n }\n />\n );\n case \"image\":\n return (\n <div>\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n placeholder=\"/uploads/image.jpg or https://...\"\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n marginBottom: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n <input\n type=\"file\"\n accept=\"image/*\"\n onChange={(e) => handleImageUpload(key, e)}\n disabled={uploading}\n style={{ marginBottom: \"0.5rem\" }}\n />\n {field.value && (\n <img\n src={field.value}\n alt={key}\n style={{\n maxWidth: \"200px\",\n display: \"block\",\n marginTop: \"0.5rem\",\n borderRadius: \"4px\",\n border: \"1px solid #ddd\",\n }}\n />\n )}\n </div>\n );\n default:\n return (\n <input\n id={key}\n type=\"text\"\n value={field.value}\n onChange={(e) => updateField(key, e.target.value)}\n />\n );\n }\n };\n\n return (\n <div\n className=\"container\"\n style={{ maxWidth: \"1200px\", margin: \"0 auto\", padding: \"2rem\" }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"2rem\",\n }}\n >\n <h1>📝 Admin Dashboard</h1>\n <button\n onClick={handleLogout}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n Logout\n </button>\n </div>\n\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: \"minmax(250px, 300px) 1fr\",\n gap: \"2rem\",\n }}\n >\n {/* Sidebar */}\n <div\n style={{\n background: \"white\",\n padding: \"1.5rem\",\n borderRadius: \"8px\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n }}\n >\n <h2 style={{ marginTop: 0, marginBottom: \"1rem\" }}>Files</h2>\n\n {/* Breadcrumb */}\n <div\n style={{\n marginBottom: \"1rem\",\n fontSize: \"0.875rem\",\n color: \"#666\",\n }}\n >\n <span\n onClick={() => setCurrentPath(\"\")}\n style={{\n cursor: \"pointer\",\n color: \"#0070f3\",\n textDecoration: \"underline\",\n }}\n >\n content\n </span>\n {currentPath && (\n <>\n {\" / \"}\n <span style={{ fontWeight: \"bold\" }}>{currentPath}</span>\n </>\n )}\n </div>\n\n {/* Back button */}\n {currentPath && (\n <button\n onClick={goUp}\n style={{\n width: \"100%\",\n marginBottom: \"1rem\",\n padding: \"0.5rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n ⬆️ Go Up\n </button>\n )}\n\n {/* New file form */}\n <div\n style={{\n marginBottom: \"1.5rem\",\n paddingBottom: \"1.5rem\",\n borderBottom: \"1px solid #eee\",\n }}\n >\n <input\n type=\"text\"\n placeholder=\"new-file.md\"\n value={newFileName}\n onChange={(e) => setNewFileName(e.target.value)}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n marginBottom: \"0.5rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n <button\n onClick={createFile}\n disabled={loading || !newFileName}\n style={{\n width: \"100%\",\n padding: \"0.5rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n + New File\n </button>\n </div>\n\n {/* File/folder list */}\n <ul style={{ listStyle: \"none\", padding: 0, margin: 0 }}>\n {entries.length === 0 && (\n <li style={{ color: \"#999\", fontStyle: \"italic\" }}>\n Empty directory\n </li>\n )}\n {entries.map((entry) => (\n <li\n key={entry.path}\n style={{\n marginBottom: \"0.5rem\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {entry.type === \"directory\" ? (\n <button\n onClick={() => navigateToDir(entry.path)}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#0070f3\",\n cursor: \"pointer\",\n textAlign: \"left\",\n fontSize: \"1rem\",\n padding: \"0.25rem 0\",\n fontWeight: \"bold\",\n }}\n >\n 📁 {entry.name}\n </button>\n ) : (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n }}\n >\n <button\n onClick={() => loadFile(entry.path)}\n style={{\n background: \"none\",\n border: \"none\",\n color: selectedFile === entry.path ? \"#000\" : \"#444\",\n cursor: \"pointer\",\n textAlign: \"left\",\n padding: \"0.25rem 0\",\n fontWeight:\n selectedFile === entry.path ? \"bold\" : \"normal\",\n textDecoration:\n selectedFile === entry.path ? \"underline\" : \"none\",\n flex: 1,\n }}\n >\n 📄 {entry.name}\n </button>\n <button\n onClick={() => deleteFile(entry.path)}\n disabled={loading}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#d32f2f\",\n cursor: \"pointer\",\n fontSize: \"0.8rem\",\n opacity: 0.7,\n }}\n >\n ✕\n </button>\n </div>\n )}\n </li>\n ))}\n </ul>\n </div>\n\n {/* Editor */}\n <div\n style={{\n background: \"white\",\n padding: \"2rem\",\n borderRadius: \"8px\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n }}\n >\n {selectedFile ? (\n <>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"2rem\",\n paddingBottom: \"1rem\",\n borderBottom: \"1px solid #eee\",\n }}\n >\n <h2 style={{ margin: 0 }}>Edit: {selectedFile}</h2>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <button\n onClick={duplicateFile}\n disabled={loading}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#f5f5f5\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n 📋 Duplicate\n </button>\n <button\n onClick={saveFile}\n disabled={loading}\n style={{\n padding: \"0.5rem 1rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n {loading ? \"Saving...\" : \"💾 Save Changes\"}\n </button>\n </div>\n </div>\n\n {message && (\n <div\n style={{\n marginBottom: \"1.5rem\",\n padding: \"0.75rem\",\n background: message.includes(\"✅\") ? \"#e6ffe6\" : \"#ffe6e6\",\n borderRadius: \"4px\",\n border: message.includes(\"✅\")\n ? \"1px solid #a5d6a7\"\n : \"1px solid #ef9a9a\",\n }}\n >\n {message}\n </div>\n )}\n\n {/* Dynamic Fields */}\n <div style={{ marginBottom: \"2rem\" }}>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"1rem\",\n }}\n >\n <h3 style={{ fontSize: \"1.1rem\", margin: 0 }}>Fields</h3>\n <button\n onClick={addField}\n style={{\n fontSize: \"0.875rem\",\n padding: \"0.4rem 0.8rem\",\n background: \"#e1f5fe\",\n color: \"#0288d1\",\n border: \"none\",\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n >\n + Add Field\n </button>\n </div>\n\n {Object.keys(fields).length === 0 ? (\n <div\n style={{\n padding: \"2rem\",\n textAlign: \"center\",\n background: \"#f9f9f9\",\n borderRadius: \"4px\",\n border: \"1px dashed #ccc\",\n }}\n >\n <p\n style={{ color: \"#666\", fontStyle: \"italic\", margin: 0 }}\n >\n No fields yet. Click \"+ Add Field\" to start.\n </p>\n <small\n style={{\n color: \"#999\",\n marginTop: \"0.5rem\",\n display: \"block\",\n }}\n >\n Add 'content' field for the main body\n </small>\n </div>\n ) : (\n Object.entries(fields).map(([key, field]) => (\n <div\n key={key}\n style={{\n marginBottom: \"1.5rem\",\n background: \"#fff\",\n border: \"1px solid #eee\",\n padding: \"1rem\",\n borderRadius: \"6px\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n alignItems: \"center\",\n marginBottom: \"0.5rem\",\n }}\n >\n <label htmlFor={key} style={{ fontWeight: 500 }}>\n {key}\n <span\n style={{\n marginLeft: \"0.5rem\",\n fontSize: \"0.75rem\",\n color: \"#999\",\n background: \"#f0f0f0\",\n padding: \"0.1rem 0.4rem\",\n borderRadius: \"4px\",\n }}\n >\n {field.type}\n </span>\n </label>\n <button\n onClick={() => removeField(key)}\n style={{\n background: \"none\",\n border: \"none\",\n color: \"#e57373\",\n cursor: \"pointer\",\n fontSize: \"0.875rem\",\n }}\n >\n ✕ Remove\n </button>\n </div>\n\n {renderField(key, field)}\n </div>\n ))\n )}\n </div>\n\n {/* General File Upload */}\n <div\n style={{\n marginTop: \"3rem\",\n paddingTop: \"1rem\",\n borderTop: \"1px solid #eee\",\n }}\n >\n <h3\n style={{\n fontSize: \"1rem\",\n marginBottom: \"0.5rem\",\n color: \"#666\",\n }}\n >\n Quick File Upload\n </h3>\n <div style={{ display: \"flex\", gap: \"0.5rem\" }}>\n <input\n type=\"file\"\n onChange={handleFileUpload}\n disabled={uploading}\n style={{ flex: 1 }}\n />\n {uploading && (\n <span style={{ color: \"#666\" }}>Uploading...</span>\n )}\n </div>\n </div>\n </>\n ) : (\n <div\n style={{\n textAlign: \"center\",\n padding: \"5rem 2rem\",\n color: \"#999\",\n }}\n >\n <div style={{ fontSize: \"3rem\", marginBottom: \"1rem\" }}>👈</div>\n <p style={{ fontSize: \"1.1rem\" }}>\n Select a file from the sidebar to edit\n </p>\n <p>or create a new file to get started</p>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n","\"use client\";\n\nimport React, { useState } from \"react\";\n\nexport function Login() {\n const [username, setUsername] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [error, setError] = useState(\"\");\n const [loading, setLoading] = useState(false);\n\n const handleSubmit = async (e: React.FormEvent) => {\n e.preventDefault();\n setError(\"\");\n setLoading(true);\n\n try {\n const response = await fetch(\"/api/cms/login\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ username, password }),\n });\n\n const data = (await response.json()) as { error?: string };\n\n if (response.ok) {\n window.location.href = \"/admin\";\n } else {\n setError(data.error || \"Login failed\");\n }\n } catch (err) {\n setError(\"An error occurred. Please try again.\");\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n minHeight: \"100vh\",\n background: \"#f5f5f5\",\n fontFamily:\n '-apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif',\n }}\n >\n <div\n style={{\n width: \"100%\",\n maxWidth: \"400px\",\n padding: \"2rem\",\n background: \"white\",\n borderRadius: \"8px\",\n boxShadow: \"0 4px 6px rgba(0,0,0,0.1)\",\n }}\n >\n <h1 style={{ marginBottom: \"0.5rem\", textAlign: \"center\" }}>\n Admin Login\n </h1>\n <p style={{ color: \"#666\", marginBottom: \"2rem\", textAlign: \"center\" }}>\n Enter your credentials to access the CMS\n </p>\n\n <form onSubmit={handleSubmit}>\n <div style={{ marginBottom: \"1rem\" }}>\n <label\n htmlFor=\"username\"\n style={{\n display: \"block\",\n marginBottom: \"0.5rem\",\n fontWeight: 500,\n }}\n >\n Username\n </label>\n <input\n id=\"username\"\n type=\"text\"\n value={username}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setUsername(e.target.value)\n }\n required\n autoFocus\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n </div>\n\n <div style={{ marginBottom: \"1.5rem\" }}>\n <label\n htmlFor=\"password\"\n style={{\n display: \"block\",\n marginBottom: \"0.5rem\",\n fontWeight: 500,\n }}\n >\n Password\n </label>\n <input\n id=\"password\"\n type=\"password\"\n value={password}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n setPassword(e.target.value)\n }\n required\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n border: \"1px solid #ddd\",\n borderRadius: \"4px\",\n }}\n />\n </div>\n\n {error && (\n <div\n style={{\n marginBottom: \"1rem\",\n padding: \"0.75rem\",\n background: \"#ffe6e6\",\n color: \"#d32f2f\",\n borderRadius: \"4px\",\n fontSize: \"0.875rem\",\n }}\n >\n {error}\n </div>\n )}\n\n <button\n type=\"submit\"\n disabled={loading}\n style={{\n width: \"100%\",\n padding: \"0.75rem\",\n background: \"#0070f3\",\n color: \"white\",\n border: \"none\",\n borderRadius: \"4px\",\n fontSize: \"1rem\",\n fontWeight: 500,\n cursor: \"pointer\",\n opacity: loading ? 0.7 : 1,\n }}\n >\n {loading ? \"Logging in...\" : \"Login\"}\n </button>\n </form>\n </div>\n </div>\n );\n}\n","import { NextRequest, NextResponse } from \"next/server\";\nimport { getSessionFromCookies } from \"../auth/session\";\n\n/**\n * Create middleware to protect admin routes\n */\nexport function createAuthMiddleware(\n options: {\n loginPath?: string;\n protectedPaths?: string[];\n } = {}\n) {\n const loginPath = options.loginPath || \"/admin/login\";\n const protectedPaths = options.protectedPaths || [\"/admin\"];\n\n return async function middleware(request: NextRequest) {\n const { pathname } = request.nextUrl;\n\n // Skip if not a protected path\n const isProtected = protectedPaths.some((path) =>\n pathname.startsWith(path)\n );\n if (!isProtected) {\n return NextResponse.next();\n }\n\n // Allow login page\n if (pathname === loginPath) {\n return NextResponse.next();\n }\n\n // Check session\n const session = await getSessionFromCookies();\n if (!session) {\n const url = request.nextUrl.clone();\n url.pathname = loginPath;\n url.searchParams.set(\"from\", pathname);\n return NextResponse.redirect(url);\n }\n\n return NextResponse.next();\n };\n}\n","import fs from \"fs/promises\";\nimport path from \"path\";\nimport { exec } from \"child_process\";\nimport { promisify } from \"util\";\n\nconst execAsync = promisify(exec);\n\nexport interface InitCMSConfig {\n /** Directory where content is stored (default: \"public/content\") */\n contentDir?: string;\n}\n\n/**\n * Initialize CMS in a Next.js project\n * Creates the content directory and an example markdown file.\n * @param config - Configuration options\n */\nexport async function initCMS(config: InitCMSConfig = {}) {\n const contentDir = config.contentDir || \"public/content\";\n const fullPath = path.join(process.cwd(), contentDir);\n const appDir = path.join(process.cwd(), \"app\");\n\n // Check if we are in a Next.js App Router project\n try {\n await fs.access(appDir);\n } catch {\n console.error(\n '❌ Error: \"app\" directory not found. This init script requires Next.js App Router.'\n );\n return;\n }\n\n console.log(\"🚀 Initializing @fydemy/cms...\");\n\n // 0. Install Dependencies\n console.log(\"📦 Checking dependencies...\");\n try {\n const packageJsonPath = path.join(process.cwd(), \"package.json\");\n const packageJson = JSON.parse(await fs.readFile(packageJsonPath, \"utf-8\"));\n const dependencies = {\n ...packageJson.dependencies,\n ...packageJson.devDependencies,\n };\n\n const missingDeps = [];\n if (!dependencies[\"@fydemy/cms\"]) missingDeps.push(\"@fydemy/cms\");\n if (!dependencies[\"tailwindcss\"]) missingDeps.push(\"tailwindcss\");\n\n // shadcn dependencies\n if (!dependencies[\"class-variance-authority\"])\n missingDeps.push(\"class-variance-authority\");\n if (!dependencies[\"clsx\"]) missingDeps.push(\"clsx\");\n if (!dependencies[\"tailwind-merge\"]) missingDeps.push(\"tailwind-merge\");\n if (!dependencies[\"@radix-ui/react-slot\"])\n missingDeps.push(\"@radix-ui/react-slot\");\n if (!dependencies[\"@radix-ui/react-label\"])\n missingDeps.push(\"@radix-ui/react-label\");\n\n if (missingDeps.length > 0) {\n console.log(\n `🔧 Installing missing dependencies: ${missingDeps.join(\", \")}...`\n );\n // Detect package manager (default to npm if locking file not found)\n let installCmd = \"npm install\";\n try {\n await fs.access(\"pnpm-lock.yaml\");\n installCmd = \"pnpm add\";\n } catch {\n try {\n await fs.access(\"yarn.lock\");\n installCmd = \"yarn add\";\n } catch {\n // npm\n }\n }\n\n await execAsync(`${installCmd} ${missingDeps.join(\" \")}`);\n console.log(\"✅ Dependencies installed\");\n }\n } catch (error) {\n console.warn(\n \"⚠️ Could not check/install dependencies automatically. Please ensure all dependencies are installed.\"\n );\n }\n\n // 1. Create content directory and example file\n await fs.mkdir(fullPath, { recursive: true });\n\n const exampleContent = `---\ntitle: Example Post\ndescription: This is an example markdown file\ndate: ${new Date().toISOString()}\n---\n\n# Welcome to your CMS!\n\nThis is an example markdown file. You can edit or delete it from the admin dashboard.\n\n## Features\n\n- File-based content storage\n- Markdown with frontmatter\n- GitHub integration for production\n- Simple authentication\n- No database required\n`;\n\n const examplePath = path.join(fullPath, \"example.md\");\n await fs.writeFile(examplePath, exampleContent, \"utf-8\");\n console.log(\"✅ Created content directory and example file\");\n\n // 2. Scaffold Admin Pages (Ejected Code)\n const adminDir = path.join(appDir, \"admin\");\n const loginDir = path.join(adminDir, \"login\");\n\n await fs.mkdir(loginDir, { recursive: true });\n\n // Read template files from the dist directory (publicDir copied them there)\n const loginTemplate = await fs.readFile(\n path.join(__dirname, \"login.template.tsx\"),\n \"utf-8\"\n );\n const adminTemplate = await fs.readFile(\n path.join(__dirname, \"admin.template.tsx\"),\n \"utf-8\"\n );\n\n await fs.writeFile(path.join(adminDir, \"page.tsx\"), adminTemplate, \"utf-8\");\n\n await fs.writeFile(path.join(loginDir, \"page.tsx\"), loginTemplate, \"utf-8\");\n console.log(\"✅ Scaffolded Admin UI (shadcn/ui components)\");\n\n // 2.5. Scaffold shadcn/ui Components and Utilities\n const componentsDir = path.join(process.cwd(), \"components\", \"ui\");\n const libDir = path.join(process.cwd(), \"lib\");\n\n await fs.mkdir(componentsDir, { recursive: true });\n await fs.mkdir(libDir, { recursive: true });\n\n // Copy utils.ts\n const utilsTemplate = await fs.readFile(\n path.join(__dirname, \"lib\", \"utils.ts\"),\n \"utf-8\"\n );\n await fs.writeFile(path.join(libDir, \"utils.ts\"), utilsTemplate, \"utf-8\");\n\n // Copy shadcn components\n const componentFiles = [\n \"button.tsx\",\n \"input.tsx\",\n \"card.tsx\",\n \"label.tsx\",\n \"textarea.tsx\",\n \"badge.tsx\",\n ];\n\n for (const componentFile of componentFiles) {\n const componentTemplate = await fs.readFile(\n path.join(__dirname, \"components\", \"ui\", componentFile),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(componentsDir, componentFile),\n componentTemplate,\n \"utf-8\"\n );\n }\n\n // Copy components.json\n const componentsJsonTemplate = await fs.readFile(\n path.join(__dirname, \"components.json\"),\n \"utf-8\"\n );\n await fs.writeFile(\n path.join(process.cwd(), \"components.json\"),\n componentsJsonTemplate,\n \"utf-8\"\n );\n\n console.log(\"✅ Scaffolded shadcn/ui components\");\n\n // 3. Scaffold API Routes\n const apiCmsDir = path.join(appDir, \"api\", \"cms\");\n\n // Login\n await fs.mkdir(path.join(apiCmsDir, \"login\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"login\", \"route.ts\"),\n `import { handleLogin } from '@fydemy/cms';\\nexport { handleLogin as POST };\\n`,\n \"utf-8\"\n );\n\n // Logout\n await fs.mkdir(path.join(apiCmsDir, \"logout\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"logout\", \"route.ts\"),\n `import { handleLogout } from '@fydemy/cms';\\nexport { handleLogout as POST };\\n`,\n \"utf-8\"\n );\n\n // Upload\n await fs.mkdir(path.join(apiCmsDir, \"upload\"), { recursive: true });\n await fs.writeFile(\n path.join(apiCmsDir, \"upload\", \"route.ts\"),\n `import { handleUpload } from '@fydemy/cms';\\nexport { handleUpload as POST };\\n`,\n \"utf-8\"\n );\n\n // List\n await fs.mkdir(path.join(apiCmsDir, \"list\", \"[[...path]]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"list\", \"[[...path]]\", \"route.ts\"),\n `import { createListApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createListApiHandlers();\\nexport const GET = handlers.GET;\\n`,\n \"utf-8\"\n );\n\n // Content\n await fs.mkdir(path.join(apiCmsDir, \"content\", \"[...path]\"), {\n recursive: true,\n });\n await fs.writeFile(\n path.join(apiCmsDir, \"content\", \"[...path]\", \"route.ts\"),\n `import { createContentApiHandlers } from '@fydemy/cms';\\n\\nconst handlers = createContentApiHandlers();\\nexport const GET = handlers.GET;\\nexport const POST = handlers.POST;\\nexport const DELETE = handlers.DELETE;\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created API routes\");\n\n // 4. Middleware\n const middlewarePath = path.join(process.cwd(), \"middleware.ts\");\n try {\n await fs.access(middlewarePath);\n console.log(\n \"⚠️ middleware.ts already exists. Please manually add the CMS auth middleware:\"\n );\n console.log(`\nimport { createAuthMiddleware } from '@fydemy/cms';\n// ... existing imports\n\nexport function middleware(request: NextRequest) {\n // Add this:\n const authResponse = createAuthMiddleware()(request);\n if (authResponse) return authResponse;\n \n // ... existing middleware logic\n}\n`);\n } catch {\n await fs.writeFile(\n middlewarePath,\n `import { createAuthMiddleware } from '@fydemy/cms';\\nimport { NextRequest } from 'next/server';\\n\\nexport function middleware(request: NextRequest) {\\n return createAuthMiddleware()(request);\\n}\\n\\nexport const config = {\\n matcher: ['/admin/:path*'],\\n};\\n`,\n \"utf-8\"\n );\n console.log(\"✅ Created middleware.ts\");\n }\n\n // 5. Env example\n const envExamplePath = path.join(process.cwd(), \".env.local.example\");\n await fs.writeFile(\n envExamplePath,\n `CMS_ADMIN_USERNAME=admin\\nCMS_ADMIN_PASSWORD=password\\nCMS_SESSION_SECRET=ensure_this_is_at_least_32_chars_long_random_string\\n\\n# GitHub Storage (Production)\\nGITHUB_TOKEN=\\nGITHUB_REPO=owner/repo\\nGITHUB_BRANCH=main\\n`,\n \"utf-8\"\n );\n\n console.log(\"\");\n console.log(\"🎉 CMS initialized successfully!\");\n console.log(\n \"1. Copy .env.local.example to .env.local and set your credentials\"\n );\n console.log(\"2. Run your dev server and visit /admin\");\n}\n"],"mappings":"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","names":["path","fs","import_path","path","matter","crypto","checkRateLimit","incrementRateLimit","resetRateLimit","import_server","path","handleLogout","import_react","import_jsx_runtime","import_server","path","import_promises","import_path","path","fs"]}