create-nextblock 0.15.10 → 0.16.2

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 (266) hide show
  1. package/docker-template/.dockerignore +1 -1
  2. package/libs/db/tsconfig.lib.json +3 -3
  3. package/libs/editor/tsconfig.lib.json +3 -3
  4. package/libs/ui/tsconfig.lib.json +3 -3
  5. package/libs/utils/tsconfig.json +3 -3
  6. package/package.json +50 -50
  7. package/project.json +19 -19
  8. package/templates/nextblock-template/.dockerignore +1 -1
  9. package/templates/nextblock-template/.swcrc +30 -30
  10. package/templates/nextblock-template/AGENTS.md +9 -9
  11. package/templates/nextblock-template/CLAUDE.md +1 -1
  12. package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -9
  13. package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -27
  14. package/templates/nextblock-template/app/.well-known/ucp/route.ts +16 -16
  15. package/templates/nextblock-template/app/ToasterProvider.tsx +26 -26
  16. package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -7
  17. package/templates/nextblock-template/app/actions/contactSellerActions.test.ts +280 -280
  18. package/templates/nextblock-template/app/actions/contactSellerActions.ts +222 -222
  19. package/templates/nextblock-template/app/actions/email-retry.test.ts +62 -62
  20. package/templates/nextblock-template/app/actions/email.ts +241 -241
  21. package/templates/nextblock-template/app/actions/formActions.ts +245 -245
  22. package/templates/nextblock-template/app/actions/interactions.ts +489 -489
  23. package/templates/nextblock-template/app/actions/threadActions.ts +166 -166
  24. package/templates/nextblock-template/app/actions/visibilityActions.ts +210 -210
  25. package/templates/nextblock-template/app/api/ai/seo/alt-text/route.ts +221 -0
  26. package/templates/nextblock-template/app/api/ai/seo/metadata/route.ts +186 -0
  27. package/templates/nextblock-template/app/api/checkout/freemius/sync/route.ts +29 -29
  28. package/templates/nextblock-template/app/api/checkout/route.ts +162 -162
  29. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +3092 -2900
  30. package/templates/nextblock-template/app/api/mcp/route.ts +415 -415
  31. package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
  32. package/templates/nextblock-template/app/api/search/route.ts +43 -43
  33. package/templates/nextblock-template/app/api/view/route.ts +114 -114
  34. package/templates/nextblock-template/app/api/visual-editing/block-draft/route.ts +47 -47
  35. package/templates/nextblock-template/app/api/visual-editing/product-draft/route.ts +47 -47
  36. package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
  37. package/templates/nextblock-template/app/cart/page.tsx +7 -7
  38. package/templates/nextblock-template/app/checkout/UcpCartHydrator.tsx +20 -20
  39. package/templates/nextblock-template/app/checkout/page.tsx +57 -57
  40. package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +558 -552
  41. package/templates/nextblock-template/app/cms/blocks/components/BlockEditorArea.tsx +27 -0
  42. package/templates/nextblock-template/app/cms/blocks/components/BlockEditorModal.tsx +241 -241
  43. package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -149
  44. package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +304 -304
  45. package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +180 -3
  46. package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +171 -6
  47. package/templates/nextblock-template/app/cms/components/ContactReminderBanner.tsx +75 -75
  48. package/templates/nextblock-template/app/cms/components/CortexAiActiveContext.tsx +23 -23
  49. package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
  50. package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +12 -3
  51. package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
  52. package/templates/nextblock-template/app/cms/components/PaymentsReminderBanner.tsx +58 -58
  53. package/templates/nextblock-template/app/cms/components/VisibilityBadge.tsx +62 -62
  54. package/templates/nextblock-template/app/cms/components/VisibilityControl.tsx +542 -542
  55. package/templates/nextblock-template/app/cms/coupons/[id]/edit/page.tsx +16 -16
  56. package/templates/nextblock-template/app/cms/coupons/page.tsx +16 -16
  57. package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
  58. package/templates/nextblock-template/app/cms/dashboard/components/DashboardComponents.tsx +200 -200
  59. package/templates/nextblock-template/app/cms/inquiries/actions.ts +66 -66
  60. package/templates/nextblock-template/app/cms/inquiries/page.tsx +12 -12
  61. package/templates/nextblock-template/app/cms/interactions/page.tsx +12 -12
  62. package/templates/nextblock-template/app/cms/layout.tsx +101 -101
  63. package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
  64. package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
  65. package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +177 -2
  66. package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -69
  67. package/templates/nextblock-template/app/cms/messages/MessagesClient.tsx +661 -661
  68. package/templates/nextblock-template/app/cms/messages/actions.ts +404 -404
  69. package/templates/nextblock-template/app/cms/messages/loadInbox.ts +333 -333
  70. package/templates/nextblock-template/app/cms/messages/page.tsx +87 -87
  71. package/templates/nextblock-template/app/cms/messages/require-admin.ts +37 -37
  72. package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +3 -3
  73. package/templates/nextblock-template/app/cms/pages/[id]/edit/EditPageClient.tsx +28 -0
  74. package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +248 -5
  75. package/templates/nextblock-template/app/cms/posts/[id]/edit/page.tsx +33 -0
  76. package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +240 -5
  77. package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +370 -370
  78. package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
  79. package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
  80. package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
  81. package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
  82. package/templates/nextblock-template/app/cms/revisions/actions.ts +332 -332
  83. package/templates/nextblock-template/app/cms/revisions/service.test.ts +498 -498
  84. package/templates/nextblock-template/app/cms/revisions/service.ts +569 -569
  85. package/templates/nextblock-template/app/cms/revisions/utils.ts +304 -304
  86. package/templates/nextblock-template/app/cms/settings/cortex-ai/CortexAiSettingsClient.tsx +948 -948
  87. package/templates/nextblock-template/app/cms/settings/cortex-ai/McpServerSettingsCard.tsx +628 -628
  88. package/templates/nextblock-template/app/cms/settings/cortex-ai/mcp-actions.ts +230 -230
  89. package/templates/nextblock-template/app/cms/settings/cortex-ai/require-admin.ts +34 -34
  90. package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
  91. package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
  92. package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +227 -227
  93. package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
  94. package/templates/nextblock-template/app/cms/settings/extra-translations/actions.ts +276 -276
  95. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
  96. package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeEditor.tsx +382 -382
  97. package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeManager.tsx +267 -267
  98. package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +40 -40
  99. package/templates/nextblock-template/app/cms/settings/global-css/theme-actions.ts +259 -259
  100. package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
  101. package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
  102. package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
  103. package/templates/nextblock-template/app/cms/settings/seo/RedirectsCard.tsx +514 -0
  104. package/templates/nextblock-template/app/cms/settings/seo/RobotsCard.tsx +529 -0
  105. package/templates/nextblock-template/app/cms/settings/seo/SeoSettingsClient.tsx +57 -0
  106. package/templates/nextblock-template/app/cms/settings/seo/actions.ts +448 -0
  107. package/templates/nextblock-template/app/cms/settings/seo/mappers.ts +93 -0
  108. package/templates/nextblock-template/app/cms/settings/seo/page.tsx +46 -0
  109. package/templates/nextblock-template/app/cms/settings/seo/require-admin.ts +47 -0
  110. package/templates/nextblock-template/app/cms/settings/site-scripts/page.tsx +51 -51
  111. package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
  112. package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
  113. package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
  114. package/templates/nextblock-template/app/layout.tsx +671 -671
  115. package/templates/nextblock-template/app/lib/seo.ts +319 -319
  116. package/templates/nextblock-template/app/lib/ucp/protocol.ts +190 -190
  117. package/templates/nextblock-template/app/lib/ucp/server.test.ts +56 -56
  118. package/templates/nextblock-template/app/product/[slug]/page.tsx +502 -502
  119. package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
  120. package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
  121. package/templates/nextblock-template/app/profile/account-links.ts +22 -22
  122. package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
  123. package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
  124. package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
  125. package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
  126. package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
  127. package/templates/nextblock-template/app/providers.tsx +96 -96
  128. package/templates/nextblock-template/app/robots.ts +123 -0
  129. package/templates/nextblock-template/app/sitemap.ts +1 -1
  130. package/templates/nextblock-template/app/thread/ThreadView.tsx +164 -164
  131. package/templates/nextblock-template/app/thread/[token]/route.ts +57 -57
  132. package/templates/nextblock-template/app/thread/layout.tsx +15 -15
  133. package/templates/nextblock-template/app/thread/page.tsx +98 -98
  134. package/templates/nextblock-template/app/ucp/v1/carts/[id]/cancel/route.ts +38 -38
  135. package/templates/nextblock-template/app/ucp/v1/carts/[id]/route.ts +68 -68
  136. package/templates/nextblock-template/app/ucp/v1/carts/route.ts +35 -35
  137. package/templates/nextblock-template/app/ucp/v1/catalog/lookup/route.ts +35 -35
  138. package/templates/nextblock-template/app/ucp/v1/catalog/product/route.ts +35 -35
  139. package/templates/nextblock-template/app/ucp/v1/catalog/search/route.ts +34 -34
  140. package/templates/nextblock-template/components/BlockRenderer.tsx +312 -312
  141. package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -7
  142. package/templates/nextblock-template/components/CartTranslator.tsx +210 -210
  143. package/templates/nextblock-template/components/ContactSellerSection.tsx +188 -188
  144. package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -23
  145. package/templates/nextblock-template/components/DeferredCartTranslator.tsx +51 -51
  146. package/templates/nextblock-template/components/DeferredGlobalSearch.tsx +68 -68
  147. package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -70
  148. package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -69
  149. package/templates/nextblock-template/components/FooterNavigation.tsx +32 -32
  150. package/templates/nextblock-template/components/GlobalSearch.tsx +557 -557
  151. package/templates/nextblock-template/components/Header.tsx +38 -38
  152. package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -47
  153. package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
  154. package/templates/nextblock-template/components/PostCommentsSection.tsx +378 -378
  155. package/templates/nextblock-template/components/ProductReviewsSection.tsx +426 -426
  156. package/templates/nextblock-template/components/SiteScripts.tsx +56 -56
  157. package/templates/nextblock-template/components/StaffReplies.tsx +102 -102
  158. package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -12
  159. package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -12
  160. package/templates/nextblock-template/components/blocks/PostsGridClient.tsx +48 -48
  161. package/templates/nextblock-template/components/blocks/TestimonialBlock.tsx +9 -9
  162. package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -23
  163. package/templates/nextblock-template/components/blocks/publicRendererLoaders.ts +25 -25
  164. package/templates/nextblock-template/components/blocks/renderers/ButtonBlockRenderer.tsx +92 -92
  165. package/templates/nextblock-template/components/blocks/renderers/CartBlockRenderer.tsx +18 -18
  166. package/templates/nextblock-template/components/blocks/renderers/CheckoutBlockRenderer.tsx +20 -20
  167. package/templates/nextblock-template/components/blocks/renderers/FeaturedProductBlockRenderer.tsx +25 -25
  168. package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +385 -385
  169. package/templates/nextblock-template/components/blocks/renderers/PostsGridBlockRenderer.tsx +24 -24
  170. package/templates/nextblock-template/components/blocks/renderers/ProductDetailsBlockRenderer.tsx +157 -157
  171. package/templates/nextblock-template/components/blocks/renderers/ProductGridBlockRenderer.tsx +34 -34
  172. package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +612 -612
  173. package/templates/nextblock-template/components/blocks/renderers/TestimonialBlockRenderer.tsx +57 -57
  174. package/templates/nextblock-template/components/blocks/renderers/inline/AlertWidgetRenderer.tsx +2 -2
  175. package/templates/nextblock-template/components/blocks/renderers/inline/CtaWidgetRenderer.tsx +2 -2
  176. package/templates/nextblock-template/components/blocks/types.ts +7 -7
  177. package/templates/nextblock-template/components/commerce/PaymentReadinessBoundary.tsx +32 -32
  178. package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
  179. package/templates/nextblock-template/components/form-message.tsx +32 -32
  180. package/templates/nextblock-template/components/seo/GenerateMetaButton.tsx +137 -0
  181. package/templates/nextblock-template/components/seo/PageSeoAuditSection.tsx +244 -0
  182. package/templates/nextblock-template/components/seo/SeoAuditPanel.tsx +749 -0
  183. package/templates/nextblock-template/components/seo/SeoIssueList.tsx +195 -0
  184. package/templates/nextblock-template/components/seo/SeoScoreDial.tsx +144 -0
  185. package/templates/nextblock-template/components/seo/SocialPreview.tsx +243 -0
  186. package/templates/nextblock-template/components/seo/SocialPreviewDialog.tsx +110 -0
  187. package/templates/nextblock-template/components/submit-button.tsx +23 -23
  188. package/templates/nextblock-template/components/theme-icon.tsx +78 -78
  189. package/templates/nextblock-template/components/theme-switcher.tsx +85 -85
  190. package/templates/nextblock-template/context/AuthContext.tsx +23 -23
  191. package/templates/nextblock-template/context/ThemeCatalogContext.tsx +44 -44
  192. package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -94
  193. package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +77 -77
  194. package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +372 -372
  195. package/templates/nextblock-template/docs/14-MESSAGES-INBOX.md +309 -309
  196. package/templates/nextblock-template/docs/README.md +42 -42
  197. package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12506 -12506
  198. package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -21
  199. package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -101
  200. package/templates/nextblock-template/index.d.ts +7 -7
  201. package/templates/nextblock-template/lib/auth-redirects.ts +46 -46
  202. package/templates/nextblock-template/lib/blocks/blockColors.test.ts +134 -134
  203. package/templates/nextblock-template/lib/blocks/blockColors.ts +175 -175
  204. package/templates/nextblock-template/lib/blocks/blockRegistry.ts +761 -761
  205. package/templates/nextblock-template/lib/blocks/inlineScriptNonce.ts +20 -20
  206. package/templates/nextblock-template/lib/cms/contact-reminder.ts +64 -64
  207. package/templates/nextblock-template/lib/cms/payments-reminder.test.ts +135 -0
  208. package/templates/nextblock-template/lib/cms/payments-reminder.ts +30 -23
  209. package/templates/nextblock-template/lib/cms/unread-messages.ts +42 -42
  210. package/templates/nextblock-template/lib/commerce/seller-contact.ts +162 -162
  211. package/templates/nextblock-template/lib/config/email-settings.ts +323 -323
  212. package/templates/nextblock-template/lib/config/email-tls.test.ts +57 -57
  213. package/templates/nextblock-template/lib/cortex-ai/alt-text-request.ts +86 -0
  214. package/templates/nextblock-template/lib/cortex-ai/sandbox-headers.ts +60 -0
  215. package/templates/nextblock-template/lib/email/placeholder-address.test.ts +59 -59
  216. package/templates/nextblock-template/lib/email/placeholder-address.ts +39 -39
  217. package/templates/nextblock-template/lib/messages/thread-reference.test.ts +70 -70
  218. package/templates/nextblock-template/lib/messages/thread-token.test.ts +93 -93
  219. package/templates/nextblock-template/lib/messages/thread-token.ts +157 -157
  220. package/templates/nextblock-template/lib/messages/threads.ts +579 -579
  221. package/templates/nextblock-template/lib/posts/readTime.ts +60 -60
  222. package/templates/nextblock-template/lib/publishing/viewUrl.ts +26 -26
  223. package/templates/nextblock-template/lib/search/types.ts +27 -27
  224. package/templates/nextblock-template/lib/seo/alt-text-write-back.test.ts +154 -0
  225. package/templates/nextblock-template/lib/seo/alt-text-write-back.ts +109 -0
  226. package/templates/nextblock-template/lib/seo/block-content.ts +123 -0
  227. package/templates/nextblock-template/lib/seo/fix-prompts.test.ts +242 -0
  228. package/templates/nextblock-template/lib/seo/fix-prompts.ts +204 -0
  229. package/templates/nextblock-template/lib/seo/page-audit-context.tsx +140 -0
  230. package/templates/nextblock-template/lib/seo/page-document.test.ts +350 -0
  231. package/templates/nextblock-template/lib/seo/page-document.ts +412 -0
  232. package/templates/nextblock-template/lib/seo/redirect-store.test.ts +479 -0
  233. package/templates/nextblock-template/lib/seo/redirect-store.ts +466 -0
  234. package/templates/nextblock-template/lib/seo/robots-settings-signature.test.ts +102 -0
  235. package/templates/nextblock-template/lib/seo/robots-settings-signature.ts +41 -0
  236. package/templates/nextblock-template/lib/seo/robots-txt.test.ts +370 -0
  237. package/templates/nextblock-template/lib/seo/robots-txt.ts +510 -0
  238. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +177 -167
  239. package/templates/nextblock-template/lib/site-scripts/revisions.ts +71 -71
  240. package/templates/nextblock-template/lib/site-scripts/types.ts +46 -46
  241. package/templates/nextblock-template/lib/site-url.test.ts +89 -89
  242. package/templates/nextblock-template/lib/site-url.ts +102 -102
  243. package/templates/nextblock-template/lib/themes/buildThemeCss.ts +124 -124
  244. package/templates/nextblock-template/lib/themes/tokenColor.ts +31 -31
  245. package/templates/nextblock-template/lib/themes/tokens.ts +143 -143
  246. package/templates/nextblock-template/lib/visual-editing/draft-content.test.ts +105 -105
  247. package/templates/nextblock-template/lib/visual-editing/draft-route.test.ts +42 -42
  248. package/templates/nextblock-template/lib/visual-editing/edit-info.test.ts +143 -143
  249. package/templates/nextblock-template/lib/visual-editing/edit-info.ts +94 -94
  250. package/templates/nextblock-template/lib/visual-editing/product-drafts.test.ts +81 -81
  251. package/templates/nextblock-template/lib/zod-config.ts +5 -5
  252. package/templates/nextblock-template/next-env.d.ts +0 -1
  253. package/templates/nextblock-template/package.json +1 -1
  254. package/templates/nextblock-template/postcss.config.js +6 -6
  255. package/templates/nextblock-template/proxy.ts +240 -20
  256. package/templates/nextblock-template/scripts/backup.js +115 -115
  257. package/templates/nextblock-template/scripts/restore.js +385 -385
  258. package/templates/nextblock-template/scripts/validate-editor-block-schema.ts +112 -112
  259. package/templates/nextblock-template/tailwind.config.js +25 -25
  260. package/templates/nextblock-template/tools/build-migrate.mjs +102 -102
  261. package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
  262. package/templates/nextblock-template/tools/deploy-supabase.js +159 -159
  263. package/templates/nextblock-template/tools/lib/migrate-core.mjs +569 -569
  264. package/templates/nextblock-template/tools/update.mjs +1303 -1303
  265. package/tsconfig.base.json +3 -3
  266. package/templates/nextblock-template/app/robots.txt/route.ts +0 -32
