create-nextblock 0.2.78 → 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.
Files changed (413) hide show
  1. package/bin/create-nextblock.js +740 -459
  2. package/package.json +1 -2
  3. package/scripts/sync-template.js +18 -1
  4. package/templates/nextblock-template/.browserslistrc +11 -0
  5. package/templates/nextblock-template/.swcrc +30 -30
  6. package/templates/nextblock-template/README.md +23 -114
  7. package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -28
  8. package/templates/nextblock-template/app/(auth-pages)/sign-in/page.tsx +50 -25
  9. package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +111 -56
  10. package/templates/nextblock-template/app/(auth-pages)/two-factor/actions.ts +91 -0
  11. package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +118 -0
  12. package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -0
  13. package/templates/nextblock-template/app/.well-known/ucp/route.ts +16 -0
  14. package/templates/nextblock-template/app/[slug]/PageClientContent.tsx +48 -28
  15. package/templates/nextblock-template/app/[slug]/page.tsx +63 -6
  16. package/templates/nextblock-template/app/[slug]/page.utils.ts +374 -157
  17. package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -0
  18. package/templates/nextblock-template/app/actions/consent.ts +57 -0
  19. package/templates/nextblock-template/app/actions/formActions.ts +130 -11
  20. package/templates/nextblock-template/app/actions/languageActions.ts +31 -30
  21. package/templates/nextblock-template/app/actions/package-actions.ts +183 -0
  22. package/templates/nextblock-template/app/actions/postActions.ts +146 -48
  23. package/templates/nextblock-template/app/actions/twoFactorEmail.ts +21 -0
  24. package/templates/nextblock-template/app/actions/visualEditingActions.test.ts +179 -0
  25. package/templates/nextblock-template/app/actions/visualEditingActions.ts +345 -0
  26. package/templates/nextblock-template/app/actions.ts +67 -12
  27. package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -0
  28. package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -0
  29. package/templates/nextblock-template/app/api/ai/global-agent/route.ts +965 -0
  30. package/templates/nextblock-template/app/api/checkout/freemius/sync/route.ts +29 -0
  31. package/templates/nextblock-template/app/api/checkout/route.ts +146 -0
  32. package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -0
  33. package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -0
  34. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3413 -17
  35. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +7830 -0
  36. package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +35 -0
  37. package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -0
  38. package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -0
  39. package/templates/nextblock-template/app/api/draft/disable/route.ts +25 -0
  40. package/templates/nextblock-template/app/api/draft/route.ts +93 -0
  41. package/templates/nextblock-template/app/api/draft/start/route.ts +77 -0
  42. package/templates/nextblock-template/app/api/media/library/route.ts +65 -0
  43. package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -0
  44. package/templates/nextblock-template/app/api/media/record/route.ts +160 -0
  45. package/templates/nextblock-template/app/api/search/route.ts +43 -0
  46. package/templates/nextblock-template/app/api/visual-editing/block-draft/route.ts +47 -0
  47. package/templates/nextblock-template/app/api/visual-editing/product-draft/route.ts +47 -0
  48. package/templates/nextblock-template/app/api/webhooks/freemius/route.ts +34 -0
  49. package/templates/nextblock-template/app/api/webhooks/stripe/route.ts +27 -0
  50. package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +392 -128
  51. package/templates/nextblock-template/app/article/[slug]/page.tsx +179 -127
  52. package/templates/nextblock-template/app/article/[slug]/page.utils.ts +262 -77
  53. package/templates/nextblock-template/app/auth/callback/route.ts +31 -58
  54. package/templates/nextblock-template/app/cart/page.tsx +7 -0
  55. package/templates/nextblock-template/app/checkout/UcpCartHydrator.tsx +20 -0
  56. package/templates/nextblock-template/app/checkout/page.tsx +52 -0
  57. package/templates/nextblock-template/app/checkout/success/actions.ts +136 -0
  58. package/templates/nextblock-template/app/checkout/success/page.tsx +186 -0
  59. package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +163 -33
  60. package/templates/nextblock-template/app/cms/blocks/actions.ts +424 -235
  61. package/templates/nextblock-template/app/cms/blocks/components/BackgroundSelector.tsx +212 -151
  62. package/templates/nextblock-template/app/cms/blocks/components/BlockEditorArea.tsx +41 -20
  63. package/templates/nextblock-template/app/cms/blocks/components/BlockEditorModal.tsx +152 -19
  64. package/templates/nextblock-template/app/cms/blocks/components/BlockTypeCard.tsx +25 -17
  65. package/templates/nextblock-template/app/cms/blocks/components/BlockTypeSelector.tsx +200 -18
  66. package/templates/nextblock-template/app/cms/blocks/components/ColumnEditor.tsx +33 -16
  67. package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -0
  68. package/templates/nextblock-template/app/cms/blocks/components/EditableBlock.tsx +37 -18
  69. package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -67
  70. package/templates/nextblock-template/app/cms/blocks/components/SectionConfigPanel.tsx +108 -31
  71. package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -0
  72. package/templates/nextblock-template/app/cms/blocks/editors/FeaturedProductBlockEditor.tsx +31 -0
  73. package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +2 -2
  74. package/templates/nextblock-template/app/cms/blocks/editors/HeadingBlockEditor.tsx +1 -1
  75. package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +29 -29
  76. package/templates/nextblock-template/app/cms/blocks/editors/PostsGridBlockEditor.tsx +14 -18
  77. package/templates/nextblock-template/app/cms/blocks/editors/ProductGridBlockEditor.tsx +41 -0
  78. package/templates/nextblock-template/app/cms/blocks/editors/SectionBlockEditor.tsx +318 -118
  79. package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +98 -21
  80. package/templates/nextblock-template/app/cms/blocks/editors/VideoEmbedBlockEditor.tsx +1 -1
  81. package/templates/nextblock-template/app/cms/components/ContentLanguageSwitcher.tsx +27 -9
  82. package/templates/nextblock-template/app/cms/components/CopyContentFromLanguage.tsx +1 -1
  83. package/templates/nextblock-template/app/cms/components/CortexAiActiveContext.tsx +23 -0
  84. package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -0
  85. package/templates/nextblock-template/app/cms/components/CortexGlobalAgentChat.tsx +1507 -0
  86. package/templates/nextblock-template/app/cms/components/DraftStatusActions.tsx +145 -0
  87. package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +244 -0
  88. package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +38 -24
  89. package/templates/nextblock-template/app/cms/coupons/[id]/edit/page.tsx +16 -0
  90. package/templates/nextblock-template/app/cms/coupons/page.tsx +16 -0
  91. package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -0
  92. package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -0
  93. package/templates/nextblock-template/app/cms/custom-blocks/components/BlockComposer.tsx +1522 -0
  94. package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -0
  95. package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -0
  96. package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -0
  97. package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -0
  98. package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -0
  99. package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -98
  100. package/templates/nextblock-template/app/cms/dashboard/components/DashboardComponents.tsx +200 -0
  101. package/templates/nextblock-template/app/cms/dashboard/page.tsx +182 -154
  102. package/templates/nextblock-template/app/cms/import-export/ContentTransferControls.tsx +391 -0
  103. package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -0
  104. package/templates/nextblock-template/app/cms/layout.tsx +29 -10
  105. package/templates/nextblock-template/app/cms/media/UploadFolderContext.tsx +22 -22
  106. package/templates/nextblock-template/app/cms/media/actions.ts +45 -124
  107. package/templates/nextblock-template/app/cms/media/components/DeleteMediaButtonClient.tsx +1 -1
  108. package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
  109. package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -64
  110. package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +227 -158
  111. package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +101 -89
  112. package/templates/nextblock-template/app/cms/media/page.tsx +1 -1
  113. package/templates/nextblock-template/app/cms/navigation/components/NavigationItemForm.tsx +2 -2
  114. package/templates/nextblock-template/app/cms/orders/[id]/MarkPaidButton.tsx +44 -0
  115. package/templates/nextblock-template/app/cms/orders/[id]/page.tsx +16 -0
  116. package/templates/nextblock-template/app/cms/orders/actions.ts +201 -0
  117. package/templates/nextblock-template/app/cms/orders/page.tsx +20 -0
  118. package/templates/nextblock-template/app/cms/orders/types.ts +20 -0
  119. package/templates/nextblock-template/app/cms/pages/[id]/edit/EditPageClient.tsx +156 -121
  120. package/templates/nextblock-template/app/cms/pages/[id]/edit/page.tsx +79 -26
  121. package/templates/nextblock-template/app/cms/pages/actions.ts +54 -38
  122. package/templates/nextblock-template/app/cms/pages/components/DeletePageButtonClient.tsx +1 -1
  123. package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +267 -116
  124. package/templates/nextblock-template/app/cms/pages/page.tsx +25 -18
  125. package/templates/nextblock-template/app/cms/payments/page.tsx +16 -0
  126. package/templates/nextblock-template/app/cms/posts/[id]/edit/page.tsx +132 -90
  127. package/templates/nextblock-template/app/cms/posts/actions.ts +71 -72
  128. package/templates/nextblock-template/app/cms/posts/components/DeletePostButtonClient.tsx +1 -1
  129. package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +256 -245
  130. package/templates/nextblock-template/app/cms/posts/new/page.tsx +1 -1
  131. package/templates/nextblock-template/app/cms/posts/page.tsx +20 -13
  132. package/templates/nextblock-template/app/cms/products/ClientNotionEditor.tsx +16 -0
  133. package/templates/nextblock-template/app/cms/products/ProductFormClientShell.tsx +56 -0
  134. package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +292 -0
  135. package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -0
  136. package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -0
  137. package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -0
  138. package/templates/nextblock-template/app/cms/products/new/page.tsx +143 -0
  139. package/templates/nextblock-template/app/cms/products/page.tsx +42 -0
  140. package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -0
  141. package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -0
  142. package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -0
  143. package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -0
  144. package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -0
  145. package/templates/nextblock-template/app/cms/revisions/RevisionHistoryButton.tsx +2 -2
  146. package/templates/nextblock-template/app/cms/revisions/actions.ts +285 -285
  147. package/templates/nextblock-template/app/cms/revisions/service.ts +19 -16
  148. package/templates/nextblock-template/app/cms/revisions/utils.ts +8 -3
  149. package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -0
  150. package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -0
  151. package/templates/nextblock-template/app/cms/settings/bot-protection/actions.ts +93 -0
  152. package/templates/nextblock-template/app/cms/settings/bot-protection/components/BotProtectionForm.tsx +129 -0
  153. package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -0
  154. package/templates/nextblock-template/app/cms/settings/copyright/actions.ts +1 -1
  155. package/templates/nextblock-template/app/cms/settings/copyright/components/CopyrightForm.tsx +2 -2
  156. package/templates/nextblock-template/app/cms/settings/copyright/page.tsx +1 -1
  157. package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +496 -0
  158. package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +410 -0
  159. package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +248 -0
  160. package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +80 -0
  161. package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -0
  162. package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -0
  163. package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -0
  164. package/templates/nextblock-template/app/cms/settings/extra-translations/actions.ts +203 -44
  165. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -242
  166. package/templates/nextblock-template/app/cms/settings/global-css/actions.ts +65 -0
  167. package/templates/nextblock-template/app/cms/settings/global-css/components/GlobalCssForm.tsx +46 -0
  168. package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +24 -0
  169. package/templates/nextblock-template/app/cms/settings/languages/components/DeleteLanguageButton.tsx +1 -1
  170. package/templates/nextblock-template/app/cms/settings/languages/components/LanguageForm.tsx +2 -2
  171. package/templates/nextblock-template/app/cms/settings/languages/page.tsx +1 -1
  172. package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
  173. package/templates/nextblock-template/app/cms/settings/logos/actions.ts +82 -6
  174. package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -0
  175. package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -18
  176. package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +20 -16
  177. package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -0
  178. package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
  179. package/templates/nextblock-template/app/cms/settings/logos/page.tsx +120 -82
  180. package/templates/nextblock-template/app/cms/settings/logos/types.ts +8 -8
  181. package/templates/nextblock-template/app/cms/settings/packages/activation-form.tsx +84 -0
  182. package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -0
  183. package/templates/nextblock-template/app/cms/settings/packages/page.tsx +49 -0
  184. package/templates/nextblock-template/app/cms/settings/privacy/actions.ts +53 -0
  185. package/templates/nextblock-template/app/cms/settings/privacy/components/PrivacyForm.tsx +196 -0
  186. package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +26 -0
  187. package/templates/nextblock-template/app/cms/settings/security/actions.ts +251 -0
  188. package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +453 -0
  189. package/templates/nextblock-template/app/cms/settings/security/page.tsx +13 -0
  190. package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -0
  191. package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -0
  192. package/templates/nextblock-template/app/cms/users/[id]/edit/page.tsx +28 -23
  193. package/templates/nextblock-template/app/cms/users/actions.ts +105 -40
  194. package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +1 -1
  195. package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +65 -152
  196. package/templates/nextblock-template/app/cms/users/page.tsx +15 -10
  197. package/templates/nextblock-template/app/globals.css +9 -0
  198. package/templates/nextblock-template/app/layout.tsx +372 -120
  199. package/templates/nextblock-template/app/lib/seo.test.ts +52 -0
  200. package/templates/nextblock-template/app/lib/seo.ts +279 -0
  201. package/templates/nextblock-template/app/lib/site-settings.ts +87 -0
  202. package/templates/nextblock-template/app/lib/sitemap-utils.ts +224 -39
  203. package/templates/nextblock-template/app/lib/ucp/protocol.ts +190 -0
  204. package/templates/nextblock-template/app/lib/ucp/server.test.ts +56 -0
  205. package/templates/nextblock-template/app/lib/ucp/server.ts +1914 -0
  206. package/templates/nextblock-template/app/page.tsx +165 -73
  207. package/templates/nextblock-template/app/product/[slug]/page.tsx +433 -0
  208. package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +73 -0
  209. package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -0
  210. package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -0
  211. package/templates/nextblock-template/app/profile/account-data.ts +37 -0
  212. package/templates/nextblock-template/app/profile/account-links.ts +22 -0
  213. package/templates/nextblock-template/app/profile/account-types.ts +11 -0
  214. package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -0
  215. package/templates/nextblock-template/app/profile/orders/[id]/CustomerOrderDetailPageClient.tsx +79 -0
  216. package/templates/nextblock-template/app/profile/orders/[id]/page.tsx +32 -0
  217. package/templates/nextblock-template/app/profile/orders/page.tsx +19 -0
  218. package/templates/nextblock-template/app/profile/page.tsx +51 -0
  219. package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -0
  220. package/templates/nextblock-template/app/profile/password/actions.ts +59 -0
  221. package/templates/nextblock-template/app/profile/password/page.tsx +27 -0
  222. package/templates/nextblock-template/app/providers.tsx +55 -17
  223. package/templates/nextblock-template/app/robots.txt/route.ts +11 -1
  224. package/templates/nextblock-template/app/sitemap.ts +128 -0
  225. package/templates/nextblock-template/app/ucp/v1/carts/[id]/cancel/route.ts +38 -0
  226. package/templates/nextblock-template/app/ucp/v1/carts/[id]/route.ts +68 -0
  227. package/templates/nextblock-template/app/ucp/v1/carts/route.ts +35 -0
  228. package/templates/nextblock-template/app/ucp/v1/catalog/lookup/route.ts +35 -0
  229. package/templates/nextblock-template/app/ucp/v1/catalog/product/route.ts +35 -0
  230. package/templates/nextblock-template/app/ucp/v1/catalog/search/route.ts +34 -0
  231. package/templates/nextblock-template/components/AppShell.tsx +154 -0
  232. package/templates/nextblock-template/components/BlockRenderer.tsx +210 -64
  233. package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -0
  234. package/templates/nextblock-template/components/CartTranslator.tsx +210 -0
  235. package/templates/nextblock-template/components/CurrentContentSetter.tsx +25 -0
  236. package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -0
  237. package/templates/nextblock-template/components/DeferredCartTranslator.tsx +51 -0
  238. package/templates/nextblock-template/components/DeferredGlobalSearch.tsx +68 -0
  239. package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -0
  240. package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -0
  241. package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -0
  242. package/templates/nextblock-template/components/GitHubLoginButton.tsx +36 -0
  243. package/templates/nextblock-template/components/GlobalSearch.tsx +557 -0
  244. package/templates/nextblock-template/components/Header.tsx +49 -41
  245. package/templates/nextblock-template/components/LanguageSwitcher.tsx +55 -32
  246. package/templates/nextblock-template/components/ResponsiveNav.tsx +138 -43
  247. package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -8
  248. package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -55
  249. package/templates/nextblock-template/components/blocks/PostsGridClient.tsx +42 -37
  250. package/templates/nextblock-template/components/blocks/TestimonialBlock.tsx +6 -2
  251. package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -0
  252. package/templates/nextblock-template/components/blocks/publicRendererLoaders.ts +25 -0
  253. package/templates/nextblock-template/components/blocks/renderers/ButtonBlockRenderer.tsx +92 -84
  254. package/templates/nextblock-template/components/blocks/renderers/CartBlockRenderer.tsx +17 -0
  255. package/templates/nextblock-template/components/blocks/renderers/CheckoutBlockRenderer.tsx +19 -0
  256. package/templates/nextblock-template/components/blocks/renderers/ClientTextBlockRenderer.tsx +262 -8
  257. package/templates/nextblock-template/components/blocks/renderers/FeaturedProductBlockRenderer.tsx +22 -0
  258. package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +320 -37
  259. package/templates/nextblock-template/components/blocks/renderers/HeadingBlockRenderer.tsx +11 -8
  260. package/templates/nextblock-template/components/blocks/renderers/ImageBlockRenderer.tsx +12 -3
  261. package/templates/nextblock-template/components/blocks/renderers/PostsGridBlockRenderer.tsx +18 -13
  262. package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +90 -0
  263. package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx +31 -0
  264. package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +424 -55
  265. package/templates/nextblock-template/components/blocks/renderers/SectionSlider.tsx +137 -0
  266. package/templates/nextblock-template/components/blocks/renderers/TestimonialBlockRenderer.tsx +57 -0
  267. package/templates/nextblock-template/components/blocks/renderers/TextBlockRenderer.tsx +37 -22
  268. package/templates/nextblock-template/components/blocks/renderers/VideoEmbedBlockRenderer.tsx +23 -15
  269. package/templates/nextblock-template/components/blocks/renderers/inline/AlertWidgetRenderer.tsx +1 -3
  270. package/templates/nextblock-template/components/blocks/renderers/inline/CtaWidgetRenderer.tsx +1 -3
  271. package/templates/nextblock-template/components/blocks/types.ts +7 -6
  272. package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
  273. package/templates/nextblock-template/components/form-message.tsx +32 -26
  274. package/templates/nextblock-template/components/header-auth.tsx +69 -17
  275. package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +127 -0
  276. package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +59 -0
  277. package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -0
  278. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -0
  279. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +464 -0
  280. package/templates/nextblock-template/components/theme-switcher.tsx +8 -8
  281. package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -0
  282. package/templates/nextblock-template/components/visual-editing/NextblockVisualEditing.tsx +1172 -0
  283. package/templates/nextblock-template/context/AuthContext.tsx +23 -90
  284. package/templates/nextblock-template/context/CurrentContentContext.tsx +10 -4
  285. package/templates/nextblock-template/context/LanguageContext.tsx +16 -16
  286. package/templates/nextblock-template/context/language-rest-client.ts +31 -0
  287. package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -0
  288. package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -0
  289. package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +202 -0
  290. package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +252 -0
  291. package/templates/nextblock-template/docs/05-DEVELOPER-GUIDE.md +238 -0
  292. package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +125 -0
  293. package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -0
  294. package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +1319 -0
  295. package/templates/nextblock-template/docs/09-LIVE-DRAFT-MODE.md +104 -0
  296. package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -0
  297. package/templates/nextblock-template/docs/README.md +34 -0
  298. package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12507 -0
  299. package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -14
  300. package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -0
  301. package/templates/nextblock-template/index.d.ts +2 -0
  302. package/templates/nextblock-template/lib/ai-block-generation.ts +339 -0
  303. package/templates/nextblock-template/lib/ai-client.ts +247 -0
  304. package/templates/nextblock-template/lib/ai-config.ts +81 -0
  305. package/templates/nextblock-template/lib/ai-cortex-widget-builder.ts +125 -0
  306. package/templates/nextblock-template/lib/ai-global-agent-custom-block-tools.ts +363 -0
  307. package/templates/nextblock-template/lib/ai-global-agent-db-tools.test.ts +405 -0
  308. package/templates/nextblock-template/lib/ai-global-agent-db-tools.ts +1228 -0
  309. package/templates/nextblock-template/lib/ai-global-agent-ecommerce.ts +5 -0
  310. package/templates/nextblock-template/lib/ai-global-agent-tools-stats.test.ts +223 -0
  311. package/templates/nextblock-template/lib/ai-global-agent-tools.test.ts +2183 -0
  312. package/templates/nextblock-template/lib/ai-global-agent-tools.ts +4807 -0
  313. package/templates/nextblock-template/lib/ai-key-crypto.test.ts +70 -0
  314. package/templates/nextblock-template/lib/ai-key-crypto.ts +132 -0
  315. package/templates/nextblock-template/lib/ai-model-catalog.test.ts +49 -0
  316. package/templates/nextblock-template/lib/ai-model-catalog.ts +41 -0
  317. package/templates/nextblock-template/lib/ai-model-registry.test.ts +231 -0
  318. package/templates/nextblock-template/lib/ai-model-registry.ts +522 -0
  319. package/templates/nextblock-template/lib/auth/cookies.ts +47 -0
  320. package/templates/nextblock-template/lib/auth/crypto.ts +42 -0
  321. package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -0
  322. package/templates/nextblock-template/lib/auth/twoFactor.ts +167 -0
  323. package/templates/nextblock-template/lib/auth-redirects.ts +46 -0
  324. package/templates/nextblock-template/lib/blocks/FeaturedProductBlock.tsx +94 -0
  325. package/templates/nextblock-template/lib/blocks/ProductGridBlock.tsx +137 -0
  326. package/templates/nextblock-template/lib/blocks/README.md +13 -670
  327. package/templates/nextblock-template/lib/blocks/blockRegistry.ts +138 -56
  328. package/templates/nextblock-template/lib/blocks/blockTypes.ts +18 -0
  329. package/templates/nextblock-template/lib/blocks/ecommerce-block-schemas.ts +31 -0
  330. package/templates/nextblock-template/lib/cms-transfer/csv.test.ts +77 -0
  331. package/templates/nextblock-template/lib/cms-transfer/csv.ts +399 -0
  332. package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -0
  333. package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -0
  334. package/templates/nextblock-template/lib/cortex-widget-registry.test.ts +199 -0
  335. package/templates/nextblock-template/lib/cortex-widget-registry.ts +88 -0
  336. package/templates/nextblock-template/lib/cortex-widget-schema.test.tsx +237 -0
  337. package/templates/nextblock-template/lib/cortex-widget-schema.ts +393 -0
  338. package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -0
  339. package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -0
  340. package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -0
  341. package/templates/nextblock-template/lib/custom-block-r2-upload.ts +68 -0
  342. package/templates/nextblock-template/lib/custom-block-relation-registry.ts +256 -0
  343. package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -0
  344. package/templates/nextblock-template/lib/custom-block-relations.ts +279 -0
  345. package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -0
  346. package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -0
  347. package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -0
  348. package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -0
  349. package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -0
  350. package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -0
  351. package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -0
  352. package/templates/nextblock-template/lib/full-backup/server.ts +743 -0
  353. package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +45 -0
  354. package/templates/nextblock-template/lib/posts/readTime.ts +60 -0
  355. package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -0
  356. package/templates/nextblock-template/lib/privacy/settings.ts +103 -0
  357. package/templates/nextblock-template/lib/privacy/types.ts +67 -0
  358. package/templates/nextblock-template/lib/promotions/server.test.ts +74 -0
  359. package/templates/nextblock-template/lib/promotions/server.ts +741 -0
  360. package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -0
  361. package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -0
  362. package/templates/nextblock-template/lib/search/server.ts +585 -0
  363. package/templates/nextblock-template/lib/search/types.ts +27 -0
  364. package/templates/nextblock-template/lib/visual-editing/draft-content.test.ts +105 -0
  365. package/templates/nextblock-template/lib/visual-editing/draft-content.ts +380 -0
  366. package/templates/nextblock-template/lib/visual-editing/draft-route.test.ts +42 -0
  367. package/templates/nextblock-template/lib/visual-editing/draft-route.ts +82 -0
  368. package/templates/nextblock-template/lib/visual-editing/edit-info.test.ts +143 -0
  369. package/templates/nextblock-template/lib/visual-editing/edit-info.ts +94 -0
  370. package/templates/nextblock-template/lib/visual-editing/mutations.ts +190 -0
  371. package/templates/nextblock-template/lib/visual-editing/product-drafts.test.ts +81 -0
  372. package/templates/nextblock-template/lib/visual-editing/product-drafts.ts +511 -0
  373. package/templates/nextblock-template/lib/visual-editing/types.ts +122 -0
  374. package/templates/nextblock-template/lib/zod-config.ts +5 -0
  375. package/templates/nextblock-template/next.config.js +190 -66
  376. package/templates/nextblock-template/package.json +34 -30
  377. package/templates/nextblock-template/proxy.ts +435 -253
  378. package/templates/nextblock-template/public/images/NBcover.webp +0 -0
  379. package/templates/nextblock-template/public/images/cap.webp +0 -0
  380. package/templates/nextblock-template/public/images/commerce-plan.webp +0 -0
  381. package/templates/nextblock-template/public/images/commerce-square.webp +0 -0
  382. package/templates/nextblock-template/public/images/commerce-wide.webp +0 -0
  383. package/templates/nextblock-template/public/images/cortex-ai-square.webp +0 -0
  384. package/templates/nextblock-template/public/images/cortex-ai.webp +0 -0
  385. package/templates/nextblock-template/public/images/extensibility.webp +0 -0
  386. package/templates/nextblock-template/public/images/goals.webp +0 -0
  387. package/templates/nextblock-template/public/images/included.webp +0 -0
  388. package/templates/nextblock-template/public/images/nx-graph.webp +0 -0
  389. package/templates/nextblock-template/public/images/pants.webp +0 -0
  390. package/templates/nextblock-template/public/images/t-shirt.webp +0 -0
  391. package/templates/nextblock-template/scripts/validate-editor-block-schema.ts +112 -0
  392. package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +100 -0
  393. package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -0
  394. package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -0
  395. package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -0
  396. package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -0
  397. package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -0
  398. package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -0
  399. package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -0
  400. package/templates/nextblock-template/tailwind.config.js +1 -0
  401. package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -0
  402. package/templates/nextblock-template/tools/deploy-supabase.js +69 -71
  403. package/templates/nextblock-template/tsconfig.json +52 -66
  404. package/templates/nextblock-template/tsconfig.tsbuildinfo +1 -1
  405. package/templates/nextblock-template/types/jsdom.d.ts +6 -0
  406. package/templates/nextblock-template/app/force-styles.tsx +0 -31
  407. package/templates/nextblock-template/app/sitemap.xml/route.ts +0 -63
  408. package/templates/nextblock-template/components/blocks/renderers/HeroBlockRenderer.tsx +0 -273
  409. package/templates/nextblock-template/docs/How to Create a Custom Block.md +0 -149
  410. package/templates/nextblock-template/docs/cms-application-overview.md +0 -56
  411. package/templates/nextblock-template/docs/cms-architecture-overview.md +0 -73
  412. package/templates/nextblock-template/docs/files-structure.md +0 -426
  413. package/templates/nextblock-template/docs/tiptap-bundle-optimization-summary.md +0 -174
