@jhits/plugin-blog 0.0.19 → 0.0.20

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 (291) hide show
  1. package/dist/api/categories.d.ts.map +1 -1
  2. package/dist/api/categories.js +42 -38
  3. package/dist/api/handler.d.ts +1 -26
  4. package/dist/api/handler.d.ts.map +1 -1
  5. package/dist/api/handler.js +81 -490
  6. package/dist/api/router.d.ts +0 -5
  7. package/dist/api/router.d.ts.map +1 -1
  8. package/dist/api/router.js +8 -35
  9. package/dist/api/service.d.ts +80 -0
  10. package/dist/api/service.d.ts.map +1 -0
  11. package/dist/api/service.js +219 -0
  12. package/dist/hooks/useAutoSave.d.ts +10 -0
  13. package/dist/hooks/useAutoSave.d.ts.map +1 -0
  14. package/dist/hooks/useAutoSave.js +57 -0
  15. package/dist/hooks/useCategories.d.ts +1 -1
  16. package/dist/hooks/useCategories.d.ts.map +1 -1
  17. package/dist/hooks/useCategories.js +15 -46
  18. package/dist/index.d.ts +24 -31
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +44 -201
  21. package/dist/init.d.ts +20 -7
  22. package/dist/init.d.ts.map +1 -1
  23. package/dist/init.js +8 -7
  24. package/dist/lib/blocks/BlockRenderer.d.ts.map +1 -1
  25. package/dist/lib/layouts/blocks/ColumnsBlock.d.ts.map +1 -1
  26. package/dist/lib/layouts/blocks/ColumnsBlock.js +30 -113
  27. package/dist/lib/layouts/blocks/SectionBlock.d.ts.map +1 -1
  28. package/dist/lib/layouts/blocks/SectionBlock.js +9 -21
  29. package/dist/lib/layouts/index.d.ts +3 -3
  30. package/dist/lib/layouts/index.js +4 -4
  31. package/dist/lib/mappers/apiMapper.d.ts +10 -0
  32. package/dist/lib/mappers/apiMapper.d.ts.map +1 -1
  33. package/dist/lib/mappers/apiMapper.js +47 -32
  34. package/dist/lib/rich-text/RichTextEditor.d.ts +4 -2
  35. package/dist/lib/rich-text/RichTextEditor.d.ts.map +1 -1
  36. package/dist/lib/rich-text/RichTextEditor.js +12 -9
  37. package/dist/lib/utils/config-resolver.d.ts +28 -0
  38. package/dist/lib/utils/config-resolver.d.ts.map +1 -0
  39. package/dist/lib/utils/config-resolver.js +46 -0
  40. package/dist/lib/utils/tree.d.ts +29 -0
  41. package/dist/lib/utils/tree.d.ts.map +1 -0
  42. package/dist/lib/utils/tree.js +129 -0
  43. package/dist/state/EditorContext.d.ts +3 -25
  44. package/dist/state/EditorContext.d.ts.map +1 -1
  45. package/dist/state/EditorContext.js +124 -174
  46. package/dist/state/reducer.d.ts +1 -5
  47. package/dist/state/reducer.d.ts.map +1 -1
  48. package/dist/state/reducer.js +128 -521
  49. package/dist/state/types.d.ts +12 -1
  50. package/dist/state/types.d.ts.map +1 -1
  51. package/dist/types/block.d.ts +9 -0
  52. package/dist/types/block.d.ts.map +1 -1
  53. package/dist/types/post.d.ts +17 -1
  54. package/dist/types/post.d.ts.map +1 -1
  55. package/dist/views/CanvasEditor/BlockWrapper.d.ts +5 -6
  56. package/dist/views/CanvasEditor/BlockWrapper.d.ts.map +1 -1
  57. package/dist/views/CanvasEditor/BlockWrapper.js +56 -264
  58. package/dist/views/CanvasEditor/CanvasEditorView.d.ts +5 -3
  59. package/dist/views/CanvasEditor/CanvasEditorView.d.ts.map +1 -1
  60. package/dist/views/CanvasEditor/CanvasEditorView.js +55 -315
  61. package/dist/views/CanvasEditor/EditorBody.d.ts +6 -8
  62. package/dist/views/CanvasEditor/EditorBody.d.ts.map +1 -1
  63. package/dist/views/CanvasEditor/EditorBody.js +34 -482
  64. package/dist/views/CanvasEditor/EditorHeader.d.ts.map +1 -1
  65. package/dist/views/CanvasEditor/EditorHeader.js +27 -63
  66. package/dist/views/CanvasEditor/LayoutContainer.d.ts.map +1 -1
  67. package/dist/views/CanvasEditor/LayoutContainer.js +49 -70
  68. package/dist/views/CanvasEditor/components/CustomBlockItem.js +1 -1
  69. package/dist/views/CanvasEditor/components/EditorCanvas.d.ts +15 -3
  70. package/dist/views/CanvasEditor/components/EditorCanvas.d.ts.map +1 -1
  71. package/dist/views/CanvasEditor/components/EditorCanvas.js +40 -18
  72. package/dist/views/CanvasEditor/components/EditorLibrary.d.ts +5 -1
  73. package/dist/views/CanvasEditor/components/EditorLibrary.d.ts.map +1 -1
  74. package/dist/views/CanvasEditor/components/EditorLibrary.js +11 -7
  75. package/dist/views/CanvasEditor/components/EditorSidebar.d.ts.map +1 -1
  76. package/dist/views/CanvasEditor/components/EditorSidebar.js +32 -14
  77. package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -6
  78. package/dist/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +1 -1
  79. package/dist/views/CanvasEditor/components/FeaturedMediaSection.js +17 -128
  80. package/dist/views/CanvasEditor/components/JSONInspector.d.ts +9 -0
  81. package/dist/views/CanvasEditor/components/JSONInspector.d.ts.map +1 -0
  82. package/dist/views/CanvasEditor/components/JSONInspector.js +56 -0
  83. package/dist/views/CanvasEditor/components/LibraryItem.js +2 -2
  84. package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -4
  85. package/dist/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +1 -1
  86. package/dist/views/CanvasEditor/components/PrivacySettingsSection.js +6 -28
  87. package/dist/views/CanvasEditor/components/index.d.ts +2 -0
  88. package/dist/views/CanvasEditor/components/index.d.ts.map +1 -1
  89. package/dist/views/CanvasEditor/components/index.js +1 -0
  90. package/dist/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +1 -1
  91. package/dist/views/CanvasEditor/hooks/useHeroBlock.js +15 -18
  92. package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts +3 -0
  93. package/dist/views/CanvasEditor/hooks/usePostLoader.d.ts.map +1 -1
  94. package/dist/views/CanvasEditor/hooks/usePostLoader.js +12 -13
  95. package/dist/views/CanvasEditor/hooks/useUnsavedChanges.js +0 -4
  96. package/dist/views/PostManager/EmptyState.d.ts +1 -1
  97. package/dist/views/PostManager/EmptyState.js +4 -4
  98. package/dist/views/PostManager/FilterDropdown.d.ts +21 -0
  99. package/dist/views/PostManager/FilterDropdown.d.ts.map +1 -0
  100. package/dist/views/PostManager/FilterDropdown.js +28 -0
  101. package/dist/views/PostManager/LanguageFlags.d.ts.map +1 -1
  102. package/dist/views/PostManager/LanguageFlags.js +4 -1
  103. package/dist/views/PostManager/PostCards.d.ts.map +1 -1
  104. package/dist/views/PostManager/PostCards.js +23 -40
  105. package/dist/views/PostManager/PostFilters.d.ts.map +1 -1
  106. package/dist/views/PostManager/PostFilters.js +34 -3
  107. package/dist/views/PostManager/PostManagerView.d.ts +1 -2
  108. package/dist/views/PostManager/PostManagerView.d.ts.map +1 -1
  109. package/dist/views/PostManager/PostManagerView.js +30 -96
  110. package/dist/views/PostManager/PostStats.d.ts.map +1 -1
  111. package/dist/views/PostManager/PostStats.js +10 -10
  112. package/dist/views/PostManager/PostTable.d.ts.map +1 -1
  113. package/dist/views/PostManager/PostTable.js +23 -40
  114. package/dist/views/Settings/SettingsView.d.ts +1 -1
  115. package/dist/views/Settings/SettingsView.d.ts.map +1 -1
  116. package/dist/views/Settings/SettingsView.js +12 -39
  117. package/dist/views/SlugSEO/SlugSEOManagerView.d.ts.map +1 -1
  118. package/dist/views/SlugSEO/SlugSEOManagerView.js +2 -2
  119. package/package.json +42 -6
  120. package/src/api/categories.ts +48 -52
  121. package/src/api/handler.ts +87 -594
  122. package/src/api/router.ts +15 -65
  123. package/src/api/service.ts +241 -0
  124. package/src/hooks/useAutoSave.ts +64 -0
  125. package/src/hooks/useCategories.ts +19 -47
  126. package/src/index.tsx +79 -293
  127. package/src/init.tsx +24 -11
  128. package/src/lib/blocks/BlockRenderer.tsx +1 -0
  129. package/src/lib/layouts/blocks/ColumnsBlock.tsx +60 -173
  130. package/src/lib/layouts/blocks/SectionBlock.tsx +22 -26
  131. package/src/lib/layouts/index.ts +4 -4
  132. package/src/lib/mappers/apiMapper.ts +63 -32
  133. package/src/lib/rich-text/RichTextEditor.tsx +16 -9
  134. package/src/lib/utils/config-resolver.ts +64 -0
  135. package/src/lib/utils/tree.ts +150 -0
  136. package/src/state/EditorContext.tsx +153 -232
  137. package/src/state/reducer.ts +141 -606
  138. package/src/state/types.ts +14 -1
  139. package/src/types/block.ts +10 -0
  140. package/src/types/post.ts +19 -1
  141. package/src/views/CanvasEditor/BlockWrapper.tsx +130 -460
  142. package/src/views/CanvasEditor/CanvasEditorView.tsx +145 -420
  143. package/src/views/CanvasEditor/EditorBody.tsx +98 -610
  144. package/src/views/CanvasEditor/EditorHeader.tsx +176 -196
  145. package/src/views/CanvasEditor/LayoutContainer.tsx +74 -89
  146. package/src/views/CanvasEditor/components/CustomBlockItem.tsx +7 -8
  147. package/src/views/CanvasEditor/components/EditorCanvas.tsx +139 -84
  148. package/src/views/CanvasEditor/components/EditorLibrary.tsx +25 -10
  149. package/src/views/CanvasEditor/components/EditorSidebar.tsx +196 -127
  150. package/src/views/CanvasEditor/components/FeaturedMediaSection.tsx +78 -210
  151. package/src/views/CanvasEditor/components/JSONInspector.tsx +125 -0
  152. package/src/views/CanvasEditor/components/LibraryItem.tsx +5 -6
  153. package/src/views/CanvasEditor/components/PrivacySettingsSection.tsx +73 -124
  154. package/src/views/CanvasEditor/components/index.ts +2 -1
  155. package/src/views/CanvasEditor/hooks/useHeroBlock.ts +15 -18
  156. package/src/views/CanvasEditor/hooks/usePostLoader.ts +21 -13
  157. package/src/views/CanvasEditor/hooks/useUnsavedChanges.ts +4 -4
  158. package/src/views/PostManager/EmptyState.tsx +9 -10
  159. package/src/views/PostManager/FilterDropdown.tsx +95 -0
  160. package/src/views/PostManager/LanguageFlags.tsx +6 -2
  161. package/src/views/PostManager/PostCards.tsx +127 -133
  162. package/src/views/PostManager/PostFilters.tsx +73 -68
  163. package/src/views/PostManager/PostManagerView.tsx +132 -179
  164. package/src/views/PostManager/PostStats.tsx +21 -20
  165. package/src/views/PostManager/PostTable.tsx +137 -165
  166. package/src/views/Settings/SettingsView.tsx +64 -180
  167. package/src/views/SlugSEO/SlugSEOManagerView.tsx +59 -44
  168. package/src/hooks/index.d.ts +0 -8
  169. package/src/hooks/index.d.ts.map +0 -1
  170. package/src/hooks/useBlog.d.ts +0 -31
  171. package/src/hooks/useBlog.d.ts.map +0 -1
  172. package/src/hooks/useBlogs.d.ts +0 -39
  173. package/src/hooks/useBlogs.d.ts.map +0 -1
  174. package/src/hooks/useCategories.d.ts +0 -9
  175. package/src/hooks/useCategories.d.ts.map +0 -1
  176. package/src/lib/blocks/BlockRenderer.d.ts +0 -54
  177. package/src/lib/blocks/BlockRenderer.d.ts.map +0 -1
  178. package/src/lib/config-storage.d.ts +0 -30
  179. package/src/lib/config-storage.d.ts.map +0 -1
  180. package/src/lib/layouts/blocks/ColumnsBlock.d.ts +0 -25
  181. package/src/lib/layouts/blocks/ColumnsBlock.d.ts.map +0 -1
  182. package/src/lib/layouts/blocks/SectionBlock.d.ts +0 -25
  183. package/src/lib/layouts/blocks/SectionBlock.d.ts.map +0 -1
  184. package/src/lib/layouts/index.d.ts +0 -23
  185. package/src/lib/layouts/index.d.ts.map +0 -1
  186. package/src/lib/layouts/registerLayoutBlocks.d.ts +0 -9
  187. package/src/lib/layouts/registerLayoutBlocks.d.ts.map +0 -1
  188. package/src/lib/mappers/apiMapper.d.ts +0 -66
  189. package/src/lib/mappers/apiMapper.d.ts.map +0 -1
  190. package/src/lib/rich-text/RichTextEditor.d.ts +0 -45
  191. package/src/lib/rich-text/RichTextEditor.d.ts.map +0 -1
  192. package/src/lib/rich-text/RichTextPreview.d.ts +0 -16
  193. package/src/lib/rich-text/RichTextPreview.d.ts.map +0 -1
  194. package/src/lib/rich-text/index.d.ts +0 -9
  195. package/src/lib/rich-text/index.d.ts.map +0 -1
  196. package/src/lib/utils/blockHelpers.d.ts +0 -23
  197. package/src/lib/utils/blockHelpers.d.ts.map +0 -1
  198. package/src/lib/utils/configValidation.d.ts +0 -23
  199. package/src/lib/utils/configValidation.d.ts.map +0 -1
  200. package/src/registry/BlockRegistry.d.ts +0 -62
  201. package/src/registry/BlockRegistry.d.ts.map +0 -1
  202. package/src/registry/index.d.ts +0 -6
  203. package/src/registry/index.d.ts.map +0 -1
  204. package/src/state/EditorContext.d.ts +0 -45
  205. package/src/state/EditorContext.d.ts.map +0 -1
  206. package/src/state/index.d.ts +0 -7
  207. package/src/state/index.d.ts.map +0 -1
  208. package/src/state/reducer.d.ts +0 -11
  209. package/src/state/reducer.d.ts.map +0 -1
  210. package/src/state/types.d.ts +0 -162
  211. package/src/state/types.d.ts.map +0 -1
  212. package/src/types/block.d.ts +0 -221
  213. package/src/types/block.d.ts.map +0 -1
  214. package/src/types/index.d.ts +0 -8
  215. package/src/types/index.d.ts.map +0 -1
  216. package/src/types/post.d.ts +0 -136
  217. package/src/types/post.d.ts.map +0 -1
  218. package/src/utils/client.d.ts +0 -48
  219. package/src/utils/client.d.ts.map +0 -1
  220. package/src/views/CanvasEditor/BlockWrapper.d.ts +0 -16
  221. package/src/views/CanvasEditor/BlockWrapper.d.ts.map +0 -1
  222. package/src/views/CanvasEditor/CanvasEditorView.d.ts +0 -14
  223. package/src/views/CanvasEditor/CanvasEditorView.d.ts.map +0 -1
  224. package/src/views/CanvasEditor/EditorBody.d.ts +0 -22
  225. package/src/views/CanvasEditor/EditorBody.d.ts.map +0 -1
  226. package/src/views/CanvasEditor/EditorHeader.d.ts +0 -18
  227. package/src/views/CanvasEditor/EditorHeader.d.ts.map +0 -1
  228. package/src/views/CanvasEditor/LayoutContainer.d.ts +0 -17
  229. package/src/views/CanvasEditor/LayoutContainer.d.ts.map +0 -1
  230. package/src/views/CanvasEditor/SaveConfirmationModal.d.ts +0 -13
  231. package/src/views/CanvasEditor/SaveConfirmationModal.d.ts.map +0 -1
  232. package/src/views/CanvasEditor/components/CustomBlockItem.d.ts +0 -14
  233. package/src/views/CanvasEditor/components/CustomBlockItem.d.ts.map +0 -1
  234. package/src/views/CanvasEditor/components/EditorCanvas.d.ts +0 -29
  235. package/src/views/CanvasEditor/components/EditorCanvas.d.ts.map +0 -1
  236. package/src/views/CanvasEditor/components/EditorLibrary.d.ts +0 -7
  237. package/src/views/CanvasEditor/components/EditorLibrary.d.ts.map +0 -1
  238. package/src/views/CanvasEditor/components/EditorSidebar.d.ts +0 -13
  239. package/src/views/CanvasEditor/components/EditorSidebar.d.ts.map +0 -1
  240. package/src/views/CanvasEditor/components/ErrorBanner.d.ts +0 -6
  241. package/src/views/CanvasEditor/components/ErrorBanner.d.ts.map +0 -1
  242. package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts +0 -25
  243. package/src/views/CanvasEditor/components/FeaturedMediaSection.d.ts.map +0 -1
  244. package/src/views/CanvasEditor/components/LibraryItem.d.ts +0 -14
  245. package/src/views/CanvasEditor/components/LibraryItem.d.ts.map +0 -1
  246. package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts +0 -15
  247. package/src/views/CanvasEditor/components/PrivacySettingsSection.d.ts.map +0 -1
  248. package/src/views/CanvasEditor/components/index.d.ts +0 -21
  249. package/src/views/CanvasEditor/components/index.d.ts.map +0 -1
  250. package/src/views/CanvasEditor/hooks/index.d.ts +0 -10
  251. package/src/views/CanvasEditor/hooks/index.d.ts.map +0 -1
  252. package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts +0 -8
  253. package/src/views/CanvasEditor/hooks/useHeroBlock.d.ts.map +0 -1
  254. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts +0 -3
  255. package/src/views/CanvasEditor/hooks/useKeyboardShortcuts.d.ts.map +0 -1
  256. package/src/views/CanvasEditor/hooks/usePostLoader.d.ts +0 -5
  257. package/src/views/CanvasEditor/hooks/usePostLoader.d.ts.map +0 -1
  258. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts +0 -2
  259. package/src/views/CanvasEditor/hooks/useRegisteredBlocks.d.ts.map +0 -1
  260. package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts +0 -25
  261. package/src/views/CanvasEditor/hooks/useUnsavedChanges.d.ts.map +0 -1
  262. package/src/views/CanvasEditor/index.d.ts +0 -16
  263. package/src/views/CanvasEditor/index.d.ts.map +0 -1
  264. package/src/views/PostManager/EmptyState.d.ts +0 -10
  265. package/src/views/PostManager/EmptyState.d.ts.map +0 -1
  266. package/src/views/PostManager/PostActionsMenu.d.ts +0 -12
  267. package/src/views/PostManager/PostActionsMenu.d.ts.map +0 -1
  268. package/src/views/PostManager/PostCards.d.ts +0 -15
  269. package/src/views/PostManager/PostCards.d.ts.map +0 -1
  270. package/src/views/PostManager/PostFilters.d.ts +0 -16
  271. package/src/views/PostManager/PostFilters.d.ts.map +0 -1
  272. package/src/views/PostManager/PostManagerView.d.ts +0 -11
  273. package/src/views/PostManager/PostManagerView.d.ts.map +0 -1
  274. package/src/views/PostManager/PostStats.d.ts +0 -11
  275. package/src/views/PostManager/PostStats.d.ts.map +0 -1
  276. package/src/views/PostManager/PostTable.d.ts +0 -15
  277. package/src/views/PostManager/PostTable.d.ts.map +0 -1
  278. package/src/views/PostManager/index.d.ts +0 -12
  279. package/src/views/PostManager/index.d.ts.map +0 -1
  280. package/src/views/Preview/PreviewBridgeView.d.ts +0 -12
  281. package/src/views/Preview/PreviewBridgeView.d.ts.map +0 -1
  282. package/src/views/Preview/index.d.ts +0 -6
  283. package/src/views/Preview/index.d.ts.map +0 -1
  284. package/src/views/Settings/SettingsView.d.ts +0 -10
  285. package/src/views/Settings/SettingsView.d.ts.map +0 -1
  286. package/src/views/Settings/index.d.ts +0 -6
  287. package/src/views/Settings/index.d.ts.map +0 -1
  288. package/src/views/SlugSEO/SlugSEOManagerView.d.ts +0 -12
  289. package/src/views/SlugSEO/SlugSEOManagerView.d.ts.map +0 -1
  290. package/src/views/SlugSEO/index.d.ts +0 -6
  291. package/src/views/SlugSEO/index.d.ts.map +0 -1
