create-nextblock 0.2.77 → 0.8.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/bin/create-nextblock.js +740 -459
- package/package.json +1 -2
- package/scripts/sync-template.js +18 -1
- package/templates/nextblock-template/.browserslistrc +11 -0
- package/templates/nextblock-template/.swcrc +30 -30
- package/templates/nextblock-template/README.md +23 -114
- package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -28
- package/templates/nextblock-template/app/(auth-pages)/sign-in/page.tsx +50 -25
- package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +111 -56
- package/templates/nextblock-template/app/(auth-pages)/two-factor/actions.ts +91 -0
- package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +118 -0
- package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -0
- package/templates/nextblock-template/app/.well-known/ucp/route.ts +16 -0
- package/templates/nextblock-template/app/[slug]/PageClientContent.tsx +48 -28
- package/templates/nextblock-template/app/[slug]/page.tsx +63 -6
- package/templates/nextblock-template/app/[slug]/page.utils.ts +374 -157
- package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -0
- package/templates/nextblock-template/app/actions/consent.ts +57 -0
- package/templates/nextblock-template/app/actions/formActions.ts +130 -11
- package/templates/nextblock-template/app/actions/languageActions.ts +31 -30
- package/templates/nextblock-template/app/actions/package-actions.ts +183 -0
- package/templates/nextblock-template/app/actions/postActions.ts +146 -48
- package/templates/nextblock-template/app/actions/twoFactorEmail.ts +21 -0
- package/templates/nextblock-template/app/actions/visualEditingActions.test.ts +179 -0
- package/templates/nextblock-template/app/actions/visualEditingActions.ts +345 -0
- package/templates/nextblock-template/app/actions.ts +67 -12
- package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -0
- package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -0
- package/templates/nextblock-template/app/api/ai/global-agent/route.ts +965 -0
- package/templates/nextblock-template/app/api/checkout/freemius/sync/route.ts +29 -0
- package/templates/nextblock-template/app/api/checkout/route.ts +146 -0
- package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -0
- package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -0
- package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3413 -17
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +7830 -0
- package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +35 -0
- package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -0
- package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -0
- package/templates/nextblock-template/app/api/draft/disable/route.ts +25 -0
- package/templates/nextblock-template/app/api/draft/route.ts +93 -0
- package/templates/nextblock-template/app/api/draft/start/route.ts +77 -0
- package/templates/nextblock-template/app/api/media/library/route.ts +65 -0
- package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -0
- package/templates/nextblock-template/app/api/media/record/route.ts +160 -0
- package/templates/nextblock-template/app/api/search/route.ts +43 -0
- package/templates/nextblock-template/app/api/visual-editing/block-draft/route.ts +47 -0
- package/templates/nextblock-template/app/api/visual-editing/product-draft/route.ts +47 -0
- package/templates/nextblock-template/app/api/webhooks/freemius/route.ts +34 -0
- package/templates/nextblock-template/app/api/webhooks/stripe/route.ts +27 -0
- package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +392 -128
- package/templates/nextblock-template/app/article/[slug]/page.tsx +179 -127
- package/templates/nextblock-template/app/article/[slug]/page.utils.ts +262 -77
- package/templates/nextblock-template/app/auth/callback/route.ts +31 -58
- package/templates/nextblock-template/app/cart/page.tsx +7 -0
- package/templates/nextblock-template/app/checkout/UcpCartHydrator.tsx +20 -0
- package/templates/nextblock-template/app/checkout/page.tsx +52 -0
- package/templates/nextblock-template/app/checkout/success/actions.ts +136 -0
- package/templates/nextblock-template/app/checkout/success/page.tsx +186 -0
- package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +163 -33
- package/templates/nextblock-template/app/cms/blocks/actions.ts +424 -235
- package/templates/nextblock-template/app/cms/blocks/components/BackgroundSelector.tsx +212 -151
- package/templates/nextblock-template/app/cms/blocks/components/BlockEditorArea.tsx +41 -20
- package/templates/nextblock-template/app/cms/blocks/components/BlockEditorModal.tsx +152 -19
- package/templates/nextblock-template/app/cms/blocks/components/BlockTypeCard.tsx +25 -17
- package/templates/nextblock-template/app/cms/blocks/components/BlockTypeSelector.tsx +200 -18
- package/templates/nextblock-template/app/cms/blocks/components/ColumnEditor.tsx +33 -16
- package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -0
- package/templates/nextblock-template/app/cms/blocks/components/EditableBlock.tsx +37 -18
- package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -67
- package/templates/nextblock-template/app/cms/blocks/components/SectionConfigPanel.tsx +108 -31
- package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -0
- package/templates/nextblock-template/app/cms/blocks/editors/FeaturedProductBlockEditor.tsx +31 -0
- package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +2 -2
- package/templates/nextblock-template/app/cms/blocks/editors/HeadingBlockEditor.tsx +1 -1
- package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +29 -29
- package/templates/nextblock-template/app/cms/blocks/editors/PostsGridBlockEditor.tsx +14 -18
- package/templates/nextblock-template/app/cms/blocks/editors/ProductGridBlockEditor.tsx +41 -0
- package/templates/nextblock-template/app/cms/blocks/editors/SectionBlockEditor.tsx +318 -118
- package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +98 -21
- package/templates/nextblock-template/app/cms/blocks/editors/VideoEmbedBlockEditor.tsx +1 -1
- package/templates/nextblock-template/app/cms/components/ContentLanguageSwitcher.tsx +27 -9
- package/templates/nextblock-template/app/cms/components/CopyContentFromLanguage.tsx +1 -1
- package/templates/nextblock-template/app/cms/components/CortexAiActiveContext.tsx +23 -0
- package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -0
- package/templates/nextblock-template/app/cms/components/CortexGlobalAgentChat.tsx +1507 -0
- package/templates/nextblock-template/app/cms/components/DraftStatusActions.tsx +145 -0
- package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +244 -0
- package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +38 -24
- package/templates/nextblock-template/app/cms/coupons/[id]/edit/page.tsx +16 -0
- package/templates/nextblock-template/app/cms/coupons/page.tsx +16 -0
- package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -0
- package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -0
- package/templates/nextblock-template/app/cms/custom-blocks/components/BlockComposer.tsx +1522 -0
- package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -0
- package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -0
- package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -0
- package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -0
- package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -0
- package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -98
- package/templates/nextblock-template/app/cms/dashboard/components/DashboardComponents.tsx +200 -0
- package/templates/nextblock-template/app/cms/dashboard/page.tsx +191 -151
- package/templates/nextblock-template/app/cms/import-export/ContentTransferControls.tsx +391 -0
- package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -0
- package/templates/nextblock-template/app/cms/layout.tsx +29 -10
- package/templates/nextblock-template/app/cms/media/UploadFolderContext.tsx +22 -22
- package/templates/nextblock-template/app/cms/media/actions.ts +45 -124
- package/templates/nextblock-template/app/cms/media/components/DeleteMediaButtonClient.tsx +1 -1
- package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
- package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -64
- package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +227 -158
- package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +101 -89
- package/templates/nextblock-template/app/cms/media/page.tsx +1 -1
- package/templates/nextblock-template/app/cms/navigation/components/NavigationItemForm.tsx +2 -2
- package/templates/nextblock-template/app/cms/orders/[id]/MarkPaidButton.tsx +44 -0
- package/templates/nextblock-template/app/cms/orders/[id]/page.tsx +16 -0
- package/templates/nextblock-template/app/cms/orders/actions.ts +201 -0
- package/templates/nextblock-template/app/cms/orders/page.tsx +20 -0
- package/templates/nextblock-template/app/cms/orders/types.ts +20 -0
- package/templates/nextblock-template/app/cms/pages/[id]/edit/EditPageClient.tsx +156 -121
- package/templates/nextblock-template/app/cms/pages/[id]/edit/page.tsx +79 -26
- package/templates/nextblock-template/app/cms/pages/actions.ts +54 -38
- package/templates/nextblock-template/app/cms/pages/components/DeletePageButtonClient.tsx +1 -1
- package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +267 -116
- package/templates/nextblock-template/app/cms/pages/page.tsx +25 -18
- package/templates/nextblock-template/app/cms/payments/page.tsx +16 -0
- package/templates/nextblock-template/app/cms/posts/[id]/edit/page.tsx +132 -90
- package/templates/nextblock-template/app/cms/posts/actions.ts +71 -72
- package/templates/nextblock-template/app/cms/posts/components/DeletePostButtonClient.tsx +1 -1
- package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +256 -245
- package/templates/nextblock-template/app/cms/posts/new/page.tsx +1 -1
- package/templates/nextblock-template/app/cms/posts/page.tsx +20 -13
- package/templates/nextblock-template/app/cms/products/ClientNotionEditor.tsx +16 -0
- package/templates/nextblock-template/app/cms/products/ProductFormClientShell.tsx +56 -0
- package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +292 -0
- package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -0
- package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -0
- package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -0
- package/templates/nextblock-template/app/cms/products/new/page.tsx +143 -0
- package/templates/nextblock-template/app/cms/products/page.tsx +42 -0
- package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -0
- package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -0
- package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -0
- package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -0
- package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -0
- package/templates/nextblock-template/app/cms/revisions/RevisionHistoryButton.tsx +2 -2
- package/templates/nextblock-template/app/cms/revisions/actions.ts +285 -285
- package/templates/nextblock-template/app/cms/revisions/service.ts +19 -16
- package/templates/nextblock-template/app/cms/revisions/utils.ts +8 -3
- package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -0
- package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -0
- package/templates/nextblock-template/app/cms/settings/bot-protection/actions.ts +93 -0
- package/templates/nextblock-template/app/cms/settings/bot-protection/components/BotProtectionForm.tsx +129 -0
- package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -0
- package/templates/nextblock-template/app/cms/settings/copyright/actions.ts +1 -1
- package/templates/nextblock-template/app/cms/settings/copyright/components/CopyrightForm.tsx +2 -2
- package/templates/nextblock-template/app/cms/settings/copyright/page.tsx +1 -1
- package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +496 -0
- package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +410 -0
- package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +248 -0
- package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +80 -0
- package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -0
- package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -0
- package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -0
- package/templates/nextblock-template/app/cms/settings/extra-translations/actions.ts +203 -44
- package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -242
- package/templates/nextblock-template/app/cms/settings/global-css/actions.ts +65 -0
- package/templates/nextblock-template/app/cms/settings/global-css/components/GlobalCssForm.tsx +46 -0
- package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +24 -0
- package/templates/nextblock-template/app/cms/settings/languages/components/DeleteLanguageButton.tsx +1 -1
- package/templates/nextblock-template/app/cms/settings/languages/components/LanguageForm.tsx +2 -2
- package/templates/nextblock-template/app/cms/settings/languages/page.tsx +1 -1
- package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
- package/templates/nextblock-template/app/cms/settings/logos/actions.ts +82 -6
- package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -0
- package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -18
- package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +20 -16
- package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -0
- package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
- package/templates/nextblock-template/app/cms/settings/logos/page.tsx +120 -82
- package/templates/nextblock-template/app/cms/settings/logos/types.ts +8 -8
- package/templates/nextblock-template/app/cms/settings/packages/activation-form.tsx +84 -0
- package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -0
- package/templates/nextblock-template/app/cms/settings/packages/page.tsx +49 -0
- package/templates/nextblock-template/app/cms/settings/privacy/actions.ts +53 -0
- package/templates/nextblock-template/app/cms/settings/privacy/components/PrivacyForm.tsx +196 -0
- package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +26 -0
- package/templates/nextblock-template/app/cms/settings/security/actions.ts +251 -0
- package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +453 -0
- package/templates/nextblock-template/app/cms/settings/security/page.tsx +13 -0
- package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -0
- package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -0
- package/templates/nextblock-template/app/cms/users/[id]/edit/page.tsx +28 -23
- package/templates/nextblock-template/app/cms/users/actions.ts +105 -40
- package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +1 -1
- package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +65 -152
- package/templates/nextblock-template/app/cms/users/page.tsx +15 -10
- package/templates/nextblock-template/app/globals.css +9 -0
- package/templates/nextblock-template/app/layout.tsx +372 -116
- package/templates/nextblock-template/app/lib/seo.test.ts +52 -0
- package/templates/nextblock-template/app/lib/seo.ts +279 -0
- package/templates/nextblock-template/app/lib/site-settings.ts +87 -0
- package/templates/nextblock-template/app/lib/sitemap-utils.ts +224 -39
- package/templates/nextblock-template/app/lib/ucp/protocol.ts +190 -0
- package/templates/nextblock-template/app/lib/ucp/server.test.ts +56 -0
- package/templates/nextblock-template/app/lib/ucp/server.ts +1914 -0
- package/templates/nextblock-template/app/page.tsx +165 -73
- package/templates/nextblock-template/app/product/[slug]/page.tsx +433 -0
- package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +73 -0
- package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -0
- package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -0
- package/templates/nextblock-template/app/profile/account-data.ts +37 -0
- package/templates/nextblock-template/app/profile/account-links.ts +22 -0
- package/templates/nextblock-template/app/profile/account-types.ts +11 -0
- package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -0
- package/templates/nextblock-template/app/profile/orders/[id]/CustomerOrderDetailPageClient.tsx +79 -0
- package/templates/nextblock-template/app/profile/orders/[id]/page.tsx +32 -0
- package/templates/nextblock-template/app/profile/orders/page.tsx +19 -0
- package/templates/nextblock-template/app/profile/page.tsx +51 -0
- package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -0
- package/templates/nextblock-template/app/profile/password/actions.ts +59 -0
- package/templates/nextblock-template/app/profile/password/page.tsx +27 -0
- package/templates/nextblock-template/app/providers.tsx +55 -17
- package/templates/nextblock-template/app/robots.txt/route.ts +11 -1
- package/templates/nextblock-template/app/sitemap.ts +128 -0
- package/templates/nextblock-template/app/ucp/v1/carts/[id]/cancel/route.ts +38 -0
- package/templates/nextblock-template/app/ucp/v1/carts/[id]/route.ts +68 -0
- package/templates/nextblock-template/app/ucp/v1/carts/route.ts +35 -0
- package/templates/nextblock-template/app/ucp/v1/catalog/lookup/route.ts +35 -0
- package/templates/nextblock-template/app/ucp/v1/catalog/product/route.ts +35 -0
- package/templates/nextblock-template/app/ucp/v1/catalog/search/route.ts +34 -0
- package/templates/nextblock-template/components/AppShell.tsx +154 -0
- package/templates/nextblock-template/components/BlockRenderer.tsx +210 -64
- package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -0
- package/templates/nextblock-template/components/CartTranslator.tsx +210 -0
- package/templates/nextblock-template/components/CurrentContentSetter.tsx +25 -0
- package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -0
- package/templates/nextblock-template/components/DeferredCartTranslator.tsx +51 -0
- package/templates/nextblock-template/components/DeferredGlobalSearch.tsx +68 -0
- package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -0
- package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -0
- package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -0
- package/templates/nextblock-template/components/GitHubLoginButton.tsx +36 -0
- package/templates/nextblock-template/components/GlobalSearch.tsx +557 -0
- package/templates/nextblock-template/components/Header.tsx +49 -41
- package/templates/nextblock-template/components/LanguageSwitcher.tsx +55 -32
- package/templates/nextblock-template/components/ResponsiveNav.tsx +138 -43
- package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -8
- package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -55
- package/templates/nextblock-template/components/blocks/PostsGridClient.tsx +42 -37
- package/templates/nextblock-template/components/blocks/TestimonialBlock.tsx +6 -2
- package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -0
- package/templates/nextblock-template/components/blocks/publicRendererLoaders.ts +25 -0
- package/templates/nextblock-template/components/blocks/renderers/ButtonBlockRenderer.tsx +92 -84
- package/templates/nextblock-template/components/blocks/renderers/CartBlockRenderer.tsx +17 -0
- package/templates/nextblock-template/components/blocks/renderers/CheckoutBlockRenderer.tsx +19 -0
- package/templates/nextblock-template/components/blocks/renderers/ClientTextBlockRenderer.tsx +262 -8
- package/templates/nextblock-template/components/blocks/renderers/FeaturedProductBlockRenderer.tsx +22 -0
- package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +320 -37
- package/templates/nextblock-template/components/blocks/renderers/HeadingBlockRenderer.tsx +11 -8
- package/templates/nextblock-template/components/blocks/renderers/ImageBlockRenderer.tsx +12 -3
- package/templates/nextblock-template/components/blocks/renderers/PostsGridBlockRenderer.tsx +18 -13
- package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +90 -0
- package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx +31 -0
- package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +424 -55
- package/templates/nextblock-template/components/blocks/renderers/SectionSlider.tsx +137 -0
- package/templates/nextblock-template/components/blocks/renderers/TestimonialBlockRenderer.tsx +57 -0
- package/templates/nextblock-template/components/blocks/renderers/TextBlockRenderer.tsx +37 -22
- package/templates/nextblock-template/components/blocks/renderers/VideoEmbedBlockRenderer.tsx +23 -15
- package/templates/nextblock-template/components/blocks/renderers/inline/AlertWidgetRenderer.tsx +1 -3
- package/templates/nextblock-template/components/blocks/renderers/inline/CtaWidgetRenderer.tsx +1 -3
- package/templates/nextblock-template/components/blocks/types.ts +7 -6
- package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
- package/templates/nextblock-template/components/form-message.tsx +32 -26
- package/templates/nextblock-template/components/header-auth.tsx +69 -17
- package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +127 -0
- package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +59 -0
- package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -0
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -0
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +464 -0
- package/templates/nextblock-template/components/theme-switcher.tsx +8 -8
- package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -0
- package/templates/nextblock-template/components/visual-editing/NextblockVisualEditing.tsx +1172 -0
- package/templates/nextblock-template/context/AuthContext.tsx +23 -90
- package/templates/nextblock-template/context/CurrentContentContext.tsx +10 -4
- package/templates/nextblock-template/context/LanguageContext.tsx +16 -16
- package/templates/nextblock-template/context/language-rest-client.ts +31 -0
- package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -0
- package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -0
- package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +202 -0
- package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +252 -0
- package/templates/nextblock-template/docs/05-DEVELOPER-GUIDE.md +238 -0
- package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +125 -0
- package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -0
- package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +1319 -0
- package/templates/nextblock-template/docs/09-LIVE-DRAFT-MODE.md +104 -0
- package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -0
- package/templates/nextblock-template/docs/README.md +34 -0
- package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12507 -0
- package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -14
- package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -0
- package/templates/nextblock-template/index.d.ts +2 -0
- package/templates/nextblock-template/lib/ai-block-generation.ts +339 -0
- package/templates/nextblock-template/lib/ai-client.ts +247 -0
- package/templates/nextblock-template/lib/ai-config.ts +81 -0
- package/templates/nextblock-template/lib/ai-cortex-widget-builder.ts +125 -0
- package/templates/nextblock-template/lib/ai-global-agent-custom-block-tools.ts +363 -0
- package/templates/nextblock-template/lib/ai-global-agent-db-tools.test.ts +405 -0
- package/templates/nextblock-template/lib/ai-global-agent-db-tools.ts +1228 -0
- package/templates/nextblock-template/lib/ai-global-agent-ecommerce.ts +5 -0
- package/templates/nextblock-template/lib/ai-global-agent-tools-stats.test.ts +223 -0
- package/templates/nextblock-template/lib/ai-global-agent-tools.test.ts +2183 -0
- package/templates/nextblock-template/lib/ai-global-agent-tools.ts +4807 -0
- package/templates/nextblock-template/lib/ai-key-crypto.test.ts +70 -0
- package/templates/nextblock-template/lib/ai-key-crypto.ts +132 -0
- package/templates/nextblock-template/lib/ai-model-catalog.test.ts +49 -0
- package/templates/nextblock-template/lib/ai-model-catalog.ts +41 -0
- package/templates/nextblock-template/lib/ai-model-registry.test.ts +231 -0
- package/templates/nextblock-template/lib/ai-model-registry.ts +522 -0
- package/templates/nextblock-template/lib/auth/cookies.ts +47 -0
- package/templates/nextblock-template/lib/auth/crypto.ts +42 -0
- package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -0
- package/templates/nextblock-template/lib/auth/twoFactor.ts +167 -0
- package/templates/nextblock-template/lib/auth-redirects.ts +46 -0
- package/templates/nextblock-template/lib/blocks/FeaturedProductBlock.tsx +94 -0
- package/templates/nextblock-template/lib/blocks/ProductGridBlock.tsx +137 -0
- package/templates/nextblock-template/lib/blocks/README.md +13 -670
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +138 -56
- package/templates/nextblock-template/lib/blocks/blockTypes.ts +18 -0
- package/templates/nextblock-template/lib/blocks/ecommerce-block-schemas.ts +31 -0
- package/templates/nextblock-template/lib/cms-transfer/csv.test.ts +77 -0
- package/templates/nextblock-template/lib/cms-transfer/csv.ts +399 -0
- package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -0
- package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -0
- package/templates/nextblock-template/lib/cortex-widget-registry.test.ts +199 -0
- package/templates/nextblock-template/lib/cortex-widget-registry.ts +88 -0
- package/templates/nextblock-template/lib/cortex-widget-schema.test.tsx +237 -0
- package/templates/nextblock-template/lib/cortex-widget-schema.ts +393 -0
- package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -0
- package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -0
- package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -0
- package/templates/nextblock-template/lib/custom-block-r2-upload.ts +68 -0
- package/templates/nextblock-template/lib/custom-block-relation-registry.ts +256 -0
- package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -0
- package/templates/nextblock-template/lib/custom-block-relations.ts +279 -0
- package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -0
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -0
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -0
- package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -0
- package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -0
- package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -0
- package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -0
- package/templates/nextblock-template/lib/full-backup/server.ts +743 -0
- package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +45 -0
- package/templates/nextblock-template/lib/posts/readTime.ts +60 -0
- package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -0
- package/templates/nextblock-template/lib/privacy/settings.ts +103 -0
- package/templates/nextblock-template/lib/privacy/types.ts +67 -0
- package/templates/nextblock-template/lib/promotions/server.test.ts +74 -0
- package/templates/nextblock-template/lib/promotions/server.ts +741 -0
- package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -0
- package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -0
- package/templates/nextblock-template/lib/search/server.ts +585 -0
- package/templates/nextblock-template/lib/search/types.ts +27 -0
- package/templates/nextblock-template/lib/visual-editing/draft-content.test.ts +105 -0
- package/templates/nextblock-template/lib/visual-editing/draft-content.ts +380 -0
- package/templates/nextblock-template/lib/visual-editing/draft-route.test.ts +42 -0
- package/templates/nextblock-template/lib/visual-editing/draft-route.ts +82 -0
- package/templates/nextblock-template/lib/visual-editing/edit-info.test.ts +143 -0
- package/templates/nextblock-template/lib/visual-editing/edit-info.ts +94 -0
- package/templates/nextblock-template/lib/visual-editing/mutations.ts +190 -0
- package/templates/nextblock-template/lib/visual-editing/product-drafts.test.ts +81 -0
- package/templates/nextblock-template/lib/visual-editing/product-drafts.ts +511 -0
- package/templates/nextblock-template/lib/visual-editing/types.ts +122 -0
- package/templates/nextblock-template/lib/zod-config.ts +5 -0
- package/templates/nextblock-template/next.config.js +190 -66
- package/templates/nextblock-template/package.json +34 -30
- package/templates/nextblock-template/proxy.ts +435 -253
- package/templates/nextblock-template/public/images/NBcover.webp +0 -0
- package/templates/nextblock-template/public/images/cap.webp +0 -0
- package/templates/nextblock-template/public/images/commerce-plan.webp +0 -0
- package/templates/nextblock-template/public/images/commerce-square.webp +0 -0
- package/templates/nextblock-template/public/images/commerce-wide.webp +0 -0
- package/templates/nextblock-template/public/images/cortex-ai-square.webp +0 -0
- package/templates/nextblock-template/public/images/cortex-ai.webp +0 -0
- package/templates/nextblock-template/public/images/extensibility.webp +0 -0
- package/templates/nextblock-template/public/images/goals.webp +0 -0
- package/templates/nextblock-template/public/images/included.webp +0 -0
- package/templates/nextblock-template/public/images/nx-graph.webp +0 -0
- package/templates/nextblock-template/public/images/pants.webp +0 -0
- package/templates/nextblock-template/public/images/t-shirt.webp +0 -0
- package/templates/nextblock-template/scripts/validate-editor-block-schema.ts +112 -0
- package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +100 -0
- package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -0
- package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -0
- package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -0
- package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -0
- package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -0
- package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -0
- package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -0
- package/templates/nextblock-template/tailwind.config.js +1 -0
- package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -0
- package/templates/nextblock-template/tools/deploy-supabase.js +69 -71
- package/templates/nextblock-template/tsconfig.json +52 -66
- package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
- package/templates/nextblock-template/types/jsdom.d.ts +6 -0
- package/templates/nextblock-template/app/force-styles.tsx +0 -31
- package/templates/nextblock-template/app/sitemap.xml/route.ts +0 -63
- package/templates/nextblock-template/components/blocks/renderers/HeroBlockRenderer.tsx +0 -273
- package/templates/nextblock-template/docs/How to Create a Custom Block.md +0 -149
- package/templates/nextblock-template/docs/cms-application-overview.md +0 -56
- package/templates/nextblock-template/docs/cms-architecture-overview.md +0 -73
- package/templates/nextblock-template/docs/files-structure.md +0 -426
- package/templates/nextblock-template/docs/tiptap-bundle-optimization-summary.md +0 -174
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
# 02 Ecommerce Capabilities
|
|
2
|
+
|
|
3
|
+
## Scope and Source of Truth
|
|
4
|
+
|
|
5
|
+
The commerce feature set is implemented across:
|
|
6
|
+
|
|
7
|
+
- `libs/ecommerce/src/lib/*`
|
|
8
|
+
- `libs/db/src/supabase/migrations/00000000000003` through `00000000000006`
|
|
9
|
+
- `apps/nextblock/app/api/checkout/route.ts`
|
|
10
|
+
- `apps/nextblock/app/api/webhooks/*`
|
|
11
|
+
- `apps/nextblock/app/cms/products`, `orders`, `shipping`, `payments`, and
|
|
12
|
+
`settings/taxes`
|
|
13
|
+
|
|
14
|
+
In workspace code, the developer-facing import paths are:
|
|
15
|
+
|
|
16
|
+
- `@nextblock-cms/ecommerce`
|
|
17
|
+
- `@nextblock-cms/ecommerce/server`
|
|
18
|
+
- `@nextblock-cms/ecommerce/actions`
|
|
19
|
+
|
|
20
|
+
One packaging discrepancy exists today: `libs/ecommerce/package.json` is still
|
|
21
|
+
named `@nextblock-cms/ecom`, while the workspace and CLI activation flow expose
|
|
22
|
+
the package through the `@nextblock-cms/ecommerce` alias.
|
|
23
|
+
|
|
24
|
+
## Commerce Data Model
|
|
25
|
+
|
|
26
|
+
The commerce schema spans:
|
|
27
|
+
|
|
28
|
+
- Catalog: `products`, `product_media`, `product_attributes`,
|
|
29
|
+
`product_attribute_terms`, `product_variants`,
|
|
30
|
+
`variant_attribute_mapping`, `categories`, `product_categories`
|
|
31
|
+
(categories and their translations were added by migrations
|
|
32
|
+
`00000000000019` and `00000000000020`)
|
|
33
|
+
- Inventory and licensing: `inventory_items`, `package_activations`,
|
|
34
|
+
`freemius_plans`, `freemius_pricing`
|
|
35
|
+
- Checkout and fulfillment: `orders`, `order_items`, `shipping_zones`,
|
|
36
|
+
`shipping_zone_locations`, `shipping_zone_methods`, `tax_rates`,
|
|
37
|
+
`currencies`
|
|
38
|
+
|
|
39
|
+
`products` can be physical or digital. The current provider selection logic
|
|
40
|
+
resolves:
|
|
41
|
+
|
|
42
|
+
- physical -> Stripe
|
|
43
|
+
- digital -> Freemius
|
|
44
|
+
|
|
45
|
+
Mixed-provider carts are rejected by `app/api/checkout/route.ts`.
|
|
46
|
+
|
|
47
|
+
## Multi-Currency
|
|
48
|
+
|
|
49
|
+
The multi-currency implementation is real and fairly deep.
|
|
50
|
+
|
|
51
|
+
### Store currencies
|
|
52
|
+
|
|
53
|
+
`currencies` stores:
|
|
54
|
+
|
|
55
|
+
- ISO code and symbol
|
|
56
|
+
- exchange rate relative to the current store default
|
|
57
|
+
- default and active flags
|
|
58
|
+
- rounding mode, rounding increment, and optional charm ending
|
|
59
|
+
- automatic FX refresh flag
|
|
60
|
+
- automatic product price sync flag
|
|
61
|
+
- last exchange-rate source and refresh timestamp
|
|
62
|
+
|
|
63
|
+
Supported rounding modes in code are:
|
|
64
|
+
|
|
65
|
+
- `none`
|
|
66
|
+
- `nearest`
|
|
67
|
+
- `up`
|
|
68
|
+
- `down`
|
|
69
|
+
- `charm`
|
|
70
|
+
|
|
71
|
+
### Product and variant pricing
|
|
72
|
+
|
|
73
|
+
Products and variants support:
|
|
74
|
+
|
|
75
|
+
- legacy single-currency `price` and `sale_price`
|
|
76
|
+
- multi-currency `prices` and `sale_prices`
|
|
77
|
+
|
|
78
|
+
The pricing helpers resolve amounts by:
|
|
79
|
+
|
|
80
|
+
1. looking for an explicit amount in the selected currency
|
|
81
|
+
2. falling back to the base price
|
|
82
|
+
3. converting from the default currency when store-managed auto-sync pricing is
|
|
83
|
+
enabled
|
|
84
|
+
|
|
85
|
+
The CMS product editor respects that distinction. Store-managed currencies can
|
|
86
|
+
be displayed in forms, but their saved overrides are stripped before
|
|
87
|
+
persisting.
|
|
88
|
+
|
|
89
|
+
### Scheduled sales, price changes, and promotions
|
|
90
|
+
|
|
91
|
+
Products and variants carry a scheduled-pricing layer (migration
|
|
92
|
+
`00000000000025_add_sale_schedule_columns.sql`):
|
|
93
|
+
|
|
94
|
+
- `sale_start_at` / `sale_end_at` — the time window during which `sale_price` /
|
|
95
|
+
`sale_prices` apply. Both null = always-on (back-compat with static sales).
|
|
96
|
+
- `scheduled_price` / `scheduled_prices` / `scheduled_price_at` — a pending,
|
|
97
|
+
permanent regular-price change applied once `scheduled_price_at` passes
|
|
98
|
+
(bulk/Stripe-oriented; Freemius regular prices are owned by Freemius).
|
|
99
|
+
- `product_freemius_sale_coupons` — maps a product to an auto-generated,
|
|
100
|
+
time-bounded Freemius coupon so a scheduled Freemius sale is actually enforced
|
|
101
|
+
at Freemius-hosted checkout (Freemius enforces the coupon's start/end dates).
|
|
102
|
+
|
|
103
|
+
**Enforcement is read-time, not cron-driven.** The helpers in
|
|
104
|
+
`libs/ecommerce/src/lib/currency.ts` decide what applies *now*:
|
|
105
|
+
|
|
106
|
+
- `isSaleWindowActive({ saleStartAt, saleEndAt, now })`
|
|
107
|
+
- `resolveEffectivePriceForCurrency({ ..., saleStartAt, saleEndAt, scheduledPrice*, now })`
|
|
108
|
+
— wraps `resolvePriceForCurrency`, gating the sale by its window and swapping in
|
|
109
|
+
a due scheduled price. A sale outside its window resolves to `sale_price: null`.
|
|
110
|
+
|
|
111
|
+
Every place that computes a payable or displayed amount goes through the
|
|
112
|
+
window-aware helper: checkout providers (`providers/stripe.ts`,
|
|
113
|
+
`providers/freemius.ts`), cart/tax/coupon math, and storefront components
|
|
114
|
+
(`ProductCard`, `FeaturedProduct`, `ProductDetailsLayout`, UCP). The CMS edit
|
|
115
|
+
form exposes the window per-product and per-variant (`SaleScheduleFields`); the
|
|
116
|
+
bulk **Promotions** admin (`/cms/promotions`, `apps/nextblock/lib/promotions/`)
|
|
117
|
+
imports/exports sales and price changes via CSV.
|
|
118
|
+
|
|
119
|
+
> **Gotchas for future agents (these caused real revert/display bugs):**
|
|
120
|
+
>
|
|
121
|
+
> 1. **`generateVariantDrafts` (`variation-utils.ts`) must carry over every
|
|
122
|
+
> per-variant field**, including `sale_start_at`/`sale_end_at`. It re-runs on
|
|
123
|
+
> editor mount/attribute change; an omitted field resets to null and is then
|
|
124
|
+
> autosaved away ("dates revert after publish").
|
|
125
|
+
> 2. **Storefront block mappers must pass the window through** on *both* the
|
|
126
|
+
> product and each variant — `ProductGridBlock`, `FeaturedProductBlock`,
|
|
127
|
+
> `app/product/[slug]/page.tsx`. If the window is dropped, `isSaleWindowActive`
|
|
128
|
+
> sees both bounds null and treats the sale as always-on, so an inactive sale
|
|
129
|
+
> price shows (e.g. a "$25 – $32" range before the sale starts).
|
|
130
|
+
> 3. **`getVariantEffectivePriceRange` is window-aware** — pass
|
|
131
|
+
> `sale_start_at`/`sale_end_at` per variant or it ignores the schedule.
|
|
132
|
+
> 4. **Persisting on save/publish does not rely on the RPC.** Products are
|
|
133
|
+
> written via `upsert_product_with_variants`, but some databases run a stale
|
|
134
|
+
> copy of that function. `persistProductSaleSchedule` (`product-actions.ts`)
|
|
135
|
+
> writes the window columns with a direct `update` right after the RPC (same
|
|
136
|
+
> pattern as `persistProductTaxability`), matching variants by SKU.
|
|
137
|
+
> 5. **Autosave must not `reset()` the form or revalidate the edit route.** The
|
|
138
|
+
> edit-form autosave (`ProductForm.tsx`) uses a serialized-snapshot guard to
|
|
139
|
+
> avoid a render loop; `updateProductAction` writes only the draft (no
|
|
140
|
+
> `revalidatePath`). Re-rendering mid-edit resets native datetime inputs.
|
|
141
|
+
|
|
142
|
+
### FX sync and rebasing
|
|
143
|
+
|
|
144
|
+
`libs/ecommerce/src/lib/currency-sync.ts` implements two separate operations:
|
|
145
|
+
|
|
146
|
+
- `syncStoreCurrencyRates()`: pulls fresh FX rates from `https://api.frankfurter.dev`
|
|
147
|
+
unless `FX_API_BASE_URL` overrides the provider.
|
|
148
|
+
- `rebaseStoreCurrencyExchangeRates()`: when an admin changes the default
|
|
149
|
+
currency, every stored rate is rebased so the new default becomes `1`.
|
|
150
|
+
|
|
151
|
+
The app exposes both through:
|
|
152
|
+
|
|
153
|
+
- CMS currency settings actions in
|
|
154
|
+
`apps/nextblock/app/cms/settings/currencies/actions.ts`
|
|
155
|
+
- `GET /api/cron/sync-currencies`, guarded by `CRON_SECRET`
|
|
156
|
+
|
|
157
|
+
## Tax Calculation
|
|
158
|
+
|
|
159
|
+
Tax behavior is driven by the `ecommerce_inventory_settings` site setting,
|
|
160
|
+
loaded through `getEcommerceInventorySettings()`.
|
|
161
|
+
|
|
162
|
+
The current settings shape is:
|
|
163
|
+
|
|
164
|
+
- `trackQuantities`
|
|
165
|
+
- `enableTaxes`
|
|
166
|
+
- `taxCalculationMode`
|
|
167
|
+
|
|
168
|
+
Supported tax modes are:
|
|
169
|
+
|
|
170
|
+
- `manual`
|
|
171
|
+
- `automatic`
|
|
172
|
+
|
|
173
|
+
### Manual mode
|
|
174
|
+
|
|
175
|
+
Manual mode uses `tax_rates` rows keyed by country and optional state/province.
|
|
176
|
+
Multiple rows can exist for the same jurisdiction, so stacked taxes such as GST
|
|
177
|
+
plus PST are supported.
|
|
178
|
+
|
|
179
|
+
During checkout:
|
|
180
|
+
|
|
181
|
+
- only taxable products are included
|
|
182
|
+
- the destination is normalized from shipping or billing data
|
|
183
|
+
- matching `tax_rates` are loaded
|
|
184
|
+
- tax lines are calculated and stored in `orders.tax_details`
|
|
185
|
+
|
|
186
|
+
### Automatic mode
|
|
187
|
+
|
|
188
|
+
Automatic mode defers final tax calculation to Stripe Tax.
|
|
189
|
+
|
|
190
|
+
In this mode:
|
|
191
|
+
|
|
192
|
+
- checkout still records a tax intent in `orders.tax_details`
|
|
193
|
+
- the Stripe provider marks product and shipping tax codes on line items
|
|
194
|
+
- the webhook resync step replaces provisional tax data with finalized Stripe
|
|
195
|
+
checkout data
|
|
196
|
+
|
|
197
|
+
## Shipping Zones and Rate Resolution
|
|
198
|
+
|
|
199
|
+
Shipping is backed by:
|
|
200
|
+
|
|
201
|
+
- `shipping_zones`
|
|
202
|
+
- `shipping_zone_locations`
|
|
203
|
+
- `shipping_zone_methods`
|
|
204
|
+
|
|
205
|
+
Each method stores:
|
|
206
|
+
|
|
207
|
+
- base amount and currency
|
|
208
|
+
- localized names
|
|
209
|
+
- per-currency amount maps and threshold maps
|
|
210
|
+
- `currency_pricing_mode` of `auto` or `manual`
|
|
211
|
+
|
|
212
|
+
### Current resolver behavior
|
|
213
|
+
|
|
214
|
+
`libs/ecommerce/src/lib/shipping/resolver.ts` currently:
|
|
215
|
+
|
|
216
|
+
1. loads active currencies
|
|
217
|
+
2. queries zone locations by destination country
|
|
218
|
+
3. prefers a state match when one exists
|
|
219
|
+
4. otherwise prefers a country-wide match
|
|
220
|
+
5. otherwise falls back to the first zone by `priority_order`
|
|
221
|
+
6. filters methods by the cart total and minimum threshold
|
|
222
|
+
7. converts method prices into the shopper currency
|
|
223
|
+
8. returns only the cheapest valid method
|
|
224
|
+
|
|
225
|
+
Important implementation detail: `shipping_zone_locations.postal_code` exists in
|
|
226
|
+
schema, but the current resolver does not yet use postal code matching during
|
|
227
|
+
runtime resolution.
|
|
228
|
+
|
|
229
|
+
The storefront calls this through
|
|
230
|
+
`libs/ecommerce/src/lib/server-actions/shipping-actions.ts`.
|
|
231
|
+
|
|
232
|
+
## Stripe Integration
|
|
233
|
+
|
|
234
|
+
Stripe is the current payment flow for physical products.
|
|
235
|
+
|
|
236
|
+
### Checkout flow
|
|
237
|
+
|
|
238
|
+
`app/api/checkout/route.ts`:
|
|
239
|
+
|
|
240
|
+
- verifies the ecommerce package is active
|
|
241
|
+
- rejects carts without provider-aware items
|
|
242
|
+
- rejects mixed-provider carts
|
|
243
|
+
- requires a billing address
|
|
244
|
+
- resolves the provider through `getPaymentProvider()`
|
|
245
|
+
|
|
246
|
+
`StripeProvider.createCheckoutSession()` then:
|
|
247
|
+
|
|
248
|
+
- loads currencies and store settings
|
|
249
|
+
- validates products and variants against the database
|
|
250
|
+
- validates inventory before session creation when quantity tracking is enabled
|
|
251
|
+
- resolves shipping cost from the selected shipping method
|
|
252
|
+
- calculates tax in manual or automatic mode
|
|
253
|
+
- upserts a Stripe customer when an email is available
|
|
254
|
+
- inserts a pending `orders` row plus `order_items`
|
|
255
|
+
- stores currency, subtotal, shipping, tax, and exchange-rate data
|
|
256
|
+
- creates the Stripe Checkout Session and stores `stripe_session_id`
|
|
257
|
+
|
|
258
|
+
### Webhook flow
|
|
259
|
+
|
|
260
|
+
`app/api/webhooks/stripe/route.ts` passes the raw body to
|
|
261
|
+
`handleStripeWebhook()`.
|
|
262
|
+
|
|
263
|
+
On `checkout.session.completed`, the sync layer:
|
|
264
|
+
|
|
265
|
+
- reloads the session with tax breakdown details
|
|
266
|
+
- finds the existing order
|
|
267
|
+
- stores payment intent, customer details, and finalized totals
|
|
268
|
+
- normalizes tax details from Stripe
|
|
269
|
+
- updates saved customer addresses
|
|
270
|
+
- assigns invoice metadata
|
|
271
|
+
- applies inventory deduction
|
|
272
|
+
|
|
273
|
+
## Freemius Licensing and Product Sync
|
|
274
|
+
|
|
275
|
+
Freemius currently handles digital-product checkout and product synchronization.
|
|
276
|
+
|
|
277
|
+
### Checkout behavior
|
|
278
|
+
|
|
279
|
+
`FreemiusProvider.createCheckoutSession()`:
|
|
280
|
+
|
|
281
|
+
- only allows one item per checkout
|
|
282
|
+
- loads the product from Supabase
|
|
283
|
+
- requires `freemius_product_id` and `freemius_plan_id`
|
|
284
|
+
- resolves pricing in the chosen currency
|
|
285
|
+
- inserts a pending order and order item
|
|
286
|
+
- optionally syncs default addresses and profile fields for the current user
|
|
287
|
+
- builds a Freemius checkout URL, including sandbox parameters when enabled
|
|
288
|
+
|
|
289
|
+
Supported credential sources include:
|
|
290
|
+
|
|
291
|
+
- product-scoped JSON map
|
|
292
|
+
- single-product sandbox overrides
|
|
293
|
+
- single-product env vars
|
|
294
|
+
- legacy shared env vars
|
|
295
|
+
|
|
296
|
+
### Product sync
|
|
297
|
+
|
|
298
|
+
`syncFreemiusProductsToSupabase()` and `syncSingleFreemiusProduct()`:
|
|
299
|
+
|
|
300
|
+
- call the Freemius API with signed requests
|
|
301
|
+
- fetch plugins, plans, and pricing
|
|
302
|
+
- upsert digital products into `products`
|
|
303
|
+
- upsert related `freemius_plans` and `freemius_pricing`
|
|
304
|
+
|
|
305
|
+
These flows are surfaced in the CMS product actions and the sandbox reset route.
|
|
306
|
+
|
|
307
|
+
### Current webhook limitation
|
|
308
|
+
|
|
309
|
+
`app/api/webhooks/freemius/route.ts` currently verifies the webhook signature
|
|
310
|
+
and acknowledges selected event types, but it does not yet reconcile license or
|
|
311
|
+
order state back into the local database.
|
|
312
|
+
|
|
313
|
+
## Inventory Management and Fulfillment
|
|
314
|
+
|
|
315
|
+
Inventory behavior is controlled by `trackQuantities`.
|
|
316
|
+
|
|
317
|
+
When tracking is enabled:
|
|
318
|
+
|
|
319
|
+
- checkout validates requested quantity against `inventory_items`
|
|
320
|
+
- if a SKU is not yet cached there, product or variant stock fields are used as
|
|
321
|
+
fallback
|
|
322
|
+
- a paid order triggers `apply_order_inventory_deduction()`
|
|
323
|
+
|
|
324
|
+
The deduction flow is resilient:
|
|
325
|
+
|
|
326
|
+
- first it calls the database RPC `apply_order_inventory_deduction`
|
|
327
|
+
- if that fails, it falls back to a direct SQL reconciliation path using
|
|
328
|
+
`POSTGRES_URL` or `DATABASE_URL`
|
|
329
|
+
|
|
330
|
+
Order statuses currently supported in code are:
|
|
331
|
+
|
|
332
|
+
- `pending`
|
|
333
|
+
- `paid`
|
|
334
|
+
- `shipped`
|
|
335
|
+
- `cancelled`
|
|
336
|
+
- `refunded`
|
|
337
|
+
|
|
338
|
+
Manual CMS order status changes also trigger invoice assignment and inventory
|
|
339
|
+
deduction when an order is moved to `paid`.
|
|
340
|
+
|
|
341
|
+
## Invoice and Order Presentation
|
|
342
|
+
|
|
343
|
+
The order/invoice layer includes:
|
|
344
|
+
|
|
345
|
+
- stable invoice numbering through database functions
|
|
346
|
+
- `invoice_settings` in `site_settings`
|
|
347
|
+
- printable invoice presentation data via `invoice-server.ts`
|
|
348
|
+
- UI components such as `InvoiceDocument` and `InvoiceViewerShell`
|
|
349
|
+
- customer order history and invoice access through `customer-orders.ts`
|
|
350
|
+
|
|
351
|
+
## CMS Commerce Surfaces
|
|
352
|
+
|
|
353
|
+
The active ecommerce CMS surface includes:
|
|
354
|
+
|
|
355
|
+
- product list, create, edit, media, attribute, and variation management
|
|
356
|
+
- inventory management
|
|
357
|
+
- orders list and detail management
|
|
358
|
+
- shipping zones and shipping rate management
|
|
359
|
+
- payment-provider enablement
|
|
360
|
+
- tax settings and manual tax-rate management
|
|
361
|
+
- currency settings under `/cms/settings/currencies`
|
|
362
|
+
|
|
363
|
+
The CMS shell only exposes these store sections when the ecommerce package is
|
|
364
|
+
reported as active.
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# 03 CMS and Editor
|
|
2
|
+
|
|
3
|
+
## Two Related Systems
|
|
4
|
+
|
|
5
|
+
NextBlock's content authoring experience is split across two real subsystems:
|
|
6
|
+
|
|
7
|
+
- `libs/editor`: a reusable Tiptap-based rich text package
|
|
8
|
+
- `apps/nextblock/lib/blocks`: the block registry and page-builder layer used
|
|
9
|
+
by pages, posts, and some commerce surfaces
|
|
10
|
+
|
|
11
|
+
They work together, but they are not the same thing.
|
|
12
|
+
|
|
13
|
+
## Block Registry and Page Builder
|
|
14
|
+
|
|
15
|
+
The block registry lives in `apps/nextblock/lib/blocks/blockRegistry.ts`. It is
|
|
16
|
+
the current source of truth for:
|
|
17
|
+
|
|
18
|
+
- available block types
|
|
19
|
+
- Zod schemas
|
|
20
|
+
- default content
|
|
21
|
+
- editor component filenames
|
|
22
|
+
- renderer component filenames
|
|
23
|
+
- human-facing labels and block metadata
|
|
24
|
+
|
|
25
|
+
### Current registered block types
|
|
26
|
+
|
|
27
|
+
The registry currently includes:
|
|
28
|
+
|
|
29
|
+
- `text`
|
|
30
|
+
- `heading`
|
|
31
|
+
- `image`
|
|
32
|
+
- `button`
|
|
33
|
+
- `posts_grid`
|
|
34
|
+
- `video_embed`
|
|
35
|
+
- `section`
|
|
36
|
+
- `form`
|
|
37
|
+
- `testimonial`
|
|
38
|
+
- `product_grid`
|
|
39
|
+
- `featured_product`
|
|
40
|
+
- `cart`
|
|
41
|
+
- `checkout`
|
|
42
|
+
- `product_details`
|
|
43
|
+
|
|
44
|
+
The authoritative type list is `apps/nextblock/lib/blocks/blockTypes.ts`
|
|
45
|
+
(`availableBlockTypes`).
|
|
46
|
+
|
|
47
|
+
A `section` block can contain nested column block arrays, so the page builder
|
|
48
|
+
supports multi-column compositions instead of only flat block lists. Legacy
|
|
49
|
+
`hero` blocks were folded into `section` (carrying an `is_hero` flag) by
|
|
50
|
+
migration `00000000000021_migrate_hero_blocks_to_sections.sql`, so `hero` is no
|
|
51
|
+
longer a standalone registered block type.
|
|
52
|
+
|
|
53
|
+
### How the CMS uses the registry
|
|
54
|
+
|
|
55
|
+
The CMS block editor components under `app/cms/blocks` use the registry to:
|
|
56
|
+
|
|
57
|
+
- validate block types
|
|
58
|
+
- build new block payloads from default content
|
|
59
|
+
- dynamically load editor components
|
|
60
|
+
- dynamically load renderer components
|
|
61
|
+
- render block labels and picker entries
|
|
62
|
+
|
|
63
|
+
The registry also exposes helper functions such as:
|
|
64
|
+
|
|
65
|
+
- `getBlockDefinition()`
|
|
66
|
+
- `getInitialContent()`
|
|
67
|
+
- `getBlockSchema()`
|
|
68
|
+
- `validateBlockContent()`
|
|
69
|
+
- `generateDefaultContent()`
|
|
70
|
+
|
|
71
|
+
## Tiptap Editor Package
|
|
72
|
+
|
|
73
|
+
The reusable editor surface lives in `libs/editor`.
|
|
74
|
+
|
|
75
|
+
The main exports today are:
|
|
76
|
+
|
|
77
|
+
- `Editor`
|
|
78
|
+
- `NotionEditor`
|
|
79
|
+
- `EditorToolbar`
|
|
80
|
+
- `EditorBubbleMenu`
|
|
81
|
+
- `EditorFloatingMenu`
|
|
82
|
+
- `EnhancedFloatingMenu`
|
|
83
|
+
- `SlashCommandList`
|
|
84
|
+
- `DragHandle`
|
|
85
|
+
- `HtmlContent`
|
|
86
|
+
- `editorExtensions`
|
|
87
|
+
|
|
88
|
+
### Core editing capabilities
|
|
89
|
+
|
|
90
|
+
`libs/editor/src/lib/kit.ts` composes the editor from Tiptap extensions and
|
|
91
|
+
custom nodes. The shipped editing surface includes:
|
|
92
|
+
|
|
93
|
+
- StarterKit-based rich text
|
|
94
|
+
- syntax-highlighted code blocks via `CodeBlockLowlight`
|
|
95
|
+
- tables
|
|
96
|
+
- task lists
|
|
97
|
+
- link handling
|
|
98
|
+
- text styling through `TextStyleKit`
|
|
99
|
+
- highlight, subscript, superscript, and typography helpers
|
|
100
|
+
- character counting
|
|
101
|
+
- slash commands
|
|
102
|
+
- drag handles and draggable node movement
|
|
103
|
+
- image handling
|
|
104
|
+
|
|
105
|
+
### Custom HTML-preserving extensions
|
|
106
|
+
|
|
107
|
+
The editor intentionally preserves more HTML than a minimal rich text field.
|
|
108
|
+
Current custom nodes/extensions include support for:
|
|
109
|
+
|
|
110
|
+
- `div`
|
|
111
|
+
- `style`
|
|
112
|
+
- `script`
|
|
113
|
+
- `svg`
|
|
114
|
+
- `span`
|
|
115
|
+
- a catch-all attribute preservation layer
|
|
116
|
+
|
|
117
|
+
This matters because some CMS-authored content and seeded content store richer
|
|
118
|
+
HTML fragments than plain paragraph markup.
|
|
119
|
+
|
|
120
|
+
## Inline Widgets
|
|
121
|
+
|
|
122
|
+
The editor currently ships two inline widget node types:
|
|
123
|
+
|
|
124
|
+
- alert widget
|
|
125
|
+
- call-to-action widget
|
|
126
|
+
|
|
127
|
+
These appear in multiple places:
|
|
128
|
+
|
|
129
|
+
- Tiptap commands and slash-command actions
|
|
130
|
+
- editor node views in `libs/editor`
|
|
131
|
+
- runtime React renderers in `apps/nextblock/components/blocks/renderers/inline`
|
|
132
|
+
|
|
133
|
+
So the widgets are not just editor-only decorations; they have both editing and
|
|
134
|
+
front-end rendering paths.
|
|
135
|
+
|
|
136
|
+
## NotionEditor Integration Pattern
|
|
137
|
+
|
|
138
|
+
`NotionEditor` is the higher-level client component used by the app. It wraps:
|
|
139
|
+
|
|
140
|
+
- the extension kit
|
|
141
|
+
- toolbars and menus
|
|
142
|
+
- content synchronization through `onChange` and `onUpdate`
|
|
143
|
+
- media picker bridging through editor storage
|
|
144
|
+
- hydration-safe initialization with `immediatelyRender: false`
|
|
145
|
+
- a scrollable editing shell and character counts
|
|
146
|
+
|
|
147
|
+
The app currently mounts it in multiple places, including:
|
|
148
|
+
|
|
149
|
+
- text block editing
|
|
150
|
+
- product description editing
|
|
151
|
+
|
|
152
|
+
## Media Picker Integration
|
|
153
|
+
|
|
154
|
+
The editor integrates with a pluggable image picker bridge:
|
|
155
|
+
|
|
156
|
+
- `setOpenImagePicker()` stores a picker callback on the editor instance
|
|
157
|
+
- menus and extensions can open the media picker without knowing app details
|
|
158
|
+
- the CMS supplies the actual picker UI
|
|
159
|
+
|
|
160
|
+
This keeps the editor package reusable while still supporting CMS media
|
|
161
|
+
selection.
|
|
162
|
+
|
|
163
|
+
## Commerce-Aware Blocks
|
|
164
|
+
|
|
165
|
+
The block layer is not content-only. The app also ships block types that render
|
|
166
|
+
commerce primitives backed by `@nextblock-cms/ecommerce`, including:
|
|
167
|
+
|
|
168
|
+
- product grid
|
|
169
|
+
- featured product
|
|
170
|
+
- cart
|
|
171
|
+
- checkout
|
|
172
|
+
- product details
|
|
173
|
+
|
|
174
|
+
These bridge the CMS page builder to the premium commerce library without
|
|
175
|
+
copying storefront logic into the app.
|
|
176
|
+
|
|
177
|
+
## Custom Blocks (Data-Driven CRUD)
|
|
178
|
+
|
|
179
|
+
Beyond the code-defined built-ins above, editors can create their own block
|
|
180
|
+
types at runtime from the CMS, with no code deploy. These **custom block
|
|
181
|
+
definitions** are stored as rows in `custom_block_definitions` (typed fields
|
|
182
|
+
plus a recursive layout schema) and rendered on the public site by a dynamic
|
|
183
|
+
layout engine instead of a compiled React renderer.
|
|
184
|
+
|
|
185
|
+
The wiring is intentionally simple: a page/post block whose `block_type` equals
|
|
186
|
+
a custom definition's `slug` is resolved through
|
|
187
|
+
`getCachedCustomBlockDefinitionBySlug()` and rendered by
|
|
188
|
+
`CachedDynamicLayoutEngine`. Authoring, CRUD, duplicate, and JSON
|
|
189
|
+
import/export/backup all live under `app/cms/custom-blocks`.
|
|
190
|
+
|
|
191
|
+
Full details, including the field types, the layout schema, caching, and the
|
|
192
|
+
Cortex AI "build widget" path, are in
|
|
193
|
+
[10-CUSTOM-BLOCKS.md](./10-CUSTOM-BLOCKS.md).
|
|
194
|
+
|
|
195
|
+
## Relationship to the SDK
|
|
196
|
+
|
|
197
|
+
The registry is the current in-app block system. The formal external authoring
|
|
198
|
+
contract lives in `libs/sdk` and is documented in
|
|
199
|
+
[07-BLOCK-SDK-AND-EXTENSIBILITY.md](./07-BLOCK-SDK-AND-EXTENSIBILITY.md).
|
|
200
|
+
|
|
201
|
+
If you are changing how blocks work inside the CMS, start here. If you are
|
|
202
|
+
designing a reusable third-party block contract, start with the SDK doc.
|