@@ -1,5 +1,8 @@
1
- import { z } from 'zod';
2
- import { TestimonialBlockConfig, TestimonialBlockContent } from '../../components/blocks/TestimonialBlock';
1
+ import { z } from '../zod-config';
2
+ import { TestimonialBlockConfig, TestimonialBlockContent } from '../../components/blocks/TestimonialBlock';
3
+ import { ProductGridBlockSchema, ProductGridBlockContent, FeaturedProductBlockSchema, FeaturedProductBlockContent, CartBlockSchema, CartBlockContent, CheckoutBlockSchema, CheckoutBlockContent, ProductDetailsBlockSchema, ProductDetailsBlockContent } from './ecommerce-block-schemas';
4
+ import { availableBlockTypes, type BlockType } from './blockTypes';
5
+ export { availableBlockTypes, type BlockType } from './blockTypes';
3
6
 
4
7
  /**
5
8
  * Block Registry System
@@ -9,13 +12,7 @@ import { TestimonialBlockConfig, TestimonialBlockContent } from '../../component
9
12
  * their initial content, editor components, renderer components, and Zod schemas.
10
13
  */
11
14
 
12
- /**
13
- * Available block types - defined here as the source of truth
14
- */
15
- export const availableBlockTypes = ["text", "heading", "image", "button", "posts_grid", "video_embed", "section", "hero", "form", "testimonial"] as const;
16
- export type BlockType = (typeof availableBlockTypes)[number];
17
-
18
- // --- Zod Schemas & Inferred Types ---
15
+ // --- Zod Schemas & Inferred Types ---
19
16
 
