@xiwebdesign/xicms-core 6.5.0 → 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (372) hide show
  1. package/dist/SiteChrome.d.ts +12 -0
  2. package/dist/SiteChrome.js +24 -0
  3. package/dist/SiteChrome.js.map +1 -0
  4. package/dist/XiCMSProvider.d.ts +16 -8
  5. package/dist/XiCMSProvider.js +83 -58
  6. package/dist/XiCMSProvider.js.map +1 -1
  7. package/dist/admin/AdminApp.d.ts +1 -1
  8. package/dist/admin/AdminApp.js +79 -35
  9. package/dist/admin/AdminApp.js.map +1 -1
  10. package/dist/admin/AdminHelp.d.ts +8 -1
  11. package/dist/admin/AdminHelp.js +2 -2
  12. package/dist/admin/AdminHelp.js.map +1 -1
  13. package/dist/admin/NewsEditor.js +9 -9
  14. package/dist/admin/SuperadminPanel.js +5 -5
  15. package/dist/admin/blockEditors/GenericEditor.d.ts +2 -2
  16. package/dist/admin/blockEditors/GenericEditor.js +12 -11
  17. package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
  18. package/dist/admin/blockEditors/StyleEditor.d.ts +1 -1
  19. package/dist/admin/blockEditors/StyleEditor.js +2 -2
  20. package/dist/admin/blockEditors/SymbolRefEditor.d.ts +1 -1
  21. package/dist/admin/blockEditors/SymbolRefEditor.js +5 -5
  22. package/dist/admin/blockEditors/index.d.ts +1 -1
  23. package/dist/admin/blockEditors/index.js +10 -10
  24. package/dist/admin/customBlocks/CustomBlocksPanel.js +7 -7
  25. package/dist/admin/editors/RichTextEditor.js +8 -7
  26. package/dist/admin/editors/RichTextEditor.js.map +1 -1
  27. package/dist/admin/editors/fontSizeExtension.js +1 -1
  28. package/dist/admin/editors/fontSizeExtension.js.map +1 -1
  29. package/dist/admin/forms/FormsPanel.js +9 -9
  30. package/dist/admin/index.d.ts +16 -16
  31. package/dist/admin/index.js +16 -16
  32. package/dist/admin/lib/mediaUsage.js +1 -1
  33. package/dist/admin/lib/pagesClient.d.ts +1 -1
  34. package/dist/admin/lib/pagesClient.js +11 -7
  35. package/dist/admin/lib/pagesClient.js.map +1 -1
  36. package/dist/admin/lib/sanitizeDraft.d.ts +9 -0
  37. package/dist/admin/lib/sanitizeDraft.js +28 -0
  38. package/dist/admin/lib/sanitizeDraft.js.map +1 -0
  39. package/dist/admin/lib/symbolsClient.d.ts +1 -1
  40. package/dist/admin/lib/symbolsClient.js +3 -3
  41. package/dist/admin/lib/upload.js +3 -3
  42. package/dist/admin/lib/useNestedDialog.d.ts +15 -0
  43. package/dist/admin/lib/useNestedDialog.js +23 -0
  44. package/dist/admin/lib/useNestedDialog.js.map +1 -0
  45. package/dist/admin/lib/zodFields.d.ts +4 -18
  46. package/dist/admin/lib/zodFields.js +54 -35
  47. package/dist/admin/lib/zodFields.js.map +1 -1
  48. package/dist/admin/media/MediaManager.js +7 -7
  49. package/dist/admin/media/MediaPicker.js +7 -7
  50. package/dist/admin/media/MediaPicker.js.map +1 -1
  51. package/dist/admin/pages/PageEditor.d.ts +1 -1
  52. package/dist/admin/pages/PageEditor.js +13 -13
  53. package/dist/admin/pages/PagesPanel.js +30 -30
  54. package/dist/admin/pages/PagesPanel.js.map +1 -1
  55. package/dist/admin/panelRegistry.js +7 -7
  56. package/dist/admin/patterns/PatternInserter.d.ts +1 -1
  57. package/dist/admin/patterns/PatternInserter.js +5 -5
  58. package/dist/admin/patterns/PatternInserter.js.map +1 -1
  59. package/dist/admin/settings/MailSettings.js +5 -5
  60. package/dist/admin/settings/MailTemplates.d.ts +1 -1
  61. package/dist/admin/settings/MailTemplates.js +5 -5
  62. package/dist/admin/settings/SettingsPanel.js +20 -20
  63. package/dist/admin/settings/SettingsPanel.js.map +1 -1
  64. package/dist/admin/settings/SnapshotsCard.js +5 -5
  65. package/dist/admin/settings/moduleSettingsForm.d.ts +1 -1
  66. package/dist/admin/settings/moduleSettingsForm.js +4 -4
  67. package/dist/admin/settings/moduleSettingsForm.js.map +1 -1
  68. package/dist/admin/shop/CategoriesTab.js +8 -8
  69. package/dist/admin/shop/ConnectionsTab.js +3 -3
  70. package/dist/admin/shop/DiscountsTab.js +8 -8
  71. package/dist/admin/shop/OrdersTab.js +10 -10
  72. package/dist/admin/shop/OrdersTab.js.map +1 -1
  73. package/dist/admin/shop/ProductsTab.js +10 -10
  74. package/dist/admin/shop/ShopPanel.js +9 -9
  75. package/dist/admin/shop/ShopSettingsTab.js +4 -4
  76. package/dist/admin/shop/index.d.ts +2 -2
  77. package/dist/admin/shop/index.js +2 -2
  78. package/dist/admin/shop/lib.js +2 -2
  79. package/dist/admin/stats/StatsPanel.js +2 -2
  80. package/dist/admin/ui/ArrayEditor.js +1 -1
  81. package/dist/admin/ui/PanelIcon.d.ts +3 -0
  82. package/dist/admin/ui/PanelIcon.js +34 -0
  83. package/dist/admin/ui/PanelIcon.js.map +1 -0
  84. package/dist/admin/ui/dialog.d.ts +21 -6
  85. package/dist/admin/ui/dialog.js +55 -34
  86. package/dist/admin/ui/dialog.js.map +1 -1
  87. package/dist/admin/ui/index.d.ts +7 -7
  88. package/dist/admin/ui/index.js +7 -7
  89. package/dist/admin/ui/primitives.js +1 -1
  90. package/dist/admin/ui/tabs.js +1 -1
  91. package/dist/admin/visual/TranslationPanel.d.ts +1 -1
  92. package/dist/admin/visual/TranslationPanel.js +3 -3
  93. package/dist/admin/visual/VisualEditor.js +47 -25
  94. package/dist/admin/visual/VisualEditor.js.map +1 -1
  95. package/dist/admin.css +2 -1
  96. package/dist/agentFiles/catalog.d.ts +2 -2
  97. package/dist/agentFiles/catalog.js +6 -5
  98. package/dist/agentFiles/catalog.js.map +1 -1
  99. package/dist/agentFiles/files.d.ts +5 -5
  100. package/dist/agentFiles/files.js +17 -17
  101. package/dist/agentFiles/files.js.map +1 -1
  102. package/dist/all.d.ts +4 -4
  103. package/dist/all.js +6 -6
  104. package/dist/auth/AuthProvider.d.ts +2 -2
  105. package/dist/auth/AuthProvider.js +51 -28
  106. package/dist/auth/AuthProvider.js.map +1 -1
  107. package/dist/auth/LoginForm.js +1 -1
  108. package/dist/auth/roles.js +4 -1
  109. package/dist/auth/roles.js.map +1 -1
  110. package/dist/blocks/BlockRenderer.d.ts +1 -1
  111. package/dist/blocks/BlockRenderer.js +3 -3
  112. package/dist/blocks/blockStyle.d.ts +1 -1
  113. package/dist/blocks/builtins/Accordion.d.ts +1 -1
  114. package/dist/blocks/builtins/Accordion.js +13 -6
  115. package/dist/blocks/builtins/Accordion.js.map +1 -1
  116. package/dist/blocks/builtins/Agenda.d.ts +1 -1
  117. package/dist/blocks/builtins/Agenda.js +5 -5
  118. package/dist/blocks/builtins/Banner.d.ts +1 -1
  119. package/dist/blocks/builtins/Banner.js +2 -2
  120. package/dist/blocks/builtins/BeforeAfter.d.ts +1 -1
  121. package/dist/blocks/builtins/BeforeAfter.js +4 -4
  122. package/dist/blocks/builtins/BeforeAfter.js.map +1 -1
  123. package/dist/blocks/builtins/Booking.d.ts +1 -1
  124. package/dist/blocks/builtins/Booking.js +5 -5
  125. package/dist/blocks/builtins/Breadcrumbs.d.ts +1 -1
  126. package/dist/blocks/builtins/Breadcrumbs.js +3 -3
  127. package/dist/blocks/builtins/Cards.d.ts +1 -1
  128. package/dist/blocks/builtins/Cards.js +5 -5
  129. package/dist/blocks/builtins/Cards.js.map +1 -1
  130. package/dist/blocks/builtins/Columns.d.ts +1 -1
  131. package/dist/blocks/builtins/Columns.js +4 -4
  132. package/dist/blocks/builtins/Contact.d.ts +3 -3
  133. package/dist/blocks/builtins/Contact.js +4 -4
  134. package/dist/blocks/builtins/Countdown.d.ts +1 -1
  135. package/dist/blocks/builtins/Countdown.js +4 -4
  136. package/dist/blocks/builtins/Countdown.js.map +1 -1
  137. package/dist/blocks/builtins/Cta.d.ts +1 -1
  138. package/dist/blocks/builtins/Cta.js +3 -3
  139. package/dist/blocks/builtins/Downloads.d.ts +1 -1
  140. package/dist/blocks/builtins/Downloads.js +4 -4
  141. package/dist/blocks/builtins/Elements.d.ts +3 -3
  142. package/dist/blocks/builtins/Elements.js +3 -3
  143. package/dist/blocks/builtins/Embed.d.ts +1 -1
  144. package/dist/blocks/builtins/Embed.js +3 -3
  145. package/dist/blocks/builtins/Faq.d.ts +1 -1
  146. package/dist/blocks/builtins/Faq.js +14 -6
  147. package/dist/blocks/builtins/Faq.js.map +1 -1
  148. package/dist/blocks/builtins/FormBlock.d.ts +1 -1
  149. package/dist/blocks/builtins/FormBlock.js +28 -18
  150. package/dist/blocks/builtins/FormBlock.js.map +1 -1
  151. package/dist/blocks/builtins/Gallery.d.ts +2 -2
  152. package/dist/blocks/builtins/Gallery.js +5 -5
  153. package/dist/blocks/builtins/Hero.d.ts +1 -1
  154. package/dist/blocks/builtins/Hero.js +4 -4
  155. package/dist/blocks/builtins/ImageBlock.d.ts +1 -1
  156. package/dist/blocks/builtins/ImageBlock.js +3 -3
  157. package/dist/blocks/builtins/Jobs.d.ts +2 -2
  158. package/dist/blocks/builtins/Jobs.js +5 -5
  159. package/dist/blocks/builtins/Layout.d.ts +2 -2
  160. package/dist/blocks/builtins/Layout.js +4 -4
  161. package/dist/blocks/builtins/MapBlock.d.ts +1 -1
  162. package/dist/blocks/builtins/MapBlock.js +3 -3
  163. package/dist/blocks/builtins/NewsListBlock.d.ts +1 -1
  164. package/dist/blocks/builtins/NewsListBlock.js +4 -4
  165. package/dist/blocks/builtins/Newsletter.d.ts +1 -1
  166. package/dist/blocks/builtins/Newsletter.js +7 -7
  167. package/dist/blocks/builtins/Newsletter.js.map +1 -1
  168. package/dist/blocks/builtins/OpenNowBadge.d.ts +1 -1
  169. package/dist/blocks/builtins/OpenNowBadge.js +8 -3
  170. package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
  171. package/dist/blocks/builtins/OpeningHours.d.ts +1 -1
  172. package/dist/blocks/builtins/OpeningHours.js +6 -6
  173. package/dist/blocks/builtins/PdfBlock.d.ts +1 -1
  174. package/dist/blocks/builtins/PdfBlock.js +3 -3
  175. package/dist/blocks/builtins/Portfolio.d.ts +1 -1
  176. package/dist/blocks/builtins/Portfolio.js +5 -5
  177. package/dist/blocks/builtins/Pricing.d.ts +2 -2
  178. package/dist/blocks/builtins/Pricing.js +5 -5
  179. package/dist/blocks/builtins/Pricing.js.map +1 -1
  180. package/dist/blocks/builtins/RichTextBlock.d.ts +1 -1
  181. package/dist/blocks/builtins/RichTextBlock.js +2 -2
  182. package/dist/blocks/builtins/RichTextBlock.js.map +1 -1
  183. package/dist/blocks/builtins/Search.d.ts +1 -1
  184. package/dist/blocks/builtins/Search.js +9 -7
  185. package/dist/blocks/builtins/Search.js.map +1 -1
  186. package/dist/blocks/builtins/Sections.d.ts +4 -4
  187. package/dist/blocks/builtins/Sections.js +4 -4
  188. package/dist/blocks/builtins/Slider.d.ts +1 -1
  189. package/dist/blocks/builtins/Slider.js +3 -3
  190. package/dist/blocks/builtins/Spacer.d.ts +1 -1
  191. package/dist/blocks/builtins/Spacer.js +2 -2
  192. package/dist/blocks/builtins/SymbolRef.d.ts +1 -1
  193. package/dist/blocks/builtins/SymbolRef.js +31 -17
  194. package/dist/blocks/builtins/SymbolRef.js.map +1 -1
  195. package/dist/blocks/builtins/Team.d.ts +1 -1
  196. package/dist/blocks/builtins/Team.js +4 -4
  197. package/dist/blocks/builtins/Testimonials.d.ts +2 -2
  198. package/dist/blocks/builtins/Testimonials.js +4 -4
  199. package/dist/blocks/builtins/Video.d.ts +2 -2
  200. package/dist/blocks/builtins/Video.js +4 -4
  201. package/dist/blocks/builtins/Video.js.map +1 -1
  202. package/dist/blocks/builtins/WhatsappChat.d.ts +1 -1
  203. package/dist/blocks/builtins/WhatsappChat.js +2 -2
  204. package/dist/blocks/builtins/Widgets.d.ts +12 -12
  205. package/dist/blocks/builtins/Widgets.js +19 -19
  206. package/dist/blocks/builtins/Widgets.js.map +1 -1
  207. package/dist/blocks/builtins/consentEmbed.js +2 -2
  208. package/dist/blocks/builtins/index.d.ts +40 -40
  209. package/dist/blocks/builtins/index.js +40 -40
  210. package/dist/blocks/builtins/lib/submitForm.js +5 -3
  211. package/dist/blocks/builtins/lib/submitForm.js.map +1 -1
  212. package/dist/blocks/context.d.ts +1 -1
  213. package/dist/blocks/customTemplate/definition.d.ts +3 -3
  214. package/dist/blocks/customTemplate/definition.js +6 -6
  215. package/dist/blocks/customTemplate/definition.js.map +1 -1
  216. package/dist/blocks/customTemplate/interpret.js +1 -1
  217. package/dist/blocks/index.d.ts +5 -5
  218. package/dist/blocks/index.js +5 -5
  219. package/dist/blocks/registry.d.ts +17 -7
  220. package/dist/blocks/registry.js +2 -1
  221. package/dist/blocks/registry.js.map +1 -1
  222. package/dist/components/EditBar.js +3 -3
  223. package/dist/components/FeedbackWidget.js +4 -4
  224. package/dist/components/News.d.ts +1 -1
  225. package/dist/components/News.js +50 -37
  226. package/dist/components/News.js.map +1 -1
  227. package/dist/components/PageView.js +11 -8
  228. package/dist/components/PageView.js.map +1 -1
  229. package/dist/components/ResponsiveImage.d.ts +1 -1
  230. package/dist/components/site/SiteFooter.d.ts +1 -1
  231. package/dist/components/site/SiteFooter.js +2 -2
  232. package/dist/config.d.ts +1 -1
  233. package/dist/demo/DemoStudio.js +3 -3
  234. package/dist/demo/demoStore.d.ts +3 -3
  235. package/dist/demo/index.d.ts +2 -2
  236. package/dist/demo/index.js +2 -2
  237. package/dist/editor/EditorProvider.js +1 -1
  238. package/dist/firebase/admin.d.ts +0 -2
  239. package/dist/firebase/admin.js +0 -6
  240. package/dist/firebase/admin.js.map +1 -1
  241. package/dist/firebase/appcheck.d.ts +1 -1
  242. package/dist/firebase/appcheck.js +5 -3
  243. package/dist/firebase/appcheck.js.map +1 -1
  244. package/dist/firebase/client.d.ts +2 -1
  245. package/dist/firebase/client.js +2 -14
  246. package/dist/firebase/client.js.map +1 -1
  247. package/dist/firebase/config.d.ts +31 -0
  248. package/dist/firebase/config.js +39 -0
  249. package/dist/firebase/config.js.map +1 -0
  250. package/dist/firebase/feedback.js +5 -3
  251. package/dist/firebase/feedback.js.map +1 -1
  252. package/dist/i18n/overlay.d.ts +2 -2
  253. package/dist/i18n/overlay.js +6 -4
  254. package/dist/i18n/overlay.js.map +1 -1
  255. package/dist/index.d.ts +45 -44
  256. package/dist/index.js +35 -33
  257. package/dist/index.js.map +1 -1
  258. package/dist/lock/DemoLock.js +1 -1
  259. package/dist/modules/builtins.d.ts +1 -1
  260. package/dist/modules/builtins.js +53 -55
  261. package/dist/modules/builtins.js.map +1 -1
  262. package/dist/modules/consent/ConsentBanner.js +1 -1
  263. package/dist/modules/consent/useConsent.js +1 -1
  264. package/dist/modules/context.d.ts +1 -1
  265. package/dist/modules/contract.d.ts +1 -1
  266. package/dist/modules/defineModule.d.ts +1 -1
  267. package/dist/modules/index.d.ts +9 -9
  268. package/dist/modules/index.js +8 -8
  269. package/dist/modules/overrides.d.ts +1 -1
  270. package/dist/modules/registry.d.ts +2 -7
  271. package/dist/modules/registry.js +2 -1
  272. package/dist/modules/registry.js.map +1 -1
  273. package/dist/modules/shop/blocks/Cart.d.ts +1 -1
  274. package/dist/modules/shop/blocks/Cart.js +6 -6
  275. package/dist/modules/shop/blocks/Checkout.d.ts +1 -1
  276. package/dist/modules/shop/blocks/Checkout.js +6 -6
  277. package/dist/modules/shop/blocks/Donation.d.ts +1 -1
  278. package/dist/modules/shop/blocks/Donation.js +5 -5
  279. package/dist/modules/shop/blocks/OrderStatus.d.ts +1 -1
  280. package/dist/modules/shop/blocks/OrderStatus.js +5 -5
  281. package/dist/modules/shop/blocks/ProductDetail.d.ts +1 -1
  282. package/dist/modules/shop/blocks/ProductDetail.js +8 -8
  283. package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -3
  284. package/dist/modules/shop/blocks/ProductGrid.js +7 -7
  285. package/dist/modules/shop/blocks/ShopCategories.d.ts +1 -1
  286. package/dist/modules/shop/blocks/ShopCategories.js +6 -6
  287. package/dist/modules/shop/index.d.ts +5 -5
  288. package/dist/modules/shop/index.js +5 -5
  289. package/dist/modules/shop/lib.d.ts +2 -2
  290. package/dist/modules/shop/lib.js +18 -13
  291. package/dist/modules/shop/lib.js.map +1 -1
  292. package/dist/modules/shop/module.d.ts +1 -1
  293. package/dist/modules/shop/module.js +9 -9
  294. package/dist/modules/shop/settings.d.ts +18 -50
  295. package/dist/modules/shop/settings.js +16 -16
  296. package/dist/modules/shop/settings.js.map +1 -1
  297. package/dist/modules/shop/strings.js +1 -1
  298. package/dist/modules/shop/types.d.ts +1 -1
  299. package/dist/modules/types.d.ts +2 -2
  300. package/dist/patterns/builtins.d.ts +1 -1
  301. package/dist/patterns/builtins.js +1 -1
  302. package/dist/patterns/index.d.ts +2 -2
  303. package/dist/patterns/index.js +2 -2
  304. package/dist/render/PageRenderer.d.ts +2 -2
  305. package/dist/render/PageRenderer.js +1 -1
  306. package/dist/render/PublishedPage.d.ts +1 -1
  307. package/dist/render/PublishedPage.js +2 -2
  308. package/dist/schema/blocks.d.ts +6793 -15095
  309. package/dist/schema/blocks.js +335 -355
  310. package/dist/schema/blocks.js.map +1 -1
  311. package/dist/schema/customBlocks.d.ts +10 -29
  312. package/dist/schema/customBlocks.js +14 -13
  313. package/dist/schema/customBlocks.js.map +1 -1
  314. package/dist/schema/fields.d.ts +10 -16
  315. package/dist/schema/fields.js +37 -37
  316. package/dist/schema/fields.js.map +1 -1
  317. package/dist/schema/forms.d.ts +62 -111
  318. package/dist/schema/forms.js +17 -17
  319. package/dist/schema/forms.js.map +1 -1
  320. package/dist/schema/index.d.ts +7 -7
  321. package/dist/schema/index.js +7 -7
  322. package/dist/schema/mail.d.ts +39 -87
  323. package/dist/schema/mail.js +4 -4
  324. package/dist/schema/mail.js.map +1 -1
  325. package/dist/schema/pages.d.ts +152 -674
  326. package/dist/schema/pages.js +26 -15
  327. package/dist/schema/pages.js.map +1 -1
  328. package/dist/schema/seo.d.ts +9 -27
  329. package/dist/schema/seo.js +7 -7
  330. package/dist/schema/seo.js.map +1 -1
  331. package/dist/schema/settings.d.ts +218 -1074
  332. package/dist/schema/settings.js +55 -55
  333. package/dist/schema/settings.js.map +1 -1
  334. package/dist/schema/shop.d.ts +470 -1214
  335. package/dist/schema/shop.js +124 -124
  336. package/dist/schema/shop.js.map +1 -1
  337. package/dist/schema/siteConfig.d.ts +73 -597
  338. package/dist/schema/siteConfig.js +17 -17
  339. package/dist/schema/siteConfig.js.map +1 -1
  340. package/dist/schema/symbols.d.ts +34 -191
  341. package/dist/schema/symbols.js +8 -8
  342. package/dist/schema/symbols.js.map +1 -1
  343. package/dist/server/auth.d.ts +17 -0
  344. package/dist/server/auth.js +11 -0
  345. package/dist/server/auth.js.map +1 -0
  346. package/dist/server/bundle.d.ts +15 -6
  347. package/dist/server/bundle.js +5 -1
  348. package/dist/server/bundle.js.map +1 -1
  349. package/dist/server/draft.d.ts +16 -0
  350. package/dist/server/draft.js +12 -0
  351. package/dist/server/draft.js.map +1 -0
  352. package/dist/server/env.js +8 -8
  353. package/dist/server/env.js.map +1 -1
  354. package/dist/server/index.d.ts +10 -9
  355. package/dist/server/index.js +11 -10
  356. package/dist/server/index.js.map +1 -1
  357. package/dist/server/pages.d.ts +11 -4
  358. package/dist/server/pages.js +43 -15
  359. package/dist/server/pages.js.map +1 -1
  360. package/dist/server/revalidate.js +11 -2
  361. package/dist/server/revalidate.js.map +1 -1
  362. package/dist/server/seo.d.ts +3 -3
  363. package/dist/server/seo.js +1 -1
  364. package/dist/server/shop.d.ts +3 -3
  365. package/dist/server/shop.js +6 -3
  366. package/dist/server/shop.js.map +1 -1
  367. package/dist/settings/useSiteSettings.d.ts +2 -2
  368. package/dist/settings/useSiteSettings.js +48 -28
  369. package/dist/settings/useSiteSettings.js.map +1 -1
  370. package/dist/styles.css +4 -1
  371. package/dist/theme/presets.d.ts +1 -1
  372. package/package.json +35 -34
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/shop.ts"],"sourcesContent":["import \"server-only\";\n\nimport { cache } from \"react\";\nimport type { Metadata } from \"next\";\n\nimport { getAdminDb } from \"../firebase/admin\";\nimport {\n ProductSchema,\n ShopCategorySchema,\n productPriceCents,\n type Product,\n type ShopCategory,\n} from \"../schema/shop\";\n\n/**\n * Server-readers voor de shop (5.6) — zelfde contract als server/pages.ts: Admin SDK als die\n * er is, anders keyless Firestore-REST met de publieke web-apiKey (de rules staan publieke\n * reads op actieve producten/categorieën toe). Reads zijn per-request gededupt via cache();\n * route-level ISR (`revalidate`) dempt de kosten tussen requests.\n *\n * Gebruik in de klantsite (catch-all):\n * const blockData = { shop: await getShopPageData(siteId, path, searchParams) };\n * <PublishedPage page={page} siteId={siteId} blockData={blockData} />\n */\n\nexport type ServerProduct = Product & { id: string };\nexport type ServerShopCategory = ShopCategory & { id: string };\n\n// Gedeelde vorm met de blocks (useBlockData(\"shop\")) — één bron van waarheid.\nexport type { ShopPageData } from \"../modules/shop/types\";\nimport type { ShopPageData } from \"../modules/shop/types\";\n\nfunction parseProduct(id: string, data: unknown): ServerProduct | null {\n const res = ProductSchema.safeParse(data);\n if (!res.success) {\n console.warn(`[xicms] product \"${id}\" faalt schema-validatie en wordt overgeslagen:`, res.error.issues[0]);\n return null;\n }\n return { id, ...res.data };\n}\n\nfunction parseCategory(id: string, data: unknown): ServerShopCategory | null {\n const res = ShopCategorySchema.safeParse(data);\n if (!res.success) {\n console.warn(`[xicms] categorie \"${id}\" faalt schema-validatie en wordt overgeslagen:`, res.error.issues[0]);\n return null;\n }\n return { id, ...res.data };\n}\n\n/* ── keyless REST (zelfde aanpak als server/pages.ts) ────────────────────── */\n\ntype FsValue = Record<string, unknown>;\nfunction decode(v: FsValue): unknown {\n if (v == null) return null;\n if (\"stringValue\" in v) return v.stringValue;\n if (\"integerValue\" in v) return Number(v.integerValue);\n if (\"doubleValue\" in v) return v.doubleValue;\n if (\"booleanValue\" in v) return v.booleanValue;\n if (\"nullValue\" in v) return null;\n if (\"timestampValue\" in v) return v.timestampValue;\n if (\"arrayValue\" in v) return (((v.arrayValue as FsValue)?.values as FsValue[]) ?? []).map(decode);\n if (\"mapValue\" in v) return decodeFields(((v.mapValue as FsValue)?.fields as Record<string, FsValue>) ?? {});\n return null;\n}\nfunction decodeFields(fields: Record<string, FsValue>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(fields).map(([k, x]) => [k, decode(x)]));\n}\n\ninterface RestDoc {\n id: string;\n data: Record<string, unknown>;\n}\n\nasync function restQuery(\n siteId: string,\n collectionId: string,\n filters: { fieldPath: string; value: string }[],\n limit?: number,\n): Promise<RestDoc[]> {\n const apiKey = process.env.NEXT_PUBLIC_FIREBASE_API_KEY;\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;\n if (!apiKey || !projectId) return [];\n const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/sites/${siteId}:runQuery?key=${apiKey}`;\n const fieldFilters = filters.map((f) => ({\n fieldFilter: { field: { fieldPath: f.fieldPath }, op: \"EQUAL\", value: { stringValue: f.value } },\n }));\n const where =\n fieldFilters.length === 0\n ? undefined\n : fieldFilters.length === 1\n ? fieldFilters[0]\n : { compositeFilter: { op: \"AND\", filters: fieldFilters } };\n const structuredQuery: Record<string, unknown> = { from: [{ collectionId }] };\n if (where) structuredQuery.where = where;\n if (limit) structuredQuery.limit = limit;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ structuredQuery }),\n next: { revalidate: 300 },\n });\n if (!res.ok) return [];\n const rows = (await res.json()) as { document?: { name: string; fields: Record<string, FsValue> } }[];\n return rows\n .filter((r) => r.document)\n .map((r) => ({ id: r.document!.name.split(\"/\").pop()!, data: decodeFields(r.document!.fields ?? {}) }));\n } catch (err) {\n console.error(\"[xicms] Firestore REST-query (shop) mislukt:\", err);\n return [];\n }\n}\n\n/* ── Readers ─────────────────────────────────────────────────────────────── */\n\nasync function getActiveProductsUncached(siteId: string): Promise<ServerProduct[]> {\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb.collection(`sites/${siteId}/products`).where(\"status\", \"==\", \"active\").limit(500).get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read producten mislukt — lege lijst:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(siteId, \"products\", [{ fieldPath: \"status\", value: \"active\" }], 500);\n }\n return docs\n .map((d) => parseProduct(d.id, d.data))\n .filter((p): p is ServerProduct => p !== null)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name, \"nl\"));\n}\n\nasync function getShopCategoriesUncached(siteId: string): Promise<ServerShopCategory[]> {\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb.collection(`sites/${siteId}/shopCategories`).limit(100).get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read categorieën mislukt — lege lijst:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(siteId, \"shopCategories\", [], 100);\n }\n return docs\n .map((d) => parseCategory(d.id, d.data))\n .filter((c): c is ServerShopCategory => c !== null && c.visible !== false)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\nasync function getProductBySlugUncached(siteId: string, slug: string): Promise<ServerProduct | null> {\n if (!slug) return null;\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb\n .collection(`sites/${siteId}/products`)\n .where(\"status\", \"==\", \"active\")\n .where(\"slug\", \"==\", slug)\n .limit(1)\n .get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read product mislukt:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(\n siteId,\n \"products\",\n [\n { fieldPath: \"status\", value: \"active\" },\n { fieldPath: \"slug\", value: slug },\n ],\n 1,\n );\n }\n const d = docs[0];\n return d ? parseProduct(d.id, d.data) : null;\n}\n\nexport const getActiveProducts = cache(getActiveProductsUncached);\nexport const getShopCategories = cache(getShopCategoriesUncached);\nexport const getProductBySlug = cache(getProductBySlugUncached);\n\n/**\n * Verzamelt de shop-startdata voor één pagina. `searchParams.p` (detailpagina) bepaalt of er\n * ook een enkel product geladen wordt. Geef het resultaat door als\n * `<PublishedPage blockData={{ shop: data }}>`.\n */\nexport async function getShopPageData(\n siteId: string,\n searchParams?: { p?: string | string[]; [k: string]: unknown },\n): Promise<ShopPageData> {\n const slugParam = searchParams?.p;\n const slug = Array.isArray(slugParam) ? slugParam[0] : slugParam;\n const [products, categories, product] = await Promise.all([\n getActiveProducts(siteId),\n getShopCategories(siteId),\n slug ? getProductBySlug(siteId, slug) : Promise.resolve(undefined),\n ]);\n const data: ShopPageData = { products, categories };\n if (slug !== undefined) data.product = product ?? null;\n return data;\n}\n\n/* ── SEO ─────────────────────────────────────────────────────────────────── */\n\n/** Metadata voor een productdetailpagina (title/description/OG-beeld). */\nexport function buildProductMetadata(\n product: ServerProduct | null,\n site: { name: string; domain?: string },\n): Metadata {\n if (!product) return { title: `Product — ${site.name}` };\n const description = (product.description || `${product.name} — ${site.name}`)\n .replace(/\\s+/g, \" \")\n .slice(0, 300);\n const image = product.images?.[0];\n return {\n title: `${product.name} — ${site.name}`,\n description,\n openGraph: {\n title: product.name,\n description,\n type: \"website\",\n ...(image ? { images: [{ url: image }] } : {}),\n },\n };\n}\n\n/** schema.org Product/Offer-JSON-LD met echte prijs en beschikbaarheid. */\nexport function buildProductJsonLd(\n product: ServerProduct,\n site: { name: string; domain?: string },\n currency = \"EUR\",\n): Record<string, unknown> {\n const soldOut =\n product.trackStock === true &&\n (product.options ?? []).length === 0 &&\n product.stock !== undefined &&\n product.stock <= 0;\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"Product\",\n name: product.name,\n ...(product.description ? { description: product.description.slice(0, 500) } : {}),\n ...(product.images?.length ? { image: product.images } : {}),\n offers: {\n \"@type\": \"Offer\",\n price: (productPriceCents(product) / 100).toFixed(2),\n priceCurrency: currency,\n availability: soldOut ? \"https://schema.org/OutOfStock\" : \"https://schema.org/InStock\",\n ...(site.domain ? { url: `https://${site.domain}/product?p=${encodeURIComponent(product.slug)}` } : {}),\n },\n brand: { \"@type\": \"Brand\", name: site.name },\n };\n}\n"],"mappings":"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","names":["d"]}
1
+ {"version":3,"sources":["../../src/server/shop.ts"],"sourcesContent":["import \"server-only\";\n\nimport { cache } from \"react\";\nimport type { Metadata } from \"next\";\n\nimport { getAdminDb } from \"../firebase/admin\";\nimport {\n ProductSchema,\n ShopCategorySchema,\n productPriceCents,\n type Product,\n type ShopCategory,\n} from \"../schema/shop\";\n\n/**\n * Server-readers voor de shop (5.6) — zelfde contract als server/pages.ts: Admin SDK als die\n * er is, anders keyless Firestore-REST met de publieke web-apiKey (de rules staan publieke\n * reads op actieve producten/categorieën toe). Reads zijn per-request gededupt via cache();\n * route-level ISR (`revalidate`) dempt de kosten tussen requests.\n *\n * Gebruik in de klantsite (catch-all):\n * const blockData = { shop: await getShopPageData(siteId, path, searchParams) };\n * <PublishedPage page={page} siteId={siteId} blockData={blockData} />\n */\n\nexport type ServerProduct = Product & { id: string };\nexport type ServerShopCategory = ShopCategory & { id: string };\n\n// Gedeelde vorm met de blocks (useBlockData(\"shop\")) — één bron van waarheid.\nexport type { ShopPageData } from \"../modules/shop/types\";\nimport type { ShopPageData } from \"../modules/shop/types\";\n\nfunction parseProduct(id: string, data: unknown): ServerProduct | null {\n const res = ProductSchema.safeParse(data);\n if (!res.success) {\n console.warn(`[xicms] product \"${id}\" faalt schema-validatie en wordt overgeslagen:`, res.error.issues[0]);\n return null;\n }\n return { id, ...res.data };\n}\n\nfunction parseCategory(id: string, data: unknown): ServerShopCategory | null {\n const res = ShopCategorySchema.safeParse(data);\n if (!res.success) {\n console.warn(`[xicms] categorie \"${id}\" faalt schema-validatie en wordt overgeslagen:`, res.error.issues[0]);\n return null;\n }\n return { id, ...res.data };\n}\n\n/* ── keyless REST (zelfde aanpak als server/pages.ts) ────────────────────── */\n\ntype FsValue = Record<string, unknown>;\nfunction decode(v: FsValue): unknown {\n if (v == null) return null;\n if (\"stringValue\" in v) return v.stringValue;\n if (\"integerValue\" in v) return Number(v.integerValue);\n if (\"doubleValue\" in v) return v.doubleValue;\n if (\"booleanValue\" in v) return v.booleanValue;\n if (\"nullValue\" in v) return null;\n if (\"timestampValue\" in v) return v.timestampValue;\n if (\"arrayValue\" in v) return (((v.arrayValue as FsValue)?.values as FsValue[]) ?? []).map(decode);\n if (\"mapValue\" in v) return decodeFields(((v.mapValue as FsValue)?.fields as Record<string, FsValue>) ?? {});\n return null;\n}\nfunction decodeFields(fields: Record<string, FsValue>): Record<string, unknown> {\n return Object.fromEntries(Object.entries(fields).map(([k, x]) => [k, decode(x)]));\n}\n\ninterface RestDoc {\n id: string;\n data: Record<string, unknown>;\n}\n\nasync function restQuery(\n siteId: string,\n collectionId: string,\n filters: { fieldPath: string; value: string }[],\n limit?: number,\n): Promise<RestDoc[]> {\n const apiKey = process.env.NEXT_PUBLIC_FIREBASE_API_KEY;\n const projectId = process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID;\n if (!apiKey || !projectId) return [];\n const url = `https://firestore.googleapis.com/v1/projects/${projectId}/databases/(default)/documents/sites/${siteId}:runQuery?key=${apiKey}`;\n const fieldFilters = filters.map((f) => ({\n fieldFilter: { field: { fieldPath: f.fieldPath }, op: \"EQUAL\", value: { stringValue: f.value } },\n }));\n const where =\n fieldFilters.length === 0\n ? undefined\n : fieldFilters.length === 1\n ? fieldFilters[0]\n : { compositeFilter: { op: \"AND\", filters: fieldFilters } };\n const structuredQuery: Record<string, unknown> = { from: [{ collectionId }] };\n if (where) structuredQuery.where = where;\n if (limit) structuredQuery.limit = limit;\n try {\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ structuredQuery }),\n // Zelfde vangnet-logica als pages.ts: de tag is het normale pad, de timer dekt een\n // gemiste revalidate-push. Shop-content wijzigt zelden; elke 5 minuten opnieuw tellen was\n // pure verspilling.\n next: { revalidate: Number(process.env.XICMS_ISR_FALLBACK) || 3600, tags: [`xicms:${siteId}:${collectionId}`] },\n });\n if (!res.ok) return [];\n const rows = (await res.json()) as { document?: { name: string; fields: Record<string, FsValue> } }[];\n return rows\n .filter((r) => r.document)\n .map((r) => ({ id: r.document!.name.split(\"/\").pop()!, data: decodeFields(r.document!.fields ?? {}) }));\n } catch (err) {\n console.error(\"[xicms] Firestore REST-query (shop) mislukt:\", err);\n return [];\n }\n}\n\n/* ── Readers ─────────────────────────────────────────────────────────────── */\n\nasync function getActiveProductsUncached(siteId: string): Promise<ServerProduct[]> {\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb.collection(`sites/${siteId}/products`).where(\"status\", \"==\", \"active\").limit(500).get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read producten mislukt — lege lijst:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(siteId, \"products\", [{ fieldPath: \"status\", value: \"active\" }], 500);\n }\n return docs\n .map((d) => parseProduct(d.id, d.data))\n .filter((p): p is ServerProduct => p !== null)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0) || a.name.localeCompare(b.name, \"nl\"));\n}\n\nasync function getShopCategoriesUncached(siteId: string): Promise<ServerShopCategory[]> {\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb.collection(`sites/${siteId}/shopCategories`).limit(100).get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read categorieën mislukt — lege lijst:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(siteId, \"shopCategories\", [], 100);\n }\n return docs\n .map((d) => parseCategory(d.id, d.data))\n .filter((c): c is ServerShopCategory => c !== null && c.visible !== false)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\nasync function getProductBySlugUncached(siteId: string, slug: string): Promise<ServerProduct | null> {\n if (!slug) return null;\n const adb = getAdminDb();\n let docs: RestDoc[];\n if (adb) {\n try {\n const snap = await adb\n .collection(`sites/${siteId}/products`)\n .where(\"status\", \"==\", \"active\")\n .where(\"slug\", \"==\", slug)\n .limit(1)\n .get();\n docs = snap.docs.map((d) => ({ id: d.id, data: d.data() }));\n } catch (e) {\n console.warn(\"[xicms] Admin-read product mislukt:\", (e as Error)?.message ?? e);\n docs = [];\n }\n } else {\n docs = await restQuery(\n siteId,\n \"products\",\n [\n { fieldPath: \"status\", value: \"active\" },\n { fieldPath: \"slug\", value: slug },\n ],\n 1,\n );\n }\n const d = docs[0];\n return d ? parseProduct(d.id, d.data) : null;\n}\n\nexport const getActiveProducts = cache(getActiveProductsUncached);\nexport const getShopCategories = cache(getShopCategoriesUncached);\nexport const getProductBySlug = cache(getProductBySlugUncached);\n\n/**\n * Verzamelt de shop-startdata voor één pagina. `searchParams.p` (detailpagina) bepaalt of er\n * ook een enkel product geladen wordt. Geef het resultaat door als\n * `<PublishedPage blockData={{ shop: data }}>`.\n */\nexport async function getShopPageData(\n siteId: string,\n searchParams?: { p?: string | string[]; [k: string]: unknown },\n): Promise<ShopPageData> {\n const slugParam = searchParams?.p;\n const slug = Array.isArray(slugParam) ? slugParam[0] : slugParam;\n const [products, categories, product] = await Promise.all([\n getActiveProducts(siteId),\n getShopCategories(siteId),\n slug ? getProductBySlug(siteId, slug) : Promise.resolve(undefined),\n ]);\n const data: ShopPageData = { products, categories };\n if (slug !== undefined) data.product = product ?? null;\n return data;\n}\n\n/* ── SEO ─────────────────────────────────────────────────────────────────── */\n\n/** Metadata voor een productdetailpagina (title/description/OG-beeld). */\nexport function buildProductMetadata(\n product: ServerProduct | null,\n site: { name: string; domain?: string },\n): Metadata {\n if (!product) return { title: `Product — ${site.name}` };\n const description = (product.description || `${product.name} — ${site.name}`)\n .replace(/\\s+/g, \" \")\n .slice(0, 300);\n const image = product.images?.[0];\n return {\n title: `${product.name} — ${site.name}`,\n description,\n openGraph: {\n title: product.name,\n description,\n type: \"website\",\n ...(image ? { images: [{ url: image }] } : {}),\n },\n };\n}\n\n/** schema.org Product/Offer-JSON-LD met echte prijs en beschikbaarheid. */\nexport function buildProductJsonLd(\n product: ServerProduct,\n site: { name: string; domain?: string },\n currency = \"EUR\",\n): Record<string, unknown> {\n const soldOut =\n product.trackStock === true &&\n (product.options ?? []).length === 0 &&\n product.stock !== undefined &&\n product.stock <= 0;\n return {\n \"@context\": \"https://schema.org\",\n \"@type\": \"Product\",\n name: product.name,\n ...(product.description ? { description: product.description.slice(0, 500) } : {}),\n ...(product.images?.length ? { image: product.images } : {}),\n offers: {\n \"@type\": \"Offer\",\n price: (productPriceCents(product) / 100).toFixed(2),\n priceCurrency: currency,\n availability: soldOut ? \"https://schema.org/OutOfStock\" : \"https://schema.org/InStock\",\n ...(site.domain ? { url: `https://${site.domain}/product?p=${encodeURIComponent(product.slug)}` } : {}),\n },\n brand: { \"@type\": \"Brand\", name: site.name },\n };\n}\n"],"mappings":"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","names":["d"]}
@@ -1,6 +1,6 @@
1
1
  import { type ReactNode } from "react";
