nextblogkit 0.6.2 → 0.7.2

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 (113) hide show
  1. package/README.md +84 -21
  2. package/dist/admin/index.cjs +656 -115
  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 +575 -37
  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 +12 -6
  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 +12 -6
  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 +49 -12
  82. package/dist/editor/index.cjs.map +1 -1
  83. package/dist/editor/index.d.cts +5 -1
  84. package/dist/editor/index.d.ts +5 -1
  85. package/dist/editor/index.js +37 -1
  86. package/dist/editor/index.js.map +1 -1
  87. package/dist/{index-vjlZDWNr.d.cts → index-Bk8gOqBq.d.cts} +25 -21
  88. package/dist/{index-Cgzphklp.d.ts → index-DsnG2kdW.d.ts} +25 -21
  89. package/dist/index.cjs +47 -47
  90. package/dist/index.d.cts +3 -3
  91. package/dist/index.d.ts +3 -3
  92. package/dist/index.js +5 -5
  93. package/dist/lib/index.cjs +39 -35
  94. package/dist/lib/index.d.cts +2 -2
  95. package/dist/lib/index.d.ts +2 -2
  96. package/dist/lib/index.js +5 -5
  97. package/dist/{types-CBEEBR4A.d.ts → types-Cu515Egx.d.cts} +16 -1
  98. package/dist/{types-CBEEBR4A.d.cts → types-Cu515Egx.d.ts} +16 -1
  99. package/package.json +1 -1
  100. package/dist/chunk-4NKOJYWJ.js.map +0 -1
  101. package/dist/chunk-4PY224XM.js.map +0 -1
  102. package/dist/chunk-64HUVJOZ.js.map +0 -1
  103. package/dist/chunk-6HKMZOI4.cjs.map +0 -1
  104. package/dist/chunk-A2S32RZN.js.map +0 -1
  105. package/dist/chunk-E2QLTHKN.cjs.map +0 -1
  106. package/dist/chunk-JLPJKNRZ.js.map +0 -1
  107. package/dist/chunk-JM7QRXXK.js.map +0 -1
  108. package/dist/chunk-KDZER3PU.cjs.map +0 -1
  109. package/dist/chunk-N5MKAD7J.cjs.map +0 -1
  110. package/dist/chunk-QE4VLQYN.cjs.map +0 -1
  111. package/dist/chunk-R6MO3QIP.js.map +0 -1
  112. package/dist/chunk-U2ROR6AY.cjs.map +0 -1
  113. package/dist/chunk-ZP5XRVVH.cjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/api/tokens.ts"],"names":[],"mappings":";;;;;AAIA,eAAsB,IAAI,OAAA,EAAkB;AAC1C,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAC3C,IAAA,IAAI,WAAW,OAAO,SAAA;AAEtB,IAAA,MAAM,MAAA,GAAS,MAAM,aAAA,EAAc;AACnC,IAAA,OAAO,YAAY,MAAM,CAAA;AAAA,EAC3B,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,oCAAoC,KAAK,CAAA;AACvD,IAAA,OAAO,SAAA,CAAU,gBAAA,EAAkB,wBAAA,EAA0B,GAAG,CAAA;AAAA,EAClE;AACF;AAEA,eAAsB,KAAK,OAAA,EAAkB;AAC3C,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAC3C,IAAA,IAAI,WAAW,OAAO,SAAA;AAEtB,IAAA,MAAM,IAAA,GAAO,MAAM,OAAA,CAAQ,IAAA,EAAK;AAChC,IAAA,MAAM,MAAA,GAAS,oBAAA,CAAqB,SAAA,CAAU,IAAI,CAAA;AAElD,IAAA,IAAI,CAAC,OAAO,OAAA,EAAS;AACnB,MAAA,MAAM,SAAS,MAAA,CAAO,KAAA,CAAM,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,EAAG,CAAA,CAAE,IAAA,CAAK,KAAK,GAAG,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,OAAO,CAAA,CAAE,CAAA;AACjF,MAAA,OAAO,SAAA,CAAU,kBAAA,EAAoB,MAAA,CAAO,IAAA,CAAK,IAAI,CAAC,CAAA;AAAA,IACxD;AAEA,IAAA,MAAM,EAAE,OAAO,UAAA,EAAW,GAAI,MAAM,cAAA,CAAe,MAAA,CAAO,KAAK,IAAI,CAAA;AACnE,IAAA,OAAO,YAAY,EAAE,GAAG,OAAO,UAAA,EAAW,EAAG,QAAW,GAAG,CAAA;AAAA,EAC7D,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,qCAAqC,KAAK,CAAA;AACxD,IAAA,OAAO,SAAA,CAAU,gBAAA,EAAkB,wBAAA,EAA0B,GAAG,CAAA;AAAA,EAClE;AACF;AAEA,eAAsB,OAAO,OAAA,EAAkB;AAC7C,EAAA,IAAI;AACF,IAAA,MAAM,SAAA,GAAY,kBAAkB,OAAO,CAAA;AAC3C,IAAA,IAAI,WAAW,OAAO,SAAA;AAEtB,IAAA,MAAM,MAAA,GAAS,gBAAgB,OAAO,CAAA;AACtC,IAAA,MAAM,KAAK,MAAA,CAAO,EAAA;AAClB,IAAA,IAAI,CAAC,EAAA,EAAI,OAAO,SAAA,CAAU,cAAc,sBAAsB,CAAA;AAE9D,IAAA,MAAM,OAAA,GAAU,MAAM,cAAA,CAAe,EAAE,CAAA;AACvC,IAAA,IAAI,CAAC,OAAA,EAAS,OAAO,SAAA,CAAU,WAAA,EAAa,mBAAmB,GAAG,CAAA;AAElE,IAAA,OAAO,WAAA,CAAY,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AAAA,EACtC,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAA,CAAM,uCAAuC,KAAK,CAAA;AAC1D,IAAA,OAAO,SAAA,CAAU,gBAAA,EAAkB,wBAAA,EAA0B,GAAG,CAAA;AAAA,EAClE;AACF","file":"tokens.js","sourcesContent":["import { createApiToken, listApiTokens, deleteApiToken } from '../lib/db';\nimport { CreateApiTokenSchema } from '../lib/types';\nimport { jsonSuccess, jsonError, requireMasterAuth, getSearchParams } from './middleware';\n\nexport async function GET(request: Request) {\n try {\n const authError = requireMasterAuth(request);\n if (authError) return authError;\n\n const tokens = await listApiTokens();\n return jsonSuccess(tokens);\n } catch (error) {\n console.error('[nextblogkit] GET /tokens error:', error);\n return jsonError('INTERNAL_ERROR', 'Failed to fetch tokens', 500);\n }\n}\n\nexport async function POST(request: Request) {\n try {\n const authError = requireMasterAuth(request);\n if (authError) return authError;\n\n const body = await request.json();\n const parsed = CreateApiTokenSchema.safeParse(body);\n\n if (!parsed.success) {\n const errors = parsed.error.issues.map((i) => `${i.path.join('.')}: ${i.message}`);\n return jsonError('VALIDATION_ERROR', errors.join('; '));\n }\n\n const { token, plainToken } = await createApiToken(parsed.data.name);\n return jsonSuccess({ ...token, plainToken }, undefined, 201);\n } catch (error) {\n console.error('[nextblogkit] POST /tokens error:', error);\n return jsonError('INTERNAL_ERROR', 'Failed to create token', 500);\n }\n}\n\nexport async function DELETE(request: Request) {\n try {\n const authError = requireMasterAuth(request);\n if (authError) return authError;\n\n const params = getSearchParams(request);\n const id = params.id;\n if (!id) return jsonError('MISSING_ID', 'Token ID is required');\n\n const deleted = await deleteApiToken(id);\n if (!deleted) return jsonError('NOT_FOUND', 'Token not found', 404);\n\n return jsonSuccess({ deleted: true });\n } catch (error) {\n console.error('[nextblogkit] DELETE /tokens error:', error);\n return jsonError('INTERNAL_ERROR', 'Failed to delete token', 500);\n }\n}\n"]}
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var chunkU2ROR6AY_cjs = require('./chunk-U2ROR6AY.cjs');
3
+ var chunkVWKVU3SE_cjs = require('./chunk-VWKVU3SE.cjs');
4
4
 
