@xiwebdesign/xicms-core 7.30.0 → 8.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/XiCMSProvider.js +22 -7
- package/dist/XiCMSProvider.js.map +1 -1
- package/dist/admin/AdminApp.js +175 -93
- package/dist/admin/AdminApp.js.map +1 -1
- package/dist/admin/AdminHelp.d.ts +1 -1
- package/dist/admin/AdminHelp.js +44 -36
- package/dist/admin/AdminHelp.js.map +1 -1
- package/dist/admin/CoreVersion.d.ts +6 -3
- package/dist/admin/CoreVersion.js +60 -24
- package/dist/admin/CoreVersion.js.map +1 -1
- package/dist/admin/NewsEditor.d.ts +7 -0
- package/dist/admin/NewsEditor.js +117 -75
- package/dist/admin/NewsEditor.js.map +1 -1
- package/dist/admin/SuperadminPanel.js +1 -1
- package/dist/admin/SuperadminPanel.js.map +1 -1
- package/dist/admin/ZoekPalet.d.ts +15 -0
- package/dist/admin/ZoekPalet.js +123 -0
- package/dist/admin/ZoekPalet.js.map +1 -0
- package/dist/admin/blockEditors/GenericEditor.js +36 -18
- package/dist/admin/blockEditors/GenericEditor.js.map +1 -1
- package/dist/admin/blockEditors/StyleEditor.js +37 -3
- package/dist/admin/blockEditors/StyleEditor.js.map +1 -1
- package/dist/admin/blockEditors/SymbolRefEditor.js +44 -2
- package/dist/admin/blockEditors/SymbolRefEditor.js.map +1 -1
- package/dist/admin/blockEditors/index.js +154 -73
- package/dist/admin/blockEditors/index.js.map +1 -1
- package/dist/admin/customBlocks/CustomBlocksPanel.js +18 -7
- package/dist/admin/customBlocks/CustomBlocksPanel.js.map +1 -1
- package/dist/admin/dashboard/DashboardPanel.js +26 -16
- package/dist/admin/dashboard/DashboardPanel.js.map +1 -1
- package/dist/admin/editors/RichTextEditor.d.ts +4 -3
- package/dist/admin/editors/RichTextEditor.js +19 -56
- package/dist/admin/editors/RichTextEditor.js.map +1 -1
- package/dist/admin/editors/fontSizeExtension.js +7 -1
- package/dist/admin/editors/fontSizeExtension.js.map +1 -1
- package/dist/admin/editors/slashMenu.d.ts +18 -0
- package/dist/admin/editors/slashMenu.js +34 -0
- package/dist/admin/editors/slashMenu.js.map +1 -0
- package/dist/admin/editors/useRijkeTekst.d.ts +48 -0
- package/dist/admin/editors/useRijkeTekst.js +310 -0
- package/dist/admin/editors/useRijkeTekst.js.map +1 -0
- package/dist/admin/forms/FormsPanel.d.ts +11 -2
- package/dist/admin/forms/FormsPanel.js +218 -65
- package/dist/admin/forms/FormsPanel.js.map +1 -1
- package/dist/admin/lib/blokInfo.d.ts +17 -0
- package/dist/admin/lib/blokInfo.js +80 -0
- package/dist/admin/lib/blokInfo.js.map +1 -0
- package/dist/admin/lib/foutNaarMens.d.ts +1 -0
- package/dist/admin/lib/foutNaarMens.js +22 -0
- package/dist/admin/lib/foutNaarMens.js.map +1 -0
- package/dist/admin/lib/gewisteVelden.d.ts +13 -0
- package/dist/admin/lib/gewisteVelden.js +31 -0
- package/dist/admin/lib/gewisteVelden.js.map +1 -0
- package/dist/admin/lib/heroHulp.d.ts +11 -0
- package/dist/admin/lib/heroHulp.js +18 -0
- package/dist/admin/lib/heroHulp.js.map +1 -0
- package/dist/admin/lib/kleur.js +2 -3
- package/dist/admin/lib/kleur.js.map +1 -1
- package/dist/admin/lib/leesbaarheid.d.ts +34 -0
- package/dist/admin/lib/leesbaarheid.js +82 -0
- package/dist/admin/lib/leesbaarheid.js.map +1 -0
- package/dist/admin/lib/lengteAdvies.d.ts +1 -0
- package/dist/admin/lib/lengteAdvies.js +16 -0
- package/dist/admin/lib/lengteAdvies.js.map +1 -0
- package/dist/admin/lib/mediaLijst.d.ts +26 -0
- package/dist/admin/lib/mediaLijst.js +42 -0
- package/dist/admin/lib/mediaLijst.js.map +1 -0
- package/dist/admin/lib/mediaUsage.d.ts +12 -1
- package/dist/admin/lib/mediaUsage.js +43 -33
- package/dist/admin/lib/mediaUsage.js.map +1 -1
- package/dist/admin/lib/menuHulp.d.ts +16 -0
- package/dist/admin/lib/menuHulp.js +41 -0
- package/dist/admin/lib/menuHulp.js.map +1 -0
- package/dist/admin/lib/onopgeslagen.d.ts +10 -0
- package/dist/admin/lib/onopgeslagen.js +35 -0
- package/dist/admin/lib/onopgeslagen.js.map +1 -0
- package/dist/admin/lib/pagesClient.d.ts +55 -2
- package/dist/admin/lib/pagesClient.js +126 -28
- package/dist/admin/lib/pagesClient.js.map +1 -1
- package/dist/admin/lib/paginaGebruik.d.ts +56 -0
- package/dist/admin/lib/paginaGebruik.js +109 -0
- package/dist/admin/lib/paginaGebruik.js.map +1 -0
- package/dist/admin/lib/publicatieCheck.d.ts +25 -0
- package/dist/admin/lib/publicatieCheck.js +114 -0
- package/dist/admin/lib/publicatieCheck.js.map +1 -0
- package/dist/admin/lib/scrollNaarDetail.d.ts +6 -0
- package/dist/admin/lib/scrollNaarDetail.js +20 -0
- package/dist/admin/lib/scrollNaarDetail.js.map +1 -0
- package/dist/admin/lib/symbolsClient.d.ts +10 -0
- package/dist/admin/lib/symbolsClient.js +14 -1
- package/dist/admin/lib/symbolsClient.js.map +1 -1
- package/dist/admin/lib/tekstVeld.d.ts +8 -0
- package/dist/admin/lib/tekstVeld.js +10 -0
- package/dist/admin/lib/tekstVeld.js.map +1 -0
- package/dist/admin/lib/useIsSuperadmin.d.ts +2 -0
- package/dist/admin/lib/useIsSuperadmin.js +13 -0
- package/dist/admin/lib/useIsSuperadmin.js.map +1 -0
- package/dist/admin/lib/veldTaal.d.ts +14 -0
- package/dist/admin/lib/veldTaal.js +247 -0
- package/dist/admin/lib/veldTaal.js.map +1 -0
- package/dist/admin/lib/versieVergelijk.d.ts +17 -0
- package/dist/admin/lib/versieVergelijk.js +24 -0
- package/dist/admin/lib/versieVergelijk.js.map +1 -0
- package/dist/admin/lib/zodFields.js +22 -4
- package/dist/admin/lib/zodFields.js.map +1 -1
- package/dist/admin/lib/zodFout.d.ts +9 -0
- package/dist/admin/lib/zodFout.js +63 -0
- package/dist/admin/lib/zodFout.js.map +1 -0
- package/dist/admin/media/MediaManager.js +162 -32
- package/dist/admin/media/MediaManager.js.map +1 -1
- package/dist/admin/media/MediaPicker.d.ts +3 -0
- package/dist/admin/media/MediaPicker.js +84 -31
- package/dist/admin/media/MediaPicker.js.map +1 -1
- package/dist/admin/menu/MenuPanel.js +144 -83
- package/dist/admin/menu/MenuPanel.js.map +1 -1
- package/dist/admin/navContext.d.ts +3 -0
- package/dist/admin/navContext.js +13 -1
- package/dist/admin/navContext.js.map +1 -1
- package/dist/admin/pages/PageEditor.js +146 -30
- package/dist/admin/pages/PageEditor.js.map +1 -1
- package/dist/admin/pages/PagesPanel.js +215 -61
- package/dist/admin/pages/PagesPanel.js.map +1 -1
- package/dist/admin/pages/StarterKiezer.d.ts +12 -0
- package/dist/admin/pages/StarterKiezer.js +113 -0
- package/dist/admin/pages/StarterKiezer.js.map +1 -0
- package/dist/admin/panelRegistry.d.ts +1 -1
- package/dist/admin/panelRegistry.js +2 -1
- package/dist/admin/panelRegistry.js.map +1 -1
- package/dist/admin/patterns/PatternInserter.js +1 -1
- package/dist/admin/patterns/PatternInserter.js.map +1 -1
- package/dist/admin/settings/BedrijfInstellingen.d.ts +20 -0
- package/dist/admin/settings/BedrijfInstellingen.js +144 -0
- package/dist/admin/settings/BedrijfInstellingen.js.map +1 -0
- package/dist/admin/settings/MailSettings.js +2 -2
- package/dist/admin/settings/MailSettings.js.map +1 -1
- package/dist/admin/settings/MailTemplates.js +5 -4
- package/dist/admin/settings/MailTemplates.js.map +1 -1
- package/dist/admin/settings/SettingsPanel.js +120 -78
- package/dist/admin/settings/SettingsPanel.js.map +1 -1
- package/dist/admin/settings/SnapshotsCard.js +4 -4
- package/dist/admin/settings/SnapshotsCard.js.map +1 -1
- package/dist/admin/settings/VorigeTerugzetten.d.ts +15 -0
- package/dist/admin/settings/VorigeTerugzetten.js +89 -0
- package/dist/admin/settings/VorigeTerugzetten.js.map +1 -0
- package/dist/admin/shop/CategoriesTab.js +6 -4
- package/dist/admin/shop/CategoriesTab.js.map +1 -1
- package/dist/admin/shop/DiscountsTab.js +4 -2
- package/dist/admin/shop/DiscountsTab.js.map +1 -1
- package/dist/admin/shop/OrdersTab.js +57 -19
- package/dist/admin/shop/OrdersTab.js.map +1 -1
- package/dist/admin/shop/ProductPaneel.js +2 -1
- package/dist/admin/shop/ProductPaneel.js.map +1 -1
- package/dist/admin/shop/ProductsTab.js +40 -19
- package/dist/admin/shop/ProductsTab.js.map +1 -1
- package/dist/admin/shop/ShopPanel.js +13 -1
- package/dist/admin/shop/ShopPanel.js.map +1 -1
- package/dist/admin/shop/ShopSettingsTab.js +27 -1
- package/dist/admin/shop/ShopSettingsTab.js.map +1 -1
- package/dist/admin/shop/productClient.js +7 -3
- package/dist/admin/shop/productClient.js.map +1 -1
- package/dist/admin/stats/NietGevonden.d.ts +10 -0
- package/dist/admin/stats/NietGevonden.js +78 -0
- package/dist/admin/stats/NietGevonden.js.map +1 -0
- package/dist/admin/stats/StatsPanel.js +6 -1
- package/dist/admin/stats/StatsPanel.js.map +1 -1
- package/dist/admin/stats/lib.d.ts +2 -0
- package/dist/admin/stats/lib.js.map +1 -1
- package/dist/admin/ui/ConfirmDialog.js +10 -1
- package/dist/admin/ui/ConfirmDialog.js.map +1 -1
- package/dist/admin/ui/Icon.d.ts +34 -0
- package/dist/admin/ui/Icon.js +44 -0
- package/dist/admin/ui/Icon.js.map +1 -0
- package/dist/admin/ui/ImageField.d.ts +15 -0
- package/dist/admin/ui/ImageField.js +67 -0
- package/dist/admin/ui/ImageField.js.map +1 -0
- package/dist/admin/ui/KleurVeld.d.ts +25 -0
- package/dist/admin/ui/KleurVeld.js +76 -0
- package/dist/admin/ui/KleurVeld.js.map +1 -0
- package/dist/admin/ui/LaadStaat.d.ts +21 -0
- package/dist/admin/ui/LaadStaat.js +43 -0
- package/dist/admin/ui/LaadStaat.js.map +1 -0
- package/dist/admin/ui/LeesbaarheidPaneel.d.ts +10 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js +68 -0
- package/dist/admin/ui/LeesbaarheidPaneel.js.map +1 -0
- package/dist/admin/ui/LinkDialog.d.ts +22 -0
- package/dist/admin/ui/LinkDialog.js +131 -0
- package/dist/admin/ui/LinkDialog.js.map +1 -0
- package/dist/admin/ui/LinkVeld.d.ts +14 -0
- package/dist/admin/ui/LinkVeld.js +49 -0
- package/dist/admin/ui/LinkVeld.js.map +1 -0
- package/dist/admin/ui/PreviewLinkResultaat.d.ts +14 -0
- package/dist/admin/ui/PreviewLinkResultaat.js +52 -0
- package/dist/admin/ui/PreviewLinkResultaat.js.map +1 -0
- package/dist/admin/ui/charts.js +5 -5
- package/dist/admin/ui/charts.js.map +1 -1
- package/dist/admin/ui/primitives.d.ts +16 -6
- package/dist/admin/ui/primitives.js +98 -26
- package/dist/admin/ui/primitives.js.map +1 -1
- package/dist/admin/ui/select.js +5 -2
- package/dist/admin/ui/select.js.map +1 -1
- package/dist/admin/ui/switch.d.ts +3 -1
- package/dist/admin/ui/switch.js +6 -3
- package/dist/admin/ui/switch.js.map +1 -1
- package/dist/admin/ui/toast.d.ts +2 -1
- package/dist/admin/ui/toast.js +17 -11
- package/dist/admin/ui/toast.js.map +1 -1
- package/dist/admin/visual/BlokKiezer.d.ts +34 -0
- package/dist/admin/visual/BlokKiezer.js +225 -0
- package/dist/admin/visual/BlokKiezer.js.map +1 -0
- package/dist/admin/visual/InlineGereedschap.d.ts +52 -0
- package/dist/admin/visual/InlineGereedschap.js +356 -0
- package/dist/admin/visual/InlineGereedschap.js.map +1 -0
- package/dist/admin/visual/InlineRijkeTekst.d.ts +23 -0
- package/dist/admin/visual/InlineRijkeTekst.js +152 -0
- package/dist/admin/visual/InlineRijkeTekst.js.map +1 -0
- package/dist/admin/visual/VisualEditor.js +273 -125
- package/dist/admin/visual/VisualEditor.js.map +1 -1
- package/dist/admin.css +1 -1
- package/dist/bedrijf/bedrijf.d.ts +36 -0
- package/dist/bedrijf/bedrijf.js +110 -0
- package/dist/bedrijf/bedrijf.js.map +1 -0
- package/dist/blocks/BlockRenderer.js +11 -1
- package/dist/blocks/BlockRenderer.js.map +1 -1
- package/dist/blocks/blockStyle.d.ts +7 -0
- package/dist/blocks/blockStyle.js +16 -3
- package/dist/blocks/blockStyle.js.map +1 -1
- package/dist/blocks/builtinSchemas.js +6 -0
- package/dist/blocks/builtinSchemas.js.map +1 -1
- package/dist/blocks/builtins/AgendaRender.d.ts +22 -0
- package/dist/blocks/builtins/AgendaRender.js +69 -9
- package/dist/blocks/builtins/AgendaRender.js.map +1 -1
- package/dist/blocks/builtins/Availability.d.ts +1 -0
- package/dist/blocks/builtins/Availability.js +23 -0
- package/dist/blocks/builtins/Availability.js.map +1 -0
- package/dist/blocks/builtins/AvailabilityRender.d.ts +12 -0
- package/dist/blocks/builtins/AvailabilityRender.js +105 -0
- package/dist/blocks/builtins/AvailabilityRender.js.map +1 -0
- package/dist/blocks/builtins/BeforeAfterRender.js +4 -3
- package/dist/blocks/builtins/BeforeAfterRender.js.map +1 -1
- package/dist/blocks/builtins/Booking.js +1 -1
- package/dist/blocks/builtins/Booking.js.map +1 -1
- package/dist/blocks/builtins/BreadcrumbsRender.d.ts +4 -3
- package/dist/blocks/builtins/BreadcrumbsRender.js +14 -8
- package/dist/blocks/builtins/BreadcrumbsRender.js.map +1 -1
- package/dist/blocks/builtins/ColumnsRender.d.ts +1 -1
- package/dist/blocks/builtins/ColumnsRender.js +3 -1
- package/dist/blocks/builtins/ColumnsRender.js.map +1 -1
- package/dist/blocks/builtins/Contact.js +1 -1
- package/dist/blocks/builtins/Contact.js.map +1 -1
- package/dist/blocks/builtins/ContactRender.d.ts +1 -1
- package/dist/blocks/builtins/ContactRender.js +29 -8
- package/dist/blocks/builtins/ContactRender.js.map +1 -1
- package/dist/blocks/builtins/Cta.js +1 -1
- package/dist/blocks/builtins/Cta.js.map +1 -1
- package/dist/blocks/builtins/CtaRender.d.ts +1 -1
- package/dist/blocks/builtins/CtaRender.js +5 -4
- package/dist/blocks/builtins/CtaRender.js.map +1 -1
- package/dist/blocks/builtins/Embed.js +1 -1
- package/dist/blocks/builtins/Embed.js.map +1 -1
- package/dist/blocks/builtins/FormBlock.js +1 -0
- package/dist/blocks/builtins/FormBlock.js.map +1 -1
- package/dist/blocks/builtins/FormBlockRender.d.ts +6 -0
- package/dist/blocks/builtins/FormBlockRender.js +88 -16
- package/dist/blocks/builtins/FormBlockRender.js.map +1 -1
- package/dist/blocks/builtins/GalleryRender.js +3 -2
- package/dist/blocks/builtins/GalleryRender.js.map +1 -1
- package/dist/blocks/builtins/Hero.js +1 -1
- package/dist/blocks/builtins/Hero.js.map +1 -1
- package/dist/blocks/builtins/HeroRender.js +7 -3
- package/dist/blocks/builtins/HeroRender.js.map +1 -1
- package/dist/blocks/builtins/OpenNowBadge.d.ts +4 -2
- package/dist/blocks/builtins/OpenNowBadge.js +6 -6
- package/dist/blocks/builtins/OpenNowBadge.js.map +1 -1
- package/dist/blocks/builtins/OpeningHoursRender.d.ts +8 -2
- package/dist/blocks/builtins/OpeningHoursRender.js +27 -6
- package/dist/blocks/builtins/OpeningHoursRender.js.map +1 -1
- package/dist/blocks/builtins/PriceList.d.ts +1 -0
- package/dist/blocks/builtins/PriceList.js +25 -0
- package/dist/blocks/builtins/PriceList.js.map +1 -0
- package/dist/blocks/builtins/PriceListRender.d.ts +17 -0
- package/dist/blocks/builtins/PriceListRender.js +87 -0
- package/dist/blocks/builtins/PriceListRender.js.map +1 -0
- package/dist/blocks/builtins/RichTextBlockRender.js +6 -1
- package/dist/blocks/builtins/RichTextBlockRender.js.map +1 -1
- package/dist/blocks/builtins/SectionHeading.d.ts +1 -0
- package/dist/blocks/builtins/SectionHeading.js +14 -0
- package/dist/blocks/builtins/SectionHeading.js.map +1 -0
- package/dist/blocks/builtins/SectionHeadingRender.d.ts +7 -0
- package/dist/blocks/builtins/SectionHeadingRender.js +14 -0
- package/dist/blocks/builtins/SectionHeadingRender.js.map +1 -0
- package/dist/blocks/builtins/SliderRender.js +3 -2
- package/dist/blocks/builtins/SliderRender.js.map +1 -1
- package/dist/blocks/builtins/SymbolRef.js +1 -1
- package/dist/blocks/builtins/SymbolRef.js.map +1 -1
- package/dist/blocks/builtins/TeamRender.js +6 -1
- package/dist/blocks/builtins/TeamRender.js.map +1 -1
- package/dist/blocks/builtins/Testimonials.js +3 -1
- package/dist/blocks/builtins/Testimonials.js.map +1 -1
- package/dist/blocks/builtins/TestimonialsRender.js +4 -0
- package/dist/blocks/builtins/TestimonialsRender.js.map +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.d.ts +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js +1 -1
- package/dist/blocks/builtins/WhatsappChatRender.js.map +1 -1
- package/dist/blocks/builtins/Widgets.js +2 -2
- package/dist/blocks/builtins/Widgets.js.map +1 -1
- package/dist/blocks/builtins/WidgetsRender.js +3 -1
- package/dist/blocks/builtins/WidgetsRender.js.map +1 -1
- package/dist/blocks/builtins/index.d.ts +3 -0
- package/dist/blocks/builtins/index.js +6 -0
- package/dist/blocks/builtins/index.js.map +1 -1
- package/dist/blocks/builtins/lib/autoComplete.d.ts +7 -0
- package/dist/blocks/builtins/lib/autoComplete.js +20 -0
- package/dist/blocks/builtins/lib/autoComplete.js.map +1 -0
- package/dist/blocks/builtins/lib/bookingUrl.d.ts +2 -2
- package/dist/blocks/builtins/lib/bookingUrl.js +1 -1
- package/dist/blocks/builtins/lib/bookingUrl.js.map +1 -1
- package/dist/blocks/builtins/lib/ical.d.ts +24 -0
- package/dist/blocks/builtins/lib/ical.js +82 -0
- package/dist/blocks/builtins/lib/ical.js.map +1 -0
- package/dist/blocks/builtins/lib/vandaag.d.ts +8 -0
- package/dist/blocks/builtins/lib/vandaag.js +22 -0
- package/dist/blocks/builtins/lib/vandaag.js.map +1 -0
- package/dist/blocks/registry.d.ts +6 -0
- package/dist/blocks/registry.js.map +1 -1
- package/dist/blocks/ui/index.js +1 -0
- package/dist/blocks/ui/index.js.map +1 -1
- package/dist/components/EditBar.js +2 -4
- package/dist/components/EditBar.js.map +1 -1
- package/dist/components/News.js +26 -18
- package/dist/components/News.js.map +1 -1
- package/dist/components/PageView.d.ts +7 -1
- package/dist/components/PageView.js +17 -0
- package/dist/components/PageView.js.map +1 -1
- package/dist/components/ResponsiveImage.js +18 -20
- package/dist/components/ResponsiveImage.js.map +1 -1
- package/dist/components/site/SiteFooter.d.ts +6 -1
- package/dist/components/site/SiteFooter.js +61 -9
- package/dist/components/site/SiteFooter.js.map +1 -1
- package/dist/components/site/SiteHeader.d.ts +15 -0
- package/dist/components/site/SiteHeader.js +70 -0
- package/dist/components/site/SiteHeader.js.map +1 -0
- package/dist/components/site/SiteNav.d.ts +2 -0
- package/dist/components/site/SiteNav.js +29 -5
- package/dist/components/site/SiteNav.js.map +1 -1
- package/dist/demo/DemoStudio.js +2 -2
- package/dist/demo/DemoStudio.js.map +1 -1
- package/dist/demo/demoStore.d.ts +13 -0
- package/dist/demo/demoStore.js +36 -0
- package/dist/demo/demoStore.js.map +1 -1
- package/dist/editor/EditorProvider.js +15 -4
- package/dist/editor/EditorProvider.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/media/ImageContext.d.ts +17 -0
- package/dist/media/ImageContext.js +65 -20
- package/dist/media/ImageContext.js.map +1 -1
- package/dist/media/altInHtml.d.ts +9 -0
- package/dist/media/altInHtml.js +17 -0
- package/dist/media/altInHtml.js.map +1 -0
- package/dist/media/srcset.d.ts +12 -0
- package/dist/media/srcset.js +13 -0
- package/dist/media/srcset.js.map +1 -0
- package/dist/modules/builtins.d.ts +1 -0
- package/dist/modules/builtins.js +16 -3
- package/dist/modules/builtins.js.map +1 -1
- package/dist/modules/shop/blocks/Cart.js +5 -3
- package/dist/modules/shop/blocks/Cart.js.map +1 -1
- package/dist/modules/shop/blocks/Checkout.js +56 -35
- package/dist/modules/shop/blocks/Checkout.js.map +1 -1
- package/dist/modules/shop/blocks/Donation.js +4 -4
- package/dist/modules/shop/blocks/Donation.js.map +1 -1
- package/dist/modules/shop/blocks/ProductDetail.js +19 -3
- package/dist/modules/shop/blocks/ProductDetail.js.map +1 -1
- package/dist/modules/shop/blocks/ProductGrid.d.ts +3 -1
- package/dist/modules/shop/blocks/ProductGrid.js +8 -4
- package/dist/modules/shop/blocks/ProductGrid.js.map +1 -1
- package/dist/modules/shop/blocks/ShopCategories.js +4 -3
- package/dist/modules/shop/blocks/ShopCategories.js.map +1 -1
- package/dist/modules/shop/lib.d.ts +4 -0
- package/dist/modules/shop/lib.js +14 -0
- package/dist/modules/shop/lib.js.map +1 -1
- package/dist/modules/shop/settings.d.ts +3 -0
- package/dist/modules/shop/settings.js +14 -0
- package/dist/modules/shop/settings.js.map +1 -1
- package/dist/modules/shop/strings.d.ts +4 -0
- package/dist/modules/shop/strings.js +8 -0
- package/dist/modules/shop/strings.js.map +1 -1
- package/dist/next/envCheck.d.ts +42 -0
- package/dist/next/envCheck.js +106 -0
- package/dist/next/envCheck.js.map +1 -0
- package/dist/next/index.cjs +185 -2
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +8 -1
- package/dist/next/index.js.map +1 -1
- package/dist/next/securityHeaders.d.ts +36 -0
- package/dist/next/securityHeaders.js +74 -0
- package/dist/next/securityHeaders.js.map +1 -0
- package/dist/patterns/builtins.d.ts +7 -0
- package/dist/patterns/builtins.js +138 -3
- package/dist/patterns/builtins.js.map +1 -1
- package/dist/releaseNotes.js +140 -0
- package/dist/releaseNotes.js.map +1 -1
- package/dist/render/PublishedPage.d.ts +2 -1
- package/dist/render/PublishedPage.js +10 -4
- package/dist/render/PublishedPage.js.map +1 -1
- package/dist/schema/blocks.d.ts +470 -0
- package/dist/schema/blocks.js +102 -4
- package/dist/schema/blocks.js.map +1 -1
- package/dist/schema/business.d.ts +117 -0
- package/dist/schema/business.js +73 -0
- package/dist/schema/business.js.map +1 -0
- package/dist/schema/fields.d.ts +2 -1
- package/dist/schema/fields.js.map +1 -1
- package/dist/schema/forms.d.ts +18 -0
- package/dist/schema/forms.js +18 -3
- package/dist/schema/forms.js.map +1 -1
- package/dist/schema/mail.d.ts +10 -0
- package/dist/schema/mail.js +7 -0
- package/dist/schema/mail.js.map +1 -1
- package/dist/schema/settings.d.ts +101 -0
- package/dist/schema/settings.js +24 -3
- package/dist/schema/settings.js.map +1 -1
- package/dist/schema/shop.d.ts +2 -0
- package/dist/schema/shop.js +4 -0
- package/dist/schema/shop.js.map +1 -1
- package/dist/schema/shopGeld.d.ts +1 -0
- package/dist/schema/shopGeld.js +1 -0
- package/dist/schema/shopGeld.js.map +1 -1
- package/dist/schema/siteConfig.d.ts +68 -1
- package/dist/schema/siteConfig.js +7 -2
- package/dist/schema/siteConfig.js.map +1 -1
- package/dist/server/blockData.d.ts +1 -1
- package/dist/server/blockData.js +74 -18
- package/dist/server/blockData.js.map +1 -1
- package/dist/server/cspRapport.d.ts +20 -0
- package/dist/server/cspRapport.js +56 -0
- package/dist/server/cspRapport.js.map +1 -0
- package/dist/server/fonts.d.ts +3 -0
- package/dist/server/fonts.js +39 -0
- package/dist/server/fonts.js.map +1 -0
- package/dist/server/index.d.ts +3 -0
- package/dist/server/index.js +8 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/sanitize.js +15 -2
- package/dist/server/sanitize.js.map +1 -1
- package/dist/settings/useSiteSettings.js +4 -1
- package/dist/settings/useSiteSettings.js.map +1 -1
- package/dist/starters/starters.d.ts +69 -0
- package/dist/starters/starters.js +171 -0
- package/dist/starters/starters.js.map +1 -0
- package/dist/styles.css +1149 -208
- package/dist/theme/color.d.ts +10 -0
- package/dist/theme/color.js +17 -1
- package/dist/theme/color.js.map +1 -1
- package/dist/theme/fontFallback.d.ts +23 -0
- package/dist/theme/fontFallback.js +58 -0
- package/dist/theme/fontFallback.js.map +1 -0
- package/dist/theme/fonts.d.ts +11 -0
- package/dist/theme/fonts.js +16 -0
- package/dist/theme/fonts.js.map +1 -0
- package/dist/version.js +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/modules/shop/lib.ts"],"sourcesContent":["\"use client\";\n\n/**\n * Client-helpers voor de shop-blocks: producten/categorieën lezen (publieke rules) en de\n * `createOrder`-callable aanroepen. Queries bewust simpel gehouden (één `where` op status,\n * filteren/sorteren client-side) zodat er géén composite-indexes nodig zijn — assortimenten\n * van XiCMS-sites zijn klein (tientallen tot honderden producten).\n */\n\n/**\n * Firestore/Functions worden hier DYNAMISCH geladen. De shop-blocks zitten in de publieke bundel,\n * dus een statische import zette de SDK op élke pagina — ook op sites zonder webshop.\n */\nasync function fsSdk() {\n const [client, sdk] = await Promise.all([import(\"../../firebase/client\"), import(\"firebase/firestore\")]);\n return { db: client.getDb(), ...sdk };\n}\nasync function fnSdk() {\n const [client, sdk] = await Promise.all([import(\"../../firebase/client\"), import(\"../../firebase/functionsClient\")]);\n return { app: client.getFirebaseApp(), ...sdk };\n}\nimport type { CreateOrderInput, Product, ProductOption, ShopCategory } from \"../../schema/shop\";\nimport { optieHeeftBeeldPerWaarde } from \"../../schema/shop\";\nimport { useModuleSettings } from \"../context\";\nimport { defaultShopSettings, type ShopSettings } from \"./settings\";\n\n/** Publieke shop-instellingen met defaults (paden, verzendkosten, valuta). */\nexport function useShopSettings(): ShopSettings {\n const raw = useModuleSettings<Partial<ShopSettings>>(\"shop\");\n return { ...defaultShopSettings, ...raw };\n}\n\nexport type StoredProduct = Product & { id: string };\nexport type StoredShopCategory = ShopCategory & { id: string };\n\nexport async function fetchActiveProducts(siteId: string): Promise<StoredProduct[]> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db) return [];\n const snap = await getDocs(\n query(collection(db, \"sites\", siteId, \"products\"), where(\"status\", \"==\", \"active\"), fsLimit(500)),\n );\n return snap.docs.map((d) => ({ id: d.id, ...(d.data() as Product) }));\n}\n\nexport async function fetchProductBySlug(siteId: string, slug: string): Promise<StoredProduct | null> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db || !slug) return null;\n // Het status-filter is verplicht: de rules staan publieke reads alleen toe voor actieve\n // producten, en Firestore weigert query's die niet aantoonbaar binnen die regel blijven.\n // Twee equality-filters → geen composite index nodig (index-merging).\n const snap = await getDocs(\n query(\n collection(db, \"sites\", siteId, \"products\"),\n where(\"slug\", \"==\", slug),\n where(\"status\", \"==\", \"active\"),\n fsLimit(1),\n ),\n );\n const doc = snap.docs[0];\n if (!doc) return null;\n return { id: doc.id, ...(doc.data() as Product) };\n}\n\nexport async function fetchShopCategories(siteId: string): Promise<StoredShopCategory[]> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db) return [];\n const snap = await getDocs(query(collection(db, \"sites\", siteId, \"shopCategories\"), fsLimit(100)));\n return snap.docs\n .map((d) => ({ id: d.id, ...(d.data() as ShopCategory) }))\n .filter((c) => c.visible !== false)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Start de checkout: order + Stripe-sessie server-side; geeft de redirect-URL terug. */\n/**\n * Verwijdert `undefined`/`null`-velden diep uit een payload vóór een callable-aanroep.\n * De Firebase-callable-SDK serialiseert `undefined` namelijk als `null` op de wire, terwijl de\n * server-side Zod-schema's optionele velden met `.optional()` valideren — dat wijst `null` af en\n * geeft \"Ongeldige invoer\". Door lege velden hier weg te laten komen ze als afwezig binnen (= ok).\n */\nfunction stripEmpty<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map((v) => stripEmpty(v)) as unknown as T;\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined || v === null) continue;\n out[k] = stripEmpty(v);\n }\n return out as T;\n }\n return value;\n}\n\nexport async function createOrderCall(input: CreateOrderInput): Promise<{ url: string; orderNumber: string }> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n const fn = callable(app, \"createOrder\");\n const res = await fn(stripEmpty(input));\n return res.data as { url: string; orderNumber: string };\n}\n\n/** Valideert een kortingscode server-side; geeft de verwachte korting terug (preview). */\nexport interface DiscountPreview {\n valid: boolean;\n code?: string;\n discountCents?: number;\n freeShipping?: boolean;\n reason?: string;\n}\nexport async function validateDiscountCall(siteId: string, code: string, itemsCents: number): Promise<DiscountPreview> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n const fn = callable(app, \"validateDiscountCode\");\n const res = await fn({ siteId, code, itemsCents });\n return res.data as DiscountPreview;\n}\n\n/**\n * Upload een personalisatie-afbeelding (eigen logo e.d.) via de begrensde callable —\n * geeft het Storage-pad terug dat op de orderregel meegaat. Max 5 MB, jpeg/png/webp.\n */\nexport async function uploadPersonalizationCall(\n siteId: string,\n productId: string,\n file: File,\n): Promise<{ path: string }> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n if (file.size > 5 * 1024 * 1024) throw new Error(\"TOO_BIG\");\n const bytesBase64 = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result).split(\",\")[1] ?? \"\");\n reader.onerror = () => reject(new Error(\"Bestand lezen mislukt.\"));\n reader.readAsDataURL(file);\n });\n const fn = callable(app, \"uploadPersonalization\");\n const res = await fn({ siteId, productId, fileName: file.name, contentType: file.type, bytesBase64 });\n return res.data as { path: string };\n}\n\n/** Leesbaar variantlabel: opties [\"Maat\",\"Kleur\"] + key \"68|Roze\" → \"Maat 68 · Roze\". */\nexport function variantLabelFor(options: { name: string; values: string[] }[], key: string): string {\n const parts = key.split(\"|\");\n return options.map((o, i) => `${o.name} ${parts[i] ?? \"?\"}`).join(\" · \");\n}\n\n/** Querystring-parameter client-side lezen (blocks zijn client components). */\nexport function readQueryParam(name: string): string | null {\n if (typeof window === \"undefined\") return null;\n return new URLSearchParams(window.location.search).get(name);\n}\n\n/**\n * Echte orderstatus opvragen (voor de bedankt-pagina). Nodig bij Mollie: die heeft één\n * redirect-URL voor alle uitkomsten, dus de status moet server-side gecheckt worden.\n */\nexport async function getOrderReturnStatusCall(\n siteId: string,\n orderId: string,\n): Promise<{ status: string; number?: string }> {\n const { app, callable } = await fnSdk();\n if (!app) return { status: \"unknown\" };\n const fn = callable(app, \"getOrderReturnStatus\");\n const res = await fn({ siteId, orderId });\n return res.data as { status: string; number?: string };\n}\n\n/* ── Kleur-swatches ──────────────────────────────────────────────────────── */\n\n// Zachte, pastelachtige swatch-tinten — informatief maar rustig (geen felle vlekken op de\n// kaart). Bewust gedempt t.o.v. de echte stofkleuren; de foto toont de precieze kleur.\nconst KLEUR_CSS: [RegExp, string][] = [\n [/fuchsia|fushia/, \"#dd8fb4\"],\n [/roze|pink/, \"#f2c3d3\"],\n [/blauw|blue/, \"#bcd3ea\"],\n [/mint/, \"#bfe0d2\"],\n [/oker|geel|yellow/, \"#eccf90\"],\n [/wit|white/, \"#f6f3ec\"],\n [/creme|crème|ecru|beige|zand/, \"#f0e7d6\"],\n [/grijs|gray|grey/, \"#c7ccd3\"],\n [/groen|green/, \"#b3d1b3\"],\n [/rood|red|bordeaux/, \"#e0a0a0\"],\n [/paars|purple|lila/, \"#cdbce6\"],\n [/oranje|orange/, \"#f2bd94\"],\n [/bruin|brown/, \"#c3a488\"],\n [/zwart|black|navy|donkerblauw/, \"#6b7488\"],\n];\n\n/**\n * Zet een kleurnaam (\"Roze\", \"Korte mouw tshirt (oker)geel\") om naar een CSS-kleur voor de\n * swatch-stipjes op productkaarten. Onbekende namen geven null (dan geen stipje).\n */\nexport function kleurNaarCss(naam: string): string | null {\n const l = naam.toLowerCase();\n for (const [re, css] of KLEUR_CSS) if (re.test(l)) return css;\n return null;\n}\n\n/**\n * De KLEUR-as van een product (naam \"Kleur\"/\"Colour\"/\"Color\"), of null.\n *\n * Blijft op de naam zoeken, en dat is hier terecht: deze as voedt de gekleurde stipjes op de\n * productkaart en het kleurfilter in het overzicht. Een stipje in de juiste tint kan alleen als\n * de wáárde een kleurnaam is (zie `kleurNaarCss`) — \"Print: Olifantje\" heeft geen tint.\n */\nexport function kleurOptie(product: Pick<Product, \"options\">): ProductOption | null {\n return (product.options ?? []).find((o) => /^kleur|^colou?r/i.test(o.name)) ?? null;\n}\n\n/**\n * De as waarvan élke waarde een eigen foto heeft — de as die het hoofdbeeld op de detailpagina\n * stuurt. Dit is losgekoppeld van de kleur-as (7.23): de winkelier zet per as een vinkje, dus het\n * mag net zo goed \"Print\" of \"Dessin\" zijn. Zonder expliciete keuze valt het terug op de oude\n * kleur-naamregel, zodat bestaande producten onveranderd blijven werken.\n *\n * Maar één as tegelijk: het hoofdbeeld kan niet twee keuzes tegelijk volgen. Staat de vlag per\n * ongeluk toch op meerdere assen (handmatig aangepaste data), dan wint de eerste.\n */\nexport function beeldOptie(product: Pick<Product, \"options\">): ProductOption | null {\n const opties = product.options ?? [];\n return opties.find((o) => o.imagePerValue === true) ?? opties.find((o) => optieHeeftBeeldPerWaarde(o)) ?? null;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/lib.ts"],"sourcesContent":["\"use client\";\n\n/**\n * Client-helpers voor de shop-blocks: producten/categorieën lezen (publieke rules) en de\n * `createOrder`-callable aanroepen. Queries bewust simpel gehouden (één `where` op status,\n * filteren/sorteren client-side) zodat er géén composite-indexes nodig zijn — assortimenten\n * van XiCMS-sites zijn klein (tientallen tot honderden producten).\n */\n\n/**\n * Firestore/Functions worden hier DYNAMISCH geladen. De shop-blocks zitten in de publieke bundel,\n * dus een statische import zette de SDK op élke pagina — ook op sites zonder webshop.\n */\nasync function fsSdk() {\n const [client, sdk] = await Promise.all([import(\"../../firebase/client\"), import(\"firebase/firestore\")]);\n return { db: client.getDb(), ...sdk };\n}\nasync function fnSdk() {\n const [client, sdk] = await Promise.all([import(\"../../firebase/client\"), import(\"../../firebase/functionsClient\")]);\n return { app: client.getFirebaseApp(), ...sdk };\n}\nimport type { CreateOrderInput, Product, ProductOption, ShopCategory } from \"../../schema/shop\";\nimport { optieHeeftBeeldPerWaarde } from \"../../schema/shop\";\nimport { useModuleSettings } from \"../context\";\nimport { defaultShopSettings, type ShopSettings } from \"./settings\";\n\n/** Publieke shop-instellingen met defaults (paden, verzendkosten, valuta). */\nexport function useShopSettings(): ShopSettings {\n const raw = useModuleSettings<Partial<ShopSettings>>(\"shop\");\n return { ...defaultShopSettings, ...raw };\n}\n\nexport type StoredProduct = Product & { id: string };\nexport type StoredShopCategory = ShopCategory & { id: string };\n\nexport async function fetchActiveProducts(siteId: string): Promise<StoredProduct[]> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db) return [];\n const snap = await getDocs(\n query(collection(db, \"sites\", siteId, \"products\"), where(\"status\", \"==\", \"active\"), fsLimit(500)),\n );\n return snap.docs.map((d) => ({ id: d.id, ...(d.data() as Product) }));\n}\n\nexport async function fetchProductBySlug(siteId: string, slug: string): Promise<StoredProduct | null> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db || !slug) return null;\n // Het status-filter is verplicht: de rules staan publieke reads alleen toe voor actieve\n // producten, en Firestore weigert query's die niet aantoonbaar binnen die regel blijven.\n // Twee equality-filters → geen composite index nodig (index-merging).\n const snap = await getDocs(\n query(\n collection(db, \"sites\", siteId, \"products\"),\n where(\"slug\", \"==\", slug),\n where(\"status\", \"==\", \"active\"),\n fsLimit(1),\n ),\n );\n const doc = snap.docs[0];\n if (!doc) return null;\n return { id: doc.id, ...(doc.data() as Product) };\n}\n\nexport async function fetchShopCategories(siteId: string): Promise<StoredShopCategory[]> {\n const { db, collection, getDocs, limit: fsLimit, query, where } = await fsSdk();\n if (!db) return [];\n const snap = await getDocs(query(collection(db, \"sites\", siteId, \"shopCategories\"), fsLimit(100)));\n return snap.docs\n .map((d) => ({ id: d.id, ...(d.data() as ShopCategory) }))\n .filter((c) => c.visible !== false)\n .sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n}\n\n/** Start de checkout: order + Stripe-sessie server-side; geeft de redirect-URL terug. */\n/**\n * Verwijdert `undefined`/`null`-velden diep uit een payload vóór een callable-aanroep.\n * De Firebase-callable-SDK serialiseert `undefined` namelijk als `null` op de wire, terwijl de\n * server-side Zod-schema's optionele velden met `.optional()` valideren — dat wijst `null` af en\n * geeft \"Ongeldige invoer\". Door lege velden hier weg te laten komen ze als afwezig binnen (= ok).\n */\nfunction stripEmpty<T>(value: T): T {\n if (Array.isArray(value)) {\n return value.map((v) => stripEmpty(v)) as unknown as T;\n }\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v === undefined || v === null) continue;\n out[k] = stripEmpty(v);\n }\n return out as T;\n }\n return value;\n}\n\nexport async function createOrderCall(input: CreateOrderInput): Promise<{ url: string; orderNumber: string }> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n const fn = callable(app, \"createOrder\");\n const res = await fn(stripEmpty(input));\n return res.data as { url: string; orderNumber: string };\n}\n\n/** Valideert een kortingscode server-side; geeft de verwachte korting terug (preview). */\nexport interface DiscountPreview {\n valid: boolean;\n code?: string;\n discountCents?: number;\n freeShipping?: boolean;\n reason?: string;\n}\nexport async function validateDiscountCall(siteId: string, code: string, itemsCents: number): Promise<DiscountPreview> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n const fn = callable(app, \"validateDiscountCode\");\n const res = await fn({ siteId, code, itemsCents });\n return res.data as DiscountPreview;\n}\n\n/**\n * Upload een personalisatie-afbeelding (eigen logo e.d.) via de begrensde callable —\n * geeft het Storage-pad terug dat op de orderregel meegaat. Max 5 MB, jpeg/png/webp.\n */\nexport async function uploadPersonalizationCall(\n siteId: string,\n productId: string,\n file: File,\n): Promise<{ path: string }> {\n const { app, callable } = await fnSdk();\n if (!app) throw new Error(\"Webwinkel niet beschikbaar.\");\n if (file.size > 5 * 1024 * 1024) throw new Error(\"TOO_BIG\");\n const bytesBase64 = await new Promise<string>((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => resolve(String(reader.result).split(\",\")[1] ?? \"\");\n reader.onerror = () => reject(new Error(\"Bestand lezen mislukt.\"));\n reader.readAsDataURL(file);\n });\n const fn = callable(app, \"uploadPersonalization\");\n const res = await fn({ siteId, productId, fileName: file.name, contentType: file.type, bytesBase64 });\n return res.data as { path: string };\n}\n\n/** Leesbaar variantlabel: opties [\"Maat\",\"Kleur\"] + key \"68|Roze\" → \"Maat 68 · Roze\". */\nexport function variantLabelFor(options: { name: string; values: string[] }[], key: string): string {\n const parts = key.split(\"|\");\n return options.map((o, i) => `${o.name} ${parts[i] ?? \"?\"}`).join(\" · \");\n}\n\n/** Querystring-parameter client-side lezen (blocks zijn client components). */\n/** De link naar een product (8.14: met `mooieUrls` als /product/naam). */\nexport function productHref(detailPath: string, slug: string, mooi?: boolean): string {\n const pad = detailPath.replace(/\\/+$/, \"\") || \"/product\";\n return mooi ? `${pad}/${encodeURIComponent(slug)}` : `${pad}?p=${encodeURIComponent(slug)}`;\n}\n\n/** Het product uit het adres: `?p=slug`, of (8.14) het laatste stuk van `/product/slug`. */\nexport function slugUitAdres(detailPath: string): string | null {\n if (typeof window === \"undefined\") return null;\n const uitQuery = new URLSearchParams(window.location.search).get(\"p\");\n if (uitQuery) return uitQuery;\n const pad = detailPath.replace(/\\/+$/, \"\");\n const huidig = window.location.pathname.replace(/\\/+$/, \"\");\n return huidig.startsWith(`${pad}/`) ? decodeURIComponent(huidig.slice(pad.length + 1)) : null;\n}\n\nexport function readQueryParam(name: string): string | null {\n if (typeof window === \"undefined\") return null;\n return new URLSearchParams(window.location.search).get(name);\n}\n\n/**\n * Echte orderstatus opvragen (voor de bedankt-pagina). Nodig bij Mollie: die heeft één\n * redirect-URL voor alle uitkomsten, dus de status moet server-side gecheckt worden.\n */\nexport async function getOrderReturnStatusCall(\n siteId: string,\n orderId: string,\n): Promise<{ status: string; number?: string }> {\n const { app, callable } = await fnSdk();\n if (!app) return { status: \"unknown\" };\n const fn = callable(app, \"getOrderReturnStatus\");\n const res = await fn({ siteId, orderId });\n return res.data as { status: string; number?: string };\n}\n\n/* ── Kleur-swatches ──────────────────────────────────────────────────────── */\n\n// Zachte, pastelachtige swatch-tinten — informatief maar rustig (geen felle vlekken op de\n// kaart). Bewust gedempt t.o.v. de echte stofkleuren; de foto toont de precieze kleur.\nconst KLEUR_CSS: [RegExp, string][] = [\n [/fuchsia|fushia/, \"#dd8fb4\"],\n [/roze|pink/, \"#f2c3d3\"],\n [/blauw|blue/, \"#bcd3ea\"],\n [/mint/, \"#bfe0d2\"],\n [/oker|geel|yellow/, \"#eccf90\"],\n [/wit|white/, \"#f6f3ec\"],\n [/creme|crème|ecru|beige|zand/, \"#f0e7d6\"],\n [/grijs|gray|grey/, \"#c7ccd3\"],\n [/groen|green/, \"#b3d1b3\"],\n [/rood|red|bordeaux/, \"#e0a0a0\"],\n [/paars|purple|lila/, \"#cdbce6\"],\n [/oranje|orange/, \"#f2bd94\"],\n [/bruin|brown/, \"#c3a488\"],\n [/zwart|black|navy|donkerblauw/, \"#6b7488\"],\n];\n\n/**\n * Zet een kleurnaam (\"Roze\", \"Korte mouw tshirt (oker)geel\") om naar een CSS-kleur voor de\n * swatch-stipjes op productkaarten. Onbekende namen geven null (dan geen stipje).\n */\nexport function kleurNaarCss(naam: string): string | null {\n const l = naam.toLowerCase();\n for (const [re, css] of KLEUR_CSS) if (re.test(l)) return css;\n return null;\n}\n\n/**\n * De KLEUR-as van een product (naam \"Kleur\"/\"Colour\"/\"Color\"), of null.\n *\n * Blijft op de naam zoeken, en dat is hier terecht: deze as voedt de gekleurde stipjes op de\n * productkaart en het kleurfilter in het overzicht. Een stipje in de juiste tint kan alleen als\n * de wáárde een kleurnaam is (zie `kleurNaarCss`) — \"Print: Olifantje\" heeft geen tint.\n */\nexport function kleurOptie(product: Pick<Product, \"options\">): ProductOption | null {\n return (product.options ?? []).find((o) => /^kleur|^colou?r/i.test(o.name)) ?? null;\n}\n\n/**\n * De as waarvan élke waarde een eigen foto heeft — de as die het hoofdbeeld op de detailpagina\n * stuurt. Dit is losgekoppeld van de kleur-as (7.23): de winkelier zet per as een vinkje, dus het\n * mag net zo goed \"Print\" of \"Dessin\" zijn. Zonder expliciete keuze valt het terug op de oude\n * kleur-naamregel, zodat bestaande producten onveranderd blijven werken.\n *\n * Maar één as tegelijk: het hoofdbeeld kan niet twee keuzes tegelijk volgen. Staat de vlag per\n * ongeluk toch op meerdere assen (handmatig aangepaste data), dan wint de eerste.\n */\nexport function beeldOptie(product: Pick<Product, \"options\">): ProductOption | null {\n const opties = product.options ?? [];\n return opties.find((o) => o.imagePerValue === true) ?? opties.find((o) => optieHeeftBeeldPerWaarde(o)) ?? null;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -9,6 +9,7 @@ import * as z from "zod/mini";
|
|
|
9
9
|
export declare const ShopSettingsSchema: z.ZodMiniObject<{
|
|
10
10
|
shopPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
11
11
|
detailPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
12
|
+
mooieUrls: z.ZodMiniDefault<z.ZodMiniBoolean<boolean>>;
|
|
12
13
|
cartPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
13
14
|
checkoutPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
14
15
|
successPath: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
@@ -21,6 +22,8 @@ export declare const ShopSettingsSchema: z.ZodMiniObject<{
|
|
|
21
22
|
flatCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
22
23
|
freeFromCents: z.ZodMiniDefault<z.ZodMiniNumberFormat>;
|
|
23
24
|
}, z.core.$strip>>>;
|
|
25
|
+
pickupEnabled: z.ZodMiniDefault<z.ZodMiniBoolean<boolean>>;
|
|
26
|
+
pickupNote: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
24
27
|
orderPrefix: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
25
28
|
invoicePrefix: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
26
29
|
businessName: z.ZodMiniDefault<z.ZodMiniString<string>>;
|
|
@@ -2,6 +2,12 @@ import * as z from "zod/mini";
|
|
|
2
2
|
const ShopSettingsSchema = z.object({
|
|
3
3
|
shopPath: z._default(z.string().check(z.maxLength(200)), "/webwinkel").register(z.globalRegistry, { description: "Pad van de winkelpagina" }),
|
|
4
4
|
detailPath: z._default(z.string().check(z.maxLength(200)), "/product").register(z.globalRegistry, { description: "Pad van de productpagina" }),
|
|
5
|
+
/**
|
|
6
|
+
* 8.14: nette productadressen — `/product/houten-rammelaar` in plaats van
|
|
7
|
+
* `/product?p=houten-rammelaar`. Vraagt de route `app/(site)/product/[slug]` uit de template
|
|
8
|
+
* (statisch gebouwd, sneller en beter vindbaar). Oude `?p=`-links blijven werken.
|
|
9
|
+
*/
|
|
10
|
+
mooieUrls: z._default(z.boolean(), false).register(z.globalRegistry, { description: "Nette productadressen (/product/naam)" }),
|
|
5
11
|
cartPath: z._default(z.string().check(z.maxLength(200)), "/winkelwagen").register(z.globalRegistry, { description: "Pad van de winkelwagen" }),
|
|
6
12
|
checkoutPath: z._default(z.string().check(z.maxLength(200)), "/afrekenen").register(z.globalRegistry, { description: "Pad van de afrekenpagina" }),
|
|
7
13
|
successPath: z._default(z.string().check(z.maxLength(200)), "/bedankt").register(z.globalRegistry, { description: "Pad van de bedankt-pagina" }),
|
|
@@ -20,6 +26,14 @@ const ShopSettingsSchema = z.object({
|
|
|
20
26
|
flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e5)), 0),
|
|
21
27
|
freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1e8)), 0)
|
|
22
28
|
})).check(z.maxLength(10)), []).register(z.globalRegistry, { description: "Verzendzones (tarief per land)" }),
|
|
29
|
+
/**
|
|
30
|
+
* Afhalen (7.33): naast verzenden kan de klant kiezen voor afhalen. Dan vervalt het
|
|
31
|
+
* verzendadres en zijn de verzendkosten €0. `pickupNote` is de toelichting van de winkelier
|
|
32
|
+
* (adres, openingstijden, "we mailen als de bestelling klaarstaan") — die ziet de klant in de
|
|
33
|
+
* checkout en in de bevestigingsmail.
|
|
34
|
+
*/
|
|
35
|
+
pickupEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: "Afhalen aanbieden bij het afrekenen" }),
|
|
36
|
+
pickupNote: z._default(z.string().check(z.maxLength(1e3)), "").register(z.globalRegistry, { description: "Toelichting bij afhalen (adres, tijden)" }),
|
|
23
37
|
orderPrefix: z._default(z.string().check(z.maxLength(12)), "ORDER").register(z.globalRegistry, { description: "Ordernummer-prefix" }),
|
|
24
38
|
/**
|
|
25
39
|
* Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/modules/shop/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\n\n/**\n * Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of\n * `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier\n * automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config\n * server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in\n * `sites/{siteId}/private/shop` en lopen via callables.\n */\nexport const ShopSettingsSchema = z.object({\n shopPath: z._default(z.string().check(z.maxLength(200)), \"/webwinkel\").register(z.globalRegistry, { description: \"Pad van de winkelpagina\" }),\n detailPath: z._default(z.string().check(z.maxLength(200)), \"/product\").register(z.globalRegistry, { description: \"Pad van de productpagina\" }),\n cartPath: z._default(z.string().check(z.maxLength(200)), \"/winkelwagen\").register(z.globalRegistry, { description: \"Pad van de winkelwagen\" }),\n checkoutPath: z._default(z.string().check(z.maxLength(200)), \"/afrekenen\").register(z.globalRegistry, { description: \"Pad van de afrekenpagina\" }),\n successPath: z._default(z.string().check(z.maxLength(200)), \"/bedankt\").register(z.globalRegistry, { description: \"Pad van de bedankt-pagina\" }),\n currency: z._default(z.string().check(z.minLength(3)).check(z.maxLength(3)), \"EUR\").register(z.globalRegistry, { description: \"Valuta (ISO-code)\" }),\n shippingFlatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 495).register(z.globalRegistry, { description: \"Verzendkosten (centen)\" }),\n shippingFreeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0).register(z.globalRegistry, { description: \"Gratis verzending vanaf (centen, 0 = nooit)\" }),\n /**\n * Verzendzones (7.20): tarief per (groep) land(en). Leeg = het enkele tarief hierboven voor\n * alles — het gedrag van vóór 7.20, dus bestaande winkels merken niets. Een zone ZONDER landen\n * is de \"overige landen\"-zone; staat die er niet, dan verzendt de winkel alleen naar de landen\n * die wél in een zone staan (en toont de checkout precies die keuze).\n */\n shippingZones: z._default(z.array(z.object({\n naam: z.string().check(z.minLength(1)).check(z.maxLength(60)),\n landen: z._default(z.array(z.string().check(z.maxLength(2))).check(z.maxLength(60)), []),\n flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0),\n freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n })).check(z.maxLength(10)), []).register(z.globalRegistry, { description: \"Verzendzones (tarief per land)\" }),\n orderPrefix: z._default(z.string().check(z.maxLength(12)), \"ORDER\").register(z.globalRegistry, { description: \"Ordernummer-prefix\" }),\n /**\n * Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is\n * een eigen doorlopende nummering die alleen bij betaling ophoogt en per jaar herstart —\n * het ordernummer mag gaten hebben (afgebroken checkouts), een factuurreeks niet.\n */\n invoicePrefix: z._default(z.string().check(z.maxLength(12)), \"\").register(z.globalRegistry, { description: \"Factuurnummer-prefix (leeg = zelfde als ordernummer)\" }),\n /* Bedrijfsgegevens — komen op de factuur-PDF (5.6). */\n businessName: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Bedrijfsnaam (factuur)\" }),\n businessAddress: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Adres (factuur)\" }),\n businessZip: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"Postcode (factuur)\" }),\n businessCity: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Plaats (factuur)\" }),\n businessKvk: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"KVK-nummer (factuur)\" }),\n businessBtw: z._default(z.string().check(z.maxLength(30)), \"\").register(z.globalRegistry, { description: \"Btw-nummer (factuur)\" }),\n /**\n * Contactgegevens in de mailfooter en op de factuur (7.21). `businessEmail` werd al door\n * `mailLayout.ts` en `invoice.ts` UITGELEZEN, maar bestond nergens als instelling — een dood\n * veld op drie plekken, waardoor de klant in zijn bestelbevestiging geen enkel adres zag om\n * op te reageren.\n */\n businessEmail: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Contact-e-mail (factuur + mailfooter)\" }),\n businessPhone: z._default(z.string().check(z.maxLength(40)), \"\").register(z.globalRegistry, { description: \"Telefoon (factuur + mailfooter)\" }),\n /**\n * Cadeauverpakking (7.27): uit = de checkout toont de optie niet. De meerprijs staat als eigen\n * orderregel (kind \"giftwrap\"), dus btw/factuur/Stripe-Mollie-regels werken er al generiek mee.\n */\n giftWrapEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: \"Cadeauverpakking aanbieden bij het afrekenen\" }),\n giftWrapPriceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0).register(z.globalRegistry, { description: \"Meerprijs cadeauverpakking (centen)\" }),\n});\nexport type ShopSettings = z.infer<typeof ShopSettingsSchema>;\n\nexport const defaultShopSettings: ShopSettings = ShopSettingsSchema.parse({});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/settings.ts"],"sourcesContent":["import * as z from \"zod/mini\";\n\n/**\n * Publieke shop-instellingen (per site, via `settings/public.modules.shop.config` of\n * `SiteConfig.modules.shop.config`). Server-safe: alleen Zod. De SettingsPanel rendert hier\n * automatisch een formulier voor (moduleSettingsForm); de Functions lezen dezelfde config\n * server-side. Geheimen (Stripe-key, SMTP) horen hier NIET — die staan in\n * `sites/{siteId}/private/shop` en lopen via callables.\n */\nexport const ShopSettingsSchema = z.object({\n shopPath: z._default(z.string().check(z.maxLength(200)), \"/webwinkel\").register(z.globalRegistry, { description: \"Pad van de winkelpagina\" }),\n detailPath: z._default(z.string().check(z.maxLength(200)), \"/product\").register(z.globalRegistry, { description: \"Pad van de productpagina\" }),\n /**\n * 8.14: nette productadressen — `/product/houten-rammelaar` in plaats van\n * `/product?p=houten-rammelaar`. Vraagt de route `app/(site)/product/[slug]` uit de template\n * (statisch gebouwd, sneller en beter vindbaar). Oude `?p=`-links blijven werken.\n */\n mooieUrls: z._default(z.boolean(), false).register(z.globalRegistry, { description: \"Nette productadressen (/product/naam)\" }),\n cartPath: z._default(z.string().check(z.maxLength(200)), \"/winkelwagen\").register(z.globalRegistry, { description: \"Pad van de winkelwagen\" }),\n checkoutPath: z._default(z.string().check(z.maxLength(200)), \"/afrekenen\").register(z.globalRegistry, { description: \"Pad van de afrekenpagina\" }),\n successPath: z._default(z.string().check(z.maxLength(200)), \"/bedankt\").register(z.globalRegistry, { description: \"Pad van de bedankt-pagina\" }),\n currency: z._default(z.string().check(z.minLength(3)).check(z.maxLength(3)), \"EUR\").register(z.globalRegistry, { description: \"Valuta (ISO-code)\" }),\n shippingFlatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 495).register(z.globalRegistry, { description: \"Verzendkosten (centen)\" }),\n shippingFreeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0).register(z.globalRegistry, { description: \"Gratis verzending vanaf (centen, 0 = nooit)\" }),\n /**\n * Verzendzones (7.20): tarief per (groep) land(en). Leeg = het enkele tarief hierboven voor\n * alles — het gedrag van vóór 7.20, dus bestaande winkels merken niets. Een zone ZONDER landen\n * is de \"overige landen\"-zone; staat die er niet, dan verzendt de winkel alleen naar de landen\n * die wél in een zone staan (en toont de checkout precies die keuze).\n */\n shippingZones: z._default(z.array(z.object({\n naam: z.string().check(z.minLength(1)).check(z.maxLength(60)),\n landen: z._default(z.array(z.string().check(z.maxLength(2))).check(z.maxLength(60)), []),\n flatCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0),\n freeFromCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(1_000_000_00)), 0),\n })).check(z.maxLength(10)), []).register(z.globalRegistry, { description: \"Verzendzones (tarief per land)\" }),\n /**\n * Afhalen (7.33): naast verzenden kan de klant kiezen voor afhalen. Dan vervalt het\n * verzendadres en zijn de verzendkosten €0. `pickupNote` is de toelichting van de winkelier\n * (adres, openingstijden, \"we mailen als de bestelling klaarstaan\") — die ziet de klant in de\n * checkout en in de bevestigingsmail.\n */\n pickupEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: \"Afhalen aanbieden bij het afrekenen\" }),\n pickupNote: z._default(z.string().check(z.maxLength(1000)), \"\").register(z.globalRegistry, { description: \"Toelichting bij afhalen (adres, tijden)\" }),\n orderPrefix: z._default(z.string().check(z.maxLength(12)), \"ORDER\").register(z.globalRegistry, { description: \"Ordernummer-prefix\" }),\n /**\n * Prefix van de FACTUURreeks (7.18). Leeg = dezelfde als het ordernummer. De factuurreeks is\n * een eigen doorlopende nummering die alleen bij betaling ophoogt en per jaar herstart —\n * het ordernummer mag gaten hebben (afgebroken checkouts), een factuurreeks niet.\n */\n invoicePrefix: z._default(z.string().check(z.maxLength(12)), \"\").register(z.globalRegistry, { description: \"Factuurnummer-prefix (leeg = zelfde als ordernummer)\" }),\n /* Bedrijfsgegevens — komen op de factuur-PDF (5.6). */\n businessName: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Bedrijfsnaam (factuur)\" }),\n businessAddress: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Adres (factuur)\" }),\n businessZip: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"Postcode (factuur)\" }),\n businessCity: z._default(z.string().check(z.maxLength(120)), \"\").register(z.globalRegistry, { description: \"Plaats (factuur)\" }),\n businessKvk: z._default(z.string().check(z.maxLength(20)), \"\").register(z.globalRegistry, { description: \"KVK-nummer (factuur)\" }),\n businessBtw: z._default(z.string().check(z.maxLength(30)), \"\").register(z.globalRegistry, { description: \"Btw-nummer (factuur)\" }),\n /**\n * Contactgegevens in de mailfooter en op de factuur (7.21). `businessEmail` werd al door\n * `mailLayout.ts` en `invoice.ts` UITGELEZEN, maar bestond nergens als instelling — een dood\n * veld op drie plekken, waardoor de klant in zijn bestelbevestiging geen enkel adres zag om\n * op te reageren.\n */\n businessEmail: z._default(z.string().check(z.maxLength(200)), \"\").register(z.globalRegistry, { description: \"Contact-e-mail (factuur + mailfooter)\" }),\n businessPhone: z._default(z.string().check(z.maxLength(40)), \"\").register(z.globalRegistry, { description: \"Telefoon (factuur + mailfooter)\" }),\n /**\n * Cadeauverpakking (7.27): uit = de checkout toont de optie niet. De meerprijs staat als eigen\n * orderregel (kind \"giftwrap\"), dus btw/factuur/Stripe-Mollie-regels werken er al generiek mee.\n */\n giftWrapEnabled: z._default(z.boolean(), false).register(z.globalRegistry, { description: \"Cadeauverpakking aanbieden bij het afrekenen\" }),\n giftWrapPriceCents: z._default(z.int().check(z.minimum(0)).check(z.maximum(100_000)), 0).register(z.globalRegistry, { description: \"Meerprijs cadeauverpakking (centen)\" }),\n});\nexport type ShopSettings = z.infer<typeof ShopSettingsSchema>;\n\nexport const defaultShopSettings: ShopSettings = ShopSettingsSchema.parse({});\n"],"mappings":"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","names":[]}
|
|
@@ -61,6 +61,10 @@ declare const NL: {
|
|
|
61
61
|
donationAmountLabel: string;
|
|
62
62
|
billingSame: string;
|
|
63
63
|
billingHeading: string;
|
|
64
|
+
deliveryHeading: string;
|
|
65
|
+
deliveryShip: string;
|
|
66
|
+
deliveryPickup: string;
|
|
67
|
+
pickupHeading: string;
|
|
64
68
|
giftWrap: string;
|
|
65
69
|
giftWrapLabel: string;
|
|
66
70
|
giftWrapCardText: string;
|
|
@@ -63,6 +63,10 @@ const NL = {
|
|
|
63
63
|
donationAmountLabel: "Bedrag in euro's (min. {min})",
|
|
64
64
|
billingSame: "Factuuradres is hetzelfde als het verzendadres",
|
|
65
65
|
billingHeading: "Factuuradres",
|
|
66
|
+
deliveryHeading: "Bezorging",
|
|
67
|
+
deliveryShip: "Laten verzenden",
|
|
68
|
+
deliveryPickup: "Zelf afhalen (geen verzendkosten)",
|
|
69
|
+
pickupHeading: "Afhalen",
|
|
66
70
|
giftWrap: "Cadeauverpakking",
|
|
67
71
|
giftWrapLabel: "Cadeauverpakking (+ {bedrag})",
|
|
68
72
|
giftWrapCardText: "Tekst op het kaartje (optioneel)",
|
|
@@ -131,6 +135,10 @@ const EN = {
|
|
|
131
135
|
donationAmountLabel: "Amount in euros (min. {min})",
|
|
132
136
|
billingSame: "Billing address is the same as the shipping address",
|
|
133
137
|
billingHeading: "Billing address",
|
|
138
|
+
deliveryHeading: "Delivery",
|
|
139
|
+
deliveryShip: "Ship to my address",
|
|
140
|
+
deliveryPickup: "Collect in person (no shipping costs)",
|
|
141
|
+
pickupHeading: "Collection",
|
|
134
142
|
giftWrap: "Gift wrap",
|
|
135
143
|
giftWrapLabel: "Gift wrap (+ {bedrag})",
|
|
136
144
|
giftWrapCardText: "Text for the card (optional)",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/modules/shop/strings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * UI-teksten van de shop-blocks, gelokaliseerd op `SiteConfig.lang` (nl = default, en).\n * Interpolatie via `{naam}`-placeholders. Bewust een platte tabel — geen i18n-framework;\n * de shop-strings zijn de enige plek in de blocks met vaste UI-tekst.\n */\nimport { useSiteConfig } from \"../../config\";\n\nconst NL = {\n addToCart: \"In winkelwagen\",\n added: \"✓ Toegevoegd aan je winkelwagen.\",\n addedGoToCart: \"✓ In winkelwagen — bekijk\",\n view: \"Bekijk\",\n toCart: \"Naar winkelwagen\",\n continueShopping: \"Verder winkelen\",\n checkout: \"Afrekenen\",\n cartEmpty: \"Je winkelwagen is leeg.\",\n toShop: \"Naar de winkel\",\n subtotal: \"Subtotaal\",\n shippingCosts: \"Verzendkosten\",\n free: \"gratis\",\n total: \"Totaal\",\n perPiece: \"p/st\",\n qty: \"Aantal\",\n outOfStock: \"Uitverkocht in deze uitvoering.\",\n variantUnavailable: \"Deze combinatie is niet leverbaar.\",\n stockLeft: \"Nog {n} beschikbaar\",\n soldOut: \"Uitverkocht\",\n productNotFound: \"Product niet gevonden.\",\n backToShop: \"Terug naar de winkel\",\n noProducts: \"Geen producten gevonden.\",\n noCategories: \"Nog geen categorieën.\",\n allCategories: \"Alle categorieën\",\n pay: \"Betalen — {bedrag}\",\n busy: \"Bezig…\",\n checkoutFailed: \"Afrekenen is niet gelukt. Controleer je gegevens en probeer het opnieuw.\",\n secureNote: \"Je rekent veilig af via een beveiligde betaalpagina (o.a. iDEAL). Na betaling ontvang je een bevestiging per e-mail.\",\n yourOrder: \"Je bestelling\",\n fieldName: \"Naam\",\n fieldEmail: \"E-mail\",\n fieldPhone: \"Telefoon (optioneel)\",\n fieldAddress: \"Straat + huisnummer\",\n fieldZip: \"Postcode\",\n fieldCity: \"Plaats\",\n fieldCountry: \"Land\",\n shippingFromCountry: \"(bij bezorging in Nederland — kies je land bij het afrekenen)\",\n fieldNote: \"Opmerking (optioneel)\",\n choose: \"Kies…\",\n discountCode: \"Kortingscode\",\n discountApply: \"Toepassen\",\n discount: \"Korting\",\n discountInvalid: \"Deze code is niet (meer) geldig.\",\n discountApplied: \"Korting toegepast: {code}\",\n related: \"Ook leuk\",\n filterAll: \"Alles\",\n sortLabel: \"Sorteren\",\n sortDefault: \"Aanbevolen\",\n sortName: \"Naam\",\n sortPriceAsc: \"Prijs (laag-hoog)\",\n sortPriceDesc: \"Prijs (hoog-laag)\",\n personalizationUpload: \"Kies bestand…\",\n personalizationUploading: \"Uploaden…\",\n personalizationUploaded: \"✓ Geüpload\",\n personalizationTooBig: \"Bestand te groot (max 5 MB).\",\n personalizationFailed: \"Uploaden mislukt — probeer het opnieuw.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Doneren is niet gelukt. Probeer het later opnieuw.\",\n donationCustomAmount: \"Ander bedrag\",\n donationAmountLabel: \"Bedrag in euro's (min. {min})\",\n billingSame: \"Factuuradres is hetzelfde als het verzendadres\",\n billingHeading: \"Factuuradres\",\n giftWrap: \"Cadeauverpakking\",\n giftWrapLabel: \"Cadeauverpakking (+ {bedrag})\",\n giftWrapCardText: \"Tekst op het kaartje (optioneel)\",\n giftWrapNote: \"Opmerking voor het inpakken (optioneel)\",\n};\n\nconst EN: typeof NL = {\n addToCart: \"Add to cart\",\n added: \"✓ Added to your cart.\",\n addedGoToCart: \"✓ In cart — view\",\n view: \"View\",\n toCart: \"Go to cart\",\n continueShopping: \"Continue shopping\",\n checkout: \"Checkout\",\n cartEmpty: \"Your cart is empty.\",\n toShop: \"Go to the shop\",\n subtotal: \"Subtotal\",\n shippingCosts: \"Shipping\",\n free: \"free\",\n total: \"Total\",\n perPiece: \"each\",\n qty: \"Quantity\",\n outOfStock: \"Sold out in this variant.\",\n variantUnavailable: \"This combination is unavailable.\",\n stockLeft: \"Only {n} left\",\n soldOut: \"Sold out\",\n productNotFound: \"Product not found.\",\n backToShop: \"Back to the shop\",\n noProducts: \"No products found.\",\n noCategories: \"No categories yet.\",\n allCategories: \"All categories\",\n pay: \"Pay — {bedrag}\",\n busy: \"Working…\",\n checkoutFailed: \"Checkout failed. Check your details and try again.\",\n secureNote: \"You pay securely via a protected checkout page (incl. iDEAL). You will receive a confirmation email after payment.\",\n yourOrder: \"Your order\",\n fieldName: \"Name\",\n fieldEmail: \"Email\",\n fieldPhone: \"Phone (optional)\",\n fieldAddress: \"Street + number\",\n fieldZip: \"Postal code\",\n fieldCity: \"City\",\n fieldCountry: \"Country\",\n shippingFromCountry: \"(for delivery in the Netherlands — choose your country at checkout)\",\n fieldNote: \"Note (optional)\",\n choose: \"Choose…\",\n discountCode: \"Discount code\",\n discountApply: \"Apply\",\n discount: \"Discount\",\n discountInvalid: \"This code is not (or no longer) valid.\",\n discountApplied: \"Discount applied: {code}\",\n related: \"You may also like\",\n filterAll: \"All\",\n sortLabel: \"Sort\",\n sortDefault: \"Recommended\",\n sortName: \"Name\",\n sortPriceAsc: \"Price (low-high)\",\n sortPriceDesc: \"Price (high-low)\",\n personalizationUpload: \"Choose file…\",\n personalizationUploading: \"Uploading…\",\n personalizationUploaded: \"✓ Uploaded\",\n personalizationTooBig: \"File too large (max 5 MB).\",\n personalizationFailed: \"Upload failed — please try again.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Donation failed. Please try again later.\",\n donationCustomAmount: \"Custom amount\",\n donationAmountLabel: \"Amount in euros (min. {min})\",\n billingSame: \"Billing address is the same as the shipping address\",\n billingHeading: \"Billing address\",\n giftWrap: \"Gift wrap\",\n giftWrapLabel: \"Gift wrap (+ {bedrag})\",\n giftWrapCardText: \"Text for the card (optional)\",\n giftWrapNote: \"Note for gift-wrapping (optional)\",\n};\n\nexport type ShopStringKey = keyof typeof NL;\nconst TABLES: Record<string, typeof NL> = { nl: NL, en: EN };\n\nexport type ShopT = (key: ShopStringKey, vars?: Record<string, string | number>) => string;\n\n/** Vertaalfunctie voor shop-blocks: `t(\"addToCart\")`, `t(\"stockLeft\", { n: 3 })`. */\nexport function useShopStrings(): ShopT {\n const lang = (useSiteConfig().lang ?? \"nl\").slice(0, 2).toLowerCase();\n const table = TABLES[lang] ?? NL;\n return (key, vars) => {\n let s = table[key] ?? NL[key] ?? key;\n if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, String(v));\n return s;\n };\n}\n"],"mappings":";AAOA,SAAS,qBAAqB;AAE9B,MAAM,KAAK;AAAA,EACT,WAAW;AAAA,EACX,OAAO;AAAA,EACP,eAAe;AAAA,EACf,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,eAAe;AAAA,EACf,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,WAAW;AAAA,EACX,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,eAAe;AAAA,EACf,KAAK;AAAA,EACL,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,aAAa;AAAA,EACb,UAAU;AAAA,EACV,cAAc;AAAA,EACd,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,cAAc;AAChB;AAEA,MAAM,KAAgB;AAAA,EACpB,WAAW;AAAA,EACX,OAAO;AAAA,EACP,eAAe;AAAA,EACf,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,UAAU;AAAA,EACV,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,eAAe;AAAA,EACf,MAAM;AAAA,EACN,OAAO;AAAA,EACP,UAAU;AAAA,EACV,KAAK;AAAA,EACL,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,WAAW;AAAA,EACX,SAAS;AAAA,EACT,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,eAAe;AAAA,EACf,KAAK;AAAA,EACL,MAAM;AAAA,EACN,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,WAAW;AAAA,EACX,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,cAAc;AAAA,EACd,UAAU;AAAA,EACV,WAAW;AAAA,EACX,cAAc;AAAA,EACd,qBAAqB;AAAA,EACrB,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,cAAc;AAAA,EACd,eAAe;AAAA,EACf,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,SAAS;AAAA,EACT,WAAW;AAAA,EACX,WAAW;AAAA,EACX,aAAa;AAAA,EACb,UAAU;AAAA,EACV,cAAc;AAAA,EACd,eAAe;AAAA,EACf,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,yBAAyB;AAAA,EACzB,uBAAuB;AAAA,EACvB,uBAAuB;AAAA,EACvB,0BAA0B;AAAA,EAC1B,gBAAgB;AAAA,EAChB,sBAAsB;AAAA,EACtB,qBAAqB;AAAA,EACrB,aAAa;AAAA,EACb,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,eAAe;AAAA,EACf,kBAAkB;AAAA,EAClB,cAAc;AAChB;AAGA,MAAM,SAAoC,EAAE,IAAI,IAAI,IAAI,GAAG;AAKpD,SAAS,iBAAwB;AACtC,QAAM,QAAQ,cAAc,EAAE,QAAQ,MAAM,MAAM,GAAG,CAAC,EAAE,YAAY;AACpE,QAAM,QAAQ,OAAO,IAAI,KAAK;AAC9B,SAAO,CAAC,KAAK,SAAS;AACpB,QAAI,IAAI,MAAM,GAAG,KAAK,GAAG,GAAG,KAAK;AACjC,QAAI,KAAM,YAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,EAAG,KAAI,EAAE,WAAW,IAAI,CAAC,KAAK,OAAO,CAAC,CAAC;AACzF,WAAO;AAAA,EACT;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../../src/modules/shop/strings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * UI-teksten van de shop-blocks, gelokaliseerd op `SiteConfig.lang` (nl = default, en).\n * Interpolatie via `{naam}`-placeholders. Bewust een platte tabel — geen i18n-framework;\n * de shop-strings zijn de enige plek in de blocks met vaste UI-tekst.\n */\nimport { useSiteConfig } from \"../../config\";\n\nconst NL = {\n addToCart: \"In winkelwagen\",\n added: \"✓ Toegevoegd aan je winkelwagen.\",\n addedGoToCart: \"✓ In winkelwagen — bekijk\",\n view: \"Bekijk\",\n toCart: \"Naar winkelwagen\",\n continueShopping: \"Verder winkelen\",\n checkout: \"Afrekenen\",\n cartEmpty: \"Je winkelwagen is leeg.\",\n toShop: \"Naar de winkel\",\n subtotal: \"Subtotaal\",\n shippingCosts: \"Verzendkosten\",\n free: \"gratis\",\n total: \"Totaal\",\n perPiece: \"p/st\",\n qty: \"Aantal\",\n outOfStock: \"Uitverkocht in deze uitvoering.\",\n variantUnavailable: \"Deze combinatie is niet leverbaar.\",\n stockLeft: \"Nog {n} beschikbaar\",\n soldOut: \"Uitverkocht\",\n productNotFound: \"Product niet gevonden.\",\n backToShop: \"Terug naar de winkel\",\n noProducts: \"Geen producten gevonden.\",\n noCategories: \"Nog geen categorieën.\",\n allCategories: \"Alle categorieën\",\n pay: \"Betalen — {bedrag}\",\n busy: \"Bezig…\",\n checkoutFailed: \"Afrekenen is niet gelukt. Controleer je gegevens en probeer het opnieuw.\",\n secureNote: \"Je rekent veilig af via een beveiligde betaalpagina (o.a. iDEAL). Na betaling ontvang je een bevestiging per e-mail.\",\n yourOrder: \"Je bestelling\",\n fieldName: \"Naam\",\n fieldEmail: \"E-mail\",\n fieldPhone: \"Telefoon (optioneel)\",\n fieldAddress: \"Straat + huisnummer\",\n fieldZip: \"Postcode\",\n fieldCity: \"Plaats\",\n fieldCountry: \"Land\",\n shippingFromCountry: \"(bij bezorging in Nederland — kies je land bij het afrekenen)\",\n fieldNote: \"Opmerking (optioneel)\",\n choose: \"Kies…\",\n discountCode: \"Kortingscode\",\n discountApply: \"Toepassen\",\n discount: \"Korting\",\n discountInvalid: \"Deze code is niet (meer) geldig.\",\n discountApplied: \"Korting toegepast: {code}\",\n related: \"Ook leuk\",\n filterAll: \"Alles\",\n sortLabel: \"Sorteren\",\n sortDefault: \"Aanbevolen\",\n sortName: \"Naam\",\n sortPriceAsc: \"Prijs (laag-hoog)\",\n sortPriceDesc: \"Prijs (hoog-laag)\",\n personalizationUpload: \"Kies bestand…\",\n personalizationUploading: \"Uploaden…\",\n personalizationUploaded: \"✓ Geüpload\",\n personalizationTooBig: \"Bestand te groot (max 5 MB).\",\n personalizationFailed: \"Uploaden mislukt — probeer het opnieuw.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Doneren is niet gelukt. Probeer het later opnieuw.\",\n donationCustomAmount: \"Ander bedrag\",\n donationAmountLabel: \"Bedrag in euro's (min. {min})\",\n billingSame: \"Factuuradres is hetzelfde als het verzendadres\",\n billingHeading: \"Factuuradres\",\n deliveryHeading: \"Bezorging\",\n deliveryShip: \"Laten verzenden\",\n deliveryPickup: \"Zelf afhalen (geen verzendkosten)\",\n pickupHeading: \"Afhalen\",\n giftWrap: \"Cadeauverpakking\",\n giftWrapLabel: \"Cadeauverpakking (+ {bedrag})\",\n giftWrapCardText: \"Tekst op het kaartje (optioneel)\",\n giftWrapNote: \"Opmerking voor het inpakken (optioneel)\",\n};\n\nconst EN: typeof NL = {\n addToCart: \"Add to cart\",\n added: \"✓ Added to your cart.\",\n addedGoToCart: \"✓ In cart — view\",\n view: \"View\",\n toCart: \"Go to cart\",\n continueShopping: \"Continue shopping\",\n checkout: \"Checkout\",\n cartEmpty: \"Your cart is empty.\",\n toShop: \"Go to the shop\",\n subtotal: \"Subtotal\",\n shippingCosts: \"Shipping\",\n free: \"free\",\n total: \"Total\",\n perPiece: \"each\",\n qty: \"Quantity\",\n outOfStock: \"Sold out in this variant.\",\n variantUnavailable: \"This combination is unavailable.\",\n stockLeft: \"Only {n} left\",\n soldOut: \"Sold out\",\n productNotFound: \"Product not found.\",\n backToShop: \"Back to the shop\",\n noProducts: \"No products found.\",\n noCategories: \"No categories yet.\",\n allCategories: \"All categories\",\n pay: \"Pay — {bedrag}\",\n busy: \"Working…\",\n checkoutFailed: \"Checkout failed. Check your details and try again.\",\n secureNote: \"You pay securely via a protected checkout page (incl. iDEAL). You will receive a confirmation email after payment.\",\n yourOrder: \"Your order\",\n fieldName: \"Name\",\n fieldEmail: \"Email\",\n fieldPhone: \"Phone (optional)\",\n fieldAddress: \"Street + number\",\n fieldZip: \"Postal code\",\n fieldCity: \"City\",\n fieldCountry: \"Country\",\n shippingFromCountry: \"(for delivery in the Netherlands — choose your country at checkout)\",\n fieldNote: \"Note (optional)\",\n choose: \"Choose…\",\n discountCode: \"Discount code\",\n discountApply: \"Apply\",\n discount: \"Discount\",\n discountInvalid: \"This code is not (or no longer) valid.\",\n discountApplied: \"Discount applied: {code}\",\n related: \"You may also like\",\n filterAll: \"All\",\n sortLabel: \"Sort\",\n sortDefault: \"Recommended\",\n sortName: \"Name\",\n sortPriceAsc: \"Price (low-high)\",\n sortPriceDesc: \"Price (high-low)\",\n personalizationUpload: \"Choose file…\",\n personalizationUploading: \"Uploading…\",\n personalizationUploaded: \"✓ Uploaded\",\n personalizationTooBig: \"File too large (max 5 MB).\",\n personalizationFailed: \"Upload failed — please try again.\",\n personalizationSurcharge: \"+ {bedrag}\",\n donationFailed: \"Donation failed. Please try again later.\",\n donationCustomAmount: \"Custom amount\",\n donationAmountLabel: \"Amount in euros (min. {min})\",\n billingSame: \"Billing address is the same as the shipping address\",\n billingHeading: \"Billing address\",\n deliveryHeading: \"Delivery\",\n deliveryShip: \"Ship to my address\",\n deliveryPickup: \"Collect in person (no shipping costs)\",\n pickupHeading: \"Collection\",\n giftWrap: \"Gift wrap\",\n giftWrapLabel: \"Gift wrap (+ {bedrag})\",\n giftWrapCardText: \"Text for the card (optional)\",\n giftWrapNote: \"Note for gift-wrapping (optional)\",\n};\n\nexport type ShopStringKey = keyof typeof NL;\nconst TABLES: Record<string, typeof NL> = { nl: NL, en: EN };\n\nexport type ShopT = (key: ShopStringKey, vars?: Record<string, string | number>) => string;\n\n/** Vertaalfunctie voor shop-blocks: `t(\"addToCart\")`, `t(\"stockLeft\", { n: 3 })`. */\nexport function useShopStrings(): ShopT {\n const lang = (useSiteConfig().lang ?? \"nl\").slice(0, 2).toLowerCase();\n const table = TABLES[lang] ?? NL;\n return (key, vars) => {\n let s = table[key] ?? NL[key] ?? key;\n if (vars) for (const [k, v] of Object.entries(vars)) s = s.replaceAll(`{${k}}`, String(v));\n return s;\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Env-controle tijdens de BUILD (8.7) — naar het idee van Astro's `astro:env`-schema.
|
|
3
|
+
*
|
|
4
|
+
* Er bestond al een controle bij serverstart (`validateEnv` in `instrumentation.ts`), maar die
|
|
5
|
+
* komt te laat voor `NEXT_PUBLIC_*`: die waarden worden tijdens `next build` letterlijk in de
|
|
6
|
+
* JavaScript-bundel gezet. Een lege waarde zit er dan al in, en de site start gewoon — alleen
|
|
7
|
+
* werkt inloggen of het beheer niet. Precies dat gebeurde in september 2026: `vercel pull` leverde
|
|
8
|
+
* Sensitive-variabelen leeg af, en dat viel pas op in de live bundel.
|
|
9
|
+
*
|
|
10
|
+
* Gebruik bovenin `next.config.ts`:
|
|
11
|
+
*
|
|
12
|
+
* import { xicmsEnvCheck } from "@xiwebdesign/xicms-core/next";
|
|
13
|
+
* xicmsEnvCheck();
|
|
14
|
+
*
|
|
15
|
+
* Een productie-build op Vercel (`VERCEL_ENV=production`) of met `XICMS_ENV_STRIKT=1` stopt bij een
|
|
16
|
+
* fout; overal elders (lokaal, CI, previews) komen fouten en waarschuwingen alleen in de log.
|
|
17
|
+
* Dit bestand draait in Node tijdens de build en mag niets uit de React-bundel importeren.
|
|
18
|
+
*/
|
|
19
|
+
export type EnvErnst = "fout" | "waarschuwing";
|
|
20
|
+
export interface EnvMelding {
|
|
21
|
+
naam: string;
|
|
22
|
+
ernst: EnvErnst;
|
|
23
|
+
tekst: string;
|
|
24
|
+
}
|
|
25
|
+
type Env = Record<string, string | undefined>;
|
|
26
|
+
/**
|
|
27
|
+
* Puur en testbaar: welke problemen heeft deze env? `demo` = een site zonder eigen Firebase
|
|
28
|
+
* (de demo-modus werkt lokaal), dan is ontbrekende Firebase-config geen fout.
|
|
29
|
+
*/
|
|
30
|
+
export declare function controleerSiteEnv(env: Env, opties?: {
|
|
31
|
+
demo?: boolean;
|
|
32
|
+
}): EnvMelding[];
|
|
33
|
+
/** Moet een fout de build stoppen? Alleen bij een productie-build, of als je het expliciet vraagt. */
|
|
34
|
+
export declare function envIsStrikt(env: Env): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Roep aan bovenin `next.config.ts`. Schrijft meldingen naar de log en gooit bij een fout als de
|
|
37
|
+
* build strikt is (zie `envIsStrikt`).
|
|
38
|
+
*/
|
|
39
|
+
export declare function xicmsEnvCheck(opties?: {
|
|
40
|
+
demo?: boolean;
|
|
41
|
+
}): EnvMelding[];
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const FIREBASE_PUBLIEK = [
|
|
2
|
+
"NEXT_PUBLIC_FIREBASE_API_KEY",
|
|
3
|
+
"NEXT_PUBLIC_FIREBASE_PROJECT_ID",
|
|
4
|
+
"NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET",
|
|
5
|
+
"NEXT_PUBLIC_FIREBASE_APP_ID"
|
|
6
|
+
];
|
|
7
|
+
const FIREBASE_ADMIN = ["FIREBASE_PROJECT_ID", "FIREBASE_CLIENT_EMAIL", "FIREBASE_PRIVATE_KEY"];
|
|
8
|
+
const LEEG_UITLEG = "staat er wel, maar is leeg. Op Vercel betekent dat meestal dat hij Sensitive is (die komen bij `vercel pull` leeg binnen). Een NEXT_PUBLIC-waarde is publiek: maak hem opnieuw met `vercel env add <NAAM> production --no-sensitive --force`.";
|
|
9
|
+
function controleerSiteEnv(env, opties = {}) {
|
|
10
|
+
const m = [];
|
|
11
|
+
const heeft = (k) => typeof env[k] === "string" && env[k].trim() !== "";
|
|
12
|
+
const leeg = (k) => typeof env[k] === "string" && env[k].trim() === "";
|
|
13
|
+
const aanwezig = FIREBASE_PUBLIEK.filter(heeft);
|
|
14
|
+
if (aanwezig.length === 0 && !FIREBASE_PUBLIEK.some(leeg)) {
|
|
15
|
+
if (!opties.demo) {
|
|
16
|
+
m.push({
|
|
17
|
+
naam: "NEXT_PUBLIC_FIREBASE_*",
|
|
18
|
+
ernst: "fout",
|
|
19
|
+
tekst: "Geen Firebase-config. Zonder deze waarden werken inloggen, het beheer en formulieren niet. (Een demo-site zonder Firebase: `xicmsEnvCheck({ demo: true })`.)"
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
for (const k of FIREBASE_PUBLIEK) {
|
|
24
|
+
if (leeg(k)) m.push({ naam: k, ernst: "fout", tekst: `${k} ${LEEG_UITLEG}` });
|
|
25
|
+
else if (!heeft(k)) m.push({ naam: k, ernst: "fout", tekst: `${k} ontbreekt, terwijl de rest van de Firebase-config er w\xE9l is.` });
|
|
26
|
+
}
|
|
27
|
+
const sameOrigin = env.NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN === "1";
|
|
28
|
+
if (leeg("NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN") && !sameOrigin) {
|
|
29
|
+
m.push({ naam: "NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN", ernst: "fout", tekst: `NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ${LEEG_UITLEG}` });
|
|
30
|
+
} else if (!heeft("NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN") && !sameOrigin) {
|
|
31
|
+
m.push({
|
|
32
|
+
naam: "NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN",
|
|
33
|
+
ernst: "waarschuwing",
|
|
34
|
+
tekst: "NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ontbreekt en NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN staat niet op 1: inloggen met Google werkt dan niet."
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const k of Object.keys(env)) {
|
|
39
|
+
if (k.startsWith("NEXT_PUBLIC_") && !k.startsWith("NEXT_PUBLIC_VERCEL_") && !FIREBASE_PUBLIEK.includes(k) && k !== "NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN" && leeg(k)) {
|
|
40
|
+
m.push({ naam: k, ernst: "waarschuwing", tekst: `${k} ${LEEG_UITLEG} (Is leeg hier bedoeld, haal hem dan weg.)` });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const so = env.NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN;
|
|
44
|
+
if (so !== void 0 && so !== "" && so !== "1" && so !== "0") {
|
|
45
|
+
m.push({ naam: "NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN", ernst: "waarschuwing", tekst: `NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN is "${so}"; alleen "1" zet hem aan.` });
|
|
46
|
+
}
|
|
47
|
+
const regio = env.NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION;
|
|
48
|
+
if (heeft("NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION") && !/^[a-z]+-[a-z]+\d$/.test(regio.trim())) {
|
|
49
|
+
m.push({ naam: "NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION", ernst: "waarschuwing", tekst: `NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION "${regio}" lijkt geen Google-regio (zoals europe-west1).` });
|
|
50
|
+
}
|
|
51
|
+
const admin = FIREBASE_ADMIN.filter(heeft);
|
|
52
|
+
if (admin.length > 0 && admin.length < FIREBASE_ADMIN.length) {
|
|
53
|
+
const mist = FIREBASE_ADMIN.filter((k) => !heeft(k));
|
|
54
|
+
m.push({ naam: mist.join(", "), ernst: "fout", tekst: `Firebase Admin is half ingesteld: ${mist.join(" en ")} ontbreekt. De server kan dan geen content lezen.` });
|
|
55
|
+
} else if (admin.length === 0 && !opties.demo && aanwezig.length > 0) {
|
|
56
|
+
m.push({
|
|
57
|
+
naam: "FIREBASE_*",
|
|
58
|
+
ernst: "waarschuwing",
|
|
59
|
+
tekst: "Geen Firebase Admin-sleutels (FIREBASE_PROJECT_ID/CLIENT_EMAIL/PRIVATE_KEY): de server leest dan alleen de gebundelde content, niet de live database."
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
if (heeft("FIREBASE_PRIVATE_KEY") && !env.FIREBASE_PRIVATE_KEY.includes("PRIVATE KEY")) {
|
|
63
|
+
m.push({ naam: "FIREBASE_PRIVATE_KEY", ernst: "fout", tekst: "FIREBASE_PRIVATE_KEY heeft niet de vorm van een sleutel (geen 'BEGIN PRIVATE KEY'). Plak de hele waarde uit het service-account-JSON, met de \\n's." });
|
|
64
|
+
}
|
|
65
|
+
if (heeft("FIREBASE_PROJECT_ID") && heeft("NEXT_PUBLIC_FIREBASE_PROJECT_ID") && env.FIREBASE_PROJECT_ID.trim() !== env.NEXT_PUBLIC_FIREBASE_PROJECT_ID.trim()) {
|
|
66
|
+
m.push({
|
|
67
|
+
naam: "FIREBASE_PROJECT_ID",
|
|
68
|
+
ernst: "fout",
|
|
69
|
+
tekst: `FIREBASE_PROJECT_ID (${env.FIREBASE_PROJECT_ID}) is een ander project dan NEXT_PUBLIC_FIREBASE_PROJECT_ID (${env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}): de server en de browser zouden verschillende databases lezen.`
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (admin.length === FIREBASE_ADMIN.length && !heeft("XICMS_REVALIDATE_SECRET")) {
|
|
73
|
+
m.push({
|
|
74
|
+
naam: "XICMS_REVALIDATE_SECRET",
|
|
75
|
+
ernst: "waarschuwing",
|
|
76
|
+
tekst: "XICMS_REVALIDATE_SECRET ontbreekt: gepubliceerde wijzigingen verschijnen pas na het ISR-vangnet (tot een uur), niet binnen seconden."
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
return m;
|
|
80
|
+
}
|
|
81
|
+
function envIsStrikt(env) {
|
|
82
|
+
return env.XICMS_ENV_STRIKT === "1" || env.VERCEL_ENV === "production" && env.XICMS_ENV_STRIKT !== "0";
|
|
83
|
+
}
|
|
84
|
+
function xicmsEnvCheck(opties = {}) {
|
|
85
|
+
const env = process.env;
|
|
86
|
+
const meldingen = controleerSiteEnv(env, opties);
|
|
87
|
+
if (meldingen.length === 0) return meldingen;
|
|
88
|
+
const fouten = meldingen.filter((x) => x.ernst === "fout");
|
|
89
|
+
const regels = meldingen.map((x) => ` ${x.ernst === "fout" ? "\u2717" : "!"} ${x.tekst}`).join("\n");
|
|
90
|
+
const kop = `[xicms] Controle van de env-variabelen: ${fouten.length} fout(en), ${meldingen.length - fouten.length} waarschuwing(en)`;
|
|
91
|
+
if (fouten.length > 0 && envIsStrikt(env)) {
|
|
92
|
+
throw new Error(`${kop}
|
|
93
|
+
${regels}
|
|
94
|
+
|
|
95
|
+
De build is gestopt zodat er geen kapotte site live gaat. Bewust negeren: XICMS_ENV_STRIKT=0.`);
|
|
96
|
+
}
|
|
97
|
+
console.warn(`${kop}
|
|
98
|
+
${regels}`);
|
|
99
|
+
return meldingen;
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
controleerSiteEnv,
|
|
103
|
+
envIsStrikt,
|
|
104
|
+
xicmsEnvCheck
|
|
105
|
+
};
|
|
106
|
+
//# sourceMappingURL=envCheck.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/next/envCheck.ts"],"sourcesContent":["/**\n * Env-controle tijdens de BUILD (8.7) — naar het idee van Astro's `astro:env`-schema.\n *\n * Er bestond al een controle bij serverstart (`validateEnv` in `instrumentation.ts`), maar die\n * komt te laat voor `NEXT_PUBLIC_*`: die waarden worden tijdens `next build` letterlijk in de\n * JavaScript-bundel gezet. Een lege waarde zit er dan al in, en de site start gewoon — alleen\n * werkt inloggen of het beheer niet. Precies dat gebeurde in september 2026: `vercel pull` leverde\n * Sensitive-variabelen leeg af, en dat viel pas op in de live bundel.\n *\n * Gebruik bovenin `next.config.ts`:\n *\n * import { xicmsEnvCheck } from \"@xiwebdesign/xicms-core/next\";\n * xicmsEnvCheck();\n *\n * Een productie-build op Vercel (`VERCEL_ENV=production`) of met `XICMS_ENV_STRIKT=1` stopt bij een\n * fout; overal elders (lokaal, CI, previews) komen fouten en waarschuwingen alleen in de log.\n * Dit bestand draait in Node tijdens de build en mag niets uit de React-bundel importeren.\n */\n\nexport type EnvErnst = \"fout\" | \"waarschuwing\";\n\nexport interface EnvMelding {\n naam: string;\n ernst: EnvErnst;\n tekst: string;\n}\n\ntype Env = Record<string, string | undefined>;\n\n/** De publieke Firebase-config die de browser nodig heeft (gaat de bundel in). */\nconst FIREBASE_PUBLIEK = [\n \"NEXT_PUBLIC_FIREBASE_API_KEY\",\n \"NEXT_PUBLIC_FIREBASE_PROJECT_ID\",\n \"NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET\",\n \"NEXT_PUBLIC_FIREBASE_APP_ID\",\n] as const;\n\n/** Server-geheimen voor het lezen van content (Firebase Admin). Alles of niets. */\nconst FIREBASE_ADMIN = [\"FIREBASE_PROJECT_ID\", \"FIREBASE_CLIENT_EMAIL\", \"FIREBASE_PRIVATE_KEY\"] as const;\n\nconst LEEG_UITLEG =\n \"staat er wel, maar is leeg. Op Vercel betekent dat meestal dat hij Sensitive is (die komen bij \" +\n \"`vercel pull` leeg binnen). Een NEXT_PUBLIC-waarde is publiek: maak hem opnieuw met \" +\n \"`vercel env add <NAAM> production --no-sensitive --force`.\";\n\n/**\n * Puur en testbaar: welke problemen heeft deze env? `demo` = een site zonder eigen Firebase\n * (de demo-modus werkt lokaal), dan is ontbrekende Firebase-config geen fout.\n */\nexport function controleerSiteEnv(env: Env, opties: { demo?: boolean } = {}): EnvMelding[] {\n const m: EnvMelding[] = [];\n const heeft = (k: string) => typeof env[k] === \"string\" && env[k]!.trim() !== \"\";\n const leeg = (k: string) => typeof env[k] === \"string\" && env[k]!.trim() === \"\";\n\n // ── Publieke Firebase-config ────────────────────────────────────────────\n const aanwezig = FIREBASE_PUBLIEK.filter(heeft);\n if (aanwezig.length === 0 && !FIREBASE_PUBLIEK.some(leeg)) {\n if (!opties.demo) {\n m.push({\n naam: \"NEXT_PUBLIC_FIREBASE_*\",\n ernst: \"fout\",\n tekst: \"Geen Firebase-config. Zonder deze waarden werken inloggen, het beheer en formulieren niet. (Een demo-site zonder Firebase: `xicmsEnvCheck({ demo: true })`.)\",\n });\n }\n } else {\n for (const k of FIREBASE_PUBLIEK) {\n if (leeg(k)) m.push({ naam: k, ernst: \"fout\", tekst: `${k} ${LEEG_UITLEG}` });\n else if (!heeft(k)) m.push({ naam: k, ernst: \"fout\", tekst: `${k} ontbreekt, terwijl de rest van de Firebase-config er wél is.` });\n }\n const sameOrigin = env.NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN === \"1\";\n if (leeg(\"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN\") && !sameOrigin) {\n m.push({ naam: \"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN\", ernst: \"fout\", tekst: `NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ${LEEG_UITLEG}` });\n } else if (!heeft(\"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN\") && !sameOrigin) {\n m.push({\n naam: \"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN\",\n ernst: \"waarschuwing\",\n tekst: \"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN ontbreekt en NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN staat niet op 1: inloggen met Google werkt dan niet.\",\n });\n }\n }\n for (const k of Object.keys(env)) {\n // Andere publieke vars die leeg zijn (App Check, regio, …): ook die gaan zo de bundel in.\n // NEXT_PUBLIC_VERCEL_* zet Vercel zelf, en sommige zijn bewust leeg (geen PR → geen PR-id).\n if (k.startsWith(\"NEXT_PUBLIC_\") && !k.startsWith(\"NEXT_PUBLIC_VERCEL_\") && !(FIREBASE_PUBLIEK as readonly string[]).includes(k) && k !== \"NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN\" && leeg(k)) {\n m.push({ naam: k, ernst: \"waarschuwing\", tekst: `${k} ${LEEG_UITLEG} (Is leeg hier bedoeld, haal hem dan weg.)` });\n }\n }\n const so = env.NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN;\n if (so !== undefined && so !== \"\" && so !== \"1\" && so !== \"0\") {\n m.push({ naam: \"NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN\", ernst: \"waarschuwing\", tekst: `NEXT_PUBLIC_FIREBASE_AUTH_SAME_ORIGIN is \"${so}\"; alleen \"1\" zet hem aan.` });\n }\n const regio = env.NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION;\n if (heeft(\"NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION\") && !/^[a-z]+-[a-z]+\\d$/.test(regio!.trim())) {\n m.push({ naam: \"NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION\", ernst: \"waarschuwing\", tekst: `NEXT_PUBLIC_FIREBASE_FUNCTIONS_REGION \"${regio}\" lijkt geen Google-regio (zoals europe-west1).` });\n }\n\n // ── Firebase Admin (server) ─────────────────────────────────────────────\n const admin = FIREBASE_ADMIN.filter(heeft);\n if (admin.length > 0 && admin.length < FIREBASE_ADMIN.length) {\n const mist = FIREBASE_ADMIN.filter((k) => !heeft(k));\n m.push({ naam: mist.join(\", \"), ernst: \"fout\", tekst: `Firebase Admin is half ingesteld: ${mist.join(\" en \")} ontbreekt. De server kan dan geen content lezen.` });\n } else if (admin.length === 0 && !opties.demo && aanwezig.length > 0) {\n m.push({\n naam: \"FIREBASE_*\",\n ernst: \"waarschuwing\",\n tekst: \"Geen Firebase Admin-sleutels (FIREBASE_PROJECT_ID/CLIENT_EMAIL/PRIVATE_KEY): de server leest dan alleen de gebundelde content, niet de live database.\",\n });\n }\n if (heeft(\"FIREBASE_PRIVATE_KEY\") && !env.FIREBASE_PRIVATE_KEY!.includes(\"PRIVATE KEY\")) {\n m.push({ naam: \"FIREBASE_PRIVATE_KEY\", ernst: \"fout\", tekst: \"FIREBASE_PRIVATE_KEY heeft niet de vorm van een sleutel (geen 'BEGIN PRIVATE KEY'). Plak de hele waarde uit het service-account-JSON, met de \\\\n's.\" });\n }\n if (heeft(\"FIREBASE_PROJECT_ID\") && heeft(\"NEXT_PUBLIC_FIREBASE_PROJECT_ID\") && env.FIREBASE_PROJECT_ID!.trim() !== env.NEXT_PUBLIC_FIREBASE_PROJECT_ID!.trim()) {\n m.push({\n naam: \"FIREBASE_PROJECT_ID\",\n ernst: \"fout\",\n tekst: `FIREBASE_PROJECT_ID (${env.FIREBASE_PROJECT_ID}) is een ander project dan NEXT_PUBLIC_FIREBASE_PROJECT_ID (${env.NEXT_PUBLIC_FIREBASE_PROJECT_ID}): de server en de browser zouden verschillende databases lezen.`,\n });\n }\n\n // ── Live zonder rebuild ─────────────────────────────────────────────────\n if (admin.length === FIREBASE_ADMIN.length && !heeft(\"XICMS_REVALIDATE_SECRET\")) {\n m.push({\n naam: \"XICMS_REVALIDATE_SECRET\",\n ernst: \"waarschuwing\",\n tekst: \"XICMS_REVALIDATE_SECRET ontbreekt: gepubliceerde wijzigingen verschijnen pas na het ISR-vangnet (tot een uur), niet binnen seconden.\",\n });\n }\n return m;\n}\n\n/** Moet een fout de build stoppen? Alleen bij een productie-build, of als je het expliciet vraagt. */\nexport function envIsStrikt(env: Env): boolean {\n return env.XICMS_ENV_STRIKT === \"1\" || (env.VERCEL_ENV === \"production\" && env.XICMS_ENV_STRIKT !== \"0\");\n}\n\n/**\n * Roep aan bovenin `next.config.ts`. Schrijft meldingen naar de log en gooit bij een fout als de\n * build strikt is (zie `envIsStrikt`).\n */\nexport function xicmsEnvCheck(opties: { demo?: boolean } = {}): EnvMelding[] {\n const env = process.env as Env;\n const meldingen = controleerSiteEnv(env, opties);\n if (meldingen.length === 0) return meldingen;\n const fouten = meldingen.filter((x) => x.ernst === \"fout\");\n const regels = meldingen.map((x) => ` ${x.ernst === \"fout\" ? \"✗\" : \"!\"} ${x.tekst}`).join(\"\\n\");\n const kop = `[xicms] Controle van de env-variabelen: ${fouten.length} fout(en), ${meldingen.length - fouten.length} waarschuwing(en)`;\n if (fouten.length > 0 && envIsStrikt(env)) {\n throw new Error(`${kop}\\n${regels}\\n\\nDe build is gestopt zodat er geen kapotte site live gaat. Bewust negeren: XICMS_ENV_STRIKT=0.`);\n }\n console.warn(`${kop}\\n${regels}`);\n return meldingen;\n}\n"],"mappings":"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","names":[]}
|