@@ -1,59 +1,59 @@
1
- 'use server';
2
-
3
- import { createClient } from '@nextblock-cms/db/server';
4
- import { encodedRedirect } from '@nextblock-cms/utils/server';
5
- import { redirect } from 'next/navigation';
6
-
7
- export async function changePasswordAction(formData: FormData) {
8
- if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
9
- redirect('/profile');
10
- }
11
-
12
- const supabase = createClient();
13
- const {
14
- data: { user },
15
- error: authError,
16
- } = await supabase.auth.getUser();
17
-
18
- if (authError || !user) {
19
- redirect('/sign-in?redirect=%2Fprofile%2Fpassword');
20
- }
21
-
22
- const password = formData.get('password')?.toString() || '';
23
- const confirmPassword =
24
- formData.get('confirmPassword')?.toString() || '';
25
-
26
- if (!password || !confirmPassword) {
27
- return encodedRedirect(
28
- 'error',
29
- '/profile/password',
30
- 'password_update_failed'
31
- );
32
- }
33
-
34
- if (password !== confirmPassword) {
35
- return encodedRedirect(
36
- 'error',
37
- '/profile/password',
38
- 'passwords_do_not_match'
39
- );
40
- }
41
-
42
- const { error } = await supabase.auth.updateUser({
43
- password,
44
- });
45
-
46
- if (error) {
47
- return encodedRedirect(
48
- 'error',
49
- '/profile/password',
50
- 'password_update_failed'
51
- );
52
- }
53
-
54
- return encodedRedirect(
55
- 'success',
56
- '/profile/password',
57
- 'password_updated_success'
58
- );
59
- }
1
+ 'use server';
2
+
3
+ import { createClient } from '@nextblock-cms/db/server';
4
+ import { encodedRedirect } from '@nextblock-cms/utils/server';
5
+ import { redirect } from 'next/navigation';
6
+
7
+ export async function changePasswordAction(formData: FormData) {
8
+ if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
9
+ redirect('/profile');
10
+ }
11
+
12
+ const supabase = createClient();
13
+ const {
14
+ data: { user },
15
+ error: authError,
16
+ } = await supabase.auth.getUser();
17
+
18
+ if (authError || !user) {
19
+ redirect('/sign-in?redirect=%2Fprofile%2Fpassword');
20
+ }
21
+
22
+ const password = formData.get('password')?.toString() || '';
23
+ const confirmPassword =
24
+ formData.get('confirmPassword')?.toString() || '';
25
+
26
+ if (!password || !confirmPassword) {
27
+ return encodedRedirect(
28
+ 'error',
29
+ '/profile/password',
30
+ 'password_update_failed'
31
+ );
32
+ }
33
+
34
+ if (password !== confirmPassword) {
35
+ return encodedRedirect(
36
+ 'error',
37
+ '/profile/password',
38
+ 'passwords_do_not_match'
39
+ );
40
+ }
41
+
42
+ const { error } = await supabase.auth.updateUser({
43
+ password,
44
+ });
45
+
46
+ if (error) {
47
+ return encodedRedirect(
48
+ 'error',
49
+ '/profile/password',
50
+ 'password_update_failed'
51
+ );
52
+ }
53
+
54
+ return encodedRedirect(
55
+ 'success',
56
+ '/profile/password',
57
+ 'password_updated_success'
58
+ );
59
+ }
@@ -1,27 +1,27 @@
1
- import { requireProfileAccountContext } from '../account-data';
2
- import { PasswordSettingsPageClient } from './PasswordSettingsPageClient';
3
- import { notFound } from 'next/navigation';
4
-
5
- export default async function ProfilePasswordPage({
6
- searchParams,
7
- }: {
8
- searchParams: Promise<{ success?: string; error?: string }>;
9
- }) {
10
- if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
11
- notFound();
12
- }
13
-
14
- const { profile, user } = await requireProfileAccountContext(
15
- '/profile/password'
16
- );
17
- const params = await searchParams;
18
-
19
- return (
20
- <PasswordSettingsPageClient
21
- profile={profile}
22
- user={user}
23
- successMessage={params.success || null}
24
- errorMessage={params.error || null}
25
- />
26
- );
27
- }
1
+ import { requireProfileAccountContext } from '../account-data';
2
+ import { PasswordSettingsPageClient } from './PasswordSettingsPageClient';
3
+ import { notFound } from 'next/navigation';
4
+
5
+ export default async function ProfilePasswordPage({
6
+ searchParams,
7
+ }: {
8
+ searchParams: Promise<{ success?: string; error?: string }>;
9
+ }) {
10
+ if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
11
+ notFound();
12
+ }
13
+
14
+ const { profile, user } = await requireProfileAccountContext(
15
+ '/profile/password'
16
+ );
17
+ const params = await searchParams;
18
+
19
+ return (
20
+ <PasswordSettingsPageClient
21
+ profile={profile}
22
+ user={user}
23
+ successMessage={params.success || null}
24
+ errorMessage={params.error || null}
25
+ />
26
+ );
27
+ }
@@ -1,96 +1,96 @@
1
- "use client";
2
-
3
- import { ThemeProvider } from "next-themes";
4
-
5
- // Suppress the React 19 warning for the <script> tag generated by next-themes in development
6
- if (typeof window !== 'undefined' && process.env.NODE_ENV === 'development') {
7
- const orig = console.error;
8
- console.error = (...args: any[]) => {
9
- if (typeof args[0] === 'string' && args[0].includes('Encountered a script tag')) {
10
- return;
11
- }
12
- orig.apply(console, args);
13
- };
14
- }
15
- import { AuthProvider } from '../context/AuthContext';
16
- import { LanguageProvider, useLanguage } from '../context/LanguageContext';
17
- import { CurrentContentProvider } from '../context/CurrentContentContext';
18
- import { ThemeCatalogProvider } from '../context/ThemeCatalogContext';
19
- import { DeferredCartTranslator } from '../components/DeferredCartTranslator';
20
- import { CurrencyProvider } from '@nextblock-cms/ecommerce/CurrencyProvider';
21
- import { TranslationsProvider } from '@nextblock-cms/utils';
22
-
23
- function TranslationBridge({
24
- children,
25
- translations,
26
- }: {
27
- children: React.ReactNode;
28
- translations: { key: string; translations: Record<string, string> }[];
29
- }) {
30
- const { currentLocale } = useLanguage();
31
-
32
- return (
33
- <TranslationsProvider translations={translations} lang={currentLocale}>
34
- {children}
35
- </TranslationsProvider>
36
- );
37
- }
38
-
39
- export function Providers({ children, ...props }: { children: React.ReactNode;[key: string]: any; }) {
40
- const {
41
- serverUser,
42
- serverProfile,
43
- serverLocale,
44
- initialCurrencies,
45
- initialCurrencyCode,
46
- initialAvailableLanguages,
47
- initialDefaultLanguage,
48
- rememberVisitorChoice,
49
- translations,
50
- nonce,
51
- themeSlugs,
52
- initialTheme,
53
- themeCatalog,
54
- } = props;
55
-
56
- // Themes come from the site_themes table. Fall back to the three that ship in
57
- // libs/ui/src/styles/theme.css if the table is empty or unreachable, so the
58
- // switcher never renders an empty list.
59
- const resolvedThemes: string[] =
60
- Array.isArray(themeSlugs) && themeSlugs.length > 0 ? themeSlugs : ['light', 'dark', 'vibrant'];
61
- const resolvedDefault: string =
62
- typeof initialTheme === 'string' && resolvedThemes.includes(initialTheme) ? initialTheme : 'light';
63
-
64
- return (
65
- <AuthProvider serverUser={serverUser} serverProfile={serverProfile}>
66
- <LanguageProvider
67
- serverLocale={serverLocale}
68
- initialAvailableLanguages={initialAvailableLanguages}
69
- initialDefaultLanguage={initialDefaultLanguage}
70
- rememberVisitorChoice={rememberVisitorChoice}
71
- >
72
- <CurrencyProvider
73
- initialCurrencies={initialCurrencies}
74
- initialCurrencyCode={initialCurrencyCode}
75
- locale={serverLocale}
76
- >
77
- <CurrentContentProvider>
78
- <DeferredCartTranslator />
79
- <TranslationBridge translations={translations}>
80
- <ThemeProvider
81
- attribute="class"
82
- defaultTheme={resolvedDefault}
83
- enableSystem
84
- disableTransitionOnChange
85
- nonce={nonce}
86
- themes={resolvedThemes}
87
- >
88
- <ThemeCatalogProvider themes={themeCatalog}>{children}</ThemeCatalogProvider>
89
- </ThemeProvider>
90
- </TranslationBridge>
91
- </CurrentContentProvider>
92
- </CurrencyProvider>
93
- </LanguageProvider>
94
- </AuthProvider>
95
- );
96
- }
1
+ "use client";
2
+
3
+ import { ThemeProvider } from "next-themes";
4
+
5
+ // Suppress the React 19 warning for the <script> tag generated by next-themes in development
6
+ if (typeof window !== 'undefined' && process.env.NODE_ENV === 'development') {
7
+ const orig = console.error;
8
+ console.error = (...args: any[]) => {
9
+ if (typeof args[0] === 'string' && args[0].includes('Encountered a script tag')) {
10
+ return;
11
+ }
12
+ orig.apply(console, args);
13
+ };
14
+ }
15
+ import { AuthProvider } from '../context/AuthContext';
16
+ import { LanguageProvider, useLanguage } from '../context/LanguageContext';
17
+ import { CurrentContentProvider } from '../context/CurrentContentContext';
18
+ import { ThemeCatalogProvider } from '../context/ThemeCatalogContext';
19
+ import { DeferredCartTranslator } from '../components/DeferredCartTranslator';
20
+ import { CurrencyProvider } from '@nextblock-cms/ecommerce/CurrencyProvider';
21
+ import { TranslationsProvider } from '@nextblock-cms/utils';
22
+
23
+ function TranslationBridge({
24
+ children,
25
+ translations,
26
+ }: {
27
+ children: React.ReactNode;
28
+ translations: { key: string; translations: Record<string, string> }[];
29
+ }) {
30
+ const { currentLocale } = useLanguage();
31
+
32
+ return (
33
+ <TranslationsProvider translations={translations} lang={currentLocale}>
34
+ {children}
35
+ </TranslationsProvider>
36
+ );
37
+ }
38
+
39
+ export function Providers({ children, ...props }: { children: React.ReactNode;[key: string]: any; }) {
40
+ const {
41
+ serverUser,
42
+ serverProfile,
43
+ serverLocale,
44
+ initialCurrencies,
45
+ initialCurrencyCode,
46
+ initialAvailableLanguages,
47
+ initialDefaultLanguage,
48
+ rememberVisitorChoice,
49
+ translations,
50
+ nonce,
51
+ themeSlugs,
52
+ initialTheme,
53
+ themeCatalog,
54
+ } = props;
55
+
56
+ // Themes come from the site_themes table. Fall back to the three that ship in
57
+ // libs/ui/src/styles/theme.css if the table is empty or unreachable, so the
58
+ // switcher never renders an empty list.
59
+ const resolvedThemes: string[] =
60
+ Array.isArray(themeSlugs) && themeSlugs.length > 0 ? themeSlugs : ['light', 'dark', 'vibrant'];
61
+ const resolvedDefault: string =
62
+ typeof initialTheme === 'string' && resolvedThemes.includes(initialTheme) ? initialTheme : 'light';
63
+
64
+ return (
65
+ <AuthProvider serverUser={serverUser} serverProfile={serverProfile}>
66
+ <LanguageProvider
67
+ serverLocale={serverLocale}
68
+ initialAvailableLanguages={initialAvailableLanguages}
69
+ initialDefaultLanguage={initialDefaultLanguage}
70
+ rememberVisitorChoice={rememberVisitorChoice}
71
+ >
72
+ <CurrencyProvider
73
+ initialCurrencies={initialCurrencies}
74
+ initialCurrencyCode={initialCurrencyCode}
75
+ locale={serverLocale}
76
+ >
77
+ <CurrentContentProvider>
78
+ <DeferredCartTranslator />
79
+ <TranslationBridge translations={translations}>
80
+ <ThemeProvider
81
+ attribute="class"
82
+ defaultTheme={resolvedDefault}
83
+ enableSystem
84
+ disableTransitionOnChange
85
+ nonce={nonce}
86
+ themes={resolvedThemes}
87
+ >
88
+ <ThemeCatalogProvider themes={themeCatalog}>{children}</ThemeCatalogProvider>
89
+ </ThemeProvider>
90
+ </TranslationBridge>
91
+ </CurrentContentProvider>
92
+ </CurrencyProvider>
93
+ </LanguageProvider>
94
+ </AuthProvider>
95
+ );
96
+ }
@@ -0,0 +1,123 @@
1
+ import type { MetadataRoute } from 'next';
2
+ import { getSsgSupabaseClient } from '@nextblock-cms/db/server';
3
+ import { normalizeRobotsSettings, type RobotsSettings } from '@nextblock-cms/utils/seo';
4
+ import { buildRobotsMetadata } from '../lib/seo/robots-txt';
5
+ import { resolveSiteUrl, hasResolvedSiteUrl } from '../lib/site-url';
6
+
7
+ /**
8
+ * /robots.txt, generated from the operator's stored settings.
9
+ *
10
+ * This replaces the hand-rolled `app/robots.txt/route.ts` that used to live here,
11
+ * and the two CANNOT coexist: Next's `normalizeMetadataRoute` rewrites the page
12
+ * `/robots` to `/robots.txt` and then appends `/route`, which is character for
13
+ * character the app path the old handler occupied. Keeping both would be a
14
+ * duplicate-route collision, not a fallback — so the old file was deleted in the
15
+ * same change that added this one. The externally visible path is unchanged, which
16
+ * is why `isSetupAllowlisted()` in proxy.ts still allowlists the literal
17
+ * '/robots.txt' and needed no edit.
18
+ *
19
+ * The move from a route handler to the metadata route is what buys the caching
20
+ * below. Everything else about the response — the served path, the content type, the
21
+ * sandbox behaviour — is identical to what shipped before.
22
+ */
23
+
24
+ /**
25
+ * Cache the generated file and rebuild it at most once an hour, mirroring
26
+ * app/sitemap.ts. Crawlers get a fast, statically-served response while a change an
27
+ * operator saves in /cms/settings still takes effect without a redeploy.
28
+ *
29
+ * NextBlock does not enable Next.js Cache Components, so the route-segment
30
+ * `revalidate` config is the idiomatic caching control here. If `cacheComponents`
31
+ * were turned on, the equivalent would be a `'use cache'` body paired with
32
+ * `cacheLife('hours')` instead of this export.
33
+ */
34
+ export const revalidate = 3600;
35
+
36
+ /**
37
+ * The `site_settings` row the SEO screen writes, seeded by migration 30 and moved into
38
+ * the ADMIN-only write group by migration 31 — a WRITER could otherwise have PATCHed
39
+ * this row through PostgREST and de-indexed the whole site, since RLS, not the server
40
+ * action, is the boundary that actually holds.
41
+ */
42
+ const ROBOTS_SETTINGS_KEY = 'seo_robots_settings';
43
+
44
+ /**
45
+ * Reads the stored robots configuration, falling back to the permissive defaults on
46
+ * any failure whatsoever.
47
+ *
48
+ * The anon client is the right one here, and deliberately so: `seo_robots_settings`
49
+ * is a non-secret key and `site_settings`' read policy is already public for
50
+ * non-secret keys, so nothing on this path needs the service role. Handing a
51
+ * service-role client to a route that anonymous crawlers hit would be a needless
52
+ * escalation.
53
+ *
54
+ * That read has to stay anonymous, which is why migration 31 tightened only the
55
+ * INSERT/UPDATE/DELETE policies and left `site_settings_read_policy` alone. Adding
56
+ * this key to the read policy's sensitive array would not fail loudly — the query
57
+ * below would simply return no row, every crawler would be served the permissive
58
+ * defaults, and the operator's configuration would stop applying without a single
59
+ * error anywhere.
60
+ *
61
+ * The failure handling matters more than it looks. A crawler that receives a 500 for
62
+ * robots.txt may treat the entire site as disallowed until it next succeeds, so an
63
+ * unreachable database — or a `cms_redirects`-era install that has not yet run
64
+ * `npm run db:migrate`, where this settings row does not exist — must produce a
65
+ * valid, permissive file rather than an error. `normalizeRobotsSettings` handles the
66
+ * other half of that: whatever jsonb hands back, including null, a string or a
67
+ * half-migrated object, becomes a complete `RobotsSettings`.
68
+ */
69
+ async function loadRobotsSettings(): Promise<RobotsSettings> {
70
+ try {
71
+ const supabase = getSsgSupabaseClient();
72
+ const { data, error } = await supabase
73
+ .from('site_settings')
74
+ .select('value')
75
+ .eq('key', ROBOTS_SETTINGS_KEY)
76
+ .maybeSingle();
77
+
78
+ if (error) {
79
+ console.error('robots.txt: failed to read the robots settings; serving defaults.', error);
80
+ return normalizeRobotsSettings(undefined);
81
+ }
82
+
83
+ // A missing row is not an error — it is a site whose operator has never opened
84
+ // the SEO screen — and the defaults are exactly what that site should serve.
85
+ return normalizeRobotsSettings(data?.value);
86
+ } catch (error) {
87
+ console.error('robots.txt: robots settings lookup threw; serving defaults.', error);
88
+ return normalizeRobotsSettings(undefined);
89
+ }
90
+ }
91
+
92
+ export default async function robots(): Promise<MetadataRoute.Robots> {
93
+ const isSandbox = process.env.NEXT_PUBLIC_IS_SANDBOX === 'true';
94
+
95
+ // The sandbox answer ignores every stored setting, so there is nothing to read.
96
+ // Skipping the query keeps a disposable deployment's robots.txt working even when
97
+ // its database is asleep or being reset by the cron job. The reasoning for why the
98
+ // sandbox ALLOWS crawling rather than disallowing it lives on SANDBOX_USER_AGENT_RULE
99
+ // in lib/seo/robots-txt.ts — it is the counter-intuitive part of this feature and
100
+ // that is where it is written down in full.
101
+ if (isSandbox) {
102
+ return buildRobotsMetadata(normalizeRobotsSettings(undefined), {
103
+ isSandbox: true,
104
+ sitemapUrl: null,
105
+ });
106
+ }
107
+
108
+ // Explicit NEXT_PUBLIC_URL → Vercel production URL → local-dev fallback.
109
+ const siteUrl = resolveSiteUrl();
110
+
111
+ if (!hasResolvedSiteUrl()) {
112
+ console.warn(
113
+ 'Warning: no site URL is set for robots.txt (NEXT_PUBLIC_URL / Vercel production URL). Defaulting to http://localhost:3000. Set NEXT_PUBLIC_URL for production.'
114
+ );
115
+ }
116
+
117
+ const settings = await loadRobotsSettings();
118
+
119
+ return buildRobotsMetadata(settings, {
120
+ isSandbox: false,
121
+ sitemapUrl: `${siteUrl}/sitemap.xml`,
122
+ });
123
+ }
@@ -70,7 +70,7 @@ async function safe(
70
70
 
71
71
  export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
72
72
  // Disposable sandbox deployments should not advertise an indexable sitemap
73
- // (mirrors the legacy app/sitemap.xml route and app/robots.txt).
73
+ // (mirrors the legacy app/sitemap.xml route and app/robots.ts).
74
74
  if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
75
75
  return [];
76
76
  }