@@ -1,548 +1,139 @@
1
1
  /**
2
2
  * Blog API Handler
3
- * RESTful API handler for blog posts
4
- * Compatible with Next.js API routes
5
- *
6
- * IMPORTANT: This file should ONLY be imported in server-side API routes.
7
- * Do NOT import this in client-side code.
3
+ * Simplified RESTful API handler using BlogService
8
4
  */
9
5
  import { NextResponse } from 'next/server';
6
+ import { BlogService } from './service';
10
7
  import { slugify } from '../lib/utils/slugify';
11
8
  /**
12
- * GET /api/blogs - List all blog posts
13
- * GET /api/blogs?admin=true - List all posts for admin (includes drafts)
14
- * GET /api/blogs?status=published - Filter by status
15
- * GET /api/blogs?language=en - Filter by language (falls back to nl if not found)
9
+ * Generic helper to find a blog post by slug across all languages
10
+ * Avoids hardcoding language codes
16
11
  */
12
+ async function findPostBySlug(collection, slug) {
13
+ // 1. Try root slug (fastest, indexed)
14
+ const rootMatch = await collection.findOne({ slug });
15
+ if (rootMatch)
16
+ return rootMatch;
17
+ // 2. Generic search across all localized slugs using aggregation
18
+ // This works for ANY language key (nl, en, sv, de, fr, es, etc.)
19
+ const results = await collection.aggregate([
20
+ // Convert the 'languages' object into an array of { k, v } entries
21
+ { $addFields: { _langEntries: { $objectToArray: { $ifNull: ["$languages", {}] } } } },
22
+ // Match if any entry's slug matches our target
23
+ { $match: { "_langEntries.v.metadata.slug": slug } },
24
+ // Remove the temporary field
25
+ { $project: { _langEntries: 0 } },
26
+ { $limit: 1 }
27
+ ]).toArray();
28
+ return results[0] || null;
29
+ }
17
30
  export async function GET(req, config) {
18
31
  try {
19
32
  const url = new URL(req.url);
20
- const limit = Number(url.searchParams.get('limit') ?? 10);
21
- const skip = Number(url.searchParams.get('skip') ?? 0);
22
- const statusFilter = url.searchParams.get('status');
23
- const isAdminView = url.searchParams.get('admin') === 'true';
24
- const requestedLanguage = url.searchParams.get('language') || 'nl';
25
- const userId = await config.getUserId(req);
26
- const dbConnection = await config.getDb();
27
- const db = dbConnection.db();
28
- const blogs = db.collection(config.collectionName || 'blogs');
29
- // Build query
30
- let query = {};
31
- if (isAdminView && userId) {
32
- // Admin view: show all posts owned by user
33
- if (statusFilter) {
34
- query = {
35
- 'publicationData.status': statusFilter,
36
- authorId: userId,
37
- };
38
- }
39
- else {
40
- query = { authorId: userId };
41
- }
42
- }
43
- else {
44
- // Public view: only published posts in the SPECIFIC language
45
- // This ensures we only fetch blogs that actually have content for this language
46
- query = {
47
- [`languages.${requestedLanguage}.status`]: 'published',
48
- 'publicationData.date': { $lte: new Date() },
49
- };
50
- if (statusFilter && statusFilter !== 'published') {
51
- // Non-admin can't filter by non-published status
52
- return NextResponse.json({ error: 'Invalid status filter' }, { status: 400 });
53
- }
54
- }
55
- const [data, totalCount] = await Promise.all([
56
- blogs
57
- .find(query)
58
- .sort({ 'publicationData.date': -1 })
59
- .skip(skip)
60
- .limit(isAdminView ? 0 : limit)
61
- .toArray(),
62
- blogs.countDocuments(query),
63
- ]);
64
- // Supported languages for fallback (in order of preference)
65
- const fallbackLanguages = [requestedLanguage, 'nl', 'en'];
66
- const formatted = data.map((doc) => {
67
- const languages = doc.languages || {};
68
- // Only use exact language match public views - no fallback for
69
- // This ensures visitors see content in their language only
70
- const hasExactLanguage = !!languages[requestedLanguage];
71
- // Skip this post if no exact language match (for public non-admin views)
72
- if (!isAdminView && !hasExactLanguage) {
73
- return null;
74
- }
75
- const postPrimaryLang = doc.metadata?.lang || 'nl';
76
- // Find the best available language for this post
77
- let bestLanguage = requestedLanguage;
78
- let isMissingTranslation = false;
79
- if (!languages[requestedLanguage]) {
80
- // For admin view, if specific language is requested, show it as missing instead of falling back
81
- // This ensures the UI is "synced" with the selected language
82
- if (isAdminView) {
83
- isMissingTranslation = true;
84
- }
85
- else {
86
- // Public view still uses fallback or filtering
87
- const fallbackLanguages = [postPrimaryLang, 'nl', 'en'];
88
- for (const lang of fallbackLanguages) {
89
- if (languages[lang]) {
90
- bestLanguage = lang;
91
- break;
92
- }
93
- }
94
- }
95
- }
96
- const langContent = languages[bestLanguage] || {};
97
- const meta = langContent.metadata || {};
98
- // Ensure all languages in doc have a status and updatedAt for the dashboard
99
- const enrichedLanguages = { ...languages };
100
- Object.keys(enrichedLanguages).forEach(lang => {
101
- if (!enrichedLanguages[lang].status) {
102
- enrichedLanguages[lang].status = doc.publicationData?.status === 'concept' ? 'draft' : (doc.publicationData?.status || 'draft');
103
- }
104
- if (!enrichedLanguages[lang].updatedAt) {
105
- enrichedLanguages[lang].updatedAt = doc.updatedAt;
106
- }
107
- });
108
- // Language display names for placeholders
109
- const langNames = {
110
- nl: 'Dutch',
111
- en: 'English',
112
- sv: 'Swedish',
113
- de: 'German',
114
- fr: 'French',
115
- es: 'Spanish'
116
- };
117
- const displayTitle = isMissingTranslation
118
- ? `(No ${langNames[requestedLanguage] || requestedLanguage.toUpperCase()} translation)`
119
- : (meta.title || doc.title || '');
120
- const displayStatus = isMissingTranslation
121
- ? 'not-translated'
122
- : (langContent.status || doc.publicationData?.status || 'concept');
123
- return {
124
- ...doc,
125
- _id: doc._id.toString(),
126
- title: displayTitle,
127
- summary: isMissingTranslation ? '' : (meta.excerpt || doc.summary || ''),
128
- contentBlocks: isMissingTranslation ? [] : (langContent.blocks || doc.contentBlocks || doc.blocks || []),
129
- image: isMissingTranslation ? null : (meta.featuredImage || doc.image),
130
- categoryTags: isMissingTranslation ? { category: '', tags: [] } : (meta.categories ? {
131
- category: meta.categories[0] || '',
132
- tags: meta.tags || doc.categoryTags?.tags || []
133
- } : (doc.categoryTags || { category: '', tags: [] })),
134
- publicationData: {
135
- ...doc.publicationData,
136
- status: displayStatus,
137
- },
138
- seo: isMissingTranslation ? {} : (meta.seo || doc.seo || {}),
139
- lang: bestLanguage,
140
- isMissingTranslation,
141
- requestedLanguage,
142
- availableLanguages: Object.keys(languages),
143
- languages: enrichedLanguages,
144
- updatedAt: isMissingTranslation ? doc.updatedAt : (langContent.updatedAt || doc.updatedAt),
145
- status: displayStatus,
146
- };
147
- }).filter(Boolean); // Remove null entries
148
- // Sort by updatedAt descending so the UI order makes sense
149
- formatted.sort((a, b) => {
150
- const dateA = new Date(a.updatedAt).getTime();
151
- const dateB = new Date(b.updatedAt).getTime();
152
- return dateB - dateA;
153
- });
154
- return NextResponse.json({
155
- blogs: formatted,
156
- total: formatted.length,
33
+ const service = new BlogService(config);
34
+ const results = await service.listBlogs({
35
+ limit: Number(url.searchParams.get('limit') ?? 10),
36
+ skip: Number(url.searchParams.get('skip') ?? 0),
37
+ status: url.searchParams.get('status') || undefined,
38
+ isAdmin: url.searchParams.get('admin') === 'true',
39
+ userId: await config.getUserId(req),
40
+ requestedLanguage: url.searchParams.get('language') || 'nl',
157
41
  });
42
+ return NextResponse.json(results);
158
43
  }
159
44
  catch (err) {
160
- console.error('[BlogAPI] GET error:', err);
161
- return NextResponse.json({ error: 'Failed to fetch blogs', detail: err.message }, { status: 500 });
45
+ return NextResponse.json({ error: 'Fetch failed', detail: err.message }, { status: 500 });
162
46
  }
163
47
  }
164
- /**
165
- * POST /api/blogs - Create new blog post
166
- */
167
48
  export async function POST(req, config) {
168
49
  try {
169
50
  const url = new URL(req.url);
170
51
  const language = url.searchParams.get('language') || 'nl';
171
52
  const userId = await config.getUserId(req);
172
- if (!userId) {
53
+ if (!userId)
173
54
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
174
- }
175
55
  const body = await req.json();
176
- const { title, summary, content, contentBlocks, image, categoryTags, publicationData, seo, } = body;
177
- const isPublishing = publicationData?.status === 'published';
178
- const isConcept = publicationData?.status === 'concept' || publicationData?.status === 'draft';
179
- // Validation
180
- const errors = [];
181
- if (!title?.trim()) {
182
- errors.push('Title is required');
183
- }
184
- if (isPublishing) {
185
- // Publishing requires all fields
186
- if (!summary?.trim())
187
- errors.push('Summary is required for publishing');
188
- if (!image?.id?.trim())
189
- errors.push('Featured image is required for publishing');
190
- // Only require category if it's explicitly provided and empty
191
- // If categoryTags is undefined or category is undefined, that's also missing
192
- if (!categoryTags || !categoryTags.category || !categoryTags.category.trim()) {
193
- errors.push('Category is required for publishing');
194
- }
195
- const hasContent = (contentBlocks && Array.isArray(contentBlocks) && contentBlocks.length > 0) ||
196
- (content && Array.isArray(content) && content.length > 0);
197
- if (!hasContent) {
198
- errors.push('Content is required for publishing');
199
- }
200
- if (!publicationData?.date)
201
- errors.push('Publication date is required');
202
- }
203
- if (errors.length > 0) {
204
- return NextResponse.json({ message: errors[0], allErrors: errors }, { status: 400 });
205
- }
206
- // Create slug
207
- let baseSlug = slugify(title);
208
- const slug = isPublishing
209
- ? baseSlug
210
- : `${baseSlug}-draft-${Date.now().toString().slice(-4)}`;
211
- const dbConnection = await config.getDb();
212
- const db = dbConnection.db();
213
- const blogs = db.collection(config.collectionName || 'blogs');
214
- // Determine the final status: if publishing, set to 'published', otherwise convert draft to concept
215
- let finalStatus = publicationData?.status;
216
- if (isPublishing) {
217
- finalStatus = 'published';
218
- }
219
- else if (publicationData?.status === 'draft') {
220
- finalStatus = 'concept';
221
- }
222
- else {
223
- finalStatus = publicationData?.status || 'concept';
224
- }
225
- const blogDocument = {
226
- title: title.trim(),
227
- summary: (summary || '').trim(),
228
- contentBlocks: contentBlocks || [],
229
- content: content || [],
230
- image: image || { id: '', alt: '' }, // Only store id and alt - plugin-images handles transforms
231
- categoryTags: {
232
- category: categoryTags?.category?.trim() || '',
233
- tags: categoryTags?.tags || [],
234
- },
235
- publicationData: {
236
- ...publicationData,
237
- status: finalStatus,
238
- date: publicationData?.date ? new Date(publicationData.date) : new Date(),
239
- },
240
- seo: seo || { title: '', description: '' },
56
+ if (!body.title?.trim())
57
+ return NextResponse.json({ message: 'Title is required' }, { status: 400 });
58
+ const service = new BlogService(config);
59
+ const isPublishing = body.publicationData?.status === 'published';
60
+ const slug = isPublishing ? slugify(body.title) : `${slugify(body.title)}-draft-${Date.now().toString().slice(-4)}`;
61
+ const updateData = service.prepareUpdateData(body, null, language);
62
+ const finalDoc = {
63
+ ...updateData,
241
64
  slug,
242
65
  authorId: userId,
243
- languages: {
244
- [language]: {
245
- blocks: contentBlocks || [],
246
- metadata: {
247
- title: title.trim(),
248
- excerpt: (summary || '').trim(),
249
- featuredImage: image,
250
- categories: categoryTags?.category ? [categoryTags.category] : [],
251
- tags: categoryTags?.tags || [],
252
- seo: seo || {},
253
- },
254
- updatedAt: new Date().toISOString(),
255
- status: finalStatus,
256
- },
257
- },
258
- metadata: {
259
- lang: language,
260
- },
66
+ metadata: { lang: language },
261
67
  createdAt: new Date(),
262
- updatedAt: new Date(),
263
68
  };
264
- const result = await blogs.insertOne(blogDocument);
265
- return NextResponse.json({
266
- message: isPublishing ? 'Blog published successfully' : 'Draft saved successfully',
267
- blogId: result.insertedId,
268
- slug,
269
- });
69
+ const dbConn = await config.getDb();
70
+ const result = await dbConn.db().collection(config.collectionName || 'blogs').insertOne(finalDoc);
71
+ return NextResponse.json({ message: 'Success', blogId: result.insertedId, slug });
270
72
  }
271
73
  catch (err) {
272
- console.error('[BlogAPI] POST error:', err);
273
- return NextResponse.json({ error: 'Failed to create blog', detail: err.message }, { status: 500 });
74
+ return NextResponse.json({ error: 'Create failed', detail: err.message }, { status: 500 });
274
75
  }
275
76
  }
276
- /**
277
- * GET /api/blogs/[slug] - Get single blog post by slug
278
- */
279
77
  export async function GET_BY_SLUG(req, slug, config) {
280
78
  try {
281
79
  const url = new URL(req.url);
282
- const requestedLanguage = url.searchParams.get('language') || 'nl';
283
- const userId = await config.getUserId(req);
284
- const dbConnection = await config.getDb();
285
- const db = dbConnection.db();
286
- const blogs = db.collection(config.collectionName || 'blogs');
287
- const blog = await blogs.findOne({ slug });
288
- if (!blog) {
80
+ const service = new BlogService(config);
81
+ const lang = url.searchParams.get('language') || 'nl';
82
+ const dbConn = await config.getDb();
83
+ const collection = dbConn.db().collection(config.collectionName || 'blogs');
84
+ const blogDoc = await findPostBySlug(collection, slug);
85
+ if (!blogDoc) {
289
86
  return NextResponse.json({ error: 'Blog not found' }, { status: 404 });
290
87
  }
291
- // Security check
292
- const isAuthor = userId && blog.authorId === userId;
293
- const isAdminView = url.searchParams.get('admin') === 'true';
294
- // For public view, we must have a published version in the requested language
295
- if (!isAdminView && !isAuthor) {
296
- const langData = blog.languages?.[requestedLanguage];
297
- if (!langData || langData.status !== 'published') {
298
- return NextResponse.json({ error: 'Blog post not available in this language' }, { status: 404 });
299
- }
300
- // Also check publication date
301
- if (blog.publicationData?.date && new Date(blog.publicationData.date) > new Date()) {
302
- return NextResponse.json({ error: 'Blog post not yet published' }, { status: 404 });
303
- }
304
- }
305
- const languages = blog.languages || {};
306
- const postPrimaryLang = blog.metadata?.lang || 'nl';
307
- // Find the best available language for this post
308
- let bestLanguage = requestedLanguage;
309
- let isMissingTranslation = false;
310
- if (!languages[requestedLanguage]) {
311
- if (isAdminView) {
312
- isMissingTranslation = true;
313
- }
314
- else {
315
- // Try fallback languages in order
316
- const fallbackLanguages = [requestedLanguage, 'nl', 'en'];
317
- for (const lang of fallbackLanguages) {
318
- if (languages[lang]) {
319
- bestLanguage = lang;
320
- break;
321
- }
322
- }
323
- // If still no match, use primary language from metadata
324
- if (!languages[bestLanguage] && languages[postPrimaryLang]) {
325
- bestLanguage = postPrimaryLang;
326
- }
327
- }
328
- }
329
- const langContent = languages[bestLanguage] || {};
330
- const meta = langContent.metadata || {};
331
- // Language display names for placeholders
332
- const langNames = {
333
- nl: 'Dutch',
334
- en: 'English',
335
- sv: 'Swedish',
336
- de: 'German',
337
- fr: 'French',
338
- es: 'Spanish'
339
- };
340
- let title = isMissingTranslation
341
- ? `(No ${langNames[requestedLanguage] || requestedLanguage.toUpperCase()} translation)`
342
- : (meta.title || blog.title || '');
343
- let summary = isMissingTranslation ? '' : (meta.excerpt || blog.summary || '');
344
- let contentBlocks = isMissingTranslation ? [] : (langContent.blocks || blog.contentBlocks || blog.blocks || []);
345
- let image = isMissingTranslation ? null : (meta.featuredImage || blog.image);
346
- let categoryTags = isMissingTranslation ? { category: '', tags: [] } : (meta.categories ? {
347
- category: meta.categories[0] || '',
348
- tags: meta.tags || blog.categoryTags?.tags || []
349
- } : (blog.categoryTags || { category: '', tags: [] }));
350
- let seo = isMissingTranslation ? {} : (meta.seo || blog.seo || {});
351
- let metadata = { ...blog.metadata, ...meta, lang: bestLanguage };
352
- // Ensure all languages in doc have a status and updatedAt for the dashboard
353
- const enrichedLanguages = { ...languages };
354
- Object.keys(enrichedLanguages).forEach(lang => {
355
- if (!enrichedLanguages[lang].status) {
356
- enrichedLanguages[lang].status = blog.publicationData?.status === 'concept' ? 'draft' : (blog.publicationData?.status || 'draft');
357
- }
358
- if (!enrichedLanguages[lang].updatedAt) {
359
- enrichedLanguages[lang].updatedAt = blog.updatedAt;
360
- }
361
- });
362
- const displayStatus = isMissingTranslation
363
- ? 'not-translated'
364
- : (langContent.status || blog.publicationData?.status || 'concept');
365
- return NextResponse.json({
366
- ...blog,
367
- _id: blog._id.toString(),
368
- title,
369
- summary,
370
- contentBlocks,
371
- image,
372
- categoryTags,
373
- publicationData: {
374
- ...blog.publicationData,
375
- status: displayStatus,
376
- },
377
- seo,
378
- metadata,
379
- languages: enrichedLanguages,
380
- availableLanguages: Object.keys(languages),
381
- lang: bestLanguage,
382
- isMissingTranslation,
383
- requestedLanguage,
384
- updatedAt: isMissingTranslation ? blog.updatedAt : (langContent.updatedAt || blog.updatedAt),
385
- status: displayStatus,
386
- });
88
+ const formatted = service.formatWithLanguage(blogDoc, lang, url.searchParams.get('admin') === 'true');
89
+ return NextResponse.json(formatted);
387
90
  }
388
91
  catch (err) {
389
92
  console.error('[BlogAPI] GET_BY_SLUG error:', err);
390
- return NextResponse.json({ error: 'Failed to fetch blog', detail: err.message }, { status: 500 });
93
+ return NextResponse.json({ error: 'Fetch failed', detail: err.message }, { status: 500 });
391
94
  }
392
95
  }
393
- /**
394
- * PUT /api/blogs/[slug] - Update blog post by slug
395
- */
396
96
  export async function PUT_BY_SLUG(req, slug, config) {
397
97
  try {
398
98
  const url = new URL(req.url);
399
99
  const language = url.searchParams.get('language') || 'nl';
400
100
  const userId = await config.getUserId(req);
401
- if (!userId) {
101
+ if (!userId)
402
102
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
403
- }
404
- const body = await req.json();
405
- const { title, summary, content, contentBlocks, image, categoryTags, publicationData, seo, } = body;
406
- const dbConnection = await config.getDb();
407
- const db = dbConnection.db();
408
- const blogs = db.collection(config.collectionName || 'blogs');
409
- // Check if blog exists and user is author
410
- const existingBlog = await blogs.findOne({ slug });
411
- if (!existingBlog) {
412
- return NextResponse.json({ error: 'Blog not found' }, { status: 404 });
413
- }
414
- if (existingBlog.authorId !== userId) {
415
- return NextResponse.json({ error: 'Forbidden: Not the author' }, { status: 403 });
416
- }
417
- // Validation
418
- const isPublishing = publicationData?.status === 'published';
419
- if (!title?.trim()) {
420
- return NextResponse.json({ message: 'Title is required' }, { status: 400 });
421
- }
422
- if (isPublishing) {
423
- const hasContent = (contentBlocks && Array.isArray(contentBlocks) && contentBlocks.length > 0) ||
424
- (content && Array.isArray(content) && content.length > 0);
425
- // Collect all missing fields for better error messages
426
- const missingFields = [];
427
- if (!summary?.trim())
428
- missingFields.push('summary');
429
- if (!image?.id?.trim())
430
- missingFields.push('featured image');
431
- // Only require category if it's explicitly provided and empty
432
- // If categoryTags is undefined or category is undefined, that's also missing
433
- if (!categoryTags || !categoryTags.category || !categoryTags.category.trim()) {
434
- missingFields.push('category');
435
- }
436
- if (!hasContent)
437
- missingFields.push('content');
438
- if (missingFields.length > 0) {
439
- return NextResponse.json({
440
- message: `Missing required fields for publishing: ${missingFields.join(', ')}`,
441
- missingFields
442
- }, { status: 400 });
443
- }
444
- }
445
- // Slug logic - DON'T change slug for existing posts, keep original
446
- // The slug should remain constant across all language versions
447
- const finalSlug = slug;
448
- // Determine the final status: if publishing, set to 'published', otherwise preserve or convert draft to concept
449
- let finalStatus = publicationData?.status;
450
- if (isPublishing) {
451
- finalStatus = 'published';
452
- }
453
- else if (publicationData?.status === 'draft') {
454
- finalStatus = 'concept';
455
- }
456
- // Preserve existing languages or initialize
457
- const existingLanguages = existingBlog.languages || {};
458
- const primaryLanguage = existingBlog.metadata?.lang || 'nl';
459
- // Update the specific language content
460
- // Only the language being saved gets a new updatedAt timestamp
461
- const now = new Date();
462
- const updatedLanguages = {
463
- ...existingLanguages,
464
- [language]: {
465
- blocks: contentBlocks || [],
466
- metadata: {
467
- title: title.trim(),
468
- excerpt: (summary || '').trim(),
469
- featuredImage: image,
470
- categories: categoryTags?.category ? [categoryTags.category] : [],
471
- tags: categoryTags?.tags || [],
472
- seo: seo || {},
473
- },
474
- updatedAt: now.toISOString(),
475
- status: finalStatus,
476
- },
477
- };
478
- // For root-level fields, only update if this is the primary language
479
- // Otherwise preserve existing root values to maintain backward compatibility
480
- const isPrimaryLanguage = language === primaryLanguage || !existingLanguages[primaryLanguage];
481
- const updateData = {
482
- // Only update root-level title/summary if saving in primary language
483
- // This maintains backward compatibility
484
- ...(isPrimaryLanguage ? {
485
- title: title.trim(),
486
- summary: (summary || '').trim(),
487
- contentBlocks: contentBlocks || [],
488
- content: content || [],
489
- image: image || {},
490
- categoryTags: {
491
- category: categoryTags?.category?.trim() || '',
492
- tags: categoryTags?.tags || [],
493
- },
494
- seo: seo || {},
495
- } : {}),
496
- publicationData: {
497
- ...existingBlog.publicationData,
498
- ...publicationData,
499
- status: finalStatus,
500
- date: publicationData?.date ? new Date(publicationData.date) : existingBlog.publicationData?.date || new Date(),
501
- },
502
- authorId: userId,
503
- languages: updatedLanguages,
504
- metadata: {
505
- ...existingBlog.metadata,
506
- lang: primaryLanguage,
507
- },
508
- updatedAt: new Date(),
509
- };
510
- await blogs.updateOne({ slug }, { $set: updateData });
511
- return NextResponse.json({
512
- message: 'Blog updated successfully',
513
- slug: slug, // Return original slug, not finalSlug
514
- });
103
+ const dbConn = await config.getDb();
104
+ const collection = dbConn.db().collection(config.collectionName || 'blogs');
105
+ const existing = await findPostBySlug(collection, slug);
106
+ if (!existing)
107
+ return NextResponse.json({ error: 'Not found' }, { status: 404 });
108
+ if (existing.authorId !== userId)
109
+ return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
110
+ const service = new BlogService(config);
111
+ const updateData = service.prepareUpdateData(await req.json(), existing, language);
112
+ await collection.updateOne({ _id: existing._id }, { $set: updateData });
113
+ // Return the potentially NEW localized slug so the editor can redirect if needed
114
+ const newSlug = updateData.languages[language].metadata.slug || existing.slug;
115
+ return NextResponse.json({ message: 'Updated', slug: newSlug });
515
116
  }
516
117
  catch (err) {
517
- console.error('[BlogAPI] PUT_BY_SLUG error:', err);
518
- return NextResponse.json({ error: 'Failed to update blog', detail: err.message }, { status: 500 });
118
+ return NextResponse.json({ error: 'Update failed', detail: err.message }, { status: 500 });
519
119
  }
520
120
  }
521
- /**
522
- * DELETE /api/blogs/[slug] - Delete blog post by slug
523
- */
524
121
  export async function DELETE_BY_SLUG(req, slug, config) {
525
122
  try {
526
123
  const userId = await config.getUserId(req);
527
- if (!userId) {
124
+ if (!userId)
528
125
  return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
529
- }
530
- const dbConnection = await config.getDb();
531
- const db = dbConnection.db();
532
- const blogs = db.collection(config.collectionName || 'blogs');
533
- // Verify ownership
534
- const blog = await blogs.findOne({ slug });
535
- if (!blog) {
536
- return NextResponse.json({ error: 'Blog not found' }, { status: 404 });
537
- }
538
- if (blog.authorId !== userId) {
539
- return NextResponse.json({ error: 'Forbidden: Not the author' }, { status: 403 });
540
- }
541
- await blogs.deleteOne({ slug });
542
- return NextResponse.json({ message: 'Blog deleted successfully' });
126
+ const dbConn = await config.getDb();
127
+ const collection = dbConn.db().collection(config.collectionName || 'blogs');
128
+ const blog = await findPostBySlug(collection, slug);
129
+ if (!blog)
130
+ return NextResponse.json({ error: 'Not found' }, { status: 404 });
131
+ if (blog.authorId !== userId)
132
+ return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
133
+ await collection.deleteOne({ _id: blog._id });
134
+ return NextResponse.json({ message: 'Deleted' });
543
135
  }
544
136
  catch (err) {
545
- console.error('[BlogAPI] DELETE_BY_SLUG error:', err);
546
- return NextResponse.json({ error: 'Failed to delete blog', detail: err.message }, { status: 500 });
137
+ return NextResponse.json({ error: 'Delete failed', detail: err.message }, { status: 500 });
547
138
  }
548
139
  }
@@ -1,9 +1,6 @@
1
1
  /**
2
2
  * Plugin Blog API Router
3
3
  * Centralized API handler for all blog plugin routes
4
- *
5
- * This router handles requests to /api/plugin-blog/*
6
- * and routes them to the appropriate handler
7
4
  */
8
5
  import { NextRequest, NextResponse } from 'next/server';
9
6
  export interface BlogApiRouterConfig {
@@ -20,8 +17,6 @@ export interface BlogApiRouterConfig {
20
17
  }
21
18
  /**
22
19
  * Handle blog API requests
23
- * Routes requests to appropriate handlers based on path
24
- * Similar to plugin-dep, accepts config directly instead of requiring initialization
25
20
  */
26
21
  export declare function handleBlogApi(req: NextRequest, path: string[], config: BlogApiRouterConfig): Promise<NextResponse>;
27
22
  //# sourceMappingURL=router.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD,MAAM,WAAW,mBAAmB;IAChC,oEAAoE;IACpE,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,GAAG,CAAA;KAAE,CAAC,CAAC;IACxC,yDAAyD;IACzD,SAAS,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAC/B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CA2FvB"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/api/router.ts"],"names":[],"mappings":"AAEA;;;GAGG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAKxD,MAAM,WAAW,mBAAmB;IAChC,oEAAoE;IACpE,KAAK,EAAE,MAAM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,GAAG,CAAA;KAAE,CAAC,CAAC;IACxC,yDAAyD;IACzD,SAAS,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACxD,yCAAyC;IACzC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oCAAoC;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAsB,aAAa,CAC/B,GAAG,EAAE,WAAW,EAChB,IAAI,EAAE,MAAM,EAAE,EACd,MAAM,EAAE,mBAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CA+CvB"}