create-nextblock 0.16.1 → 0.16.3

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 (264) 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 -221
  26. package/templates/nextblock-template/app/api/ai/seo/metadata/route.ts +186 -186
  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/route.ts +4 -4
  30. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +4542 -2904
  31. package/templates/nextblock-template/app/api/mcp/route.ts +415 -415
  32. package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
  33. package/templates/nextblock-template/app/api/search/route.ts +43 -43
  34. package/templates/nextblock-template/app/api/view/route.ts +114 -114
  35. package/templates/nextblock-template/app/api/visual-editing/block-draft/route.ts +47 -47
  36. package/templates/nextblock-template/app/api/visual-editing/product-draft/route.ts +47 -47
  37. package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
  38. package/templates/nextblock-template/app/cart/page.tsx +7 -7
  39. package/templates/nextblock-template/app/checkout/UcpCartHydrator.tsx +20 -20
  40. package/templates/nextblock-template/app/checkout/page.tsx +57 -57
  41. package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +558 -558
  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 +406 -406
  46. package/templates/nextblock-template/app/cms/components/ContactReminderBanner.tsx +75 -75
  47. package/templates/nextblock-template/app/cms/components/CortexAiActiveContext.tsx +23 -23
  48. package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
  49. package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +254 -254
  50. package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
  51. package/templates/nextblock-template/app/cms/components/PaymentsReminderBanner.tsx +58 -58
  52. package/templates/nextblock-template/app/cms/components/SeoScoreBadge.tsx +40 -0
  53. package/templates/nextblock-template/app/cms/components/TablePagination.tsx +136 -0
  54. package/templates/nextblock-template/app/cms/components/VisibilityBadge.tsx +62 -62
  55. package/templates/nextblock-template/app/cms/components/VisibilityControl.tsx +542 -542
  56. package/templates/nextblock-template/app/cms/coupons/[id]/edit/page.tsx +16 -16
  57. package/templates/nextblock-template/app/cms/coupons/page.tsx +16 -16
  58. package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
  59. package/templates/nextblock-template/app/cms/dashboard/components/DashboardComponents.tsx +200 -200
  60. package/templates/nextblock-template/app/cms/inquiries/actions.ts +66 -66
  61. package/templates/nextblock-template/app/cms/inquiries/page.tsx +12 -12
  62. package/templates/nextblock-template/app/cms/interactions/page.tsx +12 -12
  63. package/templates/nextblock-template/app/cms/layout.tsx +101 -101
  64. package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
  65. package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
  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/components/PageForm.tsx +649 -649
  74. package/templates/nextblock-template/app/cms/pages/page.tsx +273 -227
  75. package/templates/nextblock-template/app/cms/posts/[id]/edit/page.tsx +2 -0
  76. package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +624 -618
  77. package/templates/nextblock-template/app/cms/posts/page.tsx +251 -194
  78. package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +370 -370
  79. package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
  80. package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
  81. package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
  82. package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
  83. package/templates/nextblock-template/app/cms/revisions/actions.ts +332 -332
  84. package/templates/nextblock-template/app/cms/revisions/service.test.ts +498 -498
  85. package/templates/nextblock-template/app/cms/revisions/service.ts +569 -569
  86. package/templates/nextblock-template/app/cms/revisions/utils.ts +304 -304
  87. package/templates/nextblock-template/app/cms/settings/cortex-ai/CortexAiSettingsClient.tsx +948 -948
  88. package/templates/nextblock-template/app/cms/settings/cortex-ai/McpServerSettingsCard.tsx +628 -628
  89. package/templates/nextblock-template/app/cms/settings/cortex-ai/mcp-actions.ts +230 -230
  90. package/templates/nextblock-template/app/cms/settings/cortex-ai/require-admin.ts +34 -34
  91. package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
  92. package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
  93. package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +227 -227
  94. package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
  95. package/templates/nextblock-template/app/cms/settings/extra-translations/actions.ts +276 -276
  96. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
  97. package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeEditor.tsx +382 -382
  98. package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeManager.tsx +267 -267
  99. package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +40 -40
  100. package/templates/nextblock-template/app/cms/settings/global-css/theme-actions.ts +259 -259
  101. package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
  102. package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
  103. package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
  104. package/templates/nextblock-template/app/cms/settings/seo/RedirectsCard.tsx +514 -514
  105. package/templates/nextblock-template/app/cms/settings/seo/RobotsCard.tsx +529 -529
  106. package/templates/nextblock-template/app/cms/settings/seo/SeoSettingsClient.tsx +57 -57
  107. package/templates/nextblock-template/app/cms/settings/seo/actions.ts +448 -448
  108. package/templates/nextblock-template/app/cms/settings/seo/mappers.ts +93 -93
  109. package/templates/nextblock-template/app/cms/settings/seo/page.tsx +46 -46
  110. package/templates/nextblock-template/app/cms/settings/seo/require-admin.ts +47 -47
  111. package/templates/nextblock-template/app/cms/settings/site-scripts/page.tsx +51 -51
  112. package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
  113. package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
  114. package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
  115. package/templates/nextblock-template/app/layout.tsx +671 -671
  116. package/templates/nextblock-template/app/lib/seo.ts +319 -319
  117. package/templates/nextblock-template/app/lib/ucp/protocol.ts +190 -190
  118. package/templates/nextblock-template/app/lib/ucp/server.test.ts +56 -56
  119. package/templates/nextblock-template/app/product/[slug]/page.tsx +502 -502
  120. package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
  121. package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
  122. package/templates/nextblock-template/app/profile/account-links.ts +22 -22
  123. package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
  124. package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
  125. package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
  126. package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
  127. package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
  128. package/templates/nextblock-template/app/providers.tsx +96 -96
  129. package/templates/nextblock-template/app/robots.ts +123 -123
  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 -137
  181. package/templates/nextblock-template/components/seo/PageSeoAuditSection.tsx +251 -244
  182. package/templates/nextblock-template/components/seo/SeoAuditPanel.tsx +749 -749
  183. package/templates/nextblock-template/components/seo/SeoIssueList.tsx +195 -195
  184. package/templates/nextblock-template/components/seo/SeoScoreDial.tsx +144 -144
  185. package/templates/nextblock-template/components/seo/SocialPreview.tsx +243 -243
  186. package/templates/nextblock-template/components/seo/SocialPreviewDialog.tsx +110 -110
  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 -86
  214. package/templates/nextblock-template/lib/cortex-ai/sandbox-headers.ts +60 -60
  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 -154
  225. package/templates/nextblock-template/lib/seo/alt-text-write-back.ts +109 -109
  226. package/templates/nextblock-template/lib/seo/block-content.ts +123 -123
  227. package/templates/nextblock-template/lib/seo/fix-prompts.test.ts +242 -242
  228. package/templates/nextblock-template/lib/seo/fix-prompts.ts +204 -204
  229. package/templates/nextblock-template/lib/seo/page-audit-context.tsx +157 -140
  230. package/templates/nextblock-template/lib/seo/page-document.test.ts +384 -350
  231. package/templates/nextblock-template/lib/seo/page-document.ts +463 -412
  232. package/templates/nextblock-template/lib/seo/redirect-store.test.ts +479 -479
  233. package/templates/nextblock-template/lib/seo/redirect-store.ts +466 -466
  234. package/templates/nextblock-template/lib/seo/robots-settings-signature.test.ts +102 -102
  235. package/templates/nextblock-template/lib/seo/robots-settings-signature.ts +41 -41
  236. package/templates/nextblock-template/lib/seo/robots-txt.test.ts +370 -370
  237. package/templates/nextblock-template/lib/seo/robots-txt.ts +510 -510
  238. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +37 -22
  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 +1 -2
  253. package/templates/nextblock-template/package.json +1 -1
  254. package/templates/nextblock-template/postcss.config.js +6 -6
  255. package/templates/nextblock-template/scripts/backup.js +115 -115
  256. package/templates/nextblock-template/scripts/restore.js +385 -385
  257. package/templates/nextblock-template/scripts/validate-editor-block-schema.ts +112 -112
  258. package/templates/nextblock-template/tailwind.config.js +25 -25
  259. package/templates/nextblock-template/tools/build-migrate.mjs +102 -102
  260. package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
  261. package/templates/nextblock-template/tools/deploy-supabase.js +159 -159
  262. package/templates/nextblock-template/tools/lib/migrate-core.mjs +569 -569
  263. package/templates/nextblock-template/tools/update.mjs +1303 -1303
  264. package/tsconfig.base.json +3 -3
@@ -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
+ }
@@ -1,123 +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
- }
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
+ }