5
5
  // src/lib/rss.ts
6
6
  async function generateRSSFeed(fullContent = false) {
7
- const env = chunkU2ROR6AY_cjs.getEnvConfig();
8
- const posts = await chunkU2ROR6AY_cjs.getCollection("nbk_posts");
7
+ const env = chunkVWKVU3SE_cjs.getEnvConfig();
8
+ const config = chunkVWKVU3SE_cjs.getConfig();
9
+ const posts = await chunkVWKVU3SE_cjs.getCollection("nbk_posts");
9
10
  const publishedPosts = await posts.find({ status: "published" }).sort({ publishedAt: -1 }).limit(50).toArray();
10
11
  const items = publishedPosts.map((post) => {
11
- const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;
12
+ const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${post.slug}`;
12
13
  const content = fullContent ? post.contentHTML : post.excerpt;
13
14
  const pubDate = post.publishedAt ? new Date(post.publishedAt).toUTCString() : new Date(post.createdAt).toUTCString();
14
15
  let enclosure = "";
@@ -30,7 +31,7 @@ async function generateRSSFeed(fullContent = false) {
30
31
  <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
31
32
  <channel>
32
33
  <title>${escapeXml(env.NEXTBLOGKIT_SITE_NAME)} Blog</title>
33
- <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/blog</link>
34
+ <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}${config.basePath}</link>
34
35
  <description>Latest posts from ${escapeXml(env.NEXTBLOGKIT_SITE_NAME)}</description>
35
36
  <language>en</language>
36
37
  <lastBuildDate>${buildDate}</lastBuildDate>
@@ -44,5 +45,5 @@ function escapeXml(str) {
44
45
  }
45
46
 
46
47
  exports.generateRSSFeed = generateRSSFeed;
47
- //# sourceMappingURL=chunk-6HKMZOI4.cjs.map
48
- //# sourceMappingURL=chunk-6HKMZOI4.cjs.map
48
+ //# sourceMappingURL=chunk-3BKPNOES.cjs.map
49
+ //# sourceMappingURL=chunk-3BKPNOES.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/rss.ts"],"names":["getEnvConfig","getConfig","getCollection"],"mappings":";;;;;AAGA,eAAsB,eAAA,CAAgB,cAAc,KAAA,EAAwB;AAC1E,EAAA,MAAM,MAAMA,8BAAA,EAAa;AACzB,EAAA,MAAM,SAASC,2BAAA,EAAU;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,OAAA,GAAU,GAAG,GAAA,CAAI,oBAAoB,GAAG,MAAA,CAAO,QAAQ,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA;AAC1E,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,UAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA,EAAG,OAAO,QAAQ,CAAA;AAAA,mCAAA,EAC5B,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-3BKPNOES.cjs","sourcesContent":["import { getCollection } from './db';\nimport { getEnvConfig, getConfig } from './config';\n\nexport async function generateRSSFeed(fullContent = false): Promise<string> {\n const env = getEnvConfig();\n const config = getConfig();\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}${config.basePath}/${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)}${config.basePath}</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"]}
@@ -99,11 +99,15 @@ var BlogSettingsSchema = zod.z.object({
99
99
  plausibleDomain: zod.z.string().optional()
100
100
  }).optional()
101
101
  });
102
+ var CreateApiTokenSchema = zod.z.object({
103
+ name: zod.z.string().min(1, "Token name is required").max(100)
104
+ });
102
105
 
103
106
  exports.BlogSettingsSchema = BlogSettingsSchema;
107
+ exports.CreateApiTokenSchema = CreateApiTokenSchema;
104
108
  exports.CreateCategorySchema = CreateCategorySchema;
105
109
  exports.CreatePostSchema = CreatePostSchema;
106
110
  exports.UpdateCategorySchema = UpdateCategorySchema;
107
111
  exports.UpdatePostSchema = UpdatePostSchema;
108
- //# sourceMappingURL=chunk-N5MKAD7J.cjs.map
109
- //# sourceMappingURL=chunk-N5MKAD7J.cjs.map
112
+ //# sourceMappingURL=chunk-DR7QNI32.cjs.map
113
+ //# sourceMappingURL=chunk-DR7QNI32.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/types.ts"],"names":["z"],"mappings":";;;;;AAO+BA,MAAE,IAAA,CAAK;AAAA,EACpC,WAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAC;AAyB0BA,MAAE,MAAA,CAAO;AAAA,EAClC,QAAA,EAAUA,MAAE,MAAA,EAAO;AAAA,EACnB,YAAA,EAAcA,MAAE,MAAA,EAAO;AAAA,EACvB,QAAA,EAAUA,MAAE,MAAA,EAAO;AAAA,EACnB,IAAA,EAAMA,MAAE,MAAA,EAAO;AAAA,EACf,KAAA,EAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC5B,KAAA,EAAOA,MAAE,MAAA,EAAO;AAAA,EAChB,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,EACpB,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,SAAA,EAAWA,MAAE,IAAA;AACf,CAAC;AAqBM,IAAM,YAAA,GAAeA,MAAE,MAAA,CAAO;AAAA,EACnC,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACtB,QAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EAClC,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,KAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA;AACxB,CAAC,CAAA;AAaM,IAAM,aAAA,GAAgBA,MAAE,MAAA,CAAO;AAAA,EACpC,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,eAAA,EAAiBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACrC,cAAcA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACxC,SAASA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACnC,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,SAAS,CAAA;AAAA,EACpC,OAAA,EAASA,KAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA,EAClC,gBAAgBA,KAAA,CAAE,MAAA,CAAOA,MAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EAC/C,YAAA,EAAcA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAC3B,CAAC,CAAA;AA6BM,IAAM,gBAAA,GAAmBA,MAAE,IAAA,CAAK,CAAC,SAAS,WAAA,EAAa,WAAA,EAAa,UAAU,CAAC,CAAA;AAG/E,IAAM,gBAAA,GAAmBA,MAAE,MAAA,CAAO;AAAA,EACvC,OAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,mBAAmB,CAAA;AAAA,EAC5C,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,OAAA,EAASA,MAAE,GAAA,EAAI;AAAA;AAAA,EACf,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,UAAA,EAAYA,MACT,MAAA,CAAO;AAAA,IACN,GAAA,EAAKA,MAAE,MAAA,EAAO;AAAA,IACd,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,IACpB,GAAA,EAAKA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IACzB,OAAA,EAASA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC7B,KAAA,EAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC3B,MAAA,EAAQA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC7B,EACA,QAAA,EAAS;AAAA,EACZ,UAAA,EAAYA,MAAE,KAAA,CAAMA,KAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EAC1C,IAAA,EAAMA,MAAE,KAAA,CAAMA,KAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACpC,MAAA,EAAQ,aAAa,QAAA,EAAS;AAAA,EAC9B,GAAA,EAAK,cAAc,QAAA,EAAS;AAAA,EAC5B,MAAA,EAAQ,gBAAA,CAAiB,OAAA,CAAQ,OAAO,CAAA;AAAA,EACxC,WAAA,EAAaA,KAAA,CAAE,MAAA,CAAO,IAAA,GAAO,QAAA,EAAS;AAAA,EACtC,WAAA,EAAaA,KAAA,CAAE,MAAA,CAAO,IAAA,GAAO,QAAA;AAC/B,CAAC;AAEM,IAAM,gBAAA,GAAmB,iBAAiB,OAAA;AAiC1C,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,MAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,2BAA2B,CAAA;AAAA,EACnD,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,WAAA,EAAaA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,GAAA,EAAKA,MACF,MAAA,CAAO;AAAA,IACN,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC/B,eAAA,EAAiBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GACtC,EACA,QAAA,EAAS;AAAA,EACZ,KAAA,EAAOA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,CAAC,CAAA;AAAA,EAC3B,QAAA,EAAUA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACvB,CAAC;AAEM,IAAM,oBAAA,GAAuB,qBAAqB,OAAA;AAuBlD,IAAM,kBAAA,GAAqBA,MAAE,MAAA,CAAO;AAAA,EACzC,YAAA,EAAcA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACnD,aAAA,EAAe,aAAa,QAAA,EAAS;AAAA,EACrC,gBAAgBA,KAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EAC1C,aAAA,EAAeA,KAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,UAAU,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,EAClE,eAAeA,KAAA,CAAE,MAAA,CAAOA,MAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EAC9C,SAAA,EAAWA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,SAAA,EAAWA,MACR,MAAA,CAAO;AAAA,IACN,IAAA,EAAMA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC1B,eAAA,EAAiBA,KAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GACtC,EACA,QAAA;AACL,CAAC;AAoBM,IAAM,oBAAA,GAAuBA,MAAE,MAAA,CAAO;AAAA,EAC3C,IAAA,EAAMA,MAAE,MAAA,EAAO,CAAE,IAAI,CAAA,EAAG,wBAAwB,CAAA,CAAE,GAAA,CAAI,GAAG;AAC3D,CAAC","file":"chunk-DR7QNI32.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 Tokens\n// ============================================================\n\nexport const CreateApiTokenSchema = z.object({\n name: z.string().min(1, 'Token name is required').max(100),\n});\n\nexport interface ApiToken {\n _id: ObjectId;\n name: string;\n tokenHash: string;\n prefix: string;\n lastUsedAt?: Date;\n createdAt: Date;\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,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkU2ROR6AY_cjs = require('./chunk-U2ROR6AY.cjs');
3
+ var chunkVWKVU3SE_cjs = require('./chunk-VWKVU3SE.cjs');
4
4
 
5
5
  // src/lib/search.ts
6
6
  async function searchPosts(collection, query, limit = 10) {
@@ -29,8 +29,9 @@ async function searchPosts(collection, query, limit = 10) {
29
29
 
30
30
  // src/lib/seo.ts
31
31
  function generateMetaTags(post) {
32
- const env = chunkU2ROR6AY_cjs.getEnvConfig();
33
- const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;
32
+ const env = chunkVWKVU3SE_cjs.getEnvConfig();
33
+ const config = chunkVWKVU3SE_cjs.getConfig();
34
+ const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${post.slug}`;
34
35
  const title = post.seo?.metaTitle || post.title;
35
36
  const description = post.seo?.metaDescription || post.excerpt;
36
37
  const canonical = post.seo?.canonicalUrl || postUrl;
@@ -70,8 +71,9 @@ function generateMetaTags(post) {
70
71
  };
71
72
  }
72
73
  function generateStructuredData(post) {
73
- const env = chunkU2ROR6AY_cjs.getEnvConfig();
74
- const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;
74
+ const env = chunkVWKVU3SE_cjs.getEnvConfig();
75
+ const config = chunkVWKVU3SE_cjs.getConfig();
76
+ const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${post.slug}`;
75
77
  return {
76
78
  "@context": "https://schema.org",
77
79
  "@type": "BlogPosting",
@@ -113,7 +115,8 @@ function generateFAQStructuredData(faqItems) {
113
115
  };
114
116
  }
115
117
  function generateBreadcrumbs(post, categoryName) {
116
- const env = chunkU2ROR6AY_cjs.getEnvConfig();
118
+ const env = chunkVWKVU3SE_cjs.getEnvConfig();
119
+ const config = chunkVWKVU3SE_cjs.getConfig();
117
120
  const items = [
118
121
  {
119
122
  "@type": "ListItem",
@@ -125,7 +128,7 @@ function generateBreadcrumbs(post, categoryName) {
125
128
  "@type": "ListItem",
126
129
  position: 2,
127
130
  name: "Blog",
128
- item: `${env.NEXTBLOGKIT_SITE_URL}/blog`
131
+ item: `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}`
129
132
  }
130
133
  ];
131
134
  if (categoryName && post.categories[0]) {
@@ -133,7 +136,7 @@ function generateBreadcrumbs(post, categoryName) {
133
136
  "@type": "ListItem",
134
137
  position: 3,
135
138
  name: categoryName,
136
- item: `${env.NEXTBLOGKIT_SITE_URL}/blog/category/${post.categories[0]}`
139
+ item: `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/category/${post.categories[0]}`
137
140
  });
138
141
  items.push({
139
142
  "@type": "ListItem",
@@ -333,5 +336,5 @@ exports.generateFAQStructuredData = generateFAQStructuredData;
333
336
  exports.generateMetaTags = generateMetaTags;
334
337
  exports.generateStructuredData = generateStructuredData;
335
338
  exports.searchPosts = searchPosts;
336
- //# sourceMappingURL=chunk-QE4VLQYN.cjs.map
337
- //# sourceMappingURL=chunk-QE4VLQYN.cjs.map
339
+ //# sourceMappingURL=chunk-F47RPOTU.cjs.map
340
+ //# sourceMappingURL=chunk-F47RPOTU.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/search.ts","../src/lib/seo.ts","../src/lib/seo-scorer.ts"],"names":["getEnvConfig","getConfig"],"mappings":"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","file":"chunk-F47RPOTU.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, getConfig } 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 config = getConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${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 config = getConfig();\n const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${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 config = getConfig();\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}${config.basePath}`,\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}${config.basePath}/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,17 +1,23 @@
1
- import { z } from 'zod';
2
1
  import { MongoClient, ObjectId } from 'mongodb';
2
+ import { randomBytes, createHash } from 'crypto';
3
+ import { z } from 'zod';
3
4
 
4
- // src/lib/config.ts
5
+ // src/lib/db.ts
5
6
  var envSchema = z.object({
7
+ // Required
6
8
  NEXTBLOGKIT_MONGODB_URI: z.string().min(1, "MongoDB URI is required"),
7
- NEXTBLOGKIT_R2_ACCOUNT_ID: z.string().min(1, "R2 Account ID is required"),
8
- NEXTBLOGKIT_R2_ACCESS_KEY: z.string().min(1, "R2 Access Key is required"),
9
- NEXTBLOGKIT_R2_SECRET_KEY: z.string().min(1, "R2 Secret Key is required"),
10
- NEXTBLOGKIT_R2_BUCKET: z.string().min(1, "R2 Bucket name is required"),
11
- NEXTBLOGKIT_R2_PUBLIC_URL: z.string().url("R2 Public URL must be a valid URL"),
12
9
  NEXTBLOGKIT_API_KEY: z.string().min(32, "API key must be at least 32 characters"),
13
- NEXTBLOGKIT_SITE_URL: z.string().url("Site URL must be a valid URL"),
14
- NEXTBLOGKIT_SITE_NAME: z.string().min(1, "Site name is required")
10
+ // Optional — Database name (defaults to the database in your connection URI)
11
+ NEXTBLOGKIT_MONGODB_DB: z.string().optional(),
12
+ // Optional — Cloudflare R2 (image storage)
13
+ NEXTBLOGKIT_R2_ACCOUNT_ID: z.string().optional(),
14
+ NEXTBLOGKIT_R2_ACCESS_KEY: z.string().optional(),
15
+ NEXTBLOGKIT_R2_SECRET_KEY: z.string().optional(),
16
+ NEXTBLOGKIT_R2_BUCKET: z.string().optional(),
17
+ NEXTBLOGKIT_R2_PUBLIC_URL: z.string().optional(),
18
+ // Optional — Site info (defaults provided)
19
+ NEXTBLOGKIT_SITE_URL: z.string().optional().default(""),
20
+ NEXTBLOGKIT_SITE_NAME: z.string().optional().default("Blog")
15
21
  });
16
22
  var cachedEnv = null;
17
23
  function getEnvConfig() {
@@ -25,6 +31,10 @@ ${missing.join("\n")}`);
25
31
  cachedEnv = result.data;
26
32
  return cachedEnv;
27
33
  }
34
+ function isR2Configured() {
35
+ const env = getEnvConfig();
36
+ return !!(env.NEXTBLOGKIT_R2_ACCOUNT_ID && env.NEXTBLOGKIT_R2_ACCESS_KEY && env.NEXTBLOGKIT_R2_SECRET_KEY && env.NEXTBLOGKIT_R2_BUCKET && env.NEXTBLOGKIT_R2_PUBLIC_URL);
37
+ }
28
38
  var defaultConfig = {
29
39
  basePath: "/blog",
30
40
  adminPath: "/admin/blog",
@@ -192,6 +202,8 @@ function extractTextFromBlocks(blocks) {
192
202
  }
193
203
  return parts.join(" ");
194
204
  }
205
+
206
+ // src/lib/db.ts
195
207
  var client = null;
196
208
  var db = null;
197
209
  async function getDb() {
@@ -199,7 +211,7 @@ async function getDb() {
199
211
  const env = getEnvConfig();
200
212
  client = new MongoClient(env.NEXTBLOGKIT_MONGODB_URI);
201
213
  await client.connect();
202
- db = client.db();
214
+ db = client.db(env.NEXTBLOGKIT_MONGODB_DB || void 0);
203
215
  return db;
204
216
  }
205
217
  async function getCollection(name) {
@@ -221,6 +233,9 @@ async function ensureIndexes() {
221
233
  const media = database.collection("nbk_media");
222
234
  await media.createIndex({ createdAt: -1 });
223
235
  await media.createIndex({ r2Key: 1 }, { unique: true });
236
+ const tokens = database.collection("nbk_api_tokens");
237
+ await tokens.createIndex({ tokenHash: 1 }, { unique: true });
238
+ await tokens.createIndex({ createdAt: -1 });
224
239
  }
225
240
  async function createPost(input, defaultAuthor) {
226
241
  const col = await getCollection("nbk_posts");
@@ -304,6 +319,11 @@ async function deletePost(id) {
304
319
  );
305
320
  return result.modifiedCount > 0;
306
321
  }
322
+ async function hardDeletePost(id) {
323
+ const col = await getCollection("nbk_posts");
324
+ const result = await col.deleteOne({ _id: new ObjectId(id) });
325
+ return result.deletedCount > 0;
326
+ }
307
327
  async function getPostBySlug(slug) {
308
328
  const col = await getCollection("nbk_posts");
309
329
  return await col.findOne({ slug });
@@ -392,6 +412,15 @@ async function getCategoryBySlug(slug) {
392
412
  const col = await getCollection("nbk_categories");
393
413
  return await col.findOne({ slug });
394
414
  }
415
+ async function updateCategoryPostCount(categorySlug) {
416
+ const posts = await getCollection("nbk_posts");
417
+ const categories = await getCollection("nbk_categories");
418
+ const count = await posts.countDocuments({
419
+ categories: categorySlug,
420
+ status: "published"
421
+ });
422
+ await categories.updateOne({ slug: categorySlug }, { $set: { postCount: count } });
423
+ }
395
424
  async function createMedia(data) {
396
425
  const col = await getCollection("nbk_media");
397
426
  const result = await col.insertOne(data);
@@ -440,7 +469,45 @@ async function updateSettings(data) {
440
469
  );
441
470
  return getSettings();
442
471
  }
472
+ function hashToken(plain) {
473
+ return createHash("sha256").update(plain).digest("hex");
474
+ }
475
+ async function createApiToken(name) {
476
+ const col = await getCollection("nbk_api_tokens");
477
+ const plainToken = "nbk_" + randomBytes(24).toString("hex");
478
+ const tokenHash = hashToken(plainToken);
479
+ const prefix = plainToken.slice(0, 8);
480
+ const now = /* @__PURE__ */ new Date();
481
+ const doc = {
482
+ name,
483
+ tokenHash,
484
+ prefix,
485
+ createdAt: now
486
+ };
487
+ const result = await col.insertOne(doc);
488
+ const token = { _id: result.insertedId, ...doc };
489
+ return { token, plainToken };
490
+ }
491
+ async function listApiTokens() {
492
+ const col = await getCollection("nbk_api_tokens");
493
+ return await col.find({}, { projection: { tokenHash: 0 } }).sort({ createdAt: -1 }).toArray();
494
+ }
495
+ async function deleteApiToken(id) {
496
+ const col = await getCollection("nbk_api_tokens");
497
+ const result = await col.deleteOne({ _id: new ObjectId(id) });
498
+ return result.deletedCount > 0;
499
+ }
500
+ async function verifyApiToken(plainToken) {
501
+ const col = await getCollection("nbk_api_tokens");
502
+ const tokenHash = hashToken(plainToken);
503
+ const token = await col.findOneAndUpdate(
504
+ { tokenHash },
505
+ { $set: { lastUsedAt: /* @__PURE__ */ new Date() } },
506
+ { returnDocument: "after" }
507
+ );
508
+ return token;
509
+ }
443
510
 
444
- export { calculateReadingTime, countWords, createCategory, createMedia, createPost, defineConfig, deleteCategory, deleteMedia, deletePost, ensureIndexes, ensureUniqueSlug, extractTextFromBlocks, extractTextFromHTML, generateSlug, getBlogConfig, getCategoryBySlug, getCollection, getConfig, getDb, getEnvConfig, getPostById, getPostBySlug, getSettings, listCategories, listMedia, listPosts, updateCategory, updatePost, updateSettings };
445
- //# sourceMappingURL=chunk-64HUVJOZ.js.map
446
- //# sourceMappingURL=chunk-64HUVJOZ.js.map
511
+ export { calculateReadingTime, countWords, createApiToken, createCategory, createMedia, createPost, defineConfig, deleteApiToken, deleteCategory, deleteMedia, deletePost, ensureIndexes, ensureUniqueSlug, extractTextFromBlocks, extractTextFromHTML, generateSlug, getBlogConfig, getCategoryBySlug, getCollection, getConfig, getDb, getEnvConfig, getPostById, getPostBySlug, getSettings, hardDeletePost, isR2Configured, listApiTokens, listCategories, listMedia, listPosts, updateCategory, updateCategoryPostCount, updatePost, updateSettings, verifyApiToken };
512
+ //# sourceMappingURL=chunk-JI2RK6KX.js.map
513
+ //# sourceMappingURL=chunk-JI2RK6KX.js.map
@@ -0,0 +1 @@
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-JI2RK6KX.js","sourcesContent":["import { z } from 'zod';\nimport type { NextBlogKitConfig } from './types';\n\nconst envSchema = z.object({\n // Required\n NEXTBLOGKIT_MONGODB_URI: z.string().min(1, 'MongoDB URI is required'),\n NEXTBLOGKIT_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 NEXTBLOGKIT_MONGODB_DB: z.string().optional(),\n\n // Optional — Cloudflare R2 (image storage)\n NEXTBLOGKIT_R2_ACCOUNT_ID: z.string().optional(),\n NEXTBLOGKIT_R2_ACCESS_KEY: z.string().optional(),\n NEXTBLOGKIT_R2_SECRET_KEY: z.string().optional(),\n NEXTBLOGKIT_R2_BUCKET: z.string().optional(),\n NEXTBLOGKIT_R2_PUBLIC_URL: z.string().optional(),\n\n // Optional — Site info (defaults provided)\n NEXTBLOGKIT_SITE_URL: z.string().optional().default(''),\n NEXTBLOGKIT_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(`NextBlogKit configuration error:\\n${missing.join('\\n')}`);\n }\n\n cachedEnv = result.data;\n return cachedEnv;\n}\n\nexport function isR2Configured(): boolean {\n const env = getEnvConfig();\n return !!(\n env.NEXTBLOGKIT_R2_ACCOUNT_ID &&\n env.NEXTBLOGKIT_R2_ACCESS_KEY &&\n env.NEXTBLOGKIT_R2_SECRET_KEY &&\n env.NEXTBLOGKIT_R2_BUCKET &&\n env.NEXTBLOGKIT_R2_PUBLIC_URL\n );\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 { 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.NEXTBLOGKIT_MONGODB_URI);\n await client.connect();\n db = client.db(env.NEXTBLOGKIT_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({ r2Key: 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\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"]}
@@ -1,12 +1,13 @@
1
- import { getEnvConfig, getCollection } from './chunk-64HUVJOZ.js';
1
+ import { getEnvConfig, getConfig, getCollection } from './chunk-JI2RK6KX.js';
2
2
 
3
3
  // src/lib/rss.ts
4
4
  async function generateRSSFeed(fullContent = false) {
5
5
  const env = getEnvConfig();
6
+ const config = getConfig();
6
7
  const posts = await getCollection("nbk_posts");
7
8
  const publishedPosts = await posts.find({ status: "published" }).sort({ publishedAt: -1 }).limit(50).toArray();
8
9
  const items = publishedPosts.map((post) => {
9
- const postUrl = `${env.NEXTBLOGKIT_SITE_URL}/blog/${post.slug}`;
10
+ const postUrl = `${env.NEXTBLOGKIT_SITE_URL}${config.basePath}/${post.slug}`;
10
11
  const content = fullContent ? post.contentHTML : post.excerpt;
11
12
  const pubDate = post.publishedAt ? new Date(post.publishedAt).toUTCString() : new Date(post.createdAt).toUTCString();
12
13
  let enclosure = "";
@@ -28,7 +29,7 @@ async function generateRSSFeed(fullContent = false) {
28
29
  <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
29
30
  <channel>
30
31
  <title>${escapeXml(env.NEXTBLOGKIT_SITE_NAME)} Blog</title>
31
- <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}/blog</link>
32
+ <link>${escapeXml(env.NEXTBLOGKIT_SITE_URL)}${config.basePath}</link>
32
33
  <description>Latest posts from ${escapeXml(env.NEXTBLOGKIT_SITE_NAME)}</description>
33
34
  <language>en</language>
34
35
  <lastBuildDate>${buildDate}</lastBuildDate>
@@ -42,5 +43,5 @@ function escapeXml(str) {
42
43
  }
43
44
 
44
45
  export { generateRSSFeed };
45
- //# sourceMappingURL=chunk-R6MO3QIP.js.map
46
- //# sourceMappingURL=chunk-R6MO3QIP.js.map
46
+ //# sourceMappingURL=chunk-NSR7NYSB.js.map
47
+ //# sourceMappingURL=chunk-NSR7NYSB.js.map
@@ -0,0 +1 @@
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,SAAS,SAAA,EAAU;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,OAAA,GAAU,GAAG,GAAA,CAAI,oBAAoB,GAAG,MAAA,CAAO,QAAQ,CAAA,CAAA,EAAI,IAAA,CAAK,IAAI,CAAA,CAAA;AAC1E,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,UAAU,GAAA,CAAI,oBAAoB,CAAC,CAAA,EAAG,OAAO,QAAQ,CAAA;AAAA,mCAAA,EAC5B,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-NSR7NYSB.js","sourcesContent":["import { getCollection } from './db';\nimport { getEnvConfig, getConfig } from './config';\n\nexport async function generateRSSFeed(fullContent = false): Promise<string> {\n const env = getEnvConfig();\n const config = getConfig();\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}${config.basePath}/${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)}${config.basePath}</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"]}
@@ -97,7 +97,10 @@ var BlogSettingsSchema = z.object({
97
97
  plausibleDomain: z.string().optional()
98
98
  }).optional()
99
99
  });
100
+ var CreateApiTokenSchema = z.object({
101
+ name: z.string().min(1, "Token name is required").max(100)
102
+ });
100
103
 
101
- export { BlogSettingsSchema, CreateCategorySchema, CreatePostSchema, UpdateCategorySchema, UpdatePostSchema };
102
- //# sourceMappingURL=chunk-4PY224XM.js.map
103
- //# sourceMappingURL=chunk-4PY224XM.js.map
104
+ export { BlogSettingsSchema, CreateApiTokenSchema, CreateCategorySchema, CreatePostSchema, UpdateCategorySchema, UpdatePostSchema };
105
+ //# sourceMappingURL=chunk-O3XES5O2.js.map
106
+ //# sourceMappingURL=chunk-O3XES5O2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/types.ts"],"names":[],"mappings":";;;AAO+B,EAAE,IAAA,CAAK;AAAA,EACpC,WAAA;AAAA,EACA,SAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,YAAA;AAAA,EACA,aAAA;AAAA,EACA,UAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,gBAAA;AAAA,EACA,SAAA;AAAA,EACA,iBAAA;AAAA,EACA,KAAA;AAAA,EACA;AACF,CAAC;AAyB0B,EAAE,MAAA,CAAO;AAAA,EAClC,QAAA,EAAU,EAAE,MAAA,EAAO;AAAA,EACnB,YAAA,EAAc,EAAE,MAAA,EAAO;AAAA,EACvB,QAAA,EAAU,EAAE,MAAA,EAAO;AAAA,EACnB,IAAA,EAAM,EAAE,MAAA,EAAO;AAAA,EACf,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC3B,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC5B,KAAA,EAAO,EAAE,MAAA,EAAO;AAAA,EAChB,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,EACpB,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,SAAA,EAAW,EAAE,IAAA;AACf,CAAC;AAqBM,IAAM,YAAA,GAAe,EAAE,MAAA,CAAO;AAAA,EACnC,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,IAAI,CAAC,CAAA;AAAA,EACtB,QAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EAClC,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACzB,KAAK,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA;AACxB,CAAC,CAAA;AAaM,IAAM,aAAA,GAAgB,EAAE,MAAA,CAAO;AAAA,EACpC,SAAA,EAAW,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,eAAA,EAAiB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACrC,cAAc,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACxC,SAAS,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EACnC,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,SAAS,CAAA;AAAA,EACpC,OAAA,EAAS,CAAA,CAAE,OAAA,EAAQ,CAAE,QAAQ,KAAK,CAAA;AAAA,EAClC,gBAAgB,CAAA,CAAE,MAAA,CAAO,EAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EAC/C,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAC3B,CAAC,CAAA;AA6BM,IAAM,gBAAA,GAAmB,EAAE,IAAA,CAAK,CAAC,SAAS,WAAA,EAAa,WAAA,EAAa,UAAU,CAAC,CAAA;AAG/E,IAAM,gBAAA,GAAmB,EAAE,MAAA,CAAO;AAAA,EACvC,OAAO,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,mBAAmB,CAAA;AAAA,EAC5C,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC7B,OAAA,EAAS,EAAE,GAAA,EAAI;AAAA;AAAA,EACf,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,UAAA,EAAY,EACT,MAAA,CAAO;AAAA,IACN,GAAA,EAAK,EAAE,MAAA,EAAO;AAAA,IACd,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,EAAI;AAAA,IACpB,GAAA,EAAK,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IACzB,OAAA,EAAS,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC7B,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC3B,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GAC7B,EACA,QAAA,EAAS;AAAA,EACZ,UAAA,EAAY,EAAE,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EAC1C,IAAA,EAAM,EAAE,KAAA,CAAM,CAAA,CAAE,QAAQ,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACpC,MAAA,EAAQ,aAAa,QAAA,EAAS;AAAA,EAC9B,GAAA,EAAK,cAAc,QAAA,EAAS;AAAA,EAC5B,MAAA,EAAQ,gBAAA,CAAiB,OAAA,CAAQ,OAAO,CAAA;AAAA,EACxC,WAAA,EAAa,CAAA,CAAE,MAAA,CAAO,IAAA,GAAO,QAAA,EAAS;AAAA,EACtC,WAAA,EAAa,CAAA,CAAE,MAAA,CAAO,IAAA,GAAO,QAAA;AAC/B,CAAC;AAEM,IAAM,gBAAA,GAAmB,iBAAiB,OAAA;AAiC1C,IAAM,oBAAA,GAAuB,EAAE,MAAA,CAAO;AAAA,EAC3C,MAAM,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,GAAG,2BAA2B,CAAA;AAAA,EACnD,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC1B,WAAA,EAAa,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EACjC,GAAA,EAAK,EACF,MAAA,CAAO;AAAA,IACN,SAAA,EAAW,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC/B,eAAA,EAAiB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GACtC,EACA,QAAA,EAAS;AAAA,EACZ,KAAA,EAAO,CAAA,CAAE,MAAA,EAAO,CAAE,QAAQ,CAAC,CAAA;AAAA,EAC3B,QAAA,EAAU,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AACvB,CAAC;AAEM,IAAM,oBAAA,GAAuB,qBAAqB,OAAA;AAuBlD,IAAM,kBAAA,GAAqB,EAAE,MAAA,CAAO;AAAA,EACzC,YAAA,EAAc,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,CAAI,CAAC,CAAA,CAAE,GAAA,CAAI,GAAG,CAAA,CAAE,OAAA,CAAQ,EAAE,CAAA;AAAA,EACnD,aAAA,EAAe,aAAa,QAAA,EAAS;AAAA,EACrC,gBAAgB,CAAA,CAAE,MAAA,EAAO,CAAE,GAAA,GAAM,QAAA,EAAS;AAAA,EAC1C,aAAA,EAAe,CAAA,CAAE,IAAA,CAAK,CAAC,MAAA,EAAQ,UAAU,QAAQ,CAAC,CAAA,CAAE,OAAA,CAAQ,MAAM,CAAA;AAAA,EAClE,eAAe,CAAA,CAAE,MAAA,CAAO,EAAE,OAAA,EAAS,EAAE,QAAA,EAAS;AAAA,EAC9C,SAAA,EAAW,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,EAC/B,SAAA,EAAW,EACR,MAAA,CAAO;AAAA,IACN,IAAA,EAAM,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA,EAAS;AAAA,IAC1B,eAAA,EAAiB,CAAA,CAAE,MAAA,EAAO,CAAE,QAAA;AAAS,GACtC,EACA,QAAA;AACL,CAAC;AAoBM,IAAM,oBAAA,GAAuB,EAAE,MAAA,CAAO;AAAA,EAC3C,IAAA,EAAM,EAAE,MAAA,EAAO,CAAE,IAAI,CAAA,EAAG,wBAAwB,CAAA,CAAE,GAAA,CAAI,GAAG;AAC3D,CAAC","file":"chunk-O3XES5O2.js","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 Tokens\n// ============================================================\n\nexport const CreateApiTokenSchema = z.object({\n name: z.string().min(1, 'Token name is required').max(100),\n});\n\nexport interface ApiToken {\n _id: ObjectId;\n name: string;\n tokenHash: string;\n prefix: string;\n lastUsedAt?: Date;\n createdAt: Date;\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"]}