nextblogkit 0.6.2 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (111) hide show
  1. package/README.md +83 -21
  2. package/dist/admin/index.cjs +366 -10
  3. package/dist/admin/index.cjs.map +1 -1
  4. package/dist/admin/index.d.cts +7 -3
  5. package/dist/admin/index.d.ts +7 -3
  6. package/dist/admin/index.js +365 -11
  7. package/dist/admin/index.js.map +1 -1
  8. package/dist/api/categories.cjs +32 -32
  9. package/dist/api/categories.cjs.map +1 -1
  10. package/dist/api/categories.d.cts +1 -1
  11. package/dist/api/categories.d.ts +1 -1
  12. package/dist/api/categories.js +6 -6
  13. package/dist/api/categories.js.map +1 -1
  14. package/dist/api/media.cjs +37 -30
  15. package/dist/api/media.cjs.map +1 -1
  16. package/dist/api/media.d.cts +1 -1
  17. package/dist/api/media.d.ts +1 -1
  18. package/dist/api/media.js +13 -6
  19. package/dist/api/media.js.map +1 -1
  20. package/dist/api/posts.cjs +39 -39
  21. package/dist/api/posts.cjs.map +1 -1
  22. package/dist/api/posts.d.cts +1 -1
  23. package/dist/api/posts.d.ts +1 -1
  24. package/dist/api/posts.js +6 -6
  25. package/dist/api/posts.js.map +1 -1
  26. package/dist/api/rss.cjs +3 -3
  27. package/dist/api/rss.js +2 -2
  28. package/dist/api/settings.cjs +13 -13
  29. package/dist/api/settings.cjs.map +1 -1
  30. package/dist/api/settings.d.cts +1 -1
  31. package/dist/api/settings.d.ts +1 -1
  32. package/dist/api/settings.js +5 -5
  33. package/dist/api/settings.js.map +1 -1
  34. package/dist/api/sitemap.cjs +3 -3
  35. package/dist/api/sitemap.js +2 -2
  36. package/dist/api/tokens.cjs +56 -0
  37. package/dist/api/tokens.cjs.map +1 -0
  38. package/dist/api/tokens.d.cts +22 -0
  39. package/dist/api/tokens.d.ts +22 -0
  40. package/dist/api/tokens.js +52 -0
  41. package/dist/api/tokens.js.map +1 -0
  42. package/dist/{chunk-6HKMZOI4.cjs → chunk-3BKPNOES.cjs} +8 -7
  43. package/dist/chunk-3BKPNOES.cjs.map +1 -0
  44. package/dist/{chunk-N5MKAD7J.cjs → chunk-DR7QNI32.cjs} +6 -2
  45. package/dist/chunk-DR7QNI32.cjs.map +1 -0
  46. package/dist/{chunk-QE4VLQYN.cjs → chunk-F47RPOTU.cjs} +13 -10
  47. package/dist/chunk-F47RPOTU.cjs.map +1 -0
  48. package/dist/{chunk-64HUVJOZ.js → chunk-JI2RK6KX.js} +80 -13
  49. package/dist/chunk-JI2RK6KX.js.map +1 -0
  50. package/dist/{chunk-R6MO3QIP.js → chunk-NSR7NYSB.js} +6 -5
  51. package/dist/chunk-NSR7NYSB.js.map +1 -0
  52. package/dist/{chunk-4PY224XM.js → chunk-O3XES5O2.js} +6 -3
  53. package/dist/chunk-O3XES5O2.js.map +1 -0
  54. package/dist/{chunk-4NKOJYWJ.js → chunk-OOUJYUGP.js} +8 -7
  55. package/dist/chunk-OOUJYUGP.js.map +1 -0
  56. package/dist/{chunk-A2S32RZN.js → chunk-OWWWTTUT.js} +8 -3
  57. package/dist/chunk-OWWWTTUT.js.map +1 -0
  58. package/dist/{chunk-E2QLTHKN.cjs → chunk-QBZLGBHQ.cjs} +11 -10
  59. package/dist/chunk-QBZLGBHQ.cjs.map +1 -0
  60. package/dist/{chunk-ZP5XRVVH.cjs → chunk-SUJT6LWH.cjs} +12 -7
  61. package/dist/chunk-SUJT6LWH.cjs.map +1 -0
  62. package/dist/{chunk-JM7QRXXK.js → chunk-TVHY4BR2.js} +10 -7
  63. package/dist/chunk-TVHY4BR2.js.map +1 -0
  64. package/dist/{chunk-JLPJKNRZ.js → chunk-UMIBGO4S.js} +18 -5
  65. package/dist/chunk-UMIBGO4S.js.map +1 -0
  66. package/dist/{chunk-U2ROR6AY.cjs → chunk-VWKVU3SE.cjs} +86 -12
  67. package/dist/chunk-VWKVU3SE.cjs.map +1 -0
  68. package/dist/{chunk-KDZER3PU.cjs → chunk-YTJQ426D.cjs} +19 -5
  69. package/dist/chunk-YTJQ426D.cjs.map +1 -0
  70. package/dist/cli/index.cjs +90 -19
  71. package/dist/components/index.cjs +3 -2
  72. package/dist/components/index.cjs.map +1 -1
  73. package/dist/components/index.d.cts +2 -1
  74. package/dist/components/index.d.ts +2 -1
  75. package/dist/components/index.js +3 -2
  76. package/dist/components/index.js.map +1 -1
  77. package/dist/db-OUSQPM53.js +3 -0
  78. package/dist/db-OUSQPM53.js.map +1 -0
  79. package/dist/db-RFY6O5UE.cjs +108 -0
  80. package/dist/db-RFY6O5UE.cjs.map +1 -0
  81. package/dist/editor/index.cjs +1 -0
  82. package/dist/editor/index.cjs.map +1 -1
  83. package/dist/editor/index.js +1 -0
  84. package/dist/editor/index.js.map +1 -1
  85. package/dist/{index-vjlZDWNr.d.cts → index-Bk8gOqBq.d.cts} +25 -21
  86. package/dist/{index-Cgzphklp.d.ts → index-DsnG2kdW.d.ts} +25 -21
  87. package/dist/index.cjs +47 -47
  88. package/dist/index.d.cts +3 -3
  89. package/dist/index.d.ts +3 -3
  90. package/dist/index.js +5 -5
  91. package/dist/lib/index.cjs +39 -35
  92. package/dist/lib/index.d.cts +2 -2
  93. package/dist/lib/index.d.ts +2 -2
  94. package/dist/lib/index.js +5 -5
  95. package/dist/{types-CBEEBR4A.d.ts → types-Cu515Egx.d.cts} +16 -1
  96. package/dist/{types-CBEEBR4A.d.cts → types-Cu515Egx.d.ts} +16 -1
  97. package/package.json +1 -1
  98. package/dist/chunk-4NKOJYWJ.js.map +0 -1
  99. package/dist/chunk-4PY224XM.js.map +0 -1
  100. package/dist/chunk-64HUVJOZ.js.map +0 -1
  101. package/dist/chunk-6HKMZOI4.cjs.map +0 -1
  102. package/dist/chunk-A2S32RZN.js.map +0 -1
  103. package/dist/chunk-E2QLTHKN.cjs.map +0 -1
  104. package/dist/chunk-JLPJKNRZ.js.map +0 -1
  105. package/dist/chunk-JM7QRXXK.js.map +0 -1
  106. package/dist/chunk-KDZER3PU.cjs.map +0 -1
  107. package/dist/chunk-N5MKAD7J.cjs.map +0 -1
  108. package/dist/chunk-QE4VLQYN.cjs.map +0 -1
  109. package/dist/chunk-R6MO3QIP.js.map +0 -1
  110. package/dist/chunk-U2ROR6AY.cjs.map +0 -1
  111. package/dist/chunk-ZP5XRVVH.cjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/config.ts","../src/lib/slug.ts","../src/lib/reading-time.ts","../src/lib/db.ts"],"names":[],"mappings":"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","file":"chunk-64HUVJOZ.js","sourcesContent":["import { z } from 'zod';\nimport type { NextBlogKitConfig } from './types';\n\nconst envSchema = z.object({\n NEXTBLOGKIT_MONGODB_URI: z.string().min(1, 'MongoDB URI is required'),\n NEXTBLOGKIT_R2_ACCOUNT_ID: z.string().min(1, 'R2 Account ID is required'),\n NEXTBLOGKIT_R2_ACCESS_KEY: z.string().min(1, 'R2 Access Key is required'),\n NEXTBLOGKIT_R2_SECRET_KEY: z.string().min(1, 'R2 Secret Key is required'),\n NEXTBLOGKIT_R2_BUCKET: z.string().min(1, 'R2 Bucket name is required'),\n NEXTBLOGKIT_R2_PUBLIC_URL: z.string().url('R2 Public URL must be a valid URL'),\n NEXTBLOGKIT_API_KEY: z.string().min(32, 'API key must be at least 32 characters'),\n NEXTBLOGKIT_SITE_URL: z.string().url('Site URL must be a valid URL'),\n NEXTBLOGKIT_SITE_NAME: z.string().min(1, 'Site name is required'),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nlet cachedEnv: EnvConfig | null = null;\n\nexport function getEnvConfig(): EnvConfig {\n if (cachedEnv) return cachedEnv;\n\n const result = envSchema.safeParse(process.env);\n if (!result.success) {\n const missing = result.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`);\n throw new Error(`NextBlogKit configuration error:\\n${missing.join('\\n')}`);\n }\n\n cachedEnv = result.data;\n return cachedEnv;\n}\n\nconst defaultConfig: NextBlogKitConfig = {\n basePath: '/blog',\n adminPath: '/admin/blog',\n apiPath: '/api/blog',\n postsPerPage: 10,\n excerptLength: 160,\n codeHighlighter: 'shiki',\n editor: {\n blocks: [\n 'paragraph',\n 'heading',\n 'image',\n 'codeBlock',\n 'blockquote',\n 'bulletList',\n 'orderedList',\n 'taskList',\n 'table',\n 'embed',\n 'horizontalRule',\n 'callout',\n 'tableOfContents',\n 'faq',\n 'html',\n ],\n maxImageSize: 10 * 1024 * 1024,\n imageFormats: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'],\n autosaveInterval: 30000,\n },\n seo: {\n titleTemplate: '%s | %siteName%',\n generateRSS: true,\n generateSitemap: true,\n structuredData: true,\n minContentLength: 300,\n },\n auth: {\n strategy: 'api-key',\n },\n features: {\n search: true,\n relatedPosts: true,\n readingProgress: true,\n tableOfContents: true,\n shareButtons: true,\n darkMode: true,\n scheduling: true,\n revisionHistory: true,\n imageOptimization: true,\n },\n theme: {\n darkMode: true,\n variables: {\n '--nbk-primary': '#2563eb',\n '--nbk-primary-hover': '#1d4ed8',\n '--nbk-text': '#1f2937',\n '--nbk-text-muted': '#6b7280',\n '--nbk-bg': '#ffffff',\n '--nbk-bg-secondary': '#f9fafb',\n '--nbk-card-bg': '#ffffff',\n '--nbk-border': '#e5e7eb',\n '--nbk-radius': '0.5rem',\n '--nbk-font-heading': '\"Inter\", system-ui, sans-serif',\n '--nbk-font-body': '\"Inter\", system-ui, sans-serif',\n '--nbk-font-code': '\"JetBrains Mono\", \"Fira Code\", monospace',\n },\n },\n hooks: {},\n};\n\nlet cachedConfig: NextBlogKitConfig | null = null;\n\nexport function defineConfig(config: Partial<NextBlogKitConfig>): Partial<NextBlogKitConfig> {\n return config;\n}\n\nexport function getConfig(userConfig?: Partial<NextBlogKitConfig>): NextBlogKitConfig {\n if (cachedConfig && !userConfig) return cachedConfig;\n\n const merged: NextBlogKitConfig = {\n ...defaultConfig,\n ...userConfig,\n editor: { ...defaultConfig.editor, ...userConfig?.editor },\n seo: { ...defaultConfig.seo, ...userConfig?.seo },\n auth: { ...defaultConfig.auth, ...userConfig?.auth },\n features: { ...defaultConfig.features, ...userConfig?.features },\n theme: {\n ...defaultConfig.theme,\n ...userConfig?.theme,\n variables: { ...defaultConfig.theme.variables, ...userConfig?.theme?.variables },\n },\n hooks: { ...defaultConfig.hooks, ...userConfig?.hooks },\n };\n\n if (!userConfig) {\n cachedConfig = merged;\n }\n\n return merged;\n}\n\nexport function getBlogConfig() {\n const env = getEnvConfig();\n const config = getConfig();\n\n return {\n ...config,\n siteUrl: env.NEXTBLOGKIT_SITE_URL,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n metadata: {\n title: `Blog | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description: `Latest posts from ${env.NEXTBLOGKIT_SITE_NAME}`,\n openGraph: {\n title: `Blog | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description: `Latest posts from ${env.NEXTBLOGKIT_SITE_NAME}`,\n url: `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}`,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n type: 'website',\n },\n },\n };\n}\n","import type { Collection } from 'mongodb';\n\nexport function generateSlug(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nexport async function ensureUniqueSlug(\n slug: string,\n collection: Collection,\n excludeId?: string\n): Promise<string> {\n let candidate = slug;\n let counter = 1;\n\n while (true) {\n const query: Record<string, unknown> = { slug: candidate };\n if (excludeId) {\n query._id = { $ne: excludeId };\n }\n\n const existing = await collection.findOne(query);\n if (!existing) return candidate;\n\n candidate = `${slug}-${counter}`;\n counter++;\n }\n}\n","const WORDS_PER_MINUTE = 200;\n\nexport function calculateReadingTime(text: string): number {\n const words = countWords(text);\n return Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));\n}\n\nexport function countWords(text: string): number {\n if (!text || !text.trim()) return 0;\n return text.trim().split(/\\s+/).length;\n}\n\nexport function extractTextFromHTML(html: string): string {\n return html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function extractTextFromBlocks(blocks: unknown[]): string {\n if (!Array.isArray(blocks)) return '';\n\n const parts: string[] = [];\n\n function walk(node: unknown) {\n if (!node || typeof node !== 'object') return;\n const n = node as Record<string, unknown>;\n\n if (typeof n.text === 'string') {\n parts.push(n.text);\n }\n\n if (Array.isArray(n.content)) {\n for (const child of n.content) {\n walk(child);\n }\n }\n }\n\n for (const block of blocks) {\n walk(block);\n }\n\n return parts.join(' ');\n}\n","import { MongoClient, type Db, type Collection, type Document, ObjectId } from 'mongodb';\nimport { getEnvConfig } from './config';\nimport type {\n BlogPost,\n Category,\n Media,\n BlogSettings,\n CreatePostInput,\n UpdatePostInput,\n CreateCategoryInput,\n UpdateCategoryInput,\n PostListQuery,\n MediaListQuery,\n} from './types';\nimport { generateSlug, ensureUniqueSlug } from './slug';\nimport { calculateReadingTime, countWords, extractTextFromBlocks } from './reading-time';\n\nlet client: MongoClient | null = null;\nlet db: Db | null = null;\n\nexport async function getDb(): Promise<Db> {\n if (db) return db;\n\n const env = getEnvConfig();\n client = new MongoClient(env.NEXTBLOGKIT_MONGODB_URI);\n await client.connect();\n db = client.db();\n return db;\n}\n\nexport async function getCollection<T extends Document = Document>(\n name: string\n): Promise<Collection<T>> {\n const database = await getDb();\n return database.collection<T>(name);\n}\n\nexport async function ensureIndexes(): Promise<void> {\n const database = await getDb();\n\n const posts = database.collection('nbk_posts');\n await posts.createIndex({ slug: 1 }, { unique: true });\n await posts.createIndex({ status: 1, publishedAt: -1 });\n await posts.createIndex({ categories: 1, status: 1 });\n await posts.createIndex({ tags: 1, status: 1 });\n await posts.createIndex({ 'seo.focusKeyword': 1 });\n await posts.createIndex({ contentText: 'text', title: 'text', excerpt: 'text' });\n\n const categories = database.collection('nbk_categories');\n await categories.createIndex({ slug: 1 }, { unique: true });\n await categories.createIndex({ order: 1 });\n\n const media = database.collection('nbk_media');\n await media.createIndex({ createdAt: -1 });\n await media.createIndex({ r2Key: 1 }, { unique: true });\n}\n\n// ============================================================\n// Posts\n// ============================================================\n\nexport async function createPost(input: CreatePostInput, defaultAuthor?: BlogPost['author']): Promise<BlogPost> {\n const col = await getCollection('nbk_posts');\n\n const slug = await ensureUniqueSlug(\n input.slug || generateSlug(input.title),\n col\n );\n\n const contentText = input.contentText || extractTextFromBlocks(input.content || []);\n const wordCount = countWords(contentText);\n const readingTime = calculateReadingTime(contentText);\n\n const excerpt =\n input.excerpt || contentText.slice(0, 160).replace(/\\s+\\S*$/, '') + '...';\n\n const now = new Date();\n const doc = {\n title: input.title,\n slug,\n excerpt,\n content: input.content || [],\n contentHTML: input.contentHTML || '',\n contentText,\n coverImage: input.coverImage,\n categories: input.categories || [],\n tags: input.tags || [],\n author: input.author || defaultAuthor || { name: 'Admin' },\n seo: {\n ogType: 'article',\n noIndex: false,\n ...input.seo,\n },\n status: input.status || 'draft',\n publishedAt: input.status === 'published' ? now : input.publishedAt,\n scheduledAt: input.scheduledAt,\n readingTime,\n wordCount,\n version: 1,\n revisions: [],\n createdAt: now,\n updatedAt: now,\n };\n\n const result = await col.insertOne(doc);\n return { _id: result.insertedId, ...doc } as unknown as BlogPost;\n}\n\nexport async function updatePost(\n id: string,\n input: UpdatePostInput\n): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n const objectId = new ObjectId(id);\n const existing = await col.findOne({ _id: objectId });\n if (!existing) return null;\n\n const updates: Record<string, unknown> = { ...input, updatedAt: new Date() };\n\n if (input.slug && input.slug !== existing.slug) {\n updates.slug = await ensureUniqueSlug(input.slug, col, id);\n }\n\n if (input.content) {\n const contentText = input.contentText || extractTextFromBlocks(input.content);\n updates.contentText = contentText;\n updates.wordCount = countWords(contentText);\n updates.readingTime = calculateReadingTime(contentText);\n\n if (!input.excerpt) {\n updates.excerpt =\n contentText.slice(0, 160).replace(/\\s+\\S*$/, '') + '...';\n }\n\n // Save revision\n const revision = {\n version: existing.version || 1,\n title: existing.title,\n content: existing.content,\n contentHTML: existing.contentHTML,\n savedAt: new Date(),\n };\n const revisions = [...(existing.revisions || []), revision].slice(-10);\n updates.revisions = revisions;\n updates.version = (existing.version || 1) + 1;\n }\n\n if (input.status === 'published' && existing.status !== 'published') {\n updates.publishedAt = new Date();\n }\n\n await col.updateOne({ _id: objectId }, { $set: updates });\n return (await col.findOne({ _id: objectId })) as unknown as BlogPost;\n}\n\nexport async function deletePost(id: string): Promise<boolean> {\n const col = await getCollection('nbk_posts');\n const result = await col.updateOne(\n { _id: new ObjectId(id) },\n { $set: { status: 'archived', updatedAt: new Date() } }\n );\n return result.modifiedCount > 0;\n}\n\nexport async function hardDeletePost(id: string): Promise<boolean> {\n const col = await getCollection('nbk_posts');\n const result = await col.deleteOne({ _id: new ObjectId(id) });\n return result.deletedCount > 0;\n}\n\nexport async function getPostBySlug(slug: string): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n return (await col.findOne({ slug })) as unknown as BlogPost | null;\n}\n\nexport async function getPostById(id: string): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n return (await col.findOne({ _id: new ObjectId(id) })) as unknown as BlogPost | null;\n}\n\nexport async function listPosts(\n query: PostListQuery = {}\n): Promise<{ posts: BlogPost[]; total: number }> {\n const col = await getCollection('nbk_posts');\n const {\n page = 1,\n limit = 10,\n category,\n tag,\n status,\n search,\n sortBy = 'publishedAt',\n sortOrder = 'desc',\n } = query;\n\n const filter: Record<string, unknown> = {};\n\n if (status) {\n filter.status = status;\n } else {\n filter.status = { $ne: 'archived' };\n }\n\n if (category) filter.categories = category;\n if (tag) filter.tags = tag;\n if (search) {\n filter.$text = { $search: search };\n }\n\n const sort: Record<string, 1 | -1> = {\n [sortBy]: sortOrder === 'asc' ? 1 : -1,\n };\n\n const skip = (page - 1) * limit;\n\n const [posts, total] = await Promise.all([\n col.find(filter).sort(sort).skip(skip).limit(limit).toArray(),\n col.countDocuments(filter),\n ]);\n\n return {\n posts: posts as unknown as BlogPost[],\n total,\n };\n}\n\n// ============================================================\n// Categories\n// ============================================================\n\nexport async function createCategory(input: CreateCategoryInput): Promise<Category> {\n const col = await getCollection('nbk_categories');\n const slug = await ensureUniqueSlug(\n input.slug || generateSlug(input.name),\n col\n );\n\n const doc = {\n name: input.name,\n slug,\n description: input.description,\n seo: input.seo,\n order: input.order ?? 0,\n parentId: input.parentId ? new ObjectId(input.parentId) : undefined,\n postCount: 0,\n };\n\n const result = await col.insertOne(doc);\n return { _id: result.insertedId, ...doc } as unknown as Category;\n}\n\nexport async function updateCategory(\n id: string,\n input: UpdateCategoryInput\n): Promise<Category | null> {\n const col = await getCollection('nbk_categories');\n const objectId = new ObjectId(id);\n\n const updates: Record<string, unknown> = { ...input };\n if (input.slug) {\n updates.slug = await ensureUniqueSlug(input.slug, col, id);\n }\n if (input.parentId) {\n updates.parentId = new ObjectId(input.parentId);\n }\n\n await col.updateOne({ _id: objectId }, { $set: updates });\n return (await col.findOne({ _id: objectId })) as unknown as Category | null;\n}\n\nexport async function deleteCategory(id: string): Promise<boolean> {\n const col = await getCollection('nbk_categories');\n const result = await col.deleteOne({ _id: new ObjectId(id) });\n return result.deletedCount > 0;\n}\n\nexport async function listCategories(): Promise<Category[]> {\n const col = await getCollection('nbk_categories');\n return (await col.find({}).sort({ order: 1 }).toArray()) as unknown as Category[];\n}\n\nexport async function getCategoryBySlug(slug: string): Promise<Category | null> {\n const col = await getCollection('nbk_categories');\n return (await col.findOne({ slug })) as unknown as Category | null;\n}\n\nexport async function updateCategoryPostCount(categorySlug: string): Promise<void> {\n const posts = await getCollection('nbk_posts');\n const categories = await getCollection('nbk_categories');\n const count = await posts.countDocuments({\n categories: categorySlug,\n status: 'published',\n });\n await categories.updateOne({ slug: categorySlug }, { $set: { postCount: count } });\n}\n\n// ============================================================\n// Media\n// ============================================================\n\nexport async function createMedia(data: Omit<Media, '_id'>): Promise<Media> {\n const col = await getCollection('nbk_media');\n const result = await col.insertOne(data);\n return { _id: result.insertedId, ...data } as unknown as Media;\n}\n\nexport async function deleteMedia(id: string): Promise<Media | null> {\n const col = await getCollection('nbk_media');\n const media = await col.findOne({ _id: new ObjectId(id) });\n if (!media) return null;\n await col.deleteOne({ _id: new ObjectId(id) });\n return media as unknown as Media;\n}\n\nexport async function listMedia(\n query: MediaListQuery = {}\n): Promise<{ media: Media[]; total: number }> {\n const col = await getCollection('nbk_media');\n const { page = 1, limit = 20, mimeType } = query;\n\n const filter: Record<string, unknown> = {};\n if (mimeType) filter.mimeType = { $regex: mimeType };\n\n const skip = (page - 1) * limit;\n const [media, total] = await Promise.all([\n col.find(filter).sort({ createdAt: -1 }).skip(skip).limit(limit).toArray(),\n col.countDocuments(filter),\n ]);\n\n return { media: media as unknown as Media[], total };\n}\n\n// ============================================================\n// Settings\n// ============================================================\n\nexport async function getSettings(): Promise<BlogSettings> {\n const col = await getCollection('nbk_settings');\n const settings = await col.findOne({ _id: 'global' as unknown as ObjectId });\n if (!settings) {\n const defaults: Record<string, unknown> = {\n _id: 'global',\n postsPerPage: 10,\n commentSystem: 'none',\n };\n await col.insertOne(defaults as Document);\n return defaults as unknown as BlogSettings;\n }\n return settings as unknown as BlogSettings;\n}\n\nexport async function updateSettings(\n data: Partial<BlogSettings>\n): Promise<BlogSettings> {\n const col = await getCollection('nbk_settings');\n const { _id, ...updates } = data as Record<string, unknown>;\n await col.updateOne(\n { _id: 'global' as unknown as ObjectId },\n { $set: updates },\n { upsert: true }\n );\n return getSettings();\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/rss.ts"],"names":["getEnvConfig","getCollection"],"mappings":";;;;;AAGA,eAAsB,eAAA,CAAgB,cAAc,KAAA,EAAwB;AAC1E,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,KAAA,GAAQ,MAAMC,+BAAA,CAAc,WAAW,CAAA;AAE7C,EAAA,MAAM,iBAAiB,MAAM,KAAA,CAC1B,KAAK,EAAE,MAAA,EAAQ,aAAa,CAAA,CAC5B,IAAA,CAAK,EAAE,aAAa,EAAA,EAAI,EACxB,KAAA,CAAM,EAAE,EACR,OAAA,EAAQ;AAEX,EAAA,MAAM,KAAA,GAAQ,cAAA,CACX,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,UAAU,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAC7D,IAAA,MAAM,OAAA,GAAU,WAAA,GAAc,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,OAAA;AACtD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,WAAA,GACjB,IAAI,KAAK,IAAA,CAAK,WAAW,CAAA,CAAE,WAAA,KAC3B,IAAI,IAAA,CAAK,IAAA,CAAK,SAAS,EAAE,WAAA,EAAY;AAEzC,IAAA,IAAI,SAAA,GAAY,EAAA;AAChB,IAAA,IAAI,IAAA,CAAK,YAAY,GAAA,EAAK;AACxB,MAAA,SAAA,GAAY;AAAA,sBAAA,EAA2B,SAAA,CAAU,IAAA,CAAK,UAAA,CAAW,GAAG,CAAC,CAAA,sBAAA,CAAA;AAAA,IACvE;AAEA,IAAA,OAAO,CAAA;AAAA,aAAA,EACE,SAAA,CAAU,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,YAAA,EACtB,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,+BAAA,EACC,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,4BAAA,EACrB,WAAW,EAAE,CAAA;AAAA,eAAA,EAC1B,OAAO,CAAA,UAAA,EAAa,SAAS,CAAA,EACtC,IAAA,CAAK,UAAA,EAAY,MAAA,GACb,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAc;AAAA,gBAAA,EAAqB,SAAA,CAAU,CAAC,CAAC,CAAA,WAAA,CAAa,EAAE,IAAA,CAAK,EAAE,IAC1F,EACN;AAAA,WAAA,CAAA;AAAA,EAEF,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAEZ,EAAA,MAAM,SAAA,GAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAEzC,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA,WAAA,EAGI,SAAA,CAAU,GAAA,CAAI,qBAAqB,CAAC,CAAA;AAAA,UAAA,EACrC,SAAA,CAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA;AAAA,mCAAA,EACV,SAAA,CAAU,GAAA,CAAI,qBAAqB,CAAC,CAAA;AAAA;AAAA,mBAAA,EAEpD,SAAS,CAAA;AAAA,qBAAA,EACP,SAAA,CAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA;AAAA,EACxD,KAAK;AAAA;AAAA,MAAA,CAAA;AAGP;AAEA,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,OAAO,IACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B","file":"chunk-6HKMZOI4.cjs","sourcesContent":["import { getCollection } from './db';\nimport { getEnvConfig } from './config';\n\nexport async function generateRSSFeed(fullContent = false): Promise<string> {\n const env = getEnvConfig();\n const posts = await getCollection('nbk_posts');\n\n const publishedPosts = await posts\n .find({ status: 'published' })\n .sort({ publishedAt: -1 })\n .limit(50)\n .toArray();\n\n const items = publishedPosts\n .map((post) => {\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n const content = fullContent ? post.contentHTML : post.excerpt;\n const pubDate = post.publishedAt\n ? new Date(post.publishedAt).toUTCString()\n : new Date(post.createdAt).toUTCString();\n\n let enclosure = '';\n if (post.coverImage?.url) {\n enclosure = `\\n <enclosure url=\"${escapeXml(post.coverImage.url)}\" type=\"image/jpeg\" />`;\n }\n\n return ` <item>\n <title>${escapeXml(post.title)}</title>\n <link>${escapeXml(postUrl)}</link>\n <guid isPermaLink=\"true\">${escapeXml(postUrl)}</guid>\n <description><![CDATA[${content || ''}]]></description>\n <pubDate>${pubDate}</pubDate>${enclosure}${\n post.categories?.length\n ? post.categories.map((c: string) => `\\n <category>${escapeXml(c)}</category>`).join('')\n : ''\n }\n </item>`;\n })\n .join('\\n');\n\n const buildDate = new Date().toUTCString();\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>${escapeXml(env.NEXTBLOGKIT_SITE_NAME)} Blog</title>\n <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/blog</link>\n <description>Latest posts from ${escapeXml(env.NEXTBLOGKIT_SITE_NAME)}</description>\n <language>en</language>\n <lastBuildDate>${buildDate}</lastBuildDate>\n <atom:link href=\"${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/api/blog/rss.xml\" rel=\"self\" type=\"application/rss+xml\" />\n${items}\n </channel>\n</rss>`;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/storage.ts","../src/lib/image.ts"],"names":[],"mappings":"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","file":"chunk-A2S32RZN.js","sourcesContent":["import {\n S3Client,\n PutObjectCommand,\n DeleteObjectCommand,\n ListObjectsV2Command,\n} from '@aws-sdk/client-s3';\nimport { getEnvConfig } from './config';\nimport { randomUUID } from 'crypto';\n\nexport interface MediaUploadResult {\n key: string;\n url: string;\n size: number;\n contentType: string;\n}\n\nexport interface StorageObject {\n key: string;\n size: number;\n lastModified: Date;\n}\n\nexport interface StorageProvider {\n upload(file: Buffer, filename: string, contentType: string): Promise<MediaUploadResult>;\n delete(key: string): Promise<void>;\n list(prefix?: string): Promise<StorageObject[]>;\n}\n\nlet clientInstance: S3Client | null = null;\n\nfunction getS3Client(): S3Client {\n if (clientInstance) return clientInstance;\n\n const env = getEnvConfig();\n clientInstance = new S3Client({\n region: 'auto',\n endpoint: `https://${env.NEXTBLOGKIT_R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,\n credentials: {\n accessKeyId: env.NEXTBLOGKIT_R2_ACCESS_KEY,\n secretAccessKey: env.NEXTBLOGKIT_R2_SECRET_KEY,\n },\n });\n\n return clientInstance;\n}\n\nfunction generateKey(filename: string): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const uuid = randomUUID().split('-')[0];\n const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '-').toLowerCase();\n return `blog/${year}/${month}/${uuid}-${safeName}`;\n}\n\nexport class R2StorageProvider implements StorageProvider {\n async upload(\n file: Buffer,\n filename: string,\n contentType: string\n ): Promise<MediaUploadResult> {\n const env = getEnvConfig();\n const client = getS3Client();\n const key = generateKey(filename);\n\n await client.send(\n new PutObjectCommand({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Key: key,\n Body: file,\n ContentType: contentType,\n })\n );\n\n return {\n key,\n url: `${env.NEXTBLOGKIT_R2_PUBLIC_URL}/${key}`,\n size: file.length,\n contentType,\n };\n }\n\n async delete(key: string): Promise<void> {\n const env = getEnvConfig();\n const client = getS3Client();\n\n await client.send(\n new DeleteObjectCommand({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Key: key,\n })\n );\n }\n\n async list(prefix?: string): Promise<StorageObject[]> {\n const env = getEnvConfig();\n const client = getS3Client();\n\n const response = await client.send(\n new ListObjectsV2Command({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Prefix: prefix || 'blog/',\n })\n );\n\n return (response.Contents || []).map((obj) => ({\n key: obj.Key || '',\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n }));\n }\n}\n","import type { R2StorageProvider, MediaUploadResult } from './storage';\n\nexport interface ProcessedImage {\n original: MediaUploadResult;\n width: number;\n height: number;\n format: string;\n}\n\nconst RESPONSIVE_SIZES = [640, 768, 1024, 1280, 1920];\n\nexport async function processImage(\n file: Buffer,\n filename: string,\n storage: R2StorageProvider\n): Promise<ProcessedImage> {\n let sharp: typeof import('sharp');\n try {\n sharp = (await import('sharp')).default;\n } catch {\n // sharp not available — upload raw file\n const result = await storage.upload(file, filename, getMimeType(filename));\n return {\n original: result,\n width: 0,\n height: 0,\n format: getExtension(filename),\n };\n }\n\n const image = sharp(file);\n const metadata = await image.metadata();\n\n // Convert to WebP\n const webpFilename = filename.replace(/\\.[^.]+$/, '.webp');\n const webpBuffer = await image.webp({ quality: 85 }).toBuffer();\n\n const original = await storage.upload(webpBuffer, webpFilename, 'image/webp');\n\n // Generate responsive sizes in background (non-blocking for the main upload)\n generateResponsiveSizes(file, webpFilename, storage, metadata.width || 0).catch(\n () => {\n // Silently fail responsive generation — originals are sufficient\n }\n );\n\n return {\n original,\n width: metadata.width || 0,\n height: metadata.height || 0,\n format: 'webp',\n };\n}\n\nasync function generateResponsiveSizes(\n file: Buffer,\n filename: string,\n storage: R2StorageProvider,\n originalWidth: number\n): Promise<void> {\n const sharp = (await import('sharp')).default;\n\n const sizes = RESPONSIVE_SIZES.filter((s) => s < originalWidth);\n\n await Promise.all(\n sizes.map(async (width) => {\n const resized = await sharp(file)\n .resize(width)\n .webp({ quality: 80 })\n .toBuffer();\n\n const sizedFilename = filename.replace('.webp', `-${width}w.webp`);\n await storage.upload(resized, sizedFilename, 'image/webp');\n })\n );\n\n // Generate thumbnail\n const thumb = await sharp(file)\n .resize(200, 200, { fit: 'cover' })\n .webp({ quality: 70 })\n .toBuffer();\n\n const thumbFilename = filename.replace('.webp', '-thumb.webp');\n await storage.upload(thumb, thumbFilename, 'image/webp');\n}\n\nfunction getMimeType(filename: string): string {\n const ext = getExtension(filename);\n const mimeTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n avif: 'image/avif',\n };\n return mimeTypes[ext] || 'application/octet-stream';\n}\n\nfunction getExtension(filename: string): string {\n return filename.split('.').pop()?.toLowerCase() || '';\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/sitemap.ts"],"names":["getEnvConfig","getCollection"],"mappings":";;;;;AAUA,eAAsB,eAAA,GAAmC;AACvD,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,KAAA,GAAQ,MAAMC,+BAAA,CAAc,WAAW,CAAA;AAC7C,EAAA,MAAM,UAAA,GAAa,MAAMA,+BAAA,CAAc,gBAAgB,CAAA;AAEvD,EAAA,MAAM,UAA0B,EAAC;AAGjC,EAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,IACX,GAAA,EAAK,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,KAAA,CAAA;AAAA,IAChC,UAAA,EAAY,OAAA;AAAA,IACZ,QAAA,EAAU;AAAA,GACX,CAAA;AAGD,EAAA,MAAM,cAAA,GAAiB,MAAM,KAAA,CAC1B,IAAA,CAAK,EAAE,QAAQ,WAAA,EAAa,CAAA,CAC5B,IAAA,CAAK,EAAE,WAAA,EAAa,IAAI,CAAA,CACxB,OAAA,CAAQ,EAAE,IAAA,EAAM,CAAA,EAAG,SAAA,EAAW,CAAA,EAAG,WAAA,EAAa,CAAA,EAAG,CAAA,CACjD,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,QAAQ,cAAA,EAAgB;AACjC,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,SAAA,IAAa,IAAA,CAAK,WAAA;AACvC,IAAA,MAAM,mBAAmB,OAAA,GACrB,IAAA,CAAK,KAAA,CAAA,CAAO,IAAA,CAAK,KAAI,GAAI,IAAI,IAAA,CAAK,OAAO,EAAE,OAAA,EAAQ,KAAM,MAAO,EAAA,GAAK,EAAA,GAAK,GAAG,CAAA,GAC7E,CAAA;AAEJ,IAAA,IAAI,UAAA,GAAa,SAAA;AACjB,IAAA,IAAI,gBAAA,GAAmB,GAAG,UAAA,GAAa,OAAA;AAAA,SAAA,IAC9B,gBAAA,GAAmB,IAAI,UAAA,GAAa,QAAA;AAE7C,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,KAAK,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAAA,MAClD,OAAA,EAAS,OAAA,GAAU,IAAI,IAAA,CAAK,OAAO,CAAA,CAAE,WAAA,EAAY,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,GAAI,MAAA;AAAA,MACnE,UAAA;AAAA,MACA,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,gBAAgB,MAAM,UAAA,CACzB,KAAK,EAAE,EACP,IAAA,CAAK,EAAE,OAAO,CAAA,EAAG,EACjB,OAAA,CAAQ,EAAE,MAAM,CAAA,EAAG,EACnB,OAAA,EAAQ;AAEX,EAAA,KAAA,MAAW,OAAO,aAAA,EAAe;AAC/B,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,KAAK,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,eAAA,EAAkB,IAAI,IAAI,CAAA,CAAA;AAAA,MAC1D,UAAA,EAAY,QAAA;AAAA,MACZ,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH;AAGA,EAAA,MAAM,aAAa,cAAA,CAAe,MAAA;AAClC,EAAA,MAAM,YAAA,GAAe,EAAA;AACrB,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,UAAA,GAAa,YAAY,CAAA;AACtD,EAAA,KAAA,IAAS,IAAA,GAAO,CAAA,EAAG,IAAA,IAAQ,UAAA,EAAY,IAAA,EAAA,EAAQ;AAC7C,IAAA,OAAA,CAAQ,IAAA,CAAK;AAAA,MACX,GAAA,EAAK,CAAA,EAAG,GAAA,CAAI,oBAAoB,cAAc,IAAI,CAAA,CAAA;AAAA,MAClD,UAAA,EAAY,QAAA;AAAA,MACZ,QAAA,EAAU;AAAA,KACX,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,SAAS,OAAO,CAAA;AACzB;AAEA,SAAS,SAAS,OAAA,EAAiC;AACjD,EAAA,MAAM,OAAO,OAAA,CACV,GAAA;AAAA,IACC,CAAC,KAAA,KAAU,CAAA;AAAA,SAAA,EACN,UAAU,KAAA,CAAM,GAAG,CAAC,CAAA,MAAA,EAAS,MAAM,OAAA,GAAU;AAAA,aAAA,EAAkB,MAAM,OAAO,CAAA,UAAA,CAAA,GAAe,EAAE,CAAA,EAAG,MAAM,UAAA,GAAa;AAAA,gBAAA,EAAqB,MAAM,UAAU,CAAA,aAAA,CAAA,GAAkB,EAAE,CAAA,EAAG,MAAM,QAAA,GAAW;AAAA,cAAA,EAAmB,KAAA,CAAM,QAAQ,CAAA,WAAA,CAAA,GAAgB,EAAE;AAAA,QAAA;AAAA,GAE1P,CACC,KAAK,IAAI,CAAA;AAEZ,EAAA,OAAO,CAAA;AAAA;AAAA,EAEP,IAAI;AAAA,SAAA,CAAA;AAEN;AAEA,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,OAAO,IACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B","file":"chunk-E2QLTHKN.cjs","sourcesContent":["import { getCollection } from './db';\nimport { getEnvConfig } from './config';\n\ninterface SitemapEntry {\n loc: string;\n lastmod?: string;\n changefreq?: string;\n priority?: string;\n}\n\nexport async function generateSitemap(): Promise<string> {\n const env = getEnvConfig();\n const posts = await getCollection('nbk_posts');\n const categories = await getCollection('nbk_categories');\n\n const entries: SitemapEntry[] = [];\n\n // Blog listing page\n entries.push({\n loc: `${env.NEXTBLOGKIT_SITE_URL}/blog`,\n changefreq: 'daily',\n priority: '0.9',\n });\n\n // Published posts\n const publishedPosts = await posts\n .find({ status: 'published' })\n .sort({ publishedAt: -1 })\n .project({ slug: 1, updatedAt: 1, publishedAt: 1 })\n .toArray();\n\n for (const post of publishedPosts) {\n const lastmod = post.updatedAt || post.publishedAt;\n const daysSincePublish = lastmod\n ? Math.floor((Date.now() - new Date(lastmod).getTime()) / (1000 * 60 * 60 * 24))\n : 0;\n\n let changefreq = 'monthly';\n if (daysSincePublish < 7) changefreq = 'daily';\n else if (daysSincePublish < 30) changefreq = 'weekly';\n\n entries.push({\n loc: `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`,\n lastmod: lastmod ? new Date(lastmod).toISOString().split('T')[0] : undefined,\n changefreq,\n priority: '0.8',\n });\n }\n\n // Category pages\n const allCategories = await categories\n .find({})\n .sort({ order: 1 })\n .project({ slug: 1 })\n .toArray();\n\n for (const cat of allCategories) {\n entries.push({\n loc: `${env.NEXTBLOGKIT_SITE_URL}/blog/category/${cat.slug}`,\n changefreq: 'weekly',\n priority: '0.6',\n });\n }\n\n // Paginated listing pages\n const totalPosts = publishedPosts.length;\n const postsPerPage = 10;\n const totalPages = Math.ceil(totalPosts / postsPerPage);\n for (let page = 2; page <= totalPages; page++) {\n entries.push({\n loc: `${env.NEXTBLOGKIT_SITE_URL}/blog?page=${page}`,\n changefreq: 'weekly',\n priority: '0.5',\n });\n }\n\n return buildXML(entries);\n}\n\nfunction buildXML(entries: SitemapEntry[]): string {\n const urls = entries\n .map(\n (entry) => ` <url>\n <loc>${escapeXml(entry.loc)}</loc>${entry.lastmod ? `\\n <lastmod>${entry.lastmod}</lastmod>` : ''}${entry.changefreq ? `\\n <changefreq>${entry.changefreq}</changefreq>` : ''}${entry.priority ? `\\n <priority>${entry.priority}</priority>` : ''}\n </url>`\n )\n .join('\\n');\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">\n${urls}\n</urlset>`;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/middleware.ts"],"names":[],"mappings":";;;AAIO,SAAS,WAAA,CAAY,IAAA,EAAe,IAAA,EAAgC,MAAA,GAAS,GAAA,EAAK;AACvF,EAAA,OAAO,YAAA,CAAa,IAAA,CAAK,EAAE,OAAA,EAAS,IAAA,EAAM,MAAM,IAAA,EAAK,EAAG,EAAE,MAAA,EAAQ,CAAA;AACpE;AAEO,SAAS,SAAA,CAAU,IAAA,EAAc,OAAA,EAAiB,MAAA,GAAS,GAAA,EAAqC;AACrG,EAAA,OAAO,YAAA,CAAa,IAAA;AAAA,IAClB,EAAE,OAAA,EAAS,KAAA,EAAO,OAAO,EAAE,IAAA,EAAM,SAAQ,EAAE;AAAA,IAC3C,EAAE,MAAA;AAAO,GACX;AACF;AAEO,SAAS,YAAY,OAAA,EAAyD;AACnF,EAAA,MAAM,MAAM,YAAA,EAAa;AACzB,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AAEtD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,SAAA,CAAU,cAAA,EAAgB,kCAAA,EAAoC,GAAG,CAAA;AAAA,EAC1E;AAEA,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAClD,EAAA,IAAI,KAAA,KAAU,IAAI,mBAAA,EAAqB;AACrC,IAAA,OAAO,SAAA,CAAU,WAAA,EAAa,iBAAA,EAAmB,GAAG,CAAA;AAAA,EACtD;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,gBAAgB,OAAA,EAAkB;AAChD,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,GAAA,CAAI,YAAA,CAAa,SAAS,CAAA;AACtD;AAEO,SAAS,aAAA,CAAc,OAA2B,YAAA,EAA8B;AACrF,EAAA,IAAI,CAAC,OAAO,OAAO,YAAA;AACnB,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,EAAO,EAAE,CAAA;AACjC,EAAA,OAAO,KAAA,CAAM,MAAM,CAAA,GAAI,YAAA,GAAe,MAAA;AACxC","file":"chunk-JLPJKNRZ.js","sourcesContent":["import { NextResponse } from 'next/server';\nimport { getEnvConfig } from '../lib/config';\nimport type { ApiErrorResponse } from '../lib/types';\n\nexport function jsonSuccess(data: unknown, meta?: Record<string, unknown>, status = 200) {\n return NextResponse.json({ success: true, data, meta }, { status });\n}\n\nexport function jsonError(code: string, message: string, status = 400): NextResponse<ApiErrorResponse> {\n return NextResponse.json(\n { success: false, error: { code, message } },\n { status }\n ) as NextResponse<ApiErrorResponse>;\n}\n\nexport function requireAuth(request: Request): NextResponse<ApiErrorResponse> | null {\n const env = getEnvConfig();\n const authHeader = request.headers.get('authorization');\n\n if (!authHeader) {\n return jsonError('UNAUTHORIZED', 'Authorization header is required', 401);\n }\n\n const token = authHeader.replace(/^Bearer\\s+/i, '');\n if (token !== env.NEXTBLOGKIT_API_KEY) {\n return jsonError('FORBIDDEN', 'Invalid API key', 403);\n }\n\n return null;\n}\n\nexport function getSearchParams(request: Request) {\n const url = new URL(request.url);\n return Object.fromEntries(url.searchParams.entries());\n}\n\nexport function parseIntParam(value: string | undefined, defaultValue: number): number {\n if (!value) return defaultValue;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/search.ts","../src/lib/seo.ts","../src/lib/seo-scorer.ts"],"names":[],"mappings":"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","file":"chunk-JM7QRXXK.js","sourcesContent":["import type { Collection, Document } from 'mongodb';\n\nexport interface SearchResult {\n slug: string;\n title: string;\n excerpt: string;\n score: number;\n}\n\nexport async function searchPosts(\n collection: Collection,\n query: string,\n limit: number = 10\n): Promise<SearchResult[]> {\n if (!query.trim()) return [];\n\n const results = await collection\n .find(\n {\n $text: { $search: query },\n status: 'published',\n },\n {\n projection: {\n slug: 1,\n title: 1,\n excerpt: 1,\n score: { $meta: 'textScore' },\n },\n }\n )\n .sort({ score: { $meta: 'textScore' } })\n .limit(limit)\n .toArray();\n\n return results.map((doc: Document) => ({\n slug: doc.slug as string,\n title: doc.title as string,\n excerpt: doc.excerpt as string,\n score: doc.score as number,\n }));\n}\n","import type { BlogPost } from './types';\nimport { getEnvConfig } from './config';\n\nexport interface MetaTags {\n title: string;\n description: string;\n canonical: string;\n openGraph: {\n title: string;\n description: string;\n url: string;\n siteName: string;\n type: string;\n images: { url: string; width?: number; height?: number; alt?: string }[];\n article?: {\n publishedTime: string;\n modifiedTime: string;\n section?: string;\n tags?: string[];\n };\n };\n twitter: {\n card: string;\n title: string;\n description: string;\n images: string[];\n };\n robots?: string;\n}\n\nexport function generateMetaTags(post: BlogPost): MetaTags {\n const env = getEnvConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n const title = post.seo?.metaTitle || post.title;\n const description = post.seo?.metaDescription || post.excerpt;\n const canonical = post.seo?.canonicalUrl || postUrl;\n const ogImage = post.seo?.ogImage || post.coverImage?.url;\n\n return {\n title: `${title} | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description,\n canonical,\n openGraph: {\n title,\n description,\n url: postUrl,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n type: post.seo?.ogType || 'article',\n images: ogImage\n ? [\n {\n url: ogImage,\n width: 1200,\n height: 630,\n alt: title,\n },\n ]\n : [],\n article: {\n publishedTime: post.publishedAt?.toISOString() || '',\n modifiedTime: post.updatedAt.toISOString(),\n section: post.categories[0],\n tags: post.tags,\n },\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: ogImage ? [ogImage] : [],\n },\n robots: post.seo?.noIndex ? 'noindex, nofollow' : undefined,\n };\n}\n\nexport interface ArticleStructuredData {\n '@context': string;\n '@type': string;\n headline: string;\n description: string;\n image?: string;\n datePublished?: string;\n dateModified: string;\n author: {\n '@type': string;\n name: string;\n url?: string;\n };\n publisher: {\n '@type': string;\n name: string;\n };\n mainEntityOfPage: {\n '@type': string;\n '@id': string;\n };\n wordCount: number;\n articleSection?: string;\n}\n\nexport function generateStructuredData(post: BlogPost): ArticleStructuredData {\n const env = getEnvConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BlogPosting',\n headline: post.title,\n description: post.excerpt,\n image: post.coverImage?.url || post.seo?.ogImage,\n datePublished: post.publishedAt?.toISOString(),\n dateModified: post.updatedAt.toISOString(),\n author: {\n '@type': 'Person',\n name: post.author.name,\n url: post.author.url,\n },\n publisher: {\n '@type': 'Organization',\n name: env.NEXTBLOGKIT_SITE_NAME,\n },\n mainEntityOfPage: {\n '@type': 'WebPage',\n '@id': postUrl,\n },\n wordCount: post.wordCount,\n articleSection: post.categories[0],\n };\n}\n\nexport interface FAQStructuredData {\n '@context': string;\n '@type': string;\n mainEntity: {\n '@type': string;\n name: string;\n acceptedAnswer: {\n '@type': string;\n text: string;\n };\n }[];\n}\n\nexport function generateFAQStructuredData(\n faqItems: { question: string; answer: string }[]\n): FAQStructuredData | null {\n if (!faqItems.length) return null;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n mainEntity: faqItems.map((item) => ({\n '@type': 'Question',\n name: item.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: item.answer,\n },\n })),\n };\n}\n\nexport interface BreadcrumbStructuredData {\n '@context': string;\n '@type': string;\n itemListElement: {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n }[];\n}\n\nexport function generateBreadcrumbs(\n post: BlogPost,\n categoryName?: string\n): BreadcrumbStructuredData {\n const env = getEnvConfig();\n const items: BreadcrumbStructuredData['itemListElement'] = [\n {\n '@type': 'ListItem',\n position: 1,\n name: 'Home',\n item: env.NEXTBLOGKIT_SITE_URL,\n },\n {\n '@type': 'ListItem',\n position: 2,\n name: 'Blog',\n item: `${env.NEXTBLOGKIT_SITE_URL}/blog`,\n },\n ];\n\n if (categoryName && post.categories[0]) {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: categoryName,\n item: `${env.NEXTBLOGKIT_SITE_URL}/blog/category/${post.categories[0]}`,\n });\n items.push({\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n });\n } else {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: post.title,\n });\n }\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items,\n };\n}\n","import type { BlogPost, SEOScore, SEOCheck, SEOCheckStatus } from './types';\n\nfunction check(id: string, status: SEOCheckStatus, message: string): SEOCheck {\n return { id, status, message };\n}\n\nexport function calculateSEOScore(post: BlogPost): SEOScore {\n const checks: SEOCheck[] = [];\n const keyword = post.seo?.focusKeyword?.toLowerCase() || '';\n const title = post.title.toLowerCase();\n const slug = post.slug.toLowerCase();\n const excerpt = (post.seo?.metaDescription || post.excerpt || '').toLowerCase();\n const contentText = post.contentText?.toLowerCase() || '';\n const contentHTML = post.contentHTML || '';\n\n // 1. Focus keyword in title\n if (!keyword) {\n checks.push(check('focus-keyword-in-title', 'warn', 'No focus keyword set'));\n } else if (title.includes(keyword)) {\n checks.push(check('focus-keyword-in-title', 'pass', 'Focus keyword appears in title'));\n } else {\n checks.push(check('focus-keyword-in-title', 'fail', 'Focus keyword not found in title'));\n }\n\n // 2. Focus keyword in slug\n if (!keyword) {\n checks.push(check('focus-keyword-in-slug', 'warn', 'No focus keyword set'));\n } else if (slug.includes(keyword.replace(/\\s+/g, '-'))) {\n checks.push(check('focus-keyword-in-slug', 'pass', 'Focus keyword appears in URL slug'));\n } else {\n checks.push(check('focus-keyword-in-slug', 'fail', 'Focus keyword not found in URL slug'));\n }\n\n // 3. Focus keyword in meta description\n if (!keyword) {\n checks.push(check('focus-keyword-in-excerpt', 'warn', 'No focus keyword set'));\n } else if (excerpt.includes(keyword)) {\n checks.push(check('focus-keyword-in-excerpt', 'pass', 'Focus keyword appears in meta description'));\n } else {\n checks.push(check('focus-keyword-in-excerpt', 'fail', 'Focus keyword not found in meta description'));\n }\n\n // 4. Focus keyword in H2\n if (keyword) {\n const h2Regex = /<h2[^>]*>(.*?)<\\/h2>/gi;\n const h2s = contentHTML.match(h2Regex) || [];\n const keywordInH2 = h2s.some((h2) => h2.toLowerCase().includes(keyword));\n if (keywordInH2) {\n checks.push(check('focus-keyword-in-h2', 'pass', 'Focus keyword found in a subheading'));\n } else {\n checks.push(check('focus-keyword-in-h2', 'warn', 'Focus keyword not found in any H2 subheading'));\n }\n }\n\n // 5. Focus keyword in first paragraph\n if (keyword && contentText) {\n const first150Words = contentText.split(/\\s+/).slice(0, 150).join(' ');\n if (first150Words.includes(keyword)) {\n checks.push(check('focus-keyword-in-first-paragraph', 'pass', 'Focus keyword appears early in content'));\n } else {\n checks.push(check('focus-keyword-in-first-paragraph', 'warn', 'Focus keyword not found in the first paragraph'));\n }\n }\n\n // 6. Keyword density\n if (keyword && contentText) {\n const words = contentText.split(/\\s+/).length;\n const keywordCount = (contentText.match(new RegExp(keyword, 'g')) || []).length;\n const density = (keywordCount / words) * 100;\n if (density >= 0.5 && density <= 2.5) {\n checks.push(check('focus-keyword-density', 'pass', `Keyword density is ${density.toFixed(1)}% (ideal)`));\n } else if (density < 0.5) {\n checks.push(check('focus-keyword-density', 'warn', `Keyword density is ${density.toFixed(1)}% (too low, aim for 0.5-2.5%)`));\n } else {\n checks.push(check('focus-keyword-density', 'warn', `Keyword density is ${density.toFixed(1)}% (too high, aim for 0.5-2.5%)`));\n }\n }\n\n // 7. Title length\n const metaTitle = post.seo?.metaTitle || post.title;\n if (metaTitle.length >= 50 && metaTitle.length <= 60) {\n checks.push(check('title-length', 'pass', `Title is ${metaTitle.length} characters (ideal)`));\n } else if (metaTitle.length < 30) {\n checks.push(check('title-length', 'fail', `Title is ${metaTitle.length} characters (too short, aim for 50-60)`));\n } else if (metaTitle.length > 70) {\n checks.push(check('title-length', 'warn', `Title is ${metaTitle.length} characters (too long, aim for 50-60)`));\n } else {\n checks.push(check('title-length', 'warn', `Title is ${metaTitle.length} characters (aim for 50-60)`));\n }\n\n // 8. Meta description length\n const metaDesc = post.seo?.metaDescription || post.excerpt || '';\n if (metaDesc.length >= 150 && metaDesc.length <= 160) {\n checks.push(check('meta-description-length', 'pass', `Meta description is ${metaDesc.length} characters (ideal)`));\n } else if (metaDesc.length < 120) {\n checks.push(check('meta-description-length', 'warn', `Meta description is ${metaDesc.length} characters (too short, aim for 150-160)`));\n } else if (metaDesc.length > 170) {\n checks.push(check('meta-description-length', 'warn', `Meta description is ${metaDesc.length} characters (too long, may be truncated)`));\n } else {\n checks.push(check('meta-description-length', 'pass', `Meta description is ${metaDesc.length} characters`));\n }\n\n // 9. Slug length\n if (post.slug.length <= 75) {\n checks.push(check('slug-length', 'pass', `URL slug is ${post.slug.length} characters`));\n } else {\n checks.push(check('slug-length', 'warn', `URL slug is ${post.slug.length} characters (should be under 75)`));\n }\n\n // 10. Content length\n if (post.wordCount >= 300) {\n checks.push(check('content-length', 'pass', `Content is ${post.wordCount} words`));\n } else {\n checks.push(check('content-length', 'fail', `Content is only ${post.wordCount} words (aim for 300+)`));\n }\n\n // 11. Heading hierarchy\n const headingRegex = /<(h[2-6])[^>]*>/gi;\n const headings = [...contentHTML.matchAll(headingRegex)].map((m) => parseInt(m[1][1]));\n let hierarchyOk = true;\n for (let i = 1; i < headings.length; i++) {\n if (headings[i] > headings[i - 1] + 1) {\n hierarchyOk = false;\n break;\n }\n }\n if (headings.length === 0) {\n checks.push(check('heading-hierarchy', 'warn', 'No subheadings found — add H2s to structure content'));\n } else if (hierarchyOk) {\n checks.push(check('heading-hierarchy', 'pass', 'Heading hierarchy is correct'));\n } else {\n checks.push(check('heading-hierarchy', 'warn', 'Heading levels are skipped (e.g., H2 → H4)'));\n }\n\n // 12. Image alt text\n const imgRegex = /<img[^>]*>/gi;\n const images = contentHTML.match(imgRegex) || [];\n const missingAlt = images.filter((img) => !img.includes('alt=') || img.includes('alt=\"\"'));\n if (images.length === 0) {\n checks.push(check('image-alt-text', 'warn', 'No images found in content'));\n } else if (missingAlt.length === 0) {\n checks.push(check('image-alt-text', 'pass', 'All images have alt text'));\n } else {\n checks.push(check('image-alt-text', 'fail', `${missingAlt.length} image(s) missing alt text`));\n }\n\n // 13. Internal links\n const internalLinkRegex = /href=[\"']\\/[^\"']*[\"']/gi;\n const internalLinks = contentHTML.match(internalLinkRegex) || [];\n if (internalLinks.length > 0) {\n checks.push(check('internal-links', 'pass', `${internalLinks.length} internal link(s) found`));\n } else {\n checks.push(check('internal-links', 'warn', 'No internal links found — add links to related content'));\n }\n\n // 14. External links\n const externalLinkRegex = /href=[\"']https?:\\/\\/[^\"']*[\"']/gi;\n const externalLinks = contentHTML.match(externalLinkRegex) || [];\n if (externalLinks.length > 0) {\n checks.push(check('external-links', 'pass', `${externalLinks.length} external link(s) found`));\n } else {\n checks.push(check('external-links', 'warn', 'No external links found'));\n }\n\n // 15. Paragraph length\n const paragraphs = contentHTML.split(/<\\/p>/i).filter((p) => p.trim());\n const longParagraphs = paragraphs.filter((p) => {\n const text = p.replace(/<[^>]+>/g, '');\n return text.split(/\\s+/).length > 300;\n });\n if (longParagraphs.length === 0) {\n checks.push(check('paragraph-length', 'pass', 'All paragraphs are a reasonable length'));\n } else {\n checks.push(check('paragraph-length', 'warn', `${longParagraphs.length} paragraph(s) exceed 300 words`));\n }\n\n // 16. Cover image\n if (post.coverImage?.url) {\n checks.push(check('cover-image', 'pass', 'Post has a cover image'));\n } else {\n checks.push(check('cover-image', 'warn', 'No cover image set — social shares may look plain'));\n }\n\n // 17. Readability (simplified Flesch-like check)\n if (contentText) {\n const sentences = contentText.split(/[.!?]+/).filter((s) => s.trim().length > 0);\n const words = contentText.split(/\\s+/).length;\n const avgWordsPerSentence = sentences.length > 0 ? words / sentences.length : 0;\n if (avgWordsPerSentence <= 20) {\n checks.push(check('readability-score', 'pass', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words`));\n } else if (avgWordsPerSentence <= 25) {\n checks.push(check('readability-score', 'warn', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words (try to keep under 20)`));\n } else {\n checks.push(check('readability-score', 'fail', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words (too long, aim for under 20)`));\n }\n }\n\n // Calculate overall score\n const fails = checks.filter((c) => c.status === 'fail').length;\n const warns = checks.filter((c) => c.status === 'warn').length;\n\n let overall: SEOScore['overall'];\n if (fails >= 3) {\n overall = 'poor';\n } else if (fails >= 1 || warns >= 5) {\n overall = 'ok';\n } else {\n overall = 'good';\n }\n\n return { overall, checks };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/api/middleware.ts"],"names":["NextResponse","getEnvConfig"],"mappings":";;;;;AAIO,SAAS,WAAA,CAAY,IAAA,EAAe,IAAA,EAAgC,MAAA,GAAS,GAAA,EAAK;AACvF,EAAA,OAAOA,mBAAA,CAAa,IAAA,CAAK,EAAE,OAAA,EAAS,IAAA,EAAM,MAAM,IAAA,EAAK,EAAG,EAAE,MAAA,EAAQ,CAAA;AACpE;AAEO,SAAS,SAAA,CAAU,IAAA,EAAc,OAAA,EAAiB,MAAA,GAAS,GAAA,EAAqC;AACrG,EAAA,OAAOA,mBAAA,CAAa,IAAA;AAAA,IAClB,EAAE,OAAA,EAAS,KAAA,EAAO,OAAO,EAAE,IAAA,EAAM,SAAQ,EAAE;AAAA,IAC3C,EAAE,MAAA;AAAO,GACX;AACF;AAEO,SAAS,YAAY,OAAA,EAAyD;AACnF,EAAA,MAAM,MAAMC,8BAAA,EAAa;AACzB,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,GAAA,CAAI,eAAe,CAAA;AAEtD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,OAAO,SAAA,CAAU,cAAA,EAAgB,kCAAA,EAAoC,GAAG,CAAA;AAAA,EAC1E;AAEA,EAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,OAAA,CAAQ,aAAA,EAAe,EAAE,CAAA;AAClD,EAAA,IAAI,KAAA,KAAU,IAAI,mBAAA,EAAqB;AACrC,IAAA,OAAO,SAAA,CAAU,WAAA,EAAa,iBAAA,EAAmB,GAAG,CAAA;AAAA,EACtD;AAEA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,gBAAgB,OAAA,EAAkB;AAChD,EAAA,MAAM,GAAA,GAAM,IAAI,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAC/B,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,GAAA,CAAI,YAAA,CAAa,SAAS,CAAA;AACtD;AAEO,SAAS,aAAA,CAAc,OAA2B,YAAA,EAA8B;AACrF,EAAA,IAAI,CAAC,OAAO,OAAO,YAAA;AACnB,EAAA,MAAM,MAAA,GAAS,QAAA,CAAS,KAAA,EAAO,EAAE,CAAA;AACjC,EAAA,OAAO,KAAA,CAAM,MAAM,CAAA,GAAI,YAAA,GAAe,MAAA;AACxC","file":"chunk-KDZER3PU.cjs","sourcesContent":["import { NextResponse } from 'next/server';\nimport { getEnvConfig } from '../lib/config';\nimport type { ApiErrorResponse } from '../lib/types';\n\nexport function jsonSuccess(data: unknown, meta?: Record<string, unknown>, status = 200) {\n return NextResponse.json({ success: true, data, meta }, { status });\n}\n\nexport function jsonError(code: string, message: string, status = 400): NextResponse<ApiErrorResponse> {\n return NextResponse.json(\n { success: false, error: { code, message } },\n { status }\n ) as NextResponse<ApiErrorResponse>;\n}\n\nexport function requireAuth(request: Request): NextResponse<ApiErrorResponse> | null {\n const env = getEnvConfig();\n const authHeader = request.headers.get('authorization');\n\n if (!authHeader) {\n return jsonError('UNAUTHORIZED', 'Authorization header is required', 401);\n }\n\n const token = authHeader.replace(/^Bearer\\s+/i, '');\n if (token !== env.NEXTBLOGKIT_API_KEY) {\n return jsonError('FORBIDDEN', 'Invalid API key', 403);\n }\n\n return null;\n}\n\nexport function getSearchParams(request: Request) {\n const url = new URL(request.url);\n return Object.fromEntries(url.searchParams.entries());\n}\n\nexport function parseIntParam(value: string | undefined, defaultValue: number): number {\n if (!value) return defaultValue;\n const parsed = parseInt(value, 10);\n return isNaN(parsed) ? defaultValue : parsed;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/types.ts"],"names":["z"],"mappings":"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","file":"chunk-N5MKAD7J.cjs","sourcesContent":["import { z } from 'zod';\nimport type { ObjectId } from 'mongodb';\n\n// ============================================================\n// Block Editor Types\n// ============================================================\n\nexport const BlockTypeSchema = z.enum([\n 'paragraph',\n 'heading',\n 'image',\n 'codeBlock',\n 'blockquote',\n 'bulletList',\n 'orderedList',\n 'taskList',\n 'table',\n 'embed',\n 'horizontalRule',\n 'callout',\n 'tableOfContents',\n 'faq',\n 'html',\n]);\n\nexport type BlockType = z.infer<typeof BlockTypeSchema>;\n\nexport interface BlockContent {\n type: string;\n attrs?: Record<string, unknown>;\n content?: BlockContent[];\n text?: string;\n marks?: { type: string; attrs?: Record<string, unknown> }[];\n}\n\n// ============================================================\n// Media\n// ============================================================\n\nexport interface MediaReference {\n _id: string;\n url: string;\n alt?: string;\n caption?: string;\n width?: number;\n height?: number;\n}\n\nexport const MediaSchema = z.object({\n filename: z.string(),\n originalName: z.string(),\n mimeType: z.string(),\n size: z.number(),\n width: z.number().optional(),\n height: z.number().optional(),\n r2Key: z.string(),\n url: z.string().url(),\n alt: z.string().optional(),\n caption: z.string().optional(),\n createdAt: z.date(),\n});\n\nexport interface Media {\n _id: ObjectId;\n filename: string;\n originalName: string;\n mimeType: string;\n size: number;\n width?: number;\n height?: number;\n r2Key: string;\n url: string;\n alt?: string;\n caption?: string;\n createdAt: Date;\n}\n\n// ============================================================\n// Author\n// ============================================================\n\nexport const AuthorSchema = z.object({\n name: z.string().min(1),\n avatar: z.string().url().optional(),\n bio: z.string().optional(),\n url: z.string().url().optional(),\n});\n\nexport interface Author {\n name: string;\n avatar?: string;\n bio?: string;\n url?: string;\n}\n\n// ============================================================\n// SEO\n// ============================================================\n\nexport const PostSEOSchema = z.object({\n metaTitle: z.string().optional(),\n metaDescription: z.string().optional(),\n canonicalUrl: z.string().url().optional(),\n ogImage: z.string().url().optional(),\n ogType: z.string().default('article'),\n noIndex: z.boolean().default(false),\n structuredData: z.record(z.unknown()).optional(),\n focusKeyword: z.string().optional(),\n});\n\nexport interface PostSEO {\n metaTitle?: string;\n metaDescription?: string;\n canonicalUrl?: string;\n ogImage?: string;\n ogType: string;\n noIndex: boolean;\n structuredData?: Record<string, unknown>;\n focusKeyword?: string;\n}\n\n// ============================================================\n// Revision\n// ============================================================\n\nexport interface Revision {\n version: number;\n title: string;\n content: BlockContent[];\n contentHTML: string;\n savedAt: Date;\n}\n\n// ============================================================\n// Post\n// ============================================================\n\nexport const PostStatusSchema = z.enum(['draft', 'published', 'scheduled', 'archived']);\nexport type PostStatus = z.infer<typeof PostStatusSchema>;\n\nexport const CreatePostSchema = z.object({\n title: z.string().min(1, 'Title is required'),\n slug: z.string().optional(),\n excerpt: z.string().optional(),\n content: z.any(), // BlockContent[] — validated structurally\n contentHTML: z.string().optional(),\n contentText: z.string().optional(),\n coverImage: z\n .object({\n _id: z.string(),\n url: z.string().url(),\n alt: z.string().optional(),\n caption: z.string().optional(),\n width: z.number().optional(),\n height: z.number().optional(),\n })\n .optional(),\n categories: z.array(z.string()).default([]),\n tags: z.array(z.string()).default([]),\n author: AuthorSchema.optional(),\n seo: PostSEOSchema.optional(),\n status: PostStatusSchema.default('draft'),\n publishedAt: z.coerce.date().optional(),\n scheduledAt: z.coerce.date().optional(),\n});\n\nexport const UpdatePostSchema = CreatePostSchema.partial();\n\nexport type CreatePostInput = z.infer<typeof CreatePostSchema>;\nexport type UpdatePostInput = z.infer<typeof UpdatePostSchema>;\n\nexport interface BlogPost {\n _id: ObjectId;\n title: string;\n slug: string;\n excerpt: string;\n content: BlockContent[];\n contentHTML: string;\n contentText: string;\n coverImage?: MediaReference;\n categories: string[];\n tags: string[];\n author: Author;\n seo: PostSEO;\n status: PostStatus;\n publishedAt?: Date;\n scheduledAt?: Date;\n readingTime: number;\n wordCount: number;\n version: number;\n revisions: Revision[];\n createdAt: Date;\n updatedAt: Date;\n}\n\n// ============================================================\n// Category\n// ============================================================\n\nexport const CreateCategorySchema = z.object({\n name: z.string().min(1, 'Category name is required'),\n slug: z.string().optional(),\n description: z.string().optional(),\n seo: z\n .object({\n metaTitle: z.string().optional(),\n metaDescription: z.string().optional(),\n })\n .optional(),\n order: z.number().default(0),\n parentId: z.string().optional(),\n});\n\nexport const UpdateCategorySchema = CreateCategorySchema.partial();\n\nexport type CreateCategoryInput = z.infer<typeof CreateCategorySchema>;\nexport type UpdateCategoryInput = z.infer<typeof UpdateCategorySchema>;\n\nexport interface Category {\n _id: ObjectId;\n name: string;\n slug: string;\n description?: string;\n seo?: {\n metaTitle?: string;\n metaDescription?: string;\n };\n order: number;\n parentId?: ObjectId;\n postCount: number;\n}\n\n// ============================================================\n// Settings\n// ============================================================\n\nexport const BlogSettingsSchema = z.object({\n postsPerPage: z.number().min(1).max(100).default(10),\n defaultAuthor: AuthorSchema.optional(),\n defaultOgImage: z.string().url().optional(),\n commentSystem: z.enum(['none', 'giscus', 'disqus']).default('none'),\n commentConfig: z.record(z.unknown()).optional(),\n customCSS: z.string().optional(),\n analytics: z\n .object({\n gaId: z.string().optional(),\n plausibleDomain: z.string().optional(),\n })\n .optional(),\n});\n\nexport interface BlogSettings {\n _id: string;\n postsPerPage: number;\n defaultAuthor?: Author;\n defaultOgImage?: string;\n commentSystem: 'none' | 'giscus' | 'disqus';\n commentConfig?: Record<string, unknown>;\n customCSS?: string;\n analytics?: {\n gaId?: string;\n plausibleDomain?: string;\n };\n}\n\n// ============================================================\n// API Response Types\n// ============================================================\n\nexport interface ApiSuccessResponse<T = unknown> {\n success: true;\n data: T;\n meta?: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport interface ApiErrorResponse {\n success: false;\n error: {\n code: string;\n message: string;\n };\n}\n\nexport type ApiResponse<T = unknown> = ApiSuccessResponse<T> | ApiErrorResponse;\n\n// ============================================================\n// SEO Score Types\n// ============================================================\n\nexport type SEOCheckStatus = 'pass' | 'warn' | 'fail';\nexport type SEOOverallScore = 'good' | 'ok' | 'poor';\n\nexport interface SEOCheck {\n id: string;\n status: SEOCheckStatus;\n message: string;\n}\n\nexport interface SEOScore {\n overall: SEOOverallScore;\n checks: SEOCheck[];\n}\n\n// ============================================================\n// Config Types\n// ============================================================\n\nexport interface NextBlogKitConfig {\n basePath: string;\n adminPath: string;\n apiPath: string;\n postsPerPage: number;\n excerptLength: number;\n codeHighlighter: 'shiki' | 'prism';\n editor: {\n blocks: BlockType[];\n maxImageSize: number;\n imageFormats: string[];\n autosaveInterval: number;\n };\n seo: {\n titleTemplate: string;\n defaultOgImage?: string;\n generateRSS: boolean;\n generateSitemap: boolean;\n structuredData: boolean;\n minContentLength: number;\n };\n auth: {\n strategy: 'api-key' | 'custom' | 'credentials';\n verify?: (request: Request) => Promise<boolean>;\n admins?: string[];\n };\n features: {\n search: boolean;\n relatedPosts: boolean;\n readingProgress: boolean;\n tableOfContents: boolean;\n shareButtons: boolean;\n darkMode: boolean;\n scheduling: boolean;\n revisionHistory: boolean;\n imageOptimization: boolean;\n };\n theme: {\n variables?: Record<string, string>;\n darkMode?: boolean;\n components?: Record<string, React.ComponentType<unknown>>;\n };\n hooks: {\n beforePublish?: (post: BlogPost) => Promise<void>;\n afterPublish?: (post: BlogPost) => Promise<void>;\n beforeDelete?: (post: BlogPost) => Promise<void>;\n onMediaUpload?: (media: Media) => Promise<void>;\n };\n}\n\n// ============================================================\n// Query Types\n// ============================================================\n\nexport interface PostListQuery {\n page?: number;\n limit?: number;\n category?: string;\n tag?: string;\n status?: PostStatus;\n search?: string;\n sortBy?: 'publishedAt' | 'createdAt' | 'title';\n sortOrder?: 'asc' | 'desc';\n}\n\nexport interface MediaListQuery {\n page?: number;\n limit?: number;\n mimeType?: string;\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/search.ts","../src/lib/seo.ts","../src/lib/seo-scorer.ts"],"names":["getEnvConfig"],"mappings":";;;;;AASA,eAAsB,WAAA,CACpB,UAAA,EACA,KAAA,EACA,KAAA,GAAgB,EAAA,EACS;AACzB,EAAA,IAAI,CAAC,KAAA,CAAM,IAAA,EAAK,SAAU,EAAC;AAE3B,EAAA,MAAM,OAAA,GAAU,MAAM,UAAA,CACnB,IAAA;AAAA,IACC;AAAA,MACE,KAAA,EAAO,EAAE,OAAA,EAAS,KAAA,EAAM;AAAA,MACxB,MAAA,EAAQ;AAAA,KACV;AAAA,IACA;AAAA,MACE,UAAA,EAAY;AAAA,QACV,IAAA,EAAM,CAAA;AAAA,QACN,KAAA,EAAO,CAAA;AAAA,QACP,OAAA,EAAS,CAAA;AAAA,QACT,KAAA,EAAO,EAAE,KAAA,EAAO,WAAA;AAAY;AAC9B;AACF,GACF,CACC,IAAA,CAAK,EAAE,KAAA,EAAO,EAAE,KAAA,EAAO,WAAA,EAAY,EAAG,CAAA,CACtC,KAAA,CAAM,KAAK,EACX,OAAA,EAAQ;AAEX,EAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,CAAC,GAAA,MAAmB;AAAA,IACrC,MAAM,GAAA,CAAI,IAAA;AAAA,IACV,OAAO,GAAA,CAAI,KAAA;AAAA,IACX,SAAS,GAAA,CAAI,OAAA;AAAA,IACb,OAAO,GAAA,CAAI;AAAA,GACb,CAAE,CAAA;AACJ;;;ACXO,SAAS,iBAAiB,IAAA,EAA0B;AACzD,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,UAAU,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAC7D,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,EAAK,SAAA,IAAa,IAAA,CAAK,KAAA;AAC1C,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,GAAA,EAAK,eAAA,IAAmB,IAAA,CAAK,OAAA;AACtD,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,YAAA,IAAgB,OAAA;AAC5C,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,OAAA,IAAW,KAAK,UAAA,EAAY,GAAA;AAEtD,EAAA,OAAO;AAAA,IACL,KAAA,EAAO,CAAA,EAAG,KAAK,CAAA,GAAA,EAAM,IAAI,qBAAqB,CAAA,CAAA;AAAA,IAC9C,WAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA,EAAW;AAAA,MACT,KAAA;AAAA,MACA,WAAA;AAAA,MACA,GAAA,EAAK,OAAA;AAAA,MACL,UAAU,GAAA,CAAI,qBAAA;AAAA,MACd,IAAA,EAAM,IAAA,CAAK,GAAA,EAAK,MAAA,IAAU,SAAA;AAAA,MAC1B,QAAQ,OAAA,GACJ;AAAA,QACE;AAAA,UACE,GAAA,EAAK,OAAA;AAAA,UACL,KAAA,EAAO,IAAA;AAAA,UACP,MAAA,EAAQ,GAAA;AAAA,UACR,GAAA,EAAK;AAAA;AACP,UAEF,EAAC;AAAA,MACL,OAAA,EAAS;AAAA,QACP,aAAA,EAAe,IAAA,CAAK,WAAA,EAAa,WAAA,EAAY,IAAK,EAAA;AAAA,QAClD,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,WAAA,EAAY;AAAA,QACzC,OAAA,EAAS,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA;AAAA,QAC1B,MAAM,IAAA,CAAK;AAAA;AACb,KACF;AAAA,IACA,OAAA,EAAS;AAAA,MACP,IAAA,EAAM,qBAAA;AAAA,MACN,KAAA;AAAA,MACA,WAAA;AAAA,MACA,MAAA,EAAQ,OAAA,GAAU,CAAC,OAAO,IAAI;AAAC,KACjC;AAAA,IACA,MAAA,EAAQ,IAAA,CAAK,GAAA,EAAK,OAAA,GAAU,mBAAA,GAAsB;AAAA,GACpD;AACF;AA2BO,SAAS,uBAAuB,IAAA,EAAuC;AAC5E,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,UAAU,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAE7D,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,aAAA;AAAA,IACT,UAAU,IAAA,CAAK,KAAA;AAAA,IACf,aAAa,IAAA,CAAK,OAAA;AAAA,IAClB,KAAA,EAAO,IAAA,CAAK,UAAA,EAAY,GAAA,IAAO,KAAK,GAAA,EAAK,OAAA;AAAA,IACzC,aAAA,EAAe,IAAA,CAAK,WAAA,EAAa,WAAA,EAAY;AAAA,IAC7C,YAAA,EAAc,IAAA,CAAK,SAAA,CAAU,WAAA,EAAY;AAAA,IACzC,MAAA,EAAQ;AAAA,MACN,OAAA,EAAS,QAAA;AAAA,MACT,IAAA,EAAM,KAAK,MAAA,CAAO,IAAA;AAAA,MAClB,GAAA,EAAK,KAAK,MAAA,CAAO;AAAA,KACnB;AAAA,IACA,SAAA,EAAW;AAAA,MACT,OAAA,EAAS,cAAA;AAAA,MACT,MAAM,GAAA,CAAI;AAAA,KACZ;AAAA,IACA,gBAAA,EAAkB;AAAA,MAChB,OAAA,EAAS,SAAA;AAAA,MACT,KAAA,EAAO;AAAA,KACT;AAAA,IACA,WAAW,IAAA,CAAK,SAAA;AAAA,IAChB,cAAA,EAAgB,IAAA,CAAK,UAAA,CAAW,CAAC;AAAA,GACnC;AACF;AAeO,SAAS,0BACd,QAAA,EAC0B;AAC1B,EAAA,IAAI,CAAC,QAAA,CAAS,MAAA,EAAQ,OAAO,IAAA;AAE7B,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,SAAA;AAAA,IACT,UAAA,EAAY,QAAA,CAAS,GAAA,CAAI,CAAC,IAAA,MAAU;AAAA,MAClC,OAAA,EAAS,UAAA;AAAA,MACT,MAAM,IAAA,CAAK,QAAA;AAAA,MACX,cAAA,EAAgB;AAAA,QACd,OAAA,EAAS,QAAA;AAAA,QACT,MAAM,IAAA,CAAK;AAAA;AACb,KACF,CAAE;AAAA,GACJ;AACF;AAaO,SAAS,mBAAA,CACd,MACA,YAAA,EAC0B;AAC1B,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,KAAA,GAAqD;AAAA,IACzD;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,MAAA;AAAA,MACN,MAAM,GAAA,CAAI;AAAA,KACZ;AAAA,IACA;AAAA,MACE,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,MAAA;AAAA,MACN,IAAA,EAAM,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,KAAA;AAAA;AACnC,GACF;AAEA,EAAA,IAAI,YAAA,IAAgB,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,EAAG;AACtC,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,IAAA,EAAM,YAAA;AAAA,MACN,IAAA,EAAM,GAAG,GAAA,CAAI,oBAAoB,kBAAkB,IAAA,CAAK,UAAA,CAAW,CAAC,CAAC,CAAA;AAAA,KACtE,CAAA;AACD,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AAAA,EACH,CAAA,MAAO;AACL,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,OAAA,EAAS,UAAA;AAAA,MACT,QAAA,EAAU,CAAA;AAAA,MACV,MAAM,IAAA,CAAK;AAAA,KACZ,CAAA;AAAA,EACH;AAEA,EAAA,OAAO;AAAA,IACL,UAAA,EAAY,oBAAA;AAAA,IACZ,OAAA,EAAS,gBAAA;AAAA,IACT,eAAA,EAAiB;AAAA,GACnB;AACF;;;ACxNA,SAAS,KAAA,CAAM,EAAA,EAAY,MAAA,EAAwB,OAAA,EAA2B;AAC5E,EAAA,OAAO,EAAE,EAAA,EAAI,MAAA,EAAQ,OAAA,EAAQ;AAC/B;AAEO,SAAS,kBAAkB,IAAA,EAA0B;AAC1D,EAAA,MAAM,SAAqB,EAAC;AAC5B,EAAA,MAAM,OAAA,GAAU,IAAA,CAAK,GAAA,EAAK,YAAA,EAAc,aAAY,IAAK,EAAA;AACzD,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,KAAA,CAAM,WAAA,EAAY;AACrC,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAY;AACnC,EAAA,MAAM,WAAW,IAAA,CAAK,GAAA,EAAK,mBAAmB,IAAA,CAAK,OAAA,IAAW,IAAI,WAAA,EAAY;AAC9E,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,WAAA,EAAa,WAAA,EAAY,IAAK,EAAA;AACvD,EAAA,MAAM,WAAA,GAAc,KAAK,WAAA,IAAe,EAAA;AAGxC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,wBAAA,EAA0B,MAAA,EAAQ,sBAAsB,CAAC,CAAA;AAAA,EAC7E,CAAA,MAAA,IAAW,KAAA,CAAM,QAAA,CAAS,OAAO,CAAA,EAAG;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,wBAAA,EAA0B,MAAA,EAAQ,gCAAgC,CAAC,CAAA;AAAA,EACvF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,wBAAA,EAA0B,MAAA,EAAQ,kCAAkC,CAAC,CAAA;AAAA,EACzF;AAGA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,sBAAsB,CAAC,CAAA;AAAA,EAC5E,CAAA,MAAA,IAAW,KAAK,QAAA,CAAS,OAAA,CAAQ,QAAQ,MAAA,EAAQ,GAAG,CAAC,CAAA,EAAG;AACtD,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,mCAAmC,CAAC,CAAA;AAAA,EACzF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,qCAAqC,CAAC,CAAA;AAAA,EAC3F;AAGA,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,0BAAA,EAA4B,MAAA,EAAQ,sBAAsB,CAAC,CAAA;AAAA,EAC/E,CAAA,MAAA,IAAW,OAAA,CAAQ,QAAA,CAAS,OAAO,CAAA,EAAG;AACpC,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,0BAAA,EAA4B,MAAA,EAAQ,2CAA2C,CAAC,CAAA;AAAA,EACpG,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,0BAAA,EAA4B,MAAA,EAAQ,6CAA6C,CAAC,CAAA;AAAA,EACtG;AAGA,EAAA,IAAI,OAAA,EAAS;AACX,IAAA,MAAM,OAAA,GAAU,wBAAA;AAChB,IAAA,MAAM,GAAA,GAAM,WAAA,CAAY,KAAA,CAAM,OAAO,KAAK,EAAC;AAC3C,IAAA,MAAM,WAAA,GAAc,GAAA,CAAI,IAAA,CAAK,CAAC,EAAA,KAAO,GAAG,WAAA,EAAY,CAAE,QAAA,CAAS,OAAO,CAAC,CAAA;AACvE,IAAA,IAAI,WAAA,EAAa;AACf,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,qBAAA,EAAuB,MAAA,EAAQ,qCAAqC,CAAC,CAAA;AAAA,IACzF,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,qBAAA,EAAuB,MAAA,EAAQ,8CAA8C,CAAC,CAAA;AAAA,IAClG;AAAA,EACF;AAGA,EAAA,IAAI,WAAW,WAAA,EAAa;AAC1B,IAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,KAAA,CAAM,KAAK,CAAA,CAAE,MAAM,CAAA,EAAG,GAAG,CAAA,CAAE,IAAA,CAAK,GAAG,CAAA;AACrE,IAAA,IAAI,aAAA,CAAc,QAAA,CAAS,OAAO,CAAA,EAAG;AACnC,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,kCAAA,EAAoC,MAAA,EAAQ,wCAAwC,CAAC,CAAA;AAAA,IACzG,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,kCAAA,EAAoC,MAAA,EAAQ,gDAAgD,CAAC,CAAA;AAAA,IACjH;AAAA,EACF;AAGA,EAAA,IAAI,WAAW,WAAA,EAAa;AAC1B,IAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA;AACvC,IAAA,MAAM,YAAA,GAAA,CAAgB,WAAA,CAAY,KAAA,CAAM,IAAI,MAAA,CAAO,SAAS,GAAG,CAAC,CAAA,IAAK,EAAC,EAAG,MAAA;AACzE,IAAA,MAAM,OAAA,GAAW,eAAe,KAAA,GAAS,GAAA;AACzC,IAAA,IAAI,OAAA,IAAW,GAAA,IAAO,OAAA,IAAW,GAAA,EAAK;AACpC,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,CAAA,mBAAA,EAAsB,QAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,SAAA,CAAW,CAAC,CAAA;AAAA,IACzG,CAAA,MAAA,IAAW,UAAU,GAAA,EAAK;AACxB,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,CAAA,mBAAA,EAAsB,QAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,6BAAA,CAA+B,CAAC,CAAA;AAAA,IAC7H,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,uBAAA,EAAyB,MAAA,EAAQ,CAAA,mBAAA,EAAsB,QAAQ,OAAA,CAAQ,CAAC,CAAC,CAAA,8BAAA,CAAgC,CAAC,CAAA;AAAA,IAC9H;AAAA,EACF;AAGA,EAAA,MAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAK,SAAA,IAAa,IAAA,CAAK,KAAA;AAC9C,EAAA,IAAI,SAAA,CAAU,MAAA,IAAU,EAAA,IAAM,SAAA,CAAU,UAAU,EAAA,EAAI;AACpD,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,cAAA,EAAgB,MAAA,EAAQ,YAAY,SAAA,CAAU,MAAM,qBAAqB,CAAC,CAAA;AAAA,EAC9F,CAAA,MAAA,IAAW,SAAA,CAAU,MAAA,GAAS,EAAA,EAAI;AAChC,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,cAAA,EAAgB,MAAA,EAAQ,YAAY,SAAA,CAAU,MAAM,wCAAwC,CAAC,CAAA;AAAA,EACjH,CAAA,MAAA,IAAW,SAAA,CAAU,MAAA,GAAS,EAAA,EAAI;AAChC,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,cAAA,EAAgB,MAAA,EAAQ,YAAY,SAAA,CAAU,MAAM,uCAAuC,CAAC,CAAA;AAAA,EAChH,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,cAAA,EAAgB,MAAA,EAAQ,YAAY,SAAA,CAAU,MAAM,6BAA6B,CAAC,CAAA;AAAA,EACtG;AAGA,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAK,eAAA,IAAmB,KAAK,OAAA,IAAW,EAAA;AAC9D,EAAA,IAAI,QAAA,CAAS,MAAA,IAAU,GAAA,IAAO,QAAA,CAAS,UAAU,GAAA,EAAK;AACpD,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,yBAAA,EAA2B,MAAA,EAAQ,uBAAuB,QAAA,CAAS,MAAM,qBAAqB,CAAC,CAAA;AAAA,EACnH,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,GAAS,GAAA,EAAK;AAChC,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,yBAAA,EAA2B,MAAA,EAAQ,uBAAuB,QAAA,CAAS,MAAM,0CAA0C,CAAC,CAAA;AAAA,EACxI,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,GAAS,GAAA,EAAK;AAChC,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,yBAAA,EAA2B,MAAA,EAAQ,uBAAuB,QAAA,CAAS,MAAM,0CAA0C,CAAC,CAAA;AAAA,EACxI,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,yBAAA,EAA2B,MAAA,EAAQ,uBAAuB,QAAA,CAAS,MAAM,aAAa,CAAC,CAAA;AAAA,EAC3G;AAGA,EAAA,IAAI,IAAA,CAAK,IAAA,CAAK,MAAA,IAAU,EAAA,EAAI;AAC1B,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,aAAA,EAAe,MAAA,EAAQ,eAAe,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,WAAA,CAAa,CAAC,CAAA;AAAA,EACxF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,aAAA,EAAe,MAAA,EAAQ,eAAe,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,gCAAA,CAAkC,CAAC,CAAA;AAAA,EAC7G;AAGA,EAAA,IAAI,IAAA,CAAK,aAAa,GAAA,EAAK;AACzB,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,EAAkB,MAAA,EAAQ,cAAc,IAAA,CAAK,SAAS,QAAQ,CAAC,CAAA;AAAA,EACnF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,EAAkB,MAAA,EAAQ,mBAAmB,IAAA,CAAK,SAAS,uBAAuB,CAAC,CAAA;AAAA,EACvG;AAGA,EAAA,MAAM,YAAA,GAAe,mBAAA;AACrB,EAAA,MAAM,WAAW,CAAC,GAAG,WAAA,CAAY,QAAA,CAAS,YAAY,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,MAAM,QAAA,CAAS,CAAA,CAAE,CAAC,CAAA,CAAE,CAAC,CAAC,CAAC,CAAA;AACrF,EAAA,IAAI,WAAA,GAAc,IAAA;AAClB,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,QAAA,CAAS,QAAQ,CAAA,EAAA,EAAK;AACxC,IAAA,IAAI,SAAS,CAAC,CAAA,GAAI,SAAS,CAAA,GAAI,CAAC,IAAI,CAAA,EAAG;AACrC,MAAA,WAAA,GAAc,KAAA;AACd,MAAA;AAAA,IACF;AAAA,EACF;AACA,EAAA,IAAI,QAAA,CAAS,WAAW,CAAA,EAAG;AACzB,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,0DAAqD,CAAC,CAAA;AAAA,EACvG,WAAW,WAAA,EAAa;AACtB,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,8BAA8B,CAAC,CAAA;AAAA,EAChF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,iDAA4C,CAAC,CAAA;AAAA,EAC9F;AAGA,EAAA,MAAM,QAAA,GAAW,cAAA;AACjB,EAAA,MAAM,MAAA,GAAS,WAAA,CAAY,KAAA,CAAM,QAAQ,KAAK,EAAC;AAC/C,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,MAAA,CAAO,CAAC,GAAA,KAAQ,CAAC,GAAA,CAAI,QAAA,CAAS,MAAM,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAC,CAAA;AACzF,EAAA,IAAI,MAAA,CAAO,WAAW,CAAA,EAAG;AACvB,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,gBAAA,EAAkB,MAAA,EAAQ,4BAA4B,CAAC,CAAA;AAAA,EAC3E,CAAA,MAAA,IAAW,UAAA,CAAW,MAAA,KAAW,CAAA,EAAG;AAClC,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,gBAAA,EAAkB,MAAA,EAAQ,0BAA0B,CAAC,CAAA;AAAA,EACzE,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,EAAkB,MAAA,EAAQ,GAAG,UAAA,CAAW,MAAM,4BAA4B,CAAC,CAAA;AAAA,EAC/F;AAGA,EAAA,MAAM,iBAAA,GAAoB,yBAAA;AAC1B,EAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,KAAA,CAAM,iBAAiB,KAAK,EAAC;AAC/D,EAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,EAAkB,MAAA,EAAQ,GAAG,aAAA,CAAc,MAAM,yBAAyB,CAAC,CAAA;AAAA,EAC/F,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,gBAAA,EAAkB,MAAA,EAAQ,6DAAwD,CAAC,CAAA;AAAA,EACvG;AAGA,EAAA,MAAM,iBAAA,GAAoB,kCAAA;AAC1B,EAAA,MAAM,aAAA,GAAgB,WAAA,CAAY,KAAA,CAAM,iBAAiB,KAAK,EAAC;AAC/D,EAAA,IAAI,aAAA,CAAc,SAAS,CAAA,EAAG;AAC5B,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,gBAAA,EAAkB,MAAA,EAAQ,GAAG,aAAA,CAAc,MAAM,yBAAyB,CAAC,CAAA;AAAA,EAC/F,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,gBAAA,EAAkB,MAAA,EAAQ,yBAAyB,CAAC,CAAA;AAAA,EACxE;AAGA,EAAA,MAAM,UAAA,GAAa,WAAA,CAAY,KAAA,CAAM,QAAQ,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AACrE,EAAA,MAAM,cAAA,GAAiB,UAAA,CAAW,MAAA,CAAO,CAAC,CAAA,KAAM;AAC9C,IAAA,MAAM,IAAA,GAAO,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA;AACrC,IAAA,OAAO,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA,GAAS,GAAA;AAAA,EACpC,CAAC,CAAA;AACD,EAAA,IAAI,cAAA,CAAe,WAAW,CAAA,EAAG;AAC/B,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,kBAAA,EAAoB,MAAA,EAAQ,wCAAwC,CAAC,CAAA;AAAA,EACzF,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,MAAM,kBAAA,EAAoB,MAAA,EAAQ,GAAG,cAAA,CAAe,MAAM,gCAAgC,CAAC,CAAA;AAAA,EACzG;AAGA,EAAA,IAAI,IAAA,CAAK,YAAY,GAAA,EAAK;AACxB,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,aAAA,EAAe,MAAA,EAAQ,wBAAwB,CAAC,CAAA;AAAA,EACpE,CAAA,MAAO;AACL,IAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,aAAA,EAAe,MAAA,EAAQ,wDAAmD,CAAC,CAAA;AAAA,EAC/F;AAGA,EAAA,IAAI,WAAA,EAAa;AACf,IAAA,MAAM,SAAA,GAAY,WAAA,CAAY,KAAA,CAAM,QAAQ,CAAA,CAAE,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAK,CAAE,MAAA,GAAS,CAAC,CAAA;AAC/E,IAAA,MAAM,KAAA,GAAQ,WAAA,CAAY,KAAA,CAAM,KAAK,CAAA,CAAE,MAAA;AACvC,IAAA,MAAM,sBAAsB,SAAA,CAAU,MAAA,GAAS,CAAA,GAAI,KAAA,GAAQ,UAAU,MAAA,GAAS,CAAA;AAC9E,IAAA,IAAI,uBAAuB,EAAA,EAAI;AAC7B,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,CAAA,yBAAA,EAA4B,oBAAoB,OAAA,CAAQ,CAAC,CAAC,CAAA,MAAA,CAAQ,CAAC,CAAA;AAAA,IACpH,CAAA,MAAA,IAAW,uBAAuB,EAAA,EAAI;AACpC,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,CAAA,yBAAA,EAA4B,oBAAoB,OAAA,CAAQ,CAAC,CAAC,CAAA,6BAAA,CAA+B,CAAC,CAAA;AAAA,IAC3I,CAAA,MAAO;AACL,MAAA,MAAA,CAAO,IAAA,CAAK,KAAA,CAAM,mBAAA,EAAqB,MAAA,EAAQ,CAAA,yBAAA,EAA4B,oBAAoB,OAAA,CAAQ,CAAC,CAAC,CAAA,mCAAA,CAAqC,CAAC,CAAA;AAAA,IACjJ;AAAA,EACF;AAGA,EAAA,MAAM,KAAA,GAAQ,OAAO,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,MAAM,CAAA,CAAE,MAAA;AACxD,EAAA,MAAM,KAAA,GAAQ,OAAO,MAAA,CAAO,CAAC,MAAM,CAAA,CAAE,MAAA,KAAW,MAAM,CAAA,CAAE,MAAA;AAExD,EAAA,IAAI,OAAA;AACJ,EAAA,IAAI,SAAS,CAAA,EAAG;AACd,IAAA,OAAA,GAAU,MAAA;AAAA,EACZ,CAAA,MAAA,IAAW,KAAA,IAAS,CAAA,IAAK,KAAA,IAAS,CAAA,EAAG;AACnC,IAAA,OAAA,GAAU,IAAA;AAAA,EACZ,CAAA,MAAO;AACL,IAAA,OAAA,GAAU,MAAA;AAAA,EACZ;AAEA,EAAA,OAAO,EAAE,SAAS,MAAA,EAAO;AAC3B","file":"chunk-QE4VLQYN.cjs","sourcesContent":["import type { Collection, Document } from 'mongodb';\n\nexport interface SearchResult {\n slug: string;\n title: string;\n excerpt: string;\n score: number;\n}\n\nexport async function searchPosts(\n collection: Collection,\n query: string,\n limit: number = 10\n): Promise<SearchResult[]> {\n if (!query.trim()) return [];\n\n const results = await collection\n .find(\n {\n $text: { $search: query },\n status: 'published',\n },\n {\n projection: {\n slug: 1,\n title: 1,\n excerpt: 1,\n score: { $meta: 'textScore' },\n },\n }\n )\n .sort({ score: { $meta: 'textScore' } })\n .limit(limit)\n .toArray();\n\n return results.map((doc: Document) => ({\n slug: doc.slug as string,\n title: doc.title as string,\n excerpt: doc.excerpt as string,\n score: doc.score as number,\n }));\n}\n","import type { BlogPost } from './types';\nimport { getEnvConfig } from './config';\n\nexport interface MetaTags {\n title: string;\n description: string;\n canonical: string;\n openGraph: {\n title: string;\n description: string;\n url: string;\n siteName: string;\n type: string;\n images: { url: string; width?: number; height?: number; alt?: string }[];\n article?: {\n publishedTime: string;\n modifiedTime: string;\n section?: string;\n tags?: string[];\n };\n };\n twitter: {\n card: string;\n title: string;\n description: string;\n images: string[];\n };\n robots?: string;\n}\n\nexport function generateMetaTags(post: BlogPost): MetaTags {\n const env = getEnvConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n const title = post.seo?.metaTitle || post.title;\n const description = post.seo?.metaDescription || post.excerpt;\n const canonical = post.seo?.canonicalUrl || postUrl;\n const ogImage = post.seo?.ogImage || post.coverImage?.url;\n\n return {\n title: `${title} | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description,\n canonical,\n openGraph: {\n title,\n description,\n url: postUrl,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n type: post.seo?.ogType || 'article',\n images: ogImage\n ? [\n {\n url: ogImage,\n width: 1200,\n height: 630,\n alt: title,\n },\n ]\n : [],\n article: {\n publishedTime: post.publishedAt?.toISOString() || '',\n modifiedTime: post.updatedAt.toISOString(),\n section: post.categories[0],\n tags: post.tags,\n },\n },\n twitter: {\n card: 'summary_large_image',\n title,\n description,\n images: ogImage ? [ogImage] : [],\n },\n robots: post.seo?.noIndex ? 'noindex, nofollow' : undefined,\n };\n}\n\nexport interface ArticleStructuredData {\n '@context': string;\n '@type': string;\n headline: string;\n description: string;\n image?: string;\n datePublished?: string;\n dateModified: string;\n author: {\n '@type': string;\n name: string;\n url?: string;\n };\n publisher: {\n '@type': string;\n name: string;\n };\n mainEntityOfPage: {\n '@type': string;\n '@id': string;\n };\n wordCount: number;\n articleSection?: string;\n}\n\nexport function generateStructuredData(post: BlogPost): ArticleStructuredData {\n const env = getEnvConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BlogPosting',\n headline: post.title,\n description: post.excerpt,\n image: post.coverImage?.url || post.seo?.ogImage,\n datePublished: post.publishedAt?.toISOString(),\n dateModified: post.updatedAt.toISOString(),\n author: {\n '@type': 'Person',\n name: post.author.name,\n url: post.author.url,\n },\n publisher: {\n '@type': 'Organization',\n name: env.NEXTBLOGKIT_SITE_NAME,\n },\n mainEntityOfPage: {\n '@type': 'WebPage',\n '@id': postUrl,\n },\n wordCount: post.wordCount,\n articleSection: post.categories[0],\n };\n}\n\nexport interface FAQStructuredData {\n '@context': string;\n '@type': string;\n mainEntity: {\n '@type': string;\n name: string;\n acceptedAnswer: {\n '@type': string;\n text: string;\n };\n }[];\n}\n\nexport function generateFAQStructuredData(\n faqItems: { question: string; answer: string }[]\n): FAQStructuredData | null {\n if (!faqItems.length) return null;\n\n return {\n '@context': 'https://schema.org',\n '@type': 'FAQPage',\n mainEntity: faqItems.map((item) => ({\n '@type': 'Question',\n name: item.question,\n acceptedAnswer: {\n '@type': 'Answer',\n text: item.answer,\n },\n })),\n };\n}\n\nexport interface BreadcrumbStructuredData {\n '@context': string;\n '@type': string;\n itemListElement: {\n '@type': string;\n position: number;\n name: string;\n item?: string;\n }[];\n}\n\nexport function generateBreadcrumbs(\n post: BlogPost,\n categoryName?: string\n): BreadcrumbStructuredData {\n const env = getEnvConfig();\n const items: BreadcrumbStructuredData['itemListElement'] = [\n {\n '@type': 'ListItem',\n position: 1,\n name: 'Home',\n item: env.NEXTBLOGKIT_SITE_URL,\n },\n {\n '@type': 'ListItem',\n position: 2,\n name: 'Blog',\n item: `${env.NEXTBLOGKIT_SITE_URL}/blog`,\n },\n ];\n\n if (categoryName && post.categories[0]) {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: categoryName,\n item: `${env.NEXTBLOGKIT_SITE_URL}/blog/category/${post.categories[0]}`,\n });\n items.push({\n '@type': 'ListItem',\n position: 4,\n name: post.title,\n });\n } else {\n items.push({\n '@type': 'ListItem',\n position: 3,\n name: post.title,\n });\n }\n\n return {\n '@context': 'https://schema.org',\n '@type': 'BreadcrumbList',\n itemListElement: items,\n };\n}\n","import type { BlogPost, SEOScore, SEOCheck, SEOCheckStatus } from './types';\n\nfunction check(id: string, status: SEOCheckStatus, message: string): SEOCheck {\n return { id, status, message };\n}\n\nexport function calculateSEOScore(post: BlogPost): SEOScore {\n const checks: SEOCheck[] = [];\n const keyword = post.seo?.focusKeyword?.toLowerCase() || '';\n const title = post.title.toLowerCase();\n const slug = post.slug.toLowerCase();\n const excerpt = (post.seo?.metaDescription || post.excerpt || '').toLowerCase();\n const contentText = post.contentText?.toLowerCase() || '';\n const contentHTML = post.contentHTML || '';\n\n // 1. Focus keyword in title\n if (!keyword) {\n checks.push(check('focus-keyword-in-title', 'warn', 'No focus keyword set'));\n } else if (title.includes(keyword)) {\n checks.push(check('focus-keyword-in-title', 'pass', 'Focus keyword appears in title'));\n } else {\n checks.push(check('focus-keyword-in-title', 'fail', 'Focus keyword not found in title'));\n }\n\n // 2. Focus keyword in slug\n if (!keyword) {\n checks.push(check('focus-keyword-in-slug', 'warn', 'No focus keyword set'));\n } else if (slug.includes(keyword.replace(/\\s+/g, '-'))) {\n checks.push(check('focus-keyword-in-slug', 'pass', 'Focus keyword appears in URL slug'));\n } else {\n checks.push(check('focus-keyword-in-slug', 'fail', 'Focus keyword not found in URL slug'));\n }\n\n // 3. Focus keyword in meta description\n if (!keyword) {\n checks.push(check('focus-keyword-in-excerpt', 'warn', 'No focus keyword set'));\n } else if (excerpt.includes(keyword)) {\n checks.push(check('focus-keyword-in-excerpt', 'pass', 'Focus keyword appears in meta description'));\n } else {\n checks.push(check('focus-keyword-in-excerpt', 'fail', 'Focus keyword not found in meta description'));\n }\n\n // 4. Focus keyword in H2\n if (keyword) {\n const h2Regex = /<h2[^>]*>(.*?)<\\/h2>/gi;\n const h2s = contentHTML.match(h2Regex) || [];\n const keywordInH2 = h2s.some((h2) => h2.toLowerCase().includes(keyword));\n if (keywordInH2) {\n checks.push(check('focus-keyword-in-h2', 'pass', 'Focus keyword found in a subheading'));\n } else {\n checks.push(check('focus-keyword-in-h2', 'warn', 'Focus keyword not found in any H2 subheading'));\n }\n }\n\n // 5. Focus keyword in first paragraph\n if (keyword && contentText) {\n const first150Words = contentText.split(/\\s+/).slice(0, 150).join(' ');\n if (first150Words.includes(keyword)) {\n checks.push(check('focus-keyword-in-first-paragraph', 'pass', 'Focus keyword appears early in content'));\n } else {\n checks.push(check('focus-keyword-in-first-paragraph', 'warn', 'Focus keyword not found in the first paragraph'));\n }\n }\n\n // 6. Keyword density\n if (keyword && contentText) {\n const words = contentText.split(/\\s+/).length;\n const keywordCount = (contentText.match(new RegExp(keyword, 'g')) || []).length;\n const density = (keywordCount / words) * 100;\n if (density >= 0.5 && density <= 2.5) {\n checks.push(check('focus-keyword-density', 'pass', `Keyword density is ${density.toFixed(1)}% (ideal)`));\n } else if (density < 0.5) {\n checks.push(check('focus-keyword-density', 'warn', `Keyword density is ${density.toFixed(1)}% (too low, aim for 0.5-2.5%)`));\n } else {\n checks.push(check('focus-keyword-density', 'warn', `Keyword density is ${density.toFixed(1)}% (too high, aim for 0.5-2.5%)`));\n }\n }\n\n // 7. Title length\n const metaTitle = post.seo?.metaTitle || post.title;\n if (metaTitle.length >= 50 && metaTitle.length <= 60) {\n checks.push(check('title-length', 'pass', `Title is ${metaTitle.length} characters (ideal)`));\n } else if (metaTitle.length < 30) {\n checks.push(check('title-length', 'fail', `Title is ${metaTitle.length} characters (too short, aim for 50-60)`));\n } else if (metaTitle.length > 70) {\n checks.push(check('title-length', 'warn', `Title is ${metaTitle.length} characters (too long, aim for 50-60)`));\n } else {\n checks.push(check('title-length', 'warn', `Title is ${metaTitle.length} characters (aim for 50-60)`));\n }\n\n // 8. Meta description length\n const metaDesc = post.seo?.metaDescription || post.excerpt || '';\n if (metaDesc.length >= 150 && metaDesc.length <= 160) {\n checks.push(check('meta-description-length', 'pass', `Meta description is ${metaDesc.length} characters (ideal)`));\n } else if (metaDesc.length < 120) {\n checks.push(check('meta-description-length', 'warn', `Meta description is ${metaDesc.length} characters (too short, aim for 150-160)`));\n } else if (metaDesc.length > 170) {\n checks.push(check('meta-description-length', 'warn', `Meta description is ${metaDesc.length} characters (too long, may be truncated)`));\n } else {\n checks.push(check('meta-description-length', 'pass', `Meta description is ${metaDesc.length} characters`));\n }\n\n // 9. Slug length\n if (post.slug.length <= 75) {\n checks.push(check('slug-length', 'pass', `URL slug is ${post.slug.length} characters`));\n } else {\n checks.push(check('slug-length', 'warn', `URL slug is ${post.slug.length} characters (should be under 75)`));\n }\n\n // 10. Content length\n if (post.wordCount >= 300) {\n checks.push(check('content-length', 'pass', `Content is ${post.wordCount} words`));\n } else {\n checks.push(check('content-length', 'fail', `Content is only ${post.wordCount} words (aim for 300+)`));\n }\n\n // 11. Heading hierarchy\n const headingRegex = /<(h[2-6])[^>]*>/gi;\n const headings = [...contentHTML.matchAll(headingRegex)].map((m) => parseInt(m[1][1]));\n let hierarchyOk = true;\n for (let i = 1; i < headings.length; i++) {\n if (headings[i] > headings[i - 1] + 1) {\n hierarchyOk = false;\n break;\n }\n }\n if (headings.length === 0) {\n checks.push(check('heading-hierarchy', 'warn', 'No subheadings found — add H2s to structure content'));\n } else if (hierarchyOk) {\n checks.push(check('heading-hierarchy', 'pass', 'Heading hierarchy is correct'));\n } else {\n checks.push(check('heading-hierarchy', 'warn', 'Heading levels are skipped (e.g., H2 → H4)'));\n }\n\n // 12. Image alt text\n const imgRegex = /<img[^>]*>/gi;\n const images = contentHTML.match(imgRegex) || [];\n const missingAlt = images.filter((img) => !img.includes('alt=') || img.includes('alt=\"\"'));\n if (images.length === 0) {\n checks.push(check('image-alt-text', 'warn', 'No images found in content'));\n } else if (missingAlt.length === 0) {\n checks.push(check('image-alt-text', 'pass', 'All images have alt text'));\n } else {\n checks.push(check('image-alt-text', 'fail', `${missingAlt.length} image(s) missing alt text`));\n }\n\n // 13. Internal links\n const internalLinkRegex = /href=[\"']\\/[^\"']*[\"']/gi;\n const internalLinks = contentHTML.match(internalLinkRegex) || [];\n if (internalLinks.length > 0) {\n checks.push(check('internal-links', 'pass', `${internalLinks.length} internal link(s) found`));\n } else {\n checks.push(check('internal-links', 'warn', 'No internal links found — add links to related content'));\n }\n\n // 14. External links\n const externalLinkRegex = /href=[\"']https?:\\/\\/[^\"']*[\"']/gi;\n const externalLinks = contentHTML.match(externalLinkRegex) || [];\n if (externalLinks.length > 0) {\n checks.push(check('external-links', 'pass', `${externalLinks.length} external link(s) found`));\n } else {\n checks.push(check('external-links', 'warn', 'No external links found'));\n }\n\n // 15. Paragraph length\n const paragraphs = contentHTML.split(/<\\/p>/i).filter((p) => p.trim());\n const longParagraphs = paragraphs.filter((p) => {\n const text = p.replace(/<[^>]+>/g, '');\n return text.split(/\\s+/).length > 300;\n });\n if (longParagraphs.length === 0) {\n checks.push(check('paragraph-length', 'pass', 'All paragraphs are a reasonable length'));\n } else {\n checks.push(check('paragraph-length', 'warn', `${longParagraphs.length} paragraph(s) exceed 300 words`));\n }\n\n // 16. Cover image\n if (post.coverImage?.url) {\n checks.push(check('cover-image', 'pass', 'Post has a cover image'));\n } else {\n checks.push(check('cover-image', 'warn', 'No cover image set — social shares may look plain'));\n }\n\n // 17. Readability (simplified Flesch-like check)\n if (contentText) {\n const sentences = contentText.split(/[.!?]+/).filter((s) => s.trim().length > 0);\n const words = contentText.split(/\\s+/).length;\n const avgWordsPerSentence = sentences.length > 0 ? words / sentences.length : 0;\n if (avgWordsPerSentence <= 20) {\n checks.push(check('readability-score', 'pass', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words`));\n } else if (avgWordsPerSentence <= 25) {\n checks.push(check('readability-score', 'warn', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words (try to keep under 20)`));\n } else {\n checks.push(check('readability-score', 'fail', `Average sentence length: ${avgWordsPerSentence.toFixed(0)} words (too long, aim for under 20)`));\n }\n }\n\n // Calculate overall score\n const fails = checks.filter((c) => c.status === 'fail').length;\n const warns = checks.filter((c) => c.status === 'warn').length;\n\n let overall: SEOScore['overall'];\n if (fails >= 3) {\n overall = 'poor';\n } else if (fails >= 1 || warns >= 5) {\n overall = 'ok';\n } else {\n overall = 'good';\n }\n\n return { overall, checks };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/rss.ts"],"names":[],"mappings":";;;AAGA,eAAsB,eAAA,CAAgB,cAAc,KAAA,EAAwB;AAC1E,EAAA,MAAM,MAAM,YAAA,EAAa;AACzB,EAAA,MAAM,KAAA,GAAQ,MAAM,aAAA,CAAc,WAAW,CAAA;AAE7C,EAAA,MAAM,iBAAiB,MAAM,KAAA,CAC1B,KAAK,EAAE,MAAA,EAAQ,aAAa,CAAA,CAC5B,IAAA,CAAK,EAAE,aAAa,EAAA,EAAI,EACxB,KAAA,CAAM,EAAE,EACR,OAAA,EAAQ;AAEX,EAAA,MAAM,KAAA,GAAQ,cAAA,CACX,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,IAAA,MAAM,UAAU,CAAA,EAAG,GAAA,CAAI,oBAAoB,CAAA,MAAA,EAAS,KAAK,IAAI,CAAA,CAAA;AAC7D,IAAA,MAAM,OAAA,GAAU,WAAA,GAAc,IAAA,CAAK,WAAA,GAAc,IAAA,CAAK,OAAA;AACtD,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,WAAA,GACjB,IAAI,KAAK,IAAA,CAAK,WAAW,CAAA,CAAE,WAAA,KAC3B,IAAI,IAAA,CAAK,IAAA,CAAK,SAAS,EAAE,WAAA,EAAY;AAEzC,IAAA,IAAI,SAAA,GAAY,EAAA;AAChB,IAAA,IAAI,IAAA,CAAK,YAAY,GAAA,EAAK;AACxB,MAAA,SAAA,GAAY;AAAA,sBAAA,EAA2B,SAAA,CAAU,IAAA,CAAK,UAAA,CAAW,GAAG,CAAC,CAAA,sBAAA,CAAA;AAAA,IACvE;AAEA,IAAA,OAAO,CAAA;AAAA,aAAA,EACE,SAAA,CAAU,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,YAAA,EACtB,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,+BAAA,EACC,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,4BAAA,EACrB,WAAW,EAAE,CAAA;AAAA,eAAA,EAC1B,OAAO,CAAA,UAAA,EAAa,SAAS,CAAA,EACtC,IAAA,CAAK,UAAA,EAAY,MAAA,GACb,IAAA,CAAK,UAAA,CAAW,GAAA,CAAI,CAAC,CAAA,KAAc;AAAA,gBAAA,EAAqB,SAAA,CAAU,CAAC,CAAC,CAAA,WAAA,CAAa,EAAE,IAAA,CAAK,EAAE,IAC1F,EACN;AAAA,WAAA,CAAA;AAAA,EAEF,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAEZ,EAAA,MAAM,SAAA,GAAA,iBAAY,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY;AAEzC,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA,WAAA,EAGI,SAAA,CAAU,GAAA,CAAI,qBAAqB,CAAC,CAAA;AAAA,UAAA,EACrC,SAAA,CAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA;AAAA,mCAAA,EACV,SAAA,CAAU,GAAA,CAAI,qBAAqB,CAAC,CAAA;AAAA;AAAA,mBAAA,EAEpD,SAAS,CAAA;AAAA,qBAAA,EACP,SAAA,CAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA;AAAA,EACxD,KAAK;AAAA;AAAA,MAAA,CAAA;AAGP;AAEA,SAAS,UAAU,GAAA,EAAqB;AACtC,EAAA,OAAO,IACJ,OAAA,CAAQ,IAAA,EAAM,OAAO,CAAA,CACrB,OAAA,CAAQ,MAAM,MAAM,CAAA,CACpB,QAAQ,IAAA,EAAM,MAAM,EACpB,OAAA,CAAQ,IAAA,EAAM,QAAQ,CAAA,CACtB,OAAA,CAAQ,MAAM,QAAQ,CAAA;AAC3B","file":"chunk-R6MO3QIP.js","sourcesContent":["import { getCollection } from './db';\nimport { getEnvConfig } from './config';\n\nexport async function generateRSSFeed(fullContent = false): Promise<string> {\n const env = getEnvConfig();\n const posts = await getCollection('nbk_posts');\n\n const publishedPosts = await posts\n .find({ status: 'published' })\n .sort({ publishedAt: -1 })\n .limit(50)\n .toArray();\n\n const items = publishedPosts\n .map((post) => {\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;\n const content = fullContent ? post.contentHTML : post.excerpt;\n const pubDate = post.publishedAt\n ? new Date(post.publishedAt).toUTCString()\n : new Date(post.createdAt).toUTCString();\n\n let enclosure = '';\n if (post.coverImage?.url) {\n enclosure = `\\n <enclosure url=\"${escapeXml(post.coverImage.url)}\" type=\"image/jpeg\" />`;\n }\n\n return ` <item>\n <title>${escapeXml(post.title)}</title>\n <link>${escapeXml(postUrl)}</link>\n <guid isPermaLink=\"true\">${escapeXml(postUrl)}</guid>\n <description><![CDATA[${content || ''}]]></description>\n <pubDate>${pubDate}</pubDate>${enclosure}${\n post.categories?.length\n ? post.categories.map((c: string) => `\\n <category>${escapeXml(c)}</category>`).join('')\n : ''\n }\n </item>`;\n })\n .join('\\n');\n\n const buildDate = new Date().toUTCString();\n\n return `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">\n <channel>\n <title>${escapeXml(env.NEXTBLOGKIT_SITE_NAME)} Blog</title>\n <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/blog</link>\n <description>Latest posts from ${escapeXml(env.NEXTBLOGKIT_SITE_NAME)}</description>\n <language>en</language>\n <lastBuildDate>${buildDate}</lastBuildDate>\n <atom:link href=\"${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/api/blog/rss.xml\" rel=\"self\" type=\"application/rss+xml\" />\n${items}\n </channel>\n</rss>`;\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&apos;');\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/config.ts","../src/lib/slug.ts","../src/lib/reading-time.ts","../src/lib/db.ts"],"names":["z","MongoClient","ObjectId"],"mappings":"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","file":"chunk-U2ROR6AY.cjs","sourcesContent":["import { z } from 'zod';\nimport type { NextBlogKitConfig } from './types';\n\nconst envSchema = z.object({\n NEXTBLOGKIT_MONGODB_URI: z.string().min(1, 'MongoDB URI is required'),\n NEXTBLOGKIT_R2_ACCOUNT_ID: z.string().min(1, 'R2 Account ID is required'),\n NEXTBLOGKIT_R2_ACCESS_KEY: z.string().min(1, 'R2 Access Key is required'),\n NEXTBLOGKIT_R2_SECRET_KEY: z.string().min(1, 'R2 Secret Key is required'),\n NEXTBLOGKIT_R2_BUCKET: z.string().min(1, 'R2 Bucket name is required'),\n NEXTBLOGKIT_R2_PUBLIC_URL: z.string().url('R2 Public URL must be a valid URL'),\n NEXTBLOGKIT_API_KEY: z.string().min(32, 'API key must be at least 32 characters'),\n NEXTBLOGKIT_SITE_URL: z.string().url('Site URL must be a valid URL'),\n NEXTBLOGKIT_SITE_NAME: z.string().min(1, 'Site name is required'),\n});\n\nexport type EnvConfig = z.infer<typeof envSchema>;\n\nlet cachedEnv: EnvConfig | null = null;\n\nexport function getEnvConfig(): EnvConfig {\n if (cachedEnv) return cachedEnv;\n\n const result = envSchema.safeParse(process.env);\n if (!result.success) {\n const missing = result.error.issues.map((i) => ` - ${i.path.join('.')}: ${i.message}`);\n throw new Error(`NextBlogKit configuration error:\\n${missing.join('\\n')}`);\n }\n\n cachedEnv = result.data;\n return cachedEnv;\n}\n\nconst defaultConfig: NextBlogKitConfig = {\n basePath: '/blog',\n adminPath: '/admin/blog',\n apiPath: '/api/blog',\n postsPerPage: 10,\n excerptLength: 160,\n codeHighlighter: 'shiki',\n editor: {\n blocks: [\n 'paragraph',\n 'heading',\n 'image',\n 'codeBlock',\n 'blockquote',\n 'bulletList',\n 'orderedList',\n 'taskList',\n 'table',\n 'embed',\n 'horizontalRule',\n 'callout',\n 'tableOfContents',\n 'faq',\n 'html',\n ],\n maxImageSize: 10 * 1024 * 1024,\n imageFormats: ['jpg', 'jpeg', 'png', 'gif', 'webp', 'svg'],\n autosaveInterval: 30000,\n },\n seo: {\n titleTemplate: '%s | %siteName%',\n generateRSS: true,\n generateSitemap: true,\n structuredData: true,\n minContentLength: 300,\n },\n auth: {\n strategy: 'api-key',\n },\n features: {\n search: true,\n relatedPosts: true,\n readingProgress: true,\n tableOfContents: true,\n shareButtons: true,\n darkMode: true,\n scheduling: true,\n revisionHistory: true,\n imageOptimization: true,\n },\n theme: {\n darkMode: true,\n variables: {\n '--nbk-primary': '#2563eb',\n '--nbk-primary-hover': '#1d4ed8',\n '--nbk-text': '#1f2937',\n '--nbk-text-muted': '#6b7280',\n '--nbk-bg': '#ffffff',\n '--nbk-bg-secondary': '#f9fafb',\n '--nbk-card-bg': '#ffffff',\n '--nbk-border': '#e5e7eb',\n '--nbk-radius': '0.5rem',\n '--nbk-font-heading': '\"Inter\", system-ui, sans-serif',\n '--nbk-font-body': '\"Inter\", system-ui, sans-serif',\n '--nbk-font-code': '\"JetBrains Mono\", \"Fira Code\", monospace',\n },\n },\n hooks: {},\n};\n\nlet cachedConfig: NextBlogKitConfig | null = null;\n\nexport function defineConfig(config: Partial<NextBlogKitConfig>): Partial<NextBlogKitConfig> {\n return config;\n}\n\nexport function getConfig(userConfig?: Partial<NextBlogKitConfig>): NextBlogKitConfig {\n if (cachedConfig && !userConfig) return cachedConfig;\n\n const merged: NextBlogKitConfig = {\n ...defaultConfig,\n ...userConfig,\n editor: { ...defaultConfig.editor, ...userConfig?.editor },\n seo: { ...defaultConfig.seo, ...userConfig?.seo },\n auth: { ...defaultConfig.auth, ...userConfig?.auth },\n features: { ...defaultConfig.features, ...userConfig?.features },\n theme: {\n ...defaultConfig.theme,\n ...userConfig?.theme,\n variables: { ...defaultConfig.theme.variables, ...userConfig?.theme?.variables },\n },\n hooks: { ...defaultConfig.hooks, ...userConfig?.hooks },\n };\n\n if (!userConfig) {\n cachedConfig = merged;\n }\n\n return merged;\n}\n\nexport function getBlogConfig() {\n const env = getEnvConfig();\n const config = getConfig();\n\n return {\n ...config,\n siteUrl: env.NEXTBLOGKIT_SITE_URL,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n metadata: {\n title: `Blog | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description: `Latest posts from ${env.NEXTBLOGKIT_SITE_NAME}`,\n openGraph: {\n title: `Blog | ${env.NEXTBLOGKIT_SITE_NAME}`,\n description: `Latest posts from ${env.NEXTBLOGKIT_SITE_NAME}`,\n url: `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}`,\n siteName: env.NEXTBLOGKIT_SITE_NAME,\n type: 'website',\n },\n },\n };\n}\n","import type { Collection } from 'mongodb';\n\nexport function generateSlug(text: string): string {\n return text\n .toLowerCase()\n .trim()\n .replace(/[^\\w\\s-]/g, '')\n .replace(/[\\s_]+/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-+|-+$/g, '');\n}\n\nexport async function ensureUniqueSlug(\n slug: string,\n collection: Collection,\n excludeId?: string\n): Promise<string> {\n let candidate = slug;\n let counter = 1;\n\n while (true) {\n const query: Record<string, unknown> = { slug: candidate };\n if (excludeId) {\n query._id = { $ne: excludeId };\n }\n\n const existing = await collection.findOne(query);\n if (!existing) return candidate;\n\n candidate = `${slug}-${counter}`;\n counter++;\n }\n}\n","const WORDS_PER_MINUTE = 200;\n\nexport function calculateReadingTime(text: string): number {\n const words = countWords(text);\n return Math.max(1, Math.ceil(words / WORDS_PER_MINUTE));\n}\n\nexport function countWords(text: string): number {\n if (!text || !text.trim()) return 0;\n return text.trim().split(/\\s+/).length;\n}\n\nexport function extractTextFromHTML(html: string): string {\n return html\n .replace(/<script[^>]*>[\\s\\S]*?<\\/script>/gi, '')\n .replace(/<style[^>]*>[\\s\\S]*?<\\/style>/gi, '')\n .replace(/<[^>]+>/g, ' ')\n .replace(/&nbsp;/g, ' ')\n .replace(/&amp;/g, '&')\n .replace(/&lt;/g, '<')\n .replace(/&gt;/g, '>')\n .replace(/&quot;/g, '\"')\n .replace(/&#39;/g, \"'\")\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\nexport function extractTextFromBlocks(blocks: unknown[]): string {\n if (!Array.isArray(blocks)) return '';\n\n const parts: string[] = [];\n\n function walk(node: unknown) {\n if (!node || typeof node !== 'object') return;\n const n = node as Record<string, unknown>;\n\n if (typeof n.text === 'string') {\n parts.push(n.text);\n }\n\n if (Array.isArray(n.content)) {\n for (const child of n.content) {\n walk(child);\n }\n }\n }\n\n for (const block of blocks) {\n walk(block);\n }\n\n return parts.join(' ');\n}\n","import { MongoClient, type Db, type Collection, type Document, ObjectId } from 'mongodb';\nimport { getEnvConfig } from './config';\nimport type {\n BlogPost,\n Category,\n Media,\n BlogSettings,\n CreatePostInput,\n UpdatePostInput,\n CreateCategoryInput,\n UpdateCategoryInput,\n PostListQuery,\n MediaListQuery,\n} from './types';\nimport { generateSlug, ensureUniqueSlug } from './slug';\nimport { calculateReadingTime, countWords, extractTextFromBlocks } from './reading-time';\n\nlet client: MongoClient | null = null;\nlet db: Db | null = null;\n\nexport async function getDb(): Promise<Db> {\n if (db) return db;\n\n const env = getEnvConfig();\n client = new MongoClient(env.NEXTBLOGKIT_MONGODB_URI);\n await client.connect();\n db = client.db();\n return db;\n}\n\nexport async function getCollection<T extends Document = Document>(\n name: string\n): Promise<Collection<T>> {\n const database = await getDb();\n return database.collection<T>(name);\n}\n\nexport async function ensureIndexes(): Promise<void> {\n const database = await getDb();\n\n const posts = database.collection('nbk_posts');\n await posts.createIndex({ slug: 1 }, { unique: true });\n await posts.createIndex({ status: 1, publishedAt: -1 });\n await posts.createIndex({ categories: 1, status: 1 });\n await posts.createIndex({ tags: 1, status: 1 });\n await posts.createIndex({ 'seo.focusKeyword': 1 });\n await posts.createIndex({ contentText: 'text', title: 'text', excerpt: 'text' });\n\n const categories = database.collection('nbk_categories');\n await categories.createIndex({ slug: 1 }, { unique: true });\n await categories.createIndex({ order: 1 });\n\n const media = database.collection('nbk_media');\n await media.createIndex({ createdAt: -1 });\n await media.createIndex({ r2Key: 1 }, { unique: true });\n}\n\n// ============================================================\n// Posts\n// ============================================================\n\nexport async function createPost(input: CreatePostInput, defaultAuthor?: BlogPost['author']): Promise<BlogPost> {\n const col = await getCollection('nbk_posts');\n\n const slug = await ensureUniqueSlug(\n input.slug || generateSlug(input.title),\n col\n );\n\n const contentText = input.contentText || extractTextFromBlocks(input.content || []);\n const wordCount = countWords(contentText);\n const readingTime = calculateReadingTime(contentText);\n\n const excerpt =\n input.excerpt || contentText.slice(0, 160).replace(/\\s+\\S*$/, '') + '...';\n\n const now = new Date();\n const doc = {\n title: input.title,\n slug,\n excerpt,\n content: input.content || [],\n contentHTML: input.contentHTML || '',\n contentText,\n coverImage: input.coverImage,\n categories: input.categories || [],\n tags: input.tags || [],\n author: input.author || defaultAuthor || { name: 'Admin' },\n seo: {\n ogType: 'article',\n noIndex: false,\n ...input.seo,\n },\n status: input.status || 'draft',\n publishedAt: input.status === 'published' ? now : input.publishedAt,\n scheduledAt: input.scheduledAt,\n readingTime,\n wordCount,\n version: 1,\n revisions: [],\n createdAt: now,\n updatedAt: now,\n };\n\n const result = await col.insertOne(doc);\n return { _id: result.insertedId, ...doc } as unknown as BlogPost;\n}\n\nexport async function updatePost(\n id: string,\n input: UpdatePostInput\n): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n const objectId = new ObjectId(id);\n const existing = await col.findOne({ _id: objectId });\n if (!existing) return null;\n\n const updates: Record<string, unknown> = { ...input, updatedAt: new Date() };\n\n if (input.slug && input.slug !== existing.slug) {\n updates.slug = await ensureUniqueSlug(input.slug, col, id);\n }\n\n if (input.content) {\n const contentText = input.contentText || extractTextFromBlocks(input.content);\n updates.contentText = contentText;\n updates.wordCount = countWords(contentText);\n updates.readingTime = calculateReadingTime(contentText);\n\n if (!input.excerpt) {\n updates.excerpt =\n contentText.slice(0, 160).replace(/\\s+\\S*$/, '') + '...';\n }\n\n // Save revision\n const revision = {\n version: existing.version || 1,\n title: existing.title,\n content: existing.content,\n contentHTML: existing.contentHTML,\n savedAt: new Date(),\n };\n const revisions = [...(existing.revisions || []), revision].slice(-10);\n updates.revisions = revisions;\n updates.version = (existing.version || 1) + 1;\n }\n\n if (input.status === 'published' && existing.status !== 'published') {\n updates.publishedAt = new Date();\n }\n\n await col.updateOne({ _id: objectId }, { $set: updates });\n return (await col.findOne({ _id: objectId })) as unknown as BlogPost;\n}\n\nexport async function deletePost(id: string): Promise<boolean> {\n const col = await getCollection('nbk_posts');\n const result = await col.updateOne(\n { _id: new ObjectId(id) },\n { $set: { status: 'archived', updatedAt: new Date() } }\n );\n return result.modifiedCount > 0;\n}\n\nexport async function hardDeletePost(id: string): Promise<boolean> {\n const col = await getCollection('nbk_posts');\n const result = await col.deleteOne({ _id: new ObjectId(id) });\n return result.deletedCount > 0;\n}\n\nexport async function getPostBySlug(slug: string): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n return (await col.findOne({ slug })) as unknown as BlogPost | null;\n}\n\nexport async function getPostById(id: string): Promise<BlogPost | null> {\n const col = await getCollection('nbk_posts');\n return (await col.findOne({ _id: new ObjectId(id) })) as unknown as BlogPost | null;\n}\n\nexport async function listPosts(\n query: PostListQuery = {}\n): Promise<{ posts: BlogPost[]; total: number }> {\n const col = await getCollection('nbk_posts');\n const {\n page = 1,\n limit = 10,\n category,\n tag,\n status,\n search,\n sortBy = 'publishedAt',\n sortOrder = 'desc',\n } = query;\n\n const filter: Record<string, unknown> = {};\n\n if (status) {\n filter.status = status;\n } else {\n filter.status = { $ne: 'archived' };\n }\n\n if (category) filter.categories = category;\n if (tag) filter.tags = tag;\n if (search) {\n filter.$text = { $search: search };\n }\n\n const sort: Record<string, 1 | -1> = {\n [sortBy]: sortOrder === 'asc' ? 1 : -1,\n };\n\n const skip = (page - 1) * limit;\n\n const [posts, total] = await Promise.all([\n col.find(filter).sort(sort).skip(skip).limit(limit).toArray(),\n col.countDocuments(filter),\n ]);\n\n return {\n posts: posts as unknown as BlogPost[],\n total,\n };\n}\n\n// ============================================================\n// Categories\n// ============================================================\n\nexport async function createCategory(input: CreateCategoryInput): Promise<Category> {\n const col = await getCollection('nbk_categories');\n const slug = await ensureUniqueSlug(\n input.slug || generateSlug(input.name),\n col\n );\n\n const doc = {\n name: input.name,\n slug,\n description: input.description,\n seo: input.seo,\n order: input.order ?? 0,\n parentId: input.parentId ? new ObjectId(input.parentId) : undefined,\n postCount: 0,\n };\n\n const result = await col.insertOne(doc);\n return { _id: result.insertedId, ...doc } as unknown as Category;\n}\n\nexport async function updateCategory(\n id: string,\n input: UpdateCategoryInput\n): Promise<Category | null> {\n const col = await getCollection('nbk_categories');\n const objectId = new ObjectId(id);\n\n const updates: Record<string, unknown> = { ...input };\n if (input.slug) {\n updates.slug = await ensureUniqueSlug(input.slug, col, id);\n }\n if (input.parentId) {\n updates.parentId = new ObjectId(input.parentId);\n }\n\n await col.updateOne({ _id: objectId }, { $set: updates });\n return (await col.findOne({ _id: objectId })) as unknown as Category | null;\n}\n\nexport async function deleteCategory(id: string): Promise<boolean> {\n const col = await getCollection('nbk_categories');\n const result = await col.deleteOne({ _id: new ObjectId(id) });\n return result.deletedCount > 0;\n}\n\nexport async function listCategories(): Promise<Category[]> {\n const col = await getCollection('nbk_categories');\n return (await col.find({}).sort({ order: 1 }).toArray()) as unknown as Category[];\n}\n\nexport async function getCategoryBySlug(slug: string): Promise<Category | null> {\n const col = await getCollection('nbk_categories');\n return (await col.findOne({ slug })) as unknown as Category | null;\n}\n\nexport async function updateCategoryPostCount(categorySlug: string): Promise<void> {\n const posts = await getCollection('nbk_posts');\n const categories = await getCollection('nbk_categories');\n const count = await posts.countDocuments({\n categories: categorySlug,\n status: 'published',\n });\n await categories.updateOne({ slug: categorySlug }, { $set: { postCount: count } });\n}\n\n// ============================================================\n// Media\n// ============================================================\n\nexport async function createMedia(data: Omit<Media, '_id'>): Promise<Media> {\n const col = await getCollection('nbk_media');\n const result = await col.insertOne(data);\n return { _id: result.insertedId, ...data } as unknown as Media;\n}\n\nexport async function deleteMedia(id: string): Promise<Media | null> {\n const col = await getCollection('nbk_media');\n const media = await col.findOne({ _id: new ObjectId(id) });\n if (!media) return null;\n await col.deleteOne({ _id: new ObjectId(id) });\n return media as unknown as Media;\n}\n\nexport async function listMedia(\n query: MediaListQuery = {}\n): Promise<{ media: Media[]; total: number }> {\n const col = await getCollection('nbk_media');\n const { page = 1, limit = 20, mimeType } = query;\n\n const filter: Record<string, unknown> = {};\n if (mimeType) filter.mimeType = { $regex: mimeType };\n\n const skip = (page - 1) * limit;\n const [media, total] = await Promise.all([\n col.find(filter).sort({ createdAt: -1 }).skip(skip).limit(limit).toArray(),\n col.countDocuments(filter),\n ]);\n\n return { media: media as unknown as Media[], total };\n}\n\n// ============================================================\n// Settings\n// ============================================================\n\nexport async function getSettings(): Promise<BlogSettings> {\n const col = await getCollection('nbk_settings');\n const settings = await col.findOne({ _id: 'global' as unknown as ObjectId });\n if (!settings) {\n const defaults: Record<string, unknown> = {\n _id: 'global',\n postsPerPage: 10,\n commentSystem: 'none',\n };\n await col.insertOne(defaults as Document);\n return defaults as unknown as BlogSettings;\n }\n return settings as unknown as BlogSettings;\n}\n\nexport async function updateSettings(\n data: Partial<BlogSettings>\n): Promise<BlogSettings> {\n const col = await getCollection('nbk_settings');\n const { _id, ...updates } = data as Record<string, unknown>;\n await col.updateOne(\n { _id: 'global' as unknown as ObjectId },\n { $set: updates },\n { upsert: true }\n );\n return getSettings();\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/lib/storage.ts","../src/lib/image.ts"],"names":["getEnvConfig","S3Client","randomUUID","PutObjectCommand","DeleteObjectCommand","ListObjectsV2Command"],"mappings":"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","file":"chunk-ZP5XRVVH.cjs","sourcesContent":["import {\n S3Client,\n PutObjectCommand,\n DeleteObjectCommand,\n ListObjectsV2Command,\n} from '@aws-sdk/client-s3';\nimport { getEnvConfig } from './config';\nimport { randomUUID } from 'crypto';\n\nexport interface MediaUploadResult {\n key: string;\n url: string;\n size: number;\n contentType: string;\n}\n\nexport interface StorageObject {\n key: string;\n size: number;\n lastModified: Date;\n}\n\nexport interface StorageProvider {\n upload(file: Buffer, filename: string, contentType: string): Promise<MediaUploadResult>;\n delete(key: string): Promise<void>;\n list(prefix?: string): Promise<StorageObject[]>;\n}\n\nlet clientInstance: S3Client | null = null;\n\nfunction getS3Client(): S3Client {\n if (clientInstance) return clientInstance;\n\n const env = getEnvConfig();\n clientInstance = new S3Client({\n region: 'auto',\n endpoint: `https://${env.NEXTBLOGKIT_R2_ACCOUNT_ID}.r2.cloudflarestorage.com`,\n credentials: {\n accessKeyId: env.NEXTBLOGKIT_R2_ACCESS_KEY,\n secretAccessKey: env.NEXTBLOGKIT_R2_SECRET_KEY,\n },\n });\n\n return clientInstance;\n}\n\nfunction generateKey(filename: string): string {\n const now = new Date();\n const year = now.getFullYear();\n const month = String(now.getMonth() + 1).padStart(2, '0');\n const uuid = randomUUID().split('-')[0];\n const safeName = filename.replace(/[^a-zA-Z0-9._-]/g, '-').toLowerCase();\n return `blog/${year}/${month}/${uuid}-${safeName}`;\n}\n\nexport class R2StorageProvider implements StorageProvider {\n async upload(\n file: Buffer,\n filename: string,\n contentType: string\n ): Promise<MediaUploadResult> {\n const env = getEnvConfig();\n const client = getS3Client();\n const key = generateKey(filename);\n\n await client.send(\n new PutObjectCommand({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Key: key,\n Body: file,\n ContentType: contentType,\n })\n );\n\n return {\n key,\n url: `${env.NEXTBLOGKIT_R2_PUBLIC_URL}/${key}`,\n size: file.length,\n contentType,\n };\n }\n\n async delete(key: string): Promise<void> {\n const env = getEnvConfig();\n const client = getS3Client();\n\n await client.send(\n new DeleteObjectCommand({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Key: key,\n })\n );\n }\n\n async list(prefix?: string): Promise<StorageObject[]> {\n const env = getEnvConfig();\n const client = getS3Client();\n\n const response = await client.send(\n new ListObjectsV2Command({\n Bucket: env.NEXTBLOGKIT_R2_BUCKET,\n Prefix: prefix || 'blog/',\n })\n );\n\n return (response.Contents || []).map((obj) => ({\n key: obj.Key || '',\n size: obj.Size || 0,\n lastModified: obj.LastModified || new Date(),\n }));\n }\n}\n","import type { R2StorageProvider, MediaUploadResult } from './storage';\n\nexport interface ProcessedImage {\n original: MediaUploadResult;\n width: number;\n height: number;\n format: string;\n}\n\nconst RESPONSIVE_SIZES = [640, 768, 1024, 1280, 1920];\n\nexport async function processImage(\n file: Buffer,\n filename: string,\n storage: R2StorageProvider\n): Promise<ProcessedImage> {\n let sharp: typeof import('sharp');\n try {\n sharp = (await import('sharp')).default;\n } catch {\n // sharp not available — upload raw file\n const result = await storage.upload(file, filename, getMimeType(filename));\n return {\n original: result,\n width: 0,\n height: 0,\n format: getExtension(filename),\n };\n }\n\n const image = sharp(file);\n const metadata = await image.metadata();\n\n // Convert to WebP\n const webpFilename = filename.replace(/\\.[^.]+$/, '.webp');\n const webpBuffer = await image.webp({ quality: 85 }).toBuffer();\n\n const original = await storage.upload(webpBuffer, webpFilename, 'image/webp');\n\n // Generate responsive sizes in background (non-blocking for the main upload)\n generateResponsiveSizes(file, webpFilename, storage, metadata.width || 0).catch(\n () => {\n // Silently fail responsive generation — originals are sufficient\n }\n );\n\n return {\n original,\n width: metadata.width || 0,\n height: metadata.height || 0,\n format: 'webp',\n };\n}\n\nasync function generateResponsiveSizes(\n file: Buffer,\n filename: string,\n storage: R2StorageProvider,\n originalWidth: number\n): Promise<void> {\n const sharp = (await import('sharp')).default;\n\n const sizes = RESPONSIVE_SIZES.filter((s) => s < originalWidth);\n\n await Promise.all(\n sizes.map(async (width) => {\n const resized = await sharp(file)\n .resize(width)\n .webp({ quality: 80 })\n .toBuffer();\n\n const sizedFilename = filename.replace('.webp', `-${width}w.webp`);\n await storage.upload(resized, sizedFilename, 'image/webp');\n })\n );\n\n // Generate thumbnail\n const thumb = await sharp(file)\n .resize(200, 200, { fit: 'cover' })\n .webp({ quality: 70 })\n .toBuffer();\n\n const thumbFilename = filename.replace('.webp', '-thumb.webp');\n await storage.upload(thumb, thumbFilename, 'image/webp');\n}\n\nfunction getMimeType(filename: string): string {\n const ext = getExtension(filename);\n const mimeTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n svg: 'image/svg+xml',\n avif: 'image/avif',\n };\n return mimeTypes[ext] || 'application/octet-stream';\n}\n\nfunction getExtension(filename: string): string {\n return filename.split('.').pop()?.toLowerCase() || '';\n}\n"]}