20
17
  export const TextBlockSchema = z.object({
21
18
  html_content: z.string().describe('Raw HTML content for the text block'),
@@ -98,10 +95,15 @@ const BackgroundSchema = z.object({
98
95
 
99
96
  const BlockInColumnSchema = z.object({
100
97
  block_type: z.enum(availableBlockTypes),
101
- content: z.record(z.any()),
98
+ content: z.record(z.string(), z.any()),
102
99
  temp_id: z.string().optional(),
103
100
  });
104
101
 
102
+ const SlideSchema = z.object({
103
+ background: BackgroundSchema,
104
+ column_blocks: z.array(z.array(BlockInColumnSchema)),
105
+ });
106
+
105
107
  export const SectionBlockSchema = z.object({
106
108
  container_type: z.enum(['full-width', 'container', 'container-sm', 'container-lg', 'container-xl']),
107
109
  background: BackgroundSchema,
@@ -117,11 +119,15 @@ export const SectionBlockSchema = z.object({
117
119
  }),
118
120
  vertical_alignment: z.enum(['start', 'center', 'end', 'stretch']).optional(),
119
121
  column_blocks: z.array(z.array(BlockInColumnSchema)),
122
+ is_hero: z.boolean().optional(),
123
+ slider: z.boolean().optional(),
124
+ autoplay: z.boolean().optional(),
125
+ timeframe: z.number().optional(),
126
+ slides: z.array(SlideSchema).optional(),
120
127
  });
121
128
  export type SectionBlockContent = z.infer<typeof SectionBlockSchema>;
122
129
 
123
- export const HeroBlockSchema = SectionBlockSchema;
124
- export type HeroBlockContent = z.infer<typeof HeroBlockSchema>;
130
+
125
131
 
126
132
  // Form helpers
127
133
  export const FormFieldOptionSchema = z.object({
@@ -145,6 +151,8 @@ export const FormBlockSchema = z.object({
145
151
  submit_button_text: z.string(),
146
152
  success_message: z.string(),
147
153
  fields: z.array(FormFieldSchema),
154
+ botProtectionProvider: z.enum(['none', 'turnstile', 'recaptcha']).optional().default('none'),
155
+ botProtectionSiteKey: z.string().optional(),
148
156
  });
149
157
  export type FormBlockContent = z.infer<typeof FormBlockSchema>;
150
158
 
@@ -380,7 +388,12 @@ export const blockRegistry: Record<BlockType, BlockDefinition> = {
380
388
  [{ block_type: "text", content: { html_content: "<p>Column 1</p>" } }],
381
389
  [{ block_type: "text", content: { html_content: "<p>Column 2</p>" } }],
382
390
  [{ block_type: "text", content: { html_content: "<p>Column 3</p>" } }]
383
- ]
391
+ ],
392
+ is_hero: false,
393
+ slider: false,
394
+ autoplay: false,
395
+ timeframe: 5,
396
+ slides: []
384
397
  } as SectionBlockContent,
385
398
  editorComponentFilename: "SectionBlockEditor.tsx",
386
399
  rendererComponentFilename: "SectionBlockRenderer.tsx",
@@ -407,34 +420,6 @@ export const blockRegistry: Record<BlockType, BlockDefinition> = {
407
420
  },
408
421
  },
409
422
 
410
- hero: {
411
- type: "hero",
412
- label: "Hero Section",
413
- icon: "LayoutTemplate",
414
- initialContent: {
415
- container_type: 'container',
416
- background: { type: "none" },
417
- responsive_columns: { mobile: 1, tablet: 1, desktop: 2 },
418
- column_gap: 'lg',
419
- padding: { top: 'xl', bottom: 'xl' },
420
- column_blocks: [
421
- [
422
- { block_type: "heading", content: { level: 1, text_content: "Hero Title" }, temp_id: `block-${Date.now()}-1` },
423
- { block_type: "text", content: { html_content: "<p>Hero description goes here. Explain the value proposition.</p>" }, temp_id: `block-${Date.now()}-2` },
424
- { block_type: "button", content: { text: "Call to Action", url: "#" }, temp_id: `block-${Date.now()}-3` },
425
- ],
426
- [],
427
- ],
428
- } as HeroBlockContent,
429
- editorComponentFilename: "SectionBlockEditor.tsx", // Reusing section editor
430
- rendererComponentFilename: "HeroBlockRenderer.tsx", // Specific renderer for hero
431
- schema: HeroBlockSchema,
432
- documentation: {
433
- description: 'A specialized hero section for the top of a page, with prioritized images and pre-populated content.',
434
- useCases: ['Main page hero/banner', 'Introductory section with a strong call to action'],
435
- notes: ['This block reuses the Section editor but has a different renderer for optimized image loading.'],
436
- },
437
- },
438
423
 
439
424
  form: {
440
425
  type: "form",
@@ -445,6 +430,8 @@ export const blockRegistry: Record<BlockType, BlockDefinition> = {
445
430
  submit_button_text: "Submit",
446
431
  success_message: "Thank you for your submission!",
447
432
  fields: [],
433
+ botProtectionProvider: "none",
434
+ botProtectionSiteKey: "",
448
435
  } as FormBlockContent,
449
436
  editorComponentFilename: "FormBlockEditor.tsx",
450
437
  rendererComponentFilename: "FormBlockRenderer.tsx",
@@ -473,6 +460,76 @@ export const blockRegistry: Record<BlockType, BlockDefinition> = {
473
460
  useCases: ['Social proof', 'Customer reviews'],
474
461
  }
475
462
  } as BlockDefinition<TestimonialBlockContent>,
463
+
464
+ "product_grid": {
465
+ type: "product_grid",
466
+ label: "Product Grid",
467
+ icon: "ShoppingBag", // Lucide icon
468
+ initialContent: { type: 'latest', limit: 6 } as ProductGridBlockContent,
469
+ editorComponentFilename: "ProductGridBlockEditor.tsx", // Assuming standard naming
470
+ rendererComponentFilename: "ProductGridBlockRenderer.tsx", // Assuming mapping to ProductGridBlock.tsx handled by renderer map not shown here, or we need to ensure the renderer map uses the file we created. The prompt implies creating the file in `lib/blocks` serves as the component. I will assume the system maps it.
471
+ schema: ProductGridBlockSchema,
472
+ documentation: {
473
+ description: 'Displays a grid of products.',
474
+ useCases: ['Homepage featured products', 'Category pages']
475
+ }
476
+ },
477
+
478
+ "featured_product": {
479
+ type: "featured_product",
480
+ label: "Featured Product",
481
+ icon: "Star",
482
+ initialContent: { productId: '', showBackground: false } as FeaturedProductBlockContent,
483
+ editorComponentFilename: "FeaturedProductBlockEditor.tsx",
484
+ rendererComponentFilename: "FeaturedProductBlockRenderer.tsx",
485
+ schema: FeaturedProductBlockSchema,
486
+ documentation: {
487
+ description: 'Highlights a specific product with a detailed view.',
488
+ useCases: ['Product spotlight', 'Special offers']
489
+ }
490
+ },
491
+
492
+ "cart": {
493
+ type: "cart",
494
+ label: "Cart",
495
+ icon: "ShoppingCart",
496
+ initialContent: {} as CartBlockContent,
497
+ editorComponentFilename: "CartBlockEditor.tsx",
498
+ rendererComponentFilename: "CartBlockRenderer.tsx",
499
+ schema: CartBlockSchema,
500
+ documentation: {
501
+ description: 'Displays the shopping cart.',
502
+ useCases: ['Cart page']
503
+ }
504
+ },
505
+
506
+ "checkout": {
507
+ type: "checkout",
508
+ label: "Checkout",
509
+ icon: "CreditCard",
510
+ initialContent: {} as CheckoutBlockContent,
511
+ editorComponentFilename: "CheckoutBlockEditor.tsx",
512
+ rendererComponentFilename: "CheckoutBlockRenderer.tsx",
513
+ schema: CheckoutBlockSchema,
514
+ documentation: {
515
+ description: 'Displays the checkout form.',
516
+ useCases: ['Checkout page']
517
+ }
518
+ },
519
+
520
+ "product_details": {
521
+ type: "product_details",
522
+ label: "Product Details",
523
+ icon: "Tag",
524
+ initialContent: {} as ProductDetailsBlockContent,
525
+ editorComponentFilename: "ProductDetailsBlockEditor.tsx",
526
+ rendererComponentFilename: "ProductDetailsBlockRenderer.tsx",
527
+ schema: ProductDetailsBlockSchema,
528
+ documentation: {
529
+ description: 'Displays product details (Title, Price, Add to Cart) using context.',
530
+ useCases: ['Product Template Page']
531
+ }
532
+ },
476
533
  };
477
534
 
478
535
 
@@ -482,8 +539,11 @@ export const blockRegistry: Record<BlockType, BlockDefinition> = {
482
539
  * @param blockType - The type of block to get the definition for
483
540
  * @returns The block definition or undefined if not found
484
541
  */
485
- export function getBlockDefinition(blockType: BlockType): BlockDefinition | undefined {
486
- return blockRegistry[blockType];
542
+ export function getBlockDefinition(blockType: string): BlockDefinition | undefined {
543
+ if (blockType in blockRegistry) {
544
+ return blockRegistry[blockType as BlockType];
545
+ }
546
+ return undefined;
487
547
  }
488
548
 
489
549
  /**
@@ -492,8 +552,11 @@ export function getBlockDefinition(blockType: BlockType): BlockDefinition | unde
492
552
  * @param blockType - The type of block to get initial content for
493
553
  * @returns The initial content object or undefined if block type not found
494
554
  */
495
- export function getInitialContent(blockType: BlockType): object | undefined {
496
- return blockRegistry[blockType]?.initialContent;
555
+ export function getInitialContent(blockType: string): object | undefined {
556
+ if (blockType in blockRegistry) {
557
+ return blockRegistry[blockType as BlockType]?.initialContent;
558
+ }
559
+ return {};
497
560
  }
498
561
 
499
562
  /**
@@ -502,8 +565,14 @@ export function getInitialContent(blockType: BlockType): object | undefined {
502
565
  * @param blockType - The type of block to get the label for
503
566
  * @returns The user-friendly label or undefined if block type not found
504
567
  */
505
- export function getBlockLabel(blockType: BlockType): string | undefined {
506
- return blockRegistry[blockType]?.label;
568
+ export function getBlockLabel(blockType: string): string | undefined {
569
+ if (blockType in blockRegistry) {
570
+ return blockRegistry[blockType as BlockType]?.label;
571
+ }
572
+ return blockType
573
+ .split(/[-_]+/)
574
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
575
+ .join(" ");
507
576
  }
508
577
 
509
578
  /**
@@ -512,8 +581,8 @@ export function getBlockLabel(blockType: BlockType): string | undefined {
512
581
  * @param blockType - The block type to validate
513
582
  * @returns True if the block type exists in the registry
514
583
  */
515
- export function isValidBlockType(blockType: string): blockType is BlockType {
516
- return blockType in blockRegistry;
584
+ export function isValidBlockType(blockType: string): boolean {
585
+ return blockType in blockRegistry || /^[a-z0-9_-]+$/.test(blockType);
517
586
  }
518
587
 
519
588
  /**
@@ -522,8 +591,11 @@ export function isValidBlockType(blockType: string): blockType is BlockType {
522
591
  * @param blockType - The type of block to get the schema for
523
592
  * @returns The Zod schema object or undefined if not found
524
593
  */
525
- export function getBlockSchema(blockType: BlockType): z.ZodType<any> | undefined {
526
- return blockRegistry[blockType]?.schema;
594
+ export function getBlockSchema(blockType: string): z.ZodType<any> | undefined {
595
+ if (blockType in blockRegistry) {
596
+ return blockRegistry[blockType as BlockType]?.schema;
597
+ }
598
+ return z.record(z.string(), z.any());
527
599
  }
528
600
 
529
601
  /**
@@ -532,8 +604,13 @@ export function getBlockSchema(blockType: BlockType): z.ZodType<any> | undefined
532
604
  * @param blockType - The type of block to get documentation for
533
605
  * @returns The documentation object or undefined if not found
534
606
  */
535
- export function getBlockDocumentation(blockType: BlockType): BlockDefinition['documentation'] | undefined {
536
- return blockRegistry[blockType]?.documentation;
607
+ export function getBlockDocumentation(blockType: string): BlockDefinition['documentation'] | undefined {
608
+ if (blockType in blockRegistry) {
609
+ return blockRegistry[blockType as BlockType]?.documentation;
610
+ }
611
+ return {
612
+ description: "Custom user-defined block layout component",
613
+ };
537
614
  }
538
615
 
539
616
  /**
@@ -549,10 +626,15 @@ export type AllBlockContent =
549
626
  | ({ type: "button" } & ButtonBlockContent)
550
627
  | ({ type: "posts_grid" } & PostsGridBlockContent)
551
628
  | ({ type: "section" } & SectionBlockContent)
552
- | ({ type: "hero" } & HeroBlockContent)
629
+
553
630
  | ({ type: "video_embed" } & VideoEmbedBlockContent)
554
631
  | ({ type: "form" } & FormBlockContent)
555
- | ({ type: "testimonial" } & TestimonialBlockContent);
632
+ | ({ type: "testimonial" } & TestimonialBlockContent)
633
+ | ({ type: "product_grid" } & ProductGridBlockContent)
634
+ | ({ type: "featured_product" } & FeaturedProductBlockContent)
635
+ | ({ type: "cart" } & CartBlockContent)
636
+ | ({ type: "checkout" } & CheckoutBlockContent)
637
+ | ({ type: "product_details" } & ProductDetailsBlockContent);
556
638
 
557
639
  /**
558
640
  * Validate block content against its schema
@@ -581,7 +663,7 @@ export function validateBlockContent(
581
663
  return { isValid: true, errors: [], warnings: [] };
582
664
  } else {
583
665
  // Format Zod errors
584
- const errors = result.error.errors.map(e => {
666
+ const errors = result.error.issues.map(e => {
585
667
  const path = e.path.join('.');
586
668
  return path ? `${path}: ${e.message}` : e.message;
587
669
  });
@@ -0,0 +1,18 @@
1
+ export const availableBlockTypes = [
2
+ "text",
3
+ "heading",
4
+ "image",
5
+ "button",
6
+ "posts_grid",
7
+ "video_embed",
8
+ "section",
9
+ "form",
10
+ "testimonial",
11
+ "product_grid",
12
+ "featured_product",
13
+ "cart",
14
+ "checkout",
15
+ "product_details",
16
+ ] as const;
17
+
18
+ export type BlockType = (typeof availableBlockTypes)[number];
@@ -0,0 +1,31 @@
1
+ import { z } from '../zod-config';
2
+
3
+ // Product Grid Block Schema
4
+ export const ProductGridBlockSchema = z.object({
5
+ type: z.enum(['latest', 'category']).default('latest'),
6
+ categoryId: z.string().optional(),
7
+ limit: z.number().min(1).max(20).default(6),
8
+ title: z.string().optional(),
9
+ });
10
+ export type ProductGridBlockContent = z.infer<typeof ProductGridBlockSchema>;
11
+
12
+ // Featured Product Block Schema
13
+ export const FeaturedProductBlockSchema = z.object({
14
+ productId: z.string().min(1, 'Product is required'),
15
+ showBackground: z.boolean().default(false),
16
+ imagePosition: z.enum(['left', 'right']).default('left'),
17
+ });
18
+ export type FeaturedProductBlockContent = z.infer<typeof FeaturedProductBlockSchema>;
19
+
20
+ // Cart Block Schema
21
+ export const CartBlockSchema = z.object({});
22
+ export type CartBlockContent = z.infer<typeof CartBlockSchema>;
23
+
24
+ // Checkout Block Schema
25
+ export const CheckoutBlockSchema = z.object({});
26
+ export type CheckoutBlockContent = z.infer<typeof CheckoutBlockSchema>;
27
+
28
+ // Product Details Block Schema (Context Aware)
29
+ export const ProductDetailsBlockSchema = z.object({});
30
+ export type ProductDetailsBlockContent = z.infer<typeof ProductDetailsBlockSchema>;
31
+
@@ -0,0 +1,77 @@
1
+ import { describe, expect, it } from "vitest";
2
+
3
+ import {
4
+ getCsvHeaders,
5
+ getTemplateCsv,
6
+ majorToMinor,
7
+ makeUniqueSku,
8
+ makeUniqueSlug,
9
+ minorToMajor,
10
+ normalizeBlocksFromFields,
11
+ parseCsv,
12
+ stringifyCsv,
13
+ } from "./csv";
14
+
15
+ describe("cms transfer csv helpers", () => {
16
+ it("builds templates with the expected content columns", () => {
17
+ expect(getCsvHeaders("pages")).toContain("blocks_json");
18
+ expect(getCsvHeaders("products")).toContain("description_html");
19
+ expect(getCsvHeaders("products")).toContain("description_blocks_json");
20
+ expect(getTemplateCsv("products")).toContain("EXAMPLE-SKU");
21
+ });
22
+
23
+ it("round-trips JSON columns through CSV escaping", () => {
24
+ const csv = stringifyCsv(
25
+ [
26
+ {
27
+ language_code: "en",
28
+ title: "Landing",
29
+ blocks_json: JSON.stringify([
30
+ { block_type: "text", content: { html_content: "<p>Hello, world</p>" }, order: 0 },
31
+ ]),
32
+ },
33
+ ],
34
+ ["language_code", "title", "blocks_json"]
35
+ );
36
+
37
+ const parsed = parseCsv(csv);
38
+
39
+ expect(parsed.errors).toEqual([]);
40
+ expect(parsed.rows[0].blocks_json).toContain("html_content");
41
+ expect(JSON.parse(parsed.rows[0].blocks_json)).toHaveLength(1);
42
+ });
43
+
44
+ it("converts plain HTML into a text block fallback", () => {
45
+ const errors: Array<{ row: number; message: string }> = [];
46
+ const blocks = normalizeBlocksFromFields({
47
+ html: "<p>Imported description</p>",
48
+ languageId: 1,
49
+ rowNumber: 2,
50
+ errors,
51
+ });
52
+
53
+ expect(errors).toEqual([]);
54
+ expect(blocks).toEqual([
55
+ {
56
+ language_id: 1,
57
+ block_type: "text",
58
+ content: { html_content: "<p>Imported description</p>" },
59
+ order: 0,
60
+ },
61
+ ]);
62
+ });
63
+
64
+ it("generates unique slugs and SKUs for create-new imports", () => {
65
+ expect(makeUniqueSlug("Example Page", new Set(["example-page"]))).toBe(
66
+ "example-page-copy"
67
+ );
68
+ expect(makeUniqueSku("sku-1", new Set(["SKU-1", "SKU-1-COPY"]))).toBe(
69
+ "SKU-1-COPY-2"
70
+ );
71
+ });
72
+
73
+ it("converts product prices between major and minor units", () => {
74
+ expect(majorToMinor(19.99)).toBe(1999);
75
+ expect(minorToMajor(1999)).toBe(19.99);
76
+ });
77
+ });