2
- import { type PublicSiteSettings } from "../schema/settings";
3
- import type { SiteConfig } from "../schema/siteConfig";
2
+ import { type PublicSiteSettings } from "../schema/settings.js";
3
+ import type { SiteConfig } from "../schema/siteConfig.js";
4
4
  /**
5
5
  * Live, publiek-veilige site-instellingen (`sites/{siteId}/settings/public`) zodat dingen die de
6
6
  * klant in /beheer wijzigt (footer, nav, thema, module-instellingen) direct op de site verschijnen.
@@ -1,13 +1,11 @@
1
1
  "use client";
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import { createContext, useContext, useEffect, useMemo, useState } from "react";
4
- import { doc, getDoc, onSnapshot } from "firebase/firestore";
5
- import { getDb } from "../firebase/client";
6
- import { useSiteConfig } from "../config";
4
+ import { useSiteConfig } from "../config.js";
7
5
  import {
8
6
  PublicSiteSettingsSchema,
9
7
  mergeThemeTokens
10
- } from "../schema/settings";
8
+ } from "../schema/settings.js";
11
9
  const SettingsContext = createContext({ settings: {}, loaded: false });
12
10
  function SiteSettingsProvider({
13
11
  siteId,
@@ -20,28 +18,38 @@ function SiteSettingsProvider({
20
18
  const [loaded, setLoaded] = useState(hasInitial);
21
19
  useEffect(() => {
22
20
  if (hasInitial && !live) return;
23
- const db = getDb();
24
- if (!db) {
25
- setLoaded(true);
26
- return;
27
- }
28
- const ref = doc(db, "sites", siteId, "settings", "public");
29
21
  const apply = (data) => {
30
22
  const res = PublicSiteSettingsSchema.safeParse(data ?? {});
31
23
  if (res.success) setSettings(res.data);
32
24
  setLoaded(true);
33
25
  };
34
- if (live) {
35
- return onSnapshot(
36
- ref,
37
- (snap) => apply(snap.exists() ? snap.data() : {}),
38
- () => setLoaded(true)
39
- );
40
- }
41
26
  let cancelled = false;
42
- getDoc(ref).then((snap) => !cancelled && apply(snap.exists() ? snap.data() : {})).catch(() => !cancelled && setLoaded(true));
27
+ let unsub;
28
+ void (async () => {
29
+ const [{ getDb }, { doc, getDoc, onSnapshot }] = await Promise.all([
30
+ import("../firebase/client.js"),
31
+ import("firebase/firestore")
32
+ ]);
33
+ const db = getDb();
34
+ if (!db || cancelled) {
35
+ setLoaded(true);
36
+ return;
37
+ }
38
+ const ref = doc(db, "sites", siteId, "settings", "public");
39
+ if (live) {
40
+ unsub = onSnapshot(ref, (snap) => apply(snap.exists() ? snap.data() : {}), () => setLoaded(true));
41
+ return;
42
+ }
43
+ try {
44
+ const snap = await getDoc(ref);
45
+ if (!cancelled) apply(snap.exists() ? snap.data() : {});
46
+ } catch {
47
+ if (!cancelled) setLoaded(true);
48
+ }
49
+ })();
43
50
  return () => {
44
51
  cancelled = true;
52
+ unsub?.();
45
53
  };
46
54
  }, [siteId, live, hasInitial]);
47
55
  const value = useMemo(() => ({ settings, loaded, _set: setSettings }), [settings, loaded]);
@@ -54,16 +62,28 @@ function useSiteSettingsLiveSync(siteId, enabled) {
54
62
  const { _set } = useContext(SettingsContext);
55
63
  useEffect(() => {
56
64
  if (!enabled || !_set) return;
57
- const db = getDb();
58
- if (!db) return;
59
- return onSnapshot(
60
- doc(db, "sites", siteId, "settings", "public"),
61
- (snap) => {
62
- const res = PublicSiteSettingsSchema.safeParse(snap.exists() ? snap.data() : {});
63
- if (res.success) _set(res.data);
64
- },
65
- () => void 0
66
- );
65
+ let unsub;
66
+ let afgebroken = false;
67
+ void (async () => {
68
+ const [{ getDb }, { doc, onSnapshot }] = await Promise.all([
69
+ import("../firebase/client.js"),
70
+ import("firebase/firestore")
71
+ ]);
72
+ const db = getDb();
73
+ if (!db || afgebroken) return;
74
+ unsub = onSnapshot(
75
+ doc(db, "sites", siteId, "settings", "public"),
76
+ (snap) => {
77
+ const res = PublicSiteSettingsSchema.safeParse(snap.exists() ? snap.data() : {});
78
+ if (res.success) _set(res.data);
79
+ },
80
+ () => void 0
81
+ );
82
+ })();
83
+ return () => {
84
+ afgebroken = true;
85
+ unsub?.();
86
+ };
67
87
  }, [enabled, siteId, _set]);
68
88
  }
69
89
  function useMergedSiteConfig() {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/settings/useSiteSettings.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { doc, getDoc, onSnapshot } from \"firebase/firestore\";\nimport { getDb } from \"../firebase/client\";\nimport { useSiteConfig } from \"../config\";\nimport {\n PublicSiteSettingsSchema,\n mergeThemeTokens,\n type PublicSiteSettings,\n} from \"../schema/settings\";\nimport type { SiteConfig } from \"../schema/siteConfig\";\n\n/**\n * Live, publiek-veilige site-instellingen (`sites/{siteId}/settings/public`) zodat dingen die de\n * klant in /beheer wijzigt (footer, nav, thema, module-instellingen) direct op de site verschijnen.\n *\n * - Met SSR-seed (`initial`, via XiCMSProvider `settingsData`): géén client-read voor publiek —\n * de settings zitten al in de server-HTML (geen theme-flits) en verversen via ISR.\n * - Zonder seed (publiek): één `getDoc` (geen per-bezoeker listener).\n * - Editors: `useSiteSettingsLiveSync` (onSnapshot) zodat /beheer-wijzigingen meteen zichtbaar zijn.\n * Zonder Firebase of zonder doc valt alles terug op de statische `SiteConfig` (identiek aan vroeger).\n */\ninterface Ctx {\n settings: PublicSiteSettings;\n loaded: boolean;\n /** Interne setter voor de editor-live-sync (useSiteSettingsLiveSync). */\n _set?: (s: PublicSiteSettings) => void;\n}\nconst SettingsContext = createContext<Ctx>({ settings: {}, loaded: false });\n\nexport function SiteSettingsProvider({\n siteId,\n live = false,\n initial,\n children,\n}: {\n siteId: string;\n live?: boolean;\n /** SSR-startset (server-side gelezen via `getPublicSiteSettings`); slaat de client-read over. */\n initial?: PublicSiteSettings;\n children: ReactNode;\n}) {\n const hasInitial = initial !== undefined;\n const [settings, setSettings] = useState<PublicSiteSettings>(initial ?? {});\n const [loaded, setLoaded] = useState(hasInitial);\n\n useEffect(() => {\n // Met een SSR-seed doet de publieke site géén client-read meer: de layout-route is ISR-gecached\n // en levert verse settings per revalidate; editors krijgen apart een live sync.\n if (hasInitial && !live) return;\n const db = getDb();\n if (!db) {\n setLoaded(true);\n return;\n }\n const ref = doc(db, \"sites\", siteId, \"settings\", \"public\");\n const apply = (data: unknown) => {\n const res = PublicSiteSettingsSchema.safeParse(data ?? {});\n if (res.success) setSettings(res.data);\n setLoaded(true);\n };\n if (live) {\n return onSnapshot(\n ref,\n (snap) => apply(snap.exists() ? snap.data() : {}),\n () => setLoaded(true),\n );\n }\n let cancelled = false;\n getDoc(ref)\n .then((snap) => !cancelled && apply(snap.exists() ? snap.data() : {}))\n .catch(() => !cancelled && setLoaded(true));\n return () => {\n cancelled = true;\n };\n }, [siteId, live, hasInitial]);\n\n const value = useMemo<Ctx>(() => ({ settings, loaded, _set: setSettings }), [settings, loaded]);\n return <SettingsContext.Provider value={value}>{children}</SettingsContext.Provider>;\n}\n\n/** Ruwe publieke settings + laadstatus. */\nexport function useSiteSettings(): Ctx {\n return useContext(SettingsContext);\n}\n\n/**\n * Editor-live-sync: onSnapshot op `settings/public` zolang `enabled` (ingelogde editor). Aparte\n * hook (i.p.v. `live` op de provider) zodat publiek nooit een listener krijgt — zelfde patroon\n * als CustomBlocksSync in XiCMSProvider. Een leesfout laat de bestaande settings staan.\n */\nexport function useSiteSettingsLiveSync(siteId: string, enabled: boolean) {\n const { _set } = useContext(SettingsContext);\n useEffect(() => {\n if (!enabled || !_set) return;\n const db = getDb();\n if (!db) return;\n return onSnapshot(\n doc(db, \"sites\", siteId, \"settings\", \"public\"),\n (snap) => {\n const res = PublicSiteSettingsSchema.safeParse(snap.exists() ? snap.data() : {});\n if (res.success) _set(res.data);\n },\n () => undefined,\n );\n }, [enabled, siteId, _set]);\n}\n\n/** SiteConfig met de live Firestore-settings eroverheen (Firestore wint waar gezet). */\nexport function useMergedSiteConfig(): SiteConfig {\n const base = useSiteConfig();\n const { settings } = useSiteSettings();\n return useMemo(() => {\n const nav = settings.nav && settings.nav.length > 0 ? settings.nav : base.nav;\n return {\n ...base,\n name: settings.name ?? base.name,\n nav,\n theme: mergeThemeTokens(base.theme, settings.theme),\n seoDefaults: settings.seoDefaults ?? base.seoDefaults,\n };\n }, [base, settings]);\n}\n"],"mappings":";AA+ES;AA7ET,SAAS,eAAe,YAAY,WAAW,SAAS,gBAAgC;AACxF,SAAS,KAAK,QAAQ,kBAAkB;AACxC,SAAS,aAAa;AACtB,SAAS,qBAAqB;AAC9B;AAAA,EACE;AAAA,EACA;AAAA,OAEK;AAmBP,MAAM,kBAAkB,cAAmB,EAAE,UAAU,CAAC,GAAG,QAAQ,MAAM,CAAC;AAEnE,SAAS,qBAAqB;AAAA,EACnC;AAAA,EACA,OAAO;AAAA,EACP;AAAA,EACA;AACF,GAMG;AACD,QAAM,aAAa,YAAY;AAC/B,QAAM,CAAC,UAAU,WAAW,IAAI,SAA6B,WAAW,CAAC,CAAC;AAC1E,QAAM,CAAC,QAAQ,SAAS,IAAI,SAAS,UAAU;AAE/C,YAAU,MAAM;AAGd,QAAI,cAAc,CAAC,KAAM;AACzB,UAAM,KAAK,MAAM;AACjB,QAAI,CAAC,IAAI;AACP,gBAAU,IAAI;AACd;AAAA,IACF;AACA,UAAM,MAAM,IAAI,IAAI,SAAS,QAAQ,YAAY,QAAQ;AACzD,UAAM,QAAQ,CAAC,SAAkB;AAC/B,YAAM,MAAM,yBAAyB,UAAU,QAAQ,CAAC,CAAC;AACzD,UAAI,IAAI,QAAS,aAAY,IAAI,IAAI;AACrC,gBAAU,IAAI;AAAA,IAChB;AACA,QAAI,MAAM;AACR,aAAO;AAAA,QACL;AAAA,QACA,CAAC,SAAS,MAAM,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;AAAA,QAChD,MAAM,UAAU,IAAI;AAAA,MACtB;AAAA,IACF;AACA,QAAI,YAAY;AAChB,WAAO,GAAG,EACP,KAAK,CAAC,SAAS,CAAC,aAAa,MAAM,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EACpE,MAAM,MAAM,CAAC,aAAa,UAAU,IAAI,CAAC;AAC5C,WAAO,MAAM;AACX,kBAAY;AAAA,IACd;AAAA,EACF,GAAG,CAAC,QAAQ,MAAM,UAAU,CAAC;AAE7B,QAAM,QAAQ,QAAa,OAAO,EAAE,UAAU,QAAQ,MAAM,YAAY,IAAI,CAAC,UAAU,MAAM,CAAC;AAC9F,SAAO,oBAAC,gBAAgB,UAAhB,EAAyB,OAAe,UAAS;AAC3D;AAGO,SAAS,kBAAuB;AACrC,SAAO,WAAW,eAAe;AACnC;AAOO,SAAS,wBAAwB,QAAgB,SAAkB;AACxE,QAAM,EAAE,KAAK,IAAI,WAAW,eAAe;AAC3C,YAAU,MAAM;AACd,QAAI,CAAC,WAAW,CAAC,KAAM;AACvB,UAAM,KAAK,MAAM;AACjB,QAAI,CAAC,GAAI;AACT,WAAO;AAAA,MACL,IAAI,IAAI,SAAS,QAAQ,YAAY,QAAQ;AAAA,MAC7C,CAAC,SAAS;AACR,cAAM,MAAM,yBAAyB,UAAU,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC;AAC/E,YAAI,IAAI,QAAS,MAAK,IAAI,IAAI;AAAA,MAChC;AAAA,MACA,MAAM;AAAA,IACR;AAAA,EACF,GAAG,CAAC,SAAS,QAAQ,IAAI,CAAC;AAC5B;AAGO,SAAS,sBAAkC;AAChD,QAAM,OAAO,cAAc;AAC3B,QAAM,EAAE,SAAS,IAAI,gBAAgB;AACrC,SAAO,QAAQ,MAAM;AACnB,UAAM,MAAM,SAAS,OAAO,SAAS,IAAI,SAAS,IAAI,SAAS,MAAM,KAAK;AAC1E,WAAO;AAAA,MACL,GAAG;AAAA,MACH,MAAM,SAAS,QAAQ,KAAK;AAAA,MAC5B;AAAA,MACA,OAAO,iBAAiB,KAAK,OAAO,SAAS,KAAK;AAAA,MAClD,aAAa,SAAS,eAAe,KAAK;AAAA,IAC5C;AAAA,EACF,GAAG,CAAC,MAAM,QAAQ,CAAC;AACrB;","names":[]}
1
+ {"version":3,"sources":["../../src/settings/useSiteSettings.tsx"],"sourcesContent":["\"use client\";\n\nimport { createContext, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { useSiteConfig } from \"../config\";\nimport {\n PublicSiteSettingsSchema,\n mergeThemeTokens,\n type PublicSiteSettings,\n} from \"../schema/settings\";\nimport type { SiteConfig } from \"../schema/siteConfig\";\n\n/**\n * Live, publiek-veilige site-instellingen (`sites/{siteId}/settings/public`) zodat dingen die de\n * klant in /beheer wijzigt (footer, nav, thema, module-instellingen) direct op de site verschijnen.\n *\n * - Met SSR-seed (`initial`, via XiCMSProvider `settingsData`): géén client-read voor publiek —\n * de settings zitten al in de server-HTML (geen theme-flits) en verversen via ISR.\n * - Zonder seed (publiek): één `getDoc` (geen per-bezoeker listener).\n * - Editors: `useSiteSettingsLiveSync` (onSnapshot) zodat /beheer-wijzigingen meteen zichtbaar zijn.\n * Zonder Firebase of zonder doc valt alles terug op de statische `SiteConfig` (identiek aan vroeger).\n */\ninterface Ctx {\n settings: PublicSiteSettings;\n loaded: boolean;\n /** Interne setter voor de editor-live-sync (useSiteSettingsLiveSync). */\n _set?: (s: PublicSiteSettings) => void;\n}\nconst SettingsContext = createContext<Ctx>({ settings: {}, loaded: false });\n\nexport function SiteSettingsProvider({\n siteId,\n live = false,\n initial,\n children,\n}: {\n siteId: string;\n live?: boolean;\n /** SSR-startset (server-side gelezen via `getPublicSiteSettings`); slaat de client-read over. */\n initial?: PublicSiteSettings;\n children: ReactNode;\n}) {\n const hasInitial = initial !== undefined;\n const [settings, setSettings] = useState<PublicSiteSettings>(initial ?? {});\n const [loaded, setLoaded] = useState(hasInitial);\n\n useEffect(() => {\n // Met een SSR-seed doet de publieke site géén client-read meer: de layout-route is ISR-gecached\n // en levert verse settings per revalidate; editors krijgen apart een live sync.\n if (hasInitial && !live) return;\n const apply = (data: unknown) => {\n const res = PublicSiteSettingsSchema.safeParse(data ?? {});\n if (res.success) setSettings(res.data);\n setLoaded(true);\n };\n // Firestore DYNAMISCH: met een SSR-seed komt de publieke site hier niet eens, en een bezoeker\n // hoort de SDK nooit te downloaden. Statisch importeren zette hem in de bundel van elke pagina.\n let cancelled = false;\n let unsub: (() => void) | undefined;\n void (async () => {\n const [{ getDb }, { doc, getDoc, onSnapshot }] = await Promise.all([\n import(\"../firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || cancelled) {\n setLoaded(true);\n return;\n }\n const ref = doc(db, \"sites\", siteId, \"settings\", \"public\");\n if (live) {\n unsub = onSnapshot(ref, (snap) => apply(snap.exists() ? snap.data() : {}), () => setLoaded(true));\n return;\n }\n try {\n const snap = await getDoc(ref);\n if (!cancelled) apply(snap.exists() ? snap.data() : {});\n } catch {\n if (!cancelled) setLoaded(true);\n }\n })();\n return () => {\n cancelled = true;\n unsub?.();\n };\n }, [siteId, live, hasInitial]);\n\n const value = useMemo<Ctx>(() => ({ settings, loaded, _set: setSettings }), [settings, loaded]);\n return <SettingsContext.Provider value={value}>{children}</SettingsContext.Provider>;\n}\n\n/** Ruwe publieke settings + laadstatus. */\nexport function useSiteSettings(): Ctx {\n return useContext(SettingsContext);\n}\n\n/**\n * Editor-live-sync: onSnapshot op `settings/public` zolang `enabled` (ingelogde editor). Aparte\n * hook (i.p.v. `live` op de provider) zodat publiek nooit een listener krijgt — zelfde patroon\n * als CustomBlocksSync in XiCMSProvider. Een leesfout laat de bestaande settings staan.\n */\nexport function useSiteSettingsLiveSync(siteId: string, enabled: boolean) {\n const { _set } = useContext(SettingsContext);\n useEffect(() => {\n // Alleen editors (enabled) krijgen een listener, en pas dán laadt de SDK.\n if (!enabled || !_set) return;\n let unsub: (() => void) | undefined;\n let afgebroken = false;\n void (async () => {\n const [{ getDb }, { doc, onSnapshot }] = await Promise.all([\n import(\"../firebase/client\"),\n import(\"firebase/firestore\"),\n ]);\n const db = getDb();\n if (!db || afgebroken) return;\n unsub = onSnapshot(\n doc(db, \"sites\", siteId, \"settings\", \"public\"),\n (snap) => {\n const res = PublicSiteSettingsSchema.safeParse(snap.exists() ? snap.data() : {});\n if (res.success) _set(res.data);\n },\n () => undefined,\n );\n })();\n return () => {\n afgebroken = true;\n unsub?.();\n };\n }, [enabled, siteId, _set]);\n}\n\n/** SiteConfig met de live Firestore-settings eroverheen (Firestore wint waar gezet). */\nexport function useMergedSiteConfig(): SiteConfig {\n const base = useSiteConfig();\n const { settings } = useSiteSettings();\n return useMemo(() => {\n const nav = settings.nav && settings.nav.length > 0 ? settings.nav : base.nav;\n return {\n ...base,\n name: settings.name ?? base.name,\n nav,\n theme: mergeThemeTokens(base.theme, settings.theme),\n seoDefaults: settings.seoDefaults ?? base.seoDefaults,\n };\n }, [base, settings]);\n}\n"],"mappings":"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","names":[]}
package/dist/styles.css CHANGED
@@ -1346,7 +1346,10 @@
1346
1346
  text-decoration: underline;
1347
1347
  }
1348
1348
  .xicms-hours__badge {
1349
- display: inline-block;
1349
+ /* inline-flex + gap: de statusstip is nu een eigen element naast de tekst, geen teken erin. */
1350
+ display: inline-flex;
1351
+ align-items: center;
1352
+ gap: 0.4rem;
1350
1353
  margin: 0.15rem 0 0.6rem;
1351
1354
  padding: 0.2rem 0.65rem;
1352
1355
  border-radius: 999px;
@@ -1,4 +1,4 @@
1
- import type { ThemeTokens } from "../schema/settings";
1
+ import type { ThemeTokens } from "../schema/settings.js";
2
2
  /**
3
3
  * Kant-en-klare thema-presets (kleur + lettertype + afronding) waarmee een agent of editor in één
4
4
  * keuze een verzorgde huisstijl neerzet. Pas daarna gerust losse tokens aan. De `fontUrl` is een
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiwebdesign/xicms-core",
3
- "version": "6.5.0",
3
+ "version": "7.0.0",
4
4
  "description": "XiCMS engine: gestructureerde content, pagina's, draft/publish, admin (TipTap+Radix), SEO en beveiliging voor klantsites.",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -40,6 +40,10 @@
40
40
  "types": "./dist/server/shop.d.ts",
41
41
  "import": "./dist/server/shop.js"
42
42
  },
43
+ "./server/auth": {
44
+ "types": "./dist/server/auth.d.ts",
45
+ "import": "./dist/server/auth.js"
46
+ },
43
47
  "./all": {
44
48
  "types": "./dist/all.d.ts",
45
49
  "import": "./dist/all.js"
@@ -76,13 +80,13 @@
76
80
  "access": "public"
77
81
  },
78
82
  "scripts": {
79
- "build": "tsup && tsc -p tsconfig.build.json && tailwindcss -c src/admin/tailwind.config.cjs -i src/admin/admin.css -o dist/admin.css --minify && node ./scripts/copy-css.mjs",
83
+ "build": "tsup && tsc -p tsconfig.build.json && tailwindcss -i src/admin/admin.css -o dist/admin.css --minify && node ./scripts/copy-css.mjs && node ./scripts/add-extensions.mjs",
80
84
  "typecheck": "tsc --noEmit",
81
85
  "test": "vitest run",
82
86
  "prepublishOnly": "npm run build"
83
87
  },
84
88
  "peerDependencies": {
85
- "firebase": "^11.0.0",
89
+ "firebase": "^12.0.0",
86
90
  "next": "^15 || ^16",
87
91
  "react": "^18 || ^19",
88
92
  "react-dom": "^18 || ^19"
@@ -93,43 +97,40 @@
93
97
  }
94
98
  },
95
99
  "dependencies": {
96
- "@astryxdesign/core": "^0.1.1",
97
- "@astryxdesign/theme-neutral": "^0.1.1",
98
- "@radix-ui/react-dialog": "^1.1.19",
99
- "@radix-ui/react-dropdown-menu": "^2.1.20",
100
- "@radix-ui/react-label": "^2.1.11",
101
- "@radix-ui/react-select": "^2.3.3",
102
- "@radix-ui/react-switch": "^1.3.3",
103
- "@radix-ui/react-tabs": "^1.1.17",
104
- "@radix-ui/react-toast": "^1.2.19",
105
- "@radix-ui/react-tooltip": "^1.2.12",
106
- "@tiptap/extension-image": "^2.11.0",
107
- "@tiptap/extension-link": "^2.11.0",
108
- "@tiptap/extension-text-style": "^2.27.2",
109
- "@tiptap/extension-underline": "^2.27.2",
110
- "@tiptap/pm": "^2.11.0",
111
- "@tiptap/react": "^2.11.0",
112
- "@tiptap/starter-kit": "^2.11.0",
100
+ "@astryxdesign/core": "^0.4.2",
101
+ "@astryxdesign/theme-neutral": "^0.4.2",
102
+ "@radix-ui/react-tabs": "^1.1.21",
103
+ "@tiptap/extension-image": "^3.30.1",
104
+ "@tiptap/extension-link": "^3.30.1",
105
+ "@tiptap/extension-text-style": "^3.30.1",
106
+ "@tiptap/pm": "^3.30.1",
107
+ "@tiptap/react": "^3.30.1",
108
+ "@tiptap/starter-kit": "^3.30.1",
113
109
  "clsx": "^2.1.1",
114
110
  "dompurify": "^3.2.3",
115
- "firebase-admin": "^13.0.0",
116
- "html2canvas-pro": "^1.5.11",
117
- "sanitize-html": "^2.14.0",
118
- "tailwind-merge": "^2.6.0",
119
- "zod": "^3.24.1"
111
+ "firebase-admin": "^14.2.0",
112
+ "html2canvas-pro": "^2.3.8",
113
+ "sanitize-html": "^2.17.7",
114
+ "tailwind-merge": "^3.6.0",
115
+ "zod": "^4.4.3"
120
116
  },
121
117
  "devDependencies": {
122
- "@astryxdesign/cli": "^0.1.1",
123
- "@types/react": "^19.0.0",
124
- "@types/react-dom": "^19.0.0",
118
+ "@astryxdesign/cli": "^0.4.2",
119
+ "@tailwindcss/cli": "^4.3.3",
120
+ "@testing-library/dom": "^10.4.1",
121
+ "@testing-library/react": "^16.3.2",
122
+ "@testing-library/user-event": "^14.6.4",
123
+ "@types/react": "^19.2.18",
124
+ "@types/react-dom": "^19.2.4",
125
125
  "@types/sanitize-html": "^2.13.0",
126
- "firebase": "^11.0.0",
126
+ "firebase": "^12.17.1",
127
+ "jsdom": "^30.0.1",
127
128
  "next": "^16.0.0",
128
- "react": "^19.0.0",
129
- "react-dom": "^19.0.0",
130
- "tailwindcss": "^3.4.17",
129
+ "react": "^19.2.8",
130
+ "react-dom": "^19.2.8",
131
+ "tailwindcss": "^4.3.3",
131
132
  "tsup": "^8.5.0",
132
- "typescript": "^5.6.0",
133
- "vitest": "^2.1.8"
133
+ "typescript": "^7.0.2",
134
+ "vitest": "^4.1.10"
134
135
  }
135
136
  }