next-blogpanel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +211 -0
- package/dist/admin/index.cjs +3062 -0
- package/dist/admin/index.cjs.map +1 -0
- package/dist/admin/index.d.cts +51 -0
- package/dist/admin/index.d.ts +51 -0
- package/dist/admin/index.js +3029 -0
- package/dist/admin/index.js.map +1 -0
- package/dist/api/categories.cjs +82 -0
- package/dist/api/categories.cjs.map +1 -0
- package/dist/api/categories.d.cts +27 -0
- package/dist/api/categories.d.ts +27 -0
- package/dist/api/categories.js +77 -0
- package/dist/api/categories.js.map +1 -0
- package/dist/api/media-file.cjs +46 -0
- package/dist/api/media-file.cjs.map +1 -0
- package/dist/api/media-file.d.cts +7 -0
- package/dist/api/media-file.d.ts +7 -0
- package/dist/api/media-file.js +44 -0
- package/dist/api/media-file.js.map +1 -0
- package/dist/api/media.cjs +180 -0
- package/dist/api/media.cjs.map +1 -0
- package/dist/api/media.d.cts +22 -0
- package/dist/api/media.d.ts +22 -0
- package/dist/api/media.js +176 -0
- package/dist/api/media.js.map +1 -0
- package/dist/api/posts.cjs +103 -0
- package/dist/api/posts.cjs.map +1 -0
- package/dist/api/posts.d.cts +27 -0
- package/dist/api/posts.d.ts +27 -0
- package/dist/api/posts.js +98 -0
- package/dist/api/posts.js.map +1 -0
- package/dist/api/rss.cjs +25 -0
- package/dist/api/rss.cjs.map +1 -0
- package/dist/api/rss.d.cts +5 -0
- package/dist/api/rss.d.ts +5 -0
- package/dist/api/rss.js +23 -0
- package/dist/api/rss.js.map +1 -0
- package/dist/api/settings.cjs +40 -0
- package/dist/api/settings.cjs.map +1 -0
- package/dist/api/settings.d.cts +17 -0
- package/dist/api/settings.d.ts +17 -0
- package/dist/api/settings.js +37 -0
- package/dist/api/settings.js.map +1 -0
- package/dist/api/sitemap.cjs +25 -0
- package/dist/api/sitemap.cjs.map +1 -0
- package/dist/api/sitemap.d.cts +5 -0
- package/dist/api/sitemap.d.ts +5 -0
- package/dist/api/sitemap.js +23 -0
- package/dist/api/sitemap.js.map +1 -0
- package/dist/api/tokens.cjs +56 -0
- package/dist/api/tokens.cjs.map +1 -0
- package/dist/api/tokens.d.cts +22 -0
- package/dist/api/tokens.d.ts +22 -0
- package/dist/api/tokens.js +52 -0
- package/dist/api/tokens.js.map +1 -0
- package/dist/chunk-2M46MMWN.cjs +76 -0
- package/dist/chunk-2M46MMWN.cjs.map +1 -0
- package/dist/chunk-4GK22Q3R.cjs +229 -0
- package/dist/chunk-4GK22Q3R.cjs.map +1 -0
- package/dist/chunk-6PZ772NQ.js +595 -0
- package/dist/chunk-6PZ772NQ.js.map +1 -0
- package/dist/chunk-BZXPRGLN.cjs +351 -0
- package/dist/chunk-BZXPRGLN.cjs.map +1 -0
- package/dist/chunk-DAX5C6SC.cjs +86 -0
- package/dist/chunk-DAX5C6SC.cjs.map +1 -0
- package/dist/chunk-DWNMHQ4I.cjs +57 -0
- package/dist/chunk-DWNMHQ4I.cjs.map +1 -0
- package/dist/chunk-FPGVR2BX.cjs +121 -0
- package/dist/chunk-FPGVR2BX.cjs.map +1 -0
- package/dist/chunk-JBP3G4QJ.js +50 -0
- package/dist/chunk-JBP3G4QJ.js.map +1 -0
- package/dist/chunk-JDP4DIHI.js +215 -0
- package/dist/chunk-JDP4DIHI.js.map +1 -0
- package/dist/chunk-LIZOVA4W.js +118 -0
- package/dist/chunk-LIZOVA4W.js.map +1 -0
- package/dist/chunk-QLBTOCT3.js +118 -0
- package/dist/chunk-QLBTOCT3.js.map +1 -0
- package/dist/chunk-UI2KDZ5H.js +344 -0
- package/dist/chunk-UI2KDZ5H.js.map +1 -0
- package/dist/chunk-V7QPRX4A.cjs +125 -0
- package/dist/chunk-V7QPRX4A.cjs.map +1 -0
- package/dist/chunk-VEJFN65Y.js +82 -0
- package/dist/chunk-VEJFN65Y.js.map +1 -0
- package/dist/chunk-WYZFAI6O.js +74 -0
- package/dist/chunk-WYZFAI6O.js.map +1 -0
- package/dist/chunk-XLYTATRQ.cjs +637 -0
- package/dist/chunk-XLYTATRQ.cjs.map +1 -0
- package/dist/cli/index.cjs +2036 -0
- package/dist/components/index.cjs +647 -0
- package/dist/components/index.cjs.map +1 -0
- package/dist/components/index.d.cts +187 -0
- package/dist/components/index.d.ts +187 -0
- package/dist/components/index.js +633 -0
- package/dist/components/index.js.map +1 -0
- package/dist/db-M3KXLBUP.js +3 -0
- package/dist/db-M3KXLBUP.js.map +1 -0
- package/dist/db-TDCZNY3Q.cjs +112 -0
- package/dist/db-TDCZNY3Q.cjs.map +1 -0
- package/dist/editor/index.cjs +1126 -0
- package/dist/editor/index.cjs.map +1 -0
- package/dist/editor/index.d.cts +137 -0
- package/dist/editor/index.d.ts +137 -0
- package/dist/editor/index.js +1093 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/index-BcNka7gK.d.cts +475 -0
- package/dist/index-DPRgaNEE.d.ts +475 -0
- package/dist/index.cjs +433 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +27 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/index.cjs +193 -0
- package/dist/lib/index.cjs.map +1 -0
- package/dist/lib/index.d.cts +4 -0
- package/dist/lib/index.d.ts +4 -0
- package/dist/lib/index.js +8 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/styles/admin.css +667 -0
- package/dist/styles/blog.css +851 -0
- package/dist/styles/editor.css +452 -0
- package/dist/styles/globals.css +270 -0
- package/dist/styles/prose.css +299 -0
- package/dist/types-CgrBuig-.d.cts +778 -0
- package/dist/types-CgrBuig-.d.ts +778 -0
- package/package.json +140 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/limits.ts","../src/lib/config.ts","../src/lib/slug.ts","../src/lib/reading-time.ts","../src/lib/db.ts"],"names":["z","MongoClient","ObjectId","createHash","randomBytes"],"mappings":"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","file":"chunk-XLYTATRQ.cjs","sourcesContent":["/**\n * Single source of truth for the two image size ceilings.\n *\n * Deliberately dependency-free (no zod, no other imports) so that\n * client-bundled code — e.g. `src/editor/extensions/image-upload.ts`,\n * which runs in the browser — can import these constants without\n * pulling `src/lib/config.ts`'s zod env schema into the client bundle.\n *\n * `src/lib/config.ts`'s `defaultConfig.editor` reads its defaults from\n * here too, so there is exactly one place either number is defined.\n */\n\n/** Ceiling on the STORED result. Enforced by compression, never by rejection. */\nexport const DEFAULT_MAX_IMAGE_SIZE = 2 * 1024 * 1024;\n\n/** Ceiling on the RAW upload. Enforced by rejection, before buffering. */\nexport const DEFAULT_MAX_UPLOAD_SIZE = 10 * 1024 * 1024;\n","import { z } from 'zod';\nimport type { BlogPanelConfig, BlogPanelUserConfig } from './types';\nimport { DEFAULT_MAX_IMAGE_SIZE, DEFAULT_MAX_UPLOAD_SIZE } from './limits';\n\nconst envSchema = z.object({\n // Required\n BLOGPANEL_MONGODB_URI: z.string().min(1, 'MongoDB URI is required'),\n BLOGPANEL_API_KEY: z.string().min(32, 'API key must be at least 32 characters'),\n\n // Optional — Database name (defaults to the database in your connection URI)\n BLOGPANEL_MONGODB_DB: z.string().optional(),\n\n // Optional — Cloudflare R2 (image storage)\n BLOGPANEL_R2_ACCOUNT_ID: z.string().optional(),\n BLOGPANEL_R2_ACCESS_KEY: z.string().optional(),\n BLOGPANEL_R2_SECRET_KEY: z.string().optional(),\n BLOGPANEL_R2_BUCKET: z.string().optional(),\n BLOGPANEL_R2_PUBLIC_URL: z.string().optional(),\n\n // Optional — force a storage backend regardless of what is configured.\n //\n // Not a z.enum(['gridfs','r2']) any more: a custom provider registered via\n // registerStorageProvider() is selectable here by its own name, and an enum\n // could not know those names — they are supplied by application code at\n // runtime, long after this schema is evaluated.\n //\n // The enum did buy loud detection of a typo, and that is not given up, only\n // moved: getStorageProviderByName() throws StorageProviderNotRegisteredError\n // and names every resolvable provider. That is a strictly better failure\n // than the enum's, which rejected the whole environment — taking down\n // routes that never touch storage — and could only say \"expected 'gridfs' |\n // 'r2'\". Left as a plain optional string rather than .min(1) so that an\n // empty `BLOGPANEL_STORAGE=` line, which reads as \"unset\" in every .env\n // file, does not fail config parsing process-wide; getStorageProvider()\n // treats blank as absent.\n BLOGPANEL_STORAGE: z.string().optional(),\n\n // Optional — Site info (defaults provided)\n BLOGPANEL_SITE_URL: z.string().optional().default(''),\n BLOGPANEL_SITE_NAME: z.string().optional().default('Blog'),\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(`Next BlogPanel configuration error:\\n${missing.join('\\n')}`);\n }\n\n cachedEnv = result.data;\n return cachedEnv;\n}\n\n/** Test-only: invalidates the cached env so a later getEnvConfig() re-parses process.env. */\nexport function resetEnvCache(): void {\n cachedEnv = null;\n}\n\nexport function isR2Configured(): boolean {\n const env = getEnvConfig();\n return !!(\n env.BLOGPANEL_R2_ACCOUNT_ID &&\n env.BLOGPANEL_R2_ACCESS_KEY &&\n env.BLOGPANEL_R2_SECRET_KEY &&\n env.BLOGPANEL_R2_BUCKET &&\n env.BLOGPANEL_R2_PUBLIC_URL\n );\n}\n\nconst defaultConfig: BlogPanelConfig = {\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: DEFAULT_MAX_IMAGE_SIZE, // stored result ceiling — compression target\n maxUploadSize: DEFAULT_MAX_UPLOAD_SIZE, // raw ingest ceiling — rejection threshold\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 '--nbp-primary': '#2563eb',\n '--nbp-primary-hover': '#1d4ed8',\n '--nbp-text': '#1f2937',\n '--nbp-text-muted': '#6b7280',\n '--nbp-bg': '#ffffff',\n '--nbp-bg-secondary': '#f9fafb',\n '--nbp-card-bg': '#ffffff',\n '--nbp-border': '#e5e7eb',\n '--nbp-radius': '0.5rem',\n '--nbp-font-heading': '\"Inter\", system-ui, sans-serif',\n '--nbp-font-body': '\"Inter\", system-ui, sans-serif',\n '--nbp-font-code': '\"JetBrains Mono\", \"Fira Code\", monospace',\n },\n },\n hooks: {},\n};\n\n/**\n * Merges `userConfig` over `base`, per-key, including the nested groups.\n *\n * `base` is a full `BlogPanelConfig`, not necessarily `defaultConfig` — see\n * `setConfig()` below for why that distinction matters.\n */\nfunction mergeConfig(base: BlogPanelConfig, userConfig?: BlogPanelUserConfig): BlogPanelConfig {\n return {\n ...base,\n ...userConfig,\n editor: { ...base.editor, ...userConfig?.editor },\n seo: { ...base.seo, ...userConfig?.seo },\n auth: { ...base.auth, ...userConfig?.auth },\n features: { ...base.features, ...userConfig?.features },\n theme: {\n ...base.theme,\n ...userConfig?.theme,\n variables: { ...base.theme.variables, ...userConfig?.theme?.variables },\n },\n hooks: { ...base.hooks, ...userConfig?.hooks },\n };\n}\n\n/**\n * Where the installed configuration lives.\n *\n * Deliberately NOT a module-level `let`. Next.js instantiates server modules\n * per route entry: a value assigned to module scope while handling\n * `/api/blog/media` is not guaranteed to be visible to the module instance\n * that serves `/blog/[slug]`, and in a production build with per-route\n * bundling it usually is not. Module state would therefore make \"did the\n * user's config reach this code?\" depend on which route the request happened\n * to hit first — the exact class of bug that shipped `/api/blog/...` image\n * URLs into databases scaffolded with `--api-path /api/articles`.\n *\n * `globalThis` keyed by a `Symbol.for()` is process-wide and shared by every\n * bundle in that process (the same reason the standard Next.js MongoClient\n * singleton lives there), so one `setConfig()` call from any entry point\n * installs the configuration for all of them. The symbol is registry-keyed so\n * that two copies of this module — duplicated by bundling, or by two\n * different versions of the package in one tree — still address the same slot.\n */\nconst CONFIG_SLOT = Symbol.for('next-blogpanel.config.v1');\n\ninterface ConfigSlot {\n /** True once setConfig() has run in this process. */\n installed: boolean;\n config: BlogPanelConfig;\n}\n\nfunction slot(): ConfigSlot {\n const store = globalThis as unknown as Record<symbol, ConfigSlot | undefined>;\n let current = store[CONFIG_SLOT];\n if (!current) {\n current = { installed: false, config: mergeConfig(defaultConfig) };\n store[CONFIG_SLOT] = current;\n }\n return current;\n}\n\n/**\n * Where \"a later setConfig() call warned about a conflicting apiPath\"\n * de-duplication lives, so a warning is not re-emitted for a transition this\n * process has already reported. Separate from CONFIG_SLOT so `resetConfig()`\n * can drop it independently — tests reset the config between cases and\n * should not have earlier warnings suppress a later, otherwise-identical one.\n */\nconst CONFIG_WARNED = Symbol.for('next-blogpanel.config.warned');\n\nfunction warnApiPathConflict(previous: string, next: string): void {\n const store = globalThis as unknown as Record<symbol, Set<string> | undefined>;\n const seen = (store[CONFIG_WARNED] ||= new Set<string>());\n const key = `${previous}=>${next}`;\n if (seen.has(key)) return;\n seen.add(key);\n console.warn(\n `[blogpanel] setConfig() was called again with a different apiPath ('${next}', previously ` +\n `'${previous}'). apiPath is baked into every GridFS media URL already written to the ` +\n `database and into post bodies that embed those images, so this does not retroactively fix ` +\n `or break anything already stored — but every upload from this point on will use the new ` +\n `value. If that is not what you intended, look for more than one setConfig() call with a ` +\n `hardcoded apiPath (for example, your own call alongside the generated next-blogpanel.setup.ts).`\n );\n}\n\nexport function defineConfig(config: BlogPanelUserConfig): BlogPanelUserConfig {\n return config;\n}\n\n/**\n * Installs the user's `next-blogpanel.config.ts` into the server runtime.\n *\n * Called by the `next-blogpanel.setup` module that `init` scaffolds, which\n * every generated route handler, layout and page imports. Calling it more\n * than once is fine and expected — each bundled copy of the setup module\n * installs the same object, and repeating an identical call is a no-op.\n *\n * The argument is merged over whatever is already installed: the defaults on\n * the very first call in this process, and the previously installed config on\n * every call after that. It is deliberately NOT always merged over the\n * defaults — that would let a later *partial* call silently discard keys only\n * an earlier call set. Concretely: the generated setup module installs the\n * full config once; if application code then calls `setConfig({ theme: {...} })`\n * on its own (`docs/configuration.md` shows exactly that pattern), merging\n * over the defaults would reset `apiPath` back to `/api/blog` while leaving\n * `installed` true — so `requireApiPath()` would wave the reset value\n * straight through and persist it into GridFS media URLs. Merging over the\n * installed config instead means a later partial call can only add or\n * override the keys it actually mentions.\n *\n * A later call that explicitly sets a *different* `apiPath` than what is\n * already installed is still honoured — this is not a lock — but it is\n * reported with a console warning, once per distinct transition, because that\n * value gets baked into already-persisted media URLs and post bodies.\n */\nexport function setConfig(userConfig: BlogPanelUserConfig): BlogPanelConfig {\n const current = slot();\n const base = current.installed ? current.config : defaultConfig;\n\n if (\n current.installed &&\n userConfig.apiPath !== undefined &&\n userConfig.apiPath !== current.config.apiPath\n ) {\n warnApiPathConflict(current.config.apiPath, userConfig.apiPath);\n }\n\n const merged = mergeConfig(base, userConfig);\n current.config = merged;\n current.installed = true;\n return merged;\n}\n\n/** True once a `setConfig()` call has installed a configuration in this process. */\nexport function isConfigInstalled(): boolean {\n return slot().installed;\n}\n\nexport function getConfig(userConfig?: BlogPanelUserConfig): BlogPanelConfig {\n // A caller passing overrides gets a one-off merge over the defaults and\n // does not disturb, or read, whatever is installed.\n if (userConfig) return mergeConfig(defaultConfig, userConfig);\n return slot().config;\n}\n\n/**\n * Thrown by `requireApiPath()` when nothing has installed a configuration in\n * this server runtime.\n *\n * A dedicated class rather than a string-matched `Error`: callers that need\n * to tell \"no config installed\" apart from any other failure (e.g.\n * `POST /media`, which passes this specific message through to the client\n * instead of flattening it to a generic 500) should match on `instanceof`,\n * not on `error.message.startsWith(...)`. A message-prefix check breaks the\n * moment the wording changes for any reason — a typo fix, a translation, a\n * clarification — and silently falls back to the generic branch instead of\n * failing a test. `instanceof` cannot drift like that.\n */\nexport class ConfigNotInstalledError extends Error {\n constructor(context: string) {\n super(\n `Next BlogPanel: no configuration has been installed in this server runtime, so ${context} cannot be resolved.\\n` +\n ` This value is built from \\`apiPath\\` and then stored permanently, so falling back to the default ('${defaultConfig.apiPath}') would write a URL that may never resolve.\\n` +\n ` Fix: import the setup module \\`next-blogpanel init\\` generated next to your app directory (app/next-blogpanel.setup.ts) from the route handler that reaches this code, or call setConfig(config) yourself before serving requests.\\n` +\n ` See docs/configuration.md — \"Getting the config to the server\".`\n );\n this.name = 'ConfigNotInstalledError';\n }\n}\n\n/**\n * Returns `apiPath` for callers that must not fall back to the default.\n *\n * `getConfig().apiPath` answers \"/api/blog\" whether that is what the user\n * configured or whether nothing was ever installed, and the two are\n * indistinguishable. That is harmless for a link, but GridFS media URLs are\n * built from it and persisted — into the `nbk_media` document and into the\n * body of every post that embeds the image. A guessed prefix there is not\n * recoverable by fixing the config later, so guessing is refused.\n */\nexport function requireApiPath(context: string): string {\n const current = slot();\n if (!current.installed) {\n throw new ConfigNotInstalledError(context);\n }\n return current.config.apiPath;\n}\n\n/** Test-only: drops the installed configuration so the next read starts clean. */\nexport function resetConfig(): void {\n const store = globalThis as unknown as Record<symbol, unknown>;\n delete store[CONFIG_SLOT];\n delete store[CONFIG_WARNED];\n}\n\nexport function getBlogConfig() {\n const env = getEnvConfig();\n const config = getConfig();\n\n return {\n ...config,\n siteUrl: env.BLOGPANEL_SITE_URL,\n siteName: env.BLOGPANEL_SITE_NAME,\n metadata: {\n title: `Blog | ${env.BLOGPANEL_SITE_NAME}`,\n description: `Latest posts from ${env.BLOGPANEL_SITE_NAME}`,\n openGraph: {\n title: `Blog | ${env.BLOGPANEL_SITE_NAME}`,\n description: `Latest posts from ${env.BLOGPANEL_SITE_NAME}`,\n url: `${env.BLOGPANEL_SITE_URL}${config.basePath}`,\n siteName: env.BLOGPANEL_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(/ /g, ' ')\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/"/g, '\"')\n .replace(/'/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 { createHash, randomBytes } from 'crypto';\nimport { getEnvConfig } from './config';\nimport type {\n BlogPost,\n Category,\n Media,\n BlogSettings,\n ApiToken,\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.BLOGPANEL_MONGODB_URI);\n await client.connect();\n db = client.db(env.BLOGPANEL_MONGODB_DB || undefined);\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({ storageKey: 1 }, { unique: true });\n\n const tokens = database.collection('nbk_api_tokens');\n await tokens.createIndex({ tokenHash: 1 }, { unique: true });\n await tokens.createIndex({ createdAt: -1 });\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\n/**\n * Reads a media document without deleting it.\n *\n * Exists so `DELETE /media` can resolve `provider` to a real backend *before*\n * it removes the row: if the name is unresolvable, the request can fail with\n * the row still intact and be retried once the provider is registered. Doing\n * that check after the delete would leave a stranded object and no record of\n * it — the exact failure `Media.provider` exists to prevent.\n */\nexport async function getMediaById(id: string): Promise<Media | null> {\n const col = await getCollection('nbk_media');\n const media = await col.findOne({ _id: new ObjectId(id) });\n return (media as unknown as Media) || null;\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\n// ============================================================\n// API Tokens\n// ============================================================\n\nfunction hashToken(plain: string): string {\n return createHash('sha256').update(plain).digest('hex');\n}\n\nexport async function createApiToken(name: string): Promise<{ token: ApiToken; plainToken: string }> {\n const col = await getCollection('nbk_api_tokens');\n const plainToken = 'nbk_' + randomBytes(24).toString('hex');\n const tokenHash = hashToken(plainToken);\n const prefix = plainToken.slice(0, 8);\n const now = new Date();\n\n const doc = {\n name,\n tokenHash,\n prefix,\n createdAt: now,\n };\n\n const result = await col.insertOne(doc);\n const token = { _id: result.insertedId, ...doc } as unknown as ApiToken;\n return { token, plainToken };\n}\n\nexport async function listApiTokens(): Promise<ApiToken[]> {\n const col = await getCollection('nbk_api_tokens');\n return (await col.find({}, { projection: { tokenHash: 0 } }).sort({ createdAt: -1 }).toArray()) as unknown as ApiToken[];\n}\n\nexport async function deleteApiToken(id: string): Promise<boolean> {\n const col = await getCollection('nbk_api_tokens');\n const result = await col.deleteOne({ _id: new ObjectId(id) });\n return result.deletedCount > 0;\n}\n\nexport async function verifyApiToken(plainToken: string): Promise<ApiToken | null> {\n const col = await getCollection('nbk_api_tokens');\n const tokenHash = hashToken(plainToken);\n const token = await col.findOneAndUpdate(\n { tokenHash },\n { $set: { lastUsedAt: new Date() } },\n { returnDocument: 'after' }\n );\n return token as unknown as ApiToken | null;\n}\n"]}
|