create-nextblock 0.12.9 → 0.12.12

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 (293) hide show
  1. package/docker-template/.dockerignore +23 -23
  2. package/docker-template/.env.docker.example +69 -69
  3. package/docker-template/docker/db/init/99-jwt.sql +6 -6
  4. package/docker-template/docker/db/init/99-roles.sql +25 -25
  5. package/docker-template/docker/kong/kong.yml +112 -112
  6. package/docker-template/scripts/docker-setup.mjs +310 -310
  7. package/libs/db/tsconfig.lib.json +3 -3
  8. package/libs/editor/tsconfig.lib.json +3 -3
  9. package/libs/ui/tsconfig.lib.json +3 -3
  10. package/libs/utils/tsconfig.json +3 -3
  11. package/package.json +1 -1
  12. package/project.json +19 -19
  13. package/templates/nextblock-template/.browserslistrc +11 -11
  14. package/templates/nextblock-template/.dockerignore +23 -23
  15. package/templates/nextblock-template/README.md +34 -34
  16. package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -9
  17. package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -27
  18. package/templates/nextblock-template/app/(auth-pages)/sign-up/SignUpForm.tsx +141 -141
  19. package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +46 -46
  20. package/templates/nextblock-template/app/(auth-pages)/two-factor/actions.ts +91 -91
  21. package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +123 -123
  22. package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -51
  23. package/templates/nextblock-template/app/ToasterProvider.tsx +17 -17
  24. package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -7
  25. package/templates/nextblock-template/app/actions/consent.ts +57 -57
  26. package/templates/nextblock-template/app/actions/interactions.test.ts +301 -301
  27. package/templates/nextblock-template/app/actions/interactions.ts +373 -373
  28. package/templates/nextblock-template/app/actions/postActions.ts +146 -146
  29. package/templates/nextblock-template/app/actions/twoFactorEmail.ts +22 -22
  30. package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -153
  31. package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -96
  32. package/templates/nextblock-template/app/api/ai/global-agent/route.ts +964 -964
  33. package/templates/nextblock-template/app/api/brand/email-logo/route.ts +48 -48
  34. package/templates/nextblock-template/app/api/cms/check-updates/route.ts +44 -44
  35. package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -33
  36. package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -63
  37. package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3490 -3490
  38. package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +5597 -5597
  39. package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +39 -39
  40. package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -92
  41. package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -43
  42. package/templates/nextblock-template/app/api/media/library/route.ts +69 -69
  43. package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -53
  44. package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
  45. package/templates/nextblock-template/app/api/search/route.ts +43 -43
  46. package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +441 -441
  47. package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
  48. package/templates/nextblock-template/app/cart/page.tsx +7 -7
  49. package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -160
  50. package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -149
  51. package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -167
  52. package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +29 -29
  53. package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +90 -90
  54. package/templates/nextblock-template/app/cms/components/ConnectGitHubButton.tsx +122 -122
  55. package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
  56. package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +244 -244
  57. package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
  58. package/templates/nextblock-template/app/cms/components/SystemAlertsBanner.tsx +112 -112
  59. package/templates/nextblock-template/app/cms/components/TwoFactorReminderBanner.tsx +45 -45
  60. package/templates/nextblock-template/app/cms/components/github-connect-actions.ts +102 -102
  61. package/templates/nextblock-template/app/cms/components/system-alerts-actions.ts +31 -31
  62. package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -66
  63. package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -519
  64. package/templates/nextblock-template/app/cms/custom-blocks/components/BlockComposer.tsx +1522 -1522
  65. package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -256
  66. package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -384
  67. package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -221
  68. package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -12
  69. package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -438
  70. package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
  71. package/templates/nextblock-template/app/cms/dashboard/components/DashboardOnboarding.tsx +130 -130
  72. package/templates/nextblock-template/app/cms/import-export/ContentTransferControls.tsx +431 -391
  73. package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -226
  74. package/templates/nextblock-template/app/cms/interactions/InteractionsModerationClient.tsx +408 -408
  75. package/templates/nextblock-template/app/cms/interactions/page.tsx +51 -51
  76. package/templates/nextblock-template/app/cms/layout.tsx +73 -73
  77. package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
  78. package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
  79. package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
  80. package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -69
  81. package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +149 -158
  82. package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +101 -101
  83. package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +3 -3
  84. package/templates/nextblock-template/app/cms/pages/page.tsx +18 -17
  85. package/templates/nextblock-template/app/cms/posts/page.tsx +19 -18
  86. package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +12 -0
  87. package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
  88. package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -12
  89. package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
  90. package/templates/nextblock-template/app/cms/products/new/page.tsx +135 -135
  91. package/templates/nextblock-template/app/cms/products/page.tsx +39 -27
  92. package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
  93. package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
  94. package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -456
  95. package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -115
  96. package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -31
  97. package/templates/nextblock-template/app/cms/revisions/service.ts +19 -19
  98. package/templates/nextblock-template/app/cms/revisions/utils.ts +132 -132
  99. package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -1004
  100. package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -29
  101. package/templates/nextblock-template/app/cms/settings/bot-protection/actions.ts +93 -93
  102. package/templates/nextblock-template/app/cms/settings/bot-protection/components/BotProtectionForm.tsx +129 -129
  103. package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -24
  104. package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +497 -497
  105. package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +410 -410
  106. package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +246 -246
  107. package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +80 -80
  108. package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
  109. package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
  110. package/templates/nextblock-template/app/cms/settings/email/actions.ts +64 -64
  111. package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +181 -181
  112. package/templates/nextblock-template/app/cms/settings/email/page.tsx +28 -28
  113. package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
  114. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
  115. package/templates/nextblock-template/app/cms/settings/google-analytics/actions.ts +60 -60
  116. package/templates/nextblock-template/app/cms/settings/google-analytics/components/GoogleAnalyticsForm.tsx +129 -129
  117. package/templates/nextblock-template/app/cms/settings/google-analytics/page.tsx +26 -26
  118. package/templates/nextblock-template/app/cms/settings/languages/actions.ts +16 -16
  119. package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
  120. package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
  121. package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -21
  122. package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +20 -20
  123. package/templates/nextblock-template/app/cms/settings/logos/components/SetActiveLogoButton.tsx +42 -42
  124. package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -133
  125. package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
  126. package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -122
  127. package/templates/nextblock-template/app/cms/settings/privacy/actions.ts +52 -52
  128. package/templates/nextblock-template/app/cms/settings/privacy/components/PrivacyForm.tsx +148 -148
  129. package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +27 -27
  130. package/templates/nextblock-template/app/cms/settings/registration/actions.ts +44 -44
  131. package/templates/nextblock-template/app/cms/settings/registration/components/RegistrationForm.tsx +65 -65
  132. package/templates/nextblock-template/app/cms/settings/registration/page.tsx +27 -27
  133. package/templates/nextblock-template/app/cms/settings/security/actions.ts +284 -284
  134. package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +522 -522
  135. package/templates/nextblock-template/app/cms/settings/security/page.tsx +33 -33
  136. package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
  137. package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
  138. package/templates/nextblock-template/app/cms/users/actions.ts +222 -222
  139. package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
  140. package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +44 -44
  141. package/templates/nextblock-template/app/lib/site-settings.ts +105 -105
  142. package/templates/nextblock-template/app/lib/sitemap-utils.ts +253 -253
  143. package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +73 -73
  144. package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
  145. package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
  146. package/templates/nextblock-template/app/profile/account-data.ts +37 -37
  147. package/templates/nextblock-template/app/profile/account-links.ts +22 -22
  148. package/templates/nextblock-template/app/profile/account-types.ts +11 -11
  149. package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
  150. package/templates/nextblock-template/app/profile/orders/[id]/CustomerOrderDetailPageClient.tsx +79 -79
  151. package/templates/nextblock-template/app/profile/orders/[id]/page.tsx +32 -32
  152. package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
  153. package/templates/nextblock-template/app/profile/page.tsx +42 -42
  154. package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
  155. package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
  156. package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
  157. package/templates/nextblock-template/app/setup/SetupWizard.tsx +678 -678
  158. package/templates/nextblock-template/app/setup/layout.tsx +13 -13
  159. package/templates/nextblock-template/app/setup/page.tsx +111 -111
  160. package/templates/nextblock-template/app/sitemap.ts +130 -130
  161. package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -7
  162. package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -23
  163. package/templates/nextblock-template/components/DeferredGoogleAnalytics.tsx +70 -70
  164. package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -70
  165. package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -69
  166. package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -47
  167. package/templates/nextblock-template/components/FooterNavigation.tsx +32 -32
  168. package/templates/nextblock-template/components/GitHubLoginButton.tsx +15 -15
  169. package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -47
  170. package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
  171. package/templates/nextblock-template/components/PostCommentsSection.tsx +369 -369
  172. package/templates/nextblock-template/components/ProductReviewsSection.tsx +419 -419
  173. package/templates/nextblock-template/components/PublicEnvBootstrap.tsx +30 -30
  174. package/templates/nextblock-template/components/ResponsiveNav.tsx +14 -14
  175. package/templates/nextblock-template/components/auth/AuthBotProtection.tsx +182 -182
  176. package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -12
  177. package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -12
  178. package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -23
  179. package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +249 -249
  180. package/templates/nextblock-template/components/blocks/types.ts +7 -7
  181. package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
  182. package/templates/nextblock-template/components/form-message.tsx +32 -32
  183. package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +170 -170
  184. package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +70 -70
  185. package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -28
  186. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -166
  187. package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +464 -464
  188. package/templates/nextblock-template/components/submit-button.tsx +23 -23
  189. package/templates/nextblock-template/components/theme-switcher.tsx +8 -8
  190. package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -21
  191. package/templates/nextblock-template/context/AuthContext.tsx +23 -23
  192. package/templates/nextblock-template/context/LanguageContext.tsx +16 -16
  193. package/templates/nextblock-template/context/language-rest-client.ts +32 -32
  194. package/templates/nextblock-template/docker/db/init/99-jwt.sql +6 -6
  195. package/templates/nextblock-template/docker/db/init/99-roles.sql +25 -25
  196. package/templates/nextblock-template/docker/kong/kong.yml +112 -112
  197. package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -94
  198. package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -364
  199. package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +202 -202
  200. package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +246 -246
  201. package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +176 -176
  202. package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -146
  203. package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +1319 -1319
  204. package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -222
  205. package/templates/nextblock-template/docs/11-SELF-HOSTED-DOCKER.md +173 -173
  206. package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +170 -170
  207. package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +151 -151
  208. package/templates/nextblock-template/docs/README.md +39 -39
  209. package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12505 -12505
  210. package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -21
  211. package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -101
  212. package/templates/nextblock-template/index.d.ts +7 -7
  213. package/templates/nextblock-template/lib/app-secrets.ts +39 -39
  214. package/templates/nextblock-template/lib/auth/cookies.ts +47 -47
  215. package/templates/nextblock-template/lib/auth/crypto.ts +45 -45
  216. package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -92
  217. package/templates/nextblock-template/lib/auth/twoFactor.ts +208 -208
  218. package/templates/nextblock-template/lib/auth-redirects.ts +46 -46
  219. package/templates/nextblock-template/lib/blocks/README.md +13 -13
  220. package/templates/nextblock-template/lib/blocks/blockRegistry.ts +6 -6
  221. package/templates/nextblock-template/lib/blocks/blockTypes.ts +18 -18
  222. package/templates/nextblock-template/lib/botProtection/verify.ts +134 -134
  223. package/templates/nextblock-template/lib/cms-transfer/csv.test.ts +100 -77
  224. package/templates/nextblock-template/lib/cms-transfer/csv.ts +403 -399
  225. package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -2243
  226. package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -145
  227. package/templates/nextblock-template/lib/config/email-settings.ts +217 -217
  228. package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -87
  229. package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -178
  230. package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -140
  231. package/templates/nextblock-template/lib/custom-block-r2-upload.ts +88 -88
  232. package/templates/nextblock-template/lib/custom-block-relation-registry.ts +256 -256
  233. package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -227
  234. package/templates/nextblock-template/lib/custom-block-relations.ts +279 -279
  235. package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -14
  236. package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -172
  237. package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -213
  238. package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -22
  239. package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -193
  240. package/templates/nextblock-template/lib/email/branding-format.test.ts +133 -133
  241. package/templates/nextblock-template/lib/email/branding-format.ts +123 -123
  242. package/templates/nextblock-template/lib/email/branding.ts +76 -76
  243. package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -121
  244. package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -206
  245. package/templates/nextblock-template/lib/full-backup/server.ts +743 -743
  246. package/templates/nextblock-template/lib/logos/active-logo.ts +53 -53
  247. package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +54 -54
  248. package/templates/nextblock-template/lib/onboarding/actions.ts +31 -31
  249. package/templates/nextblock-template/lib/onboarding/status.ts +222 -222
  250. package/templates/nextblock-template/lib/posts/readTime.ts +60 -60
  251. package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -57
  252. package/templates/nextblock-template/lib/privacy/contact-emails.ts +64 -64
  253. package/templates/nextblock-template/lib/privacy/settings.ts +115 -115
  254. package/templates/nextblock-template/lib/privacy/types.ts +69 -69
  255. package/templates/nextblock-template/lib/promotions/server.test.ts +74 -74
  256. package/templates/nextblock-template/lib/promotions/server.ts +741 -741
  257. package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -142
  258. package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -255
  259. package/templates/nextblock-template/lib/search/server.ts +585 -585
  260. package/templates/nextblock-template/lib/search/types.ts +27 -27
  261. package/templates/nextblock-template/lib/setup/actions.ts +460 -460
  262. package/templates/nextblock-template/lib/setup/env-status.ts +125 -125
  263. package/templates/nextblock-template/lib/setup/env-write.ts +111 -111
  264. package/templates/nextblock-template/lib/setup/migrations-bundle.ts +37 -37
  265. package/templates/nextblock-template/lib/setup/provisioning.ts +59 -59
  266. package/templates/nextblock-template/lib/setup/schema-apply.ts +408 -408
  267. package/templates/nextblock-template/lib/setup/system-config.ts +105 -105
  268. package/templates/nextblock-template/lib/setup/types.ts +18 -18
  269. package/templates/nextblock-template/lib/site-url.ts +48 -48
  270. package/templates/nextblock-template/lib/storage/provider.ts +66 -66
  271. package/templates/nextblock-template/lib/storage/supabase-storage.ts +103 -103
  272. package/templates/nextblock-template/lib/updates/check-upstream.ts +441 -441
  273. package/templates/nextblock-template/lib/updates/github-device.ts +206 -206
  274. package/templates/nextblock-template/lib/updates/repo-identity.ts +56 -56
  275. package/templates/nextblock-template/package.json +1 -1
  276. package/templates/nextblock-template/postcss.config.js +6 -6
  277. package/templates/nextblock-template/scripts/backup.js +115 -115
  278. package/templates/nextblock-template/scripts/docker-setup.mjs +310 -310
  279. package/templates/nextblock-template/scripts/restore.js +385 -385
  280. package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +98 -98
  281. package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -62
  282. package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -537
  283. package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -58
  284. package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -188
  285. package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -123
  286. package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -133
  287. package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -65
  288. package/templates/nextblock-template/tailwind.config.js +25 -25
  289. package/templates/nextblock-template/tools/build-migrate.mjs +209 -209
  290. package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
  291. package/templates/nextblock-template/types/jsdom.d.ts +6 -6
  292. package/tsconfig.base.json +3 -3
  293. package/templates/nextblock-template/tsconfig.tsbuildinfo +0 -1
@@ -1,4 +1,4 @@
1
- import { useEffect, type DependencyList } from 'react';
1
+ import { useEffect, type DependencyList } from 'react';
2
2
 
3
3
  /**
4
4
  * Hook to handle keyboard shortcuts.
@@ -8,26 +8,26 @@ import { useEffect, type DependencyList } from 'react';
8
8
  * @param callback The function to call when the key combination is pressed
9
9
  * @param deps Dependencies array for the effect
10
10
  */
11
- export function useHotkeys(
12
- key: string,
13
- callback: (event: KeyboardEvent) => void,
14
- deps: DependencyList = [],
15
- ) {
16
- useEffect(() => {
17
- const normalizedShortcut = key.toLowerCase();
18
-
19
- const handleKeyDown = (event: KeyboardEvent) => {
20
- const isCtrl = event.ctrlKey || event.metaKey; // cmd on mac, ctrl on windows
21
- const keyLower = typeof event.key === 'string' ? event.key.toLowerCase() : '';
22
- const isSaveKey = keyLower === 's' || event.code === 'KeyS';
23
-
24
- // Check for ctrl+s / cmd+s
25
- if ((normalizedShortcut === 'ctrl+s' || normalizedShortcut === 'meta+s') && isCtrl && isSaveKey) {
26
- event.preventDefault();
27
- callback(event);
28
- }
29
- };
30
-
11
+ export function useHotkeys(
12
+ key: string,
13
+ callback: (event: KeyboardEvent) => void,
14
+ deps: DependencyList = [],
15
+ ) {
16
+ useEffect(() => {
17
+ const normalizedShortcut = key.toLowerCase();
18
+
19
+ const handleKeyDown = (event: KeyboardEvent) => {
20
+ const isCtrl = event.ctrlKey || event.metaKey; // cmd on mac, ctrl on windows
21
+ const keyLower = typeof event.key === 'string' ? event.key.toLowerCase() : '';
22
+ const isSaveKey = keyLower === 's' || event.code === 'KeyS';
23
+
24
+ // Check for ctrl+s / cmd+s
25
+ if ((normalizedShortcut === 'ctrl+s' || normalizedShortcut === 'meta+s') && isCtrl && isSaveKey) {
26
+ event.preventDefault();
27
+ callback(event);
28
+ }
29
+ };
30
+
31
31
  window.addEventListener('keydown', handleKeyDown);
32
32
  return () => window.removeEventListener('keydown', handleKeyDown);
33
33
  }, [key, ...deps]); // callback should be stable or included in deps if handled by caller
@@ -1,101 +1,101 @@
1
- 'use client';
2
-
3
- import { useEffect, useMemo, useState } from 'react';
4
- import { useLanguage } from '../context/LanguageContext';
5
- import type {
6
- GlobalSearchFilter,
7
- GlobalSearchResponse,
8
- GlobalSearchResult,
9
- } from '../lib/search/types';
10
-
11
- type SearchStatus = 'idle' | 'loading' | 'success' | 'error';
12
-
13
- export function useGlobalSearch({
14
- initialQuery = '',
15
- initialFilter = 'all',
16
- limit = 12,
17
- }: {
18
- initialQuery?: string;
19
- initialFilter?: GlobalSearchFilter;
20
- limit?: number;
21
- } = {}) {
22
- const { currentLocale } = useLanguage();
23
- const [query, setQuery] = useState(initialQuery);
24
- const [filter, setFilter] = useState<GlobalSearchFilter>(initialFilter);
25
- const [results, setResults] = useState<GlobalSearchResult[]>([]);
26
- const [counts, setCounts] = useState<GlobalSearchResponse['counts']>({
27
- all: 0,
28
- page: 0,
29
- post: 0,
30
- product: 0,
31
- });
32
- const [status, setStatus] = useState<SearchStatus>('idle');
33
-
34
- const normalizedQuery = useMemo(() => query.replace(/\s+/g, ' ').trim(), [query]);
35
- const canSearch = normalizedQuery.length >= 2;
36
-
37
- useEffect(() => {
38
- if (!canSearch) {
39
- setResults([]);
40
- setCounts({ all: 0, page: 0, post: 0, product: 0 });
41
- setStatus('idle');
42
- return;
43
- }
44
-
45
- const controller = new AbortController();
46
- const timeoutId = window.setTimeout(async () => {
47
- setStatus('loading');
48
-
49
- const params = new URLSearchParams({
50
- q: normalizedQuery,
51
- type: filter,
52
- limit: String(limit),
53
- });
54
-
55
- if (currentLocale) {
56
- params.set('locale', currentLocale);
57
- }
58
-
59
- try {
60
- const response = await fetch(`/api/search?${params.toString()}`, {
61
- signal: controller.signal,
62
- });
63
-
64
- if (!response.ok) {
65
- throw new Error(`Search request failed with ${response.status}`);
66
- }
67
-
68
- const payload = (await response.json()) as GlobalSearchResponse;
69
- setResults(payload.results);
70
- setCounts(payload.counts);
71
- setStatus('success');
72
- } catch (error) {
73
- if ((error as Error).name === 'AbortError') {
74
- return;
75
- }
76
-
77
- console.error('Global search request failed:', error);
78
- setResults([]);
79
- setCounts({ all: 0, page: 0, post: 0, product: 0 });
80
- setStatus('error');
81
- }
82
- }, 180);
83
-
84
- return () => {
85
- controller.abort();
86
- window.clearTimeout(timeoutId);
87
- };
88
- }, [canSearch, currentLocale, filter, limit, normalizedQuery]);
89
-
90
- return {
91
- query,
92
- setQuery,
93
- filter,
94
- setFilter,
95
- results,
96
- counts,
97
- status,
98
- canSearch,
99
- isLoading: status === 'loading',
100
- };
101
- }
1
+ 'use client';
2
+
3
+ import { useEffect, useMemo, useState } from 'react';
4
+ import { useLanguage } from '../context/LanguageContext';
5
+ import type {
6
+ GlobalSearchFilter,
7
+ GlobalSearchResponse,
8
+ GlobalSearchResult,
9
+ } from '../lib/search/types';
10
+
11
+ type SearchStatus = 'idle' | 'loading' | 'success' | 'error';
12
+
13
+ export function useGlobalSearch({
14
+ initialQuery = '',
15
+ initialFilter = 'all',
16
+ limit = 12,
17
+ }: {
18
+ initialQuery?: string;
19
+ initialFilter?: GlobalSearchFilter;
20
+ limit?: number;
21
+ } = {}) {
22
+ const { currentLocale } = useLanguage();
23
+ const [query, setQuery] = useState(initialQuery);
24
+ const [filter, setFilter] = useState<GlobalSearchFilter>(initialFilter);
25
+ const [results, setResults] = useState<GlobalSearchResult[]>([]);
26
+ const [counts, setCounts] = useState<GlobalSearchResponse['counts']>({
27
+ all: 0,
28
+ page: 0,
29
+ post: 0,
30
+ product: 0,
31
+ });
32
+ const [status, setStatus] = useState<SearchStatus>('idle');
33
+
34
+ const normalizedQuery = useMemo(() => query.replace(/\s+/g, ' ').trim(), [query]);
35
+ const canSearch = normalizedQuery.length >= 2;
36
+
37
+ useEffect(() => {
38
+ if (!canSearch) {
39
+ setResults([]);
40
+ setCounts({ all: 0, page: 0, post: 0, product: 0 });
41
+ setStatus('idle');
42
+ return;
43
+ }
44
+
45
+ const controller = new AbortController();
46
+ const timeoutId = window.setTimeout(async () => {
47
+ setStatus('loading');
48
+
49
+ const params = new URLSearchParams({
50
+ q: normalizedQuery,
51
+ type: filter,
52
+ limit: String(limit),
53
+ });
54
+
55
+ if (currentLocale) {
56
+ params.set('locale', currentLocale);
57
+ }
58
+
59
+ try {
60
+ const response = await fetch(`/api/search?${params.toString()}`, {
61
+ signal: controller.signal,
62
+ });
63
+
64
+ if (!response.ok) {
65
+ throw new Error(`Search request failed with ${response.status}`);
66
+ }
67
+
68
+ const payload = (await response.json()) as GlobalSearchResponse;
69
+ setResults(payload.results);
70
+ setCounts(payload.counts);
71
+ setStatus('success');
72
+ } catch (error) {
73
+ if ((error as Error).name === 'AbortError') {
74
+ return;
75
+ }
76
+
77
+ console.error('Global search request failed:', error);
78
+ setResults([]);
79
+ setCounts({ all: 0, page: 0, post: 0, product: 0 });
80
+ setStatus('error');
81
+ }
82
+ }, 180);
83
+
84
+ return () => {
85
+ controller.abort();
86
+ window.clearTimeout(timeoutId);
87
+ };
88
+ }, [canSearch, currentLocale, filter, limit, normalizedQuery]);
89
+
90
+ return {
91
+ query,
92
+ setQuery,
93
+ filter,
94
+ setFilter,
95
+ results,
96
+ counts,
97
+ status,
98
+ canSearch,
99
+ isLoading: status === 'loading',
100
+ };
101
+ }
@@ -1,7 +1,7 @@
1
- declare module '*.svg' {
2
- const content: any;
3
- export const ReactComponent: any;
4
- export default content;
5
- }
6
-
7
- declare module 'uuid';
1
+ declare module '*.svg' {
2
+ const content: any;
3
+ export const ReactComponent: any;
4
+ export default content;
5
+ }
6
+
7
+ declare module 'uuid';
@@ -1,39 +1,39 @@
1
- import 'server-only';
2
- import { createHmac } from 'node:crypto';
3
-
4
- // Resolve the app's internal shared secrets WITHOUT requiring the operator to paste
5
- // random strings at deploy time. When an explicit env var is set it always wins;
6
- // otherwise the secret is derived deterministically from the always-present Supabase
7
- // service-role key. This is what lets a one-click Vercel deploy work with zero env
8
- // input while Draft Mode and on-demand revalidation still function out of the box.
9
- //
10
- // HMAC-SHA256 is one-way, so a leaked derived secret never exposes the service-role
11
- // key. The derived value is stable for a given Supabase project; rotating the
12
- // service-role key rotates these secrets too (set the explicit env var to pin one
13
- // independently — e.g. to configure a Supabase revalidation webhook with a fixed
14
- // token). `npm run setup` still writes explicit values locally, so dev is unchanged.
15
- //
16
- // CRON_SECRET is intentionally NOT derived here: Vercel Cron injects
17
- // `Authorization: Bearer ${process.env.CRON_SECRET}` read from the env at invocation,
18
- // so a derived value could never match it. The cron routes instead treat CRON_SECRET
19
- // as optional (enforced only when set) — see app/api/cron/*/route.ts.
20
-
21
- function deriveFromServiceRole(label: string): string {
22
- // Accept the Marketplace integration's SUPABASE_SECRET_KEY alias too, so derivation
23
- // still works on a one-click deploy that only injected the new key name.
24
- const master = (
25
- process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_SECRET_KEY
26
- )?.trim();
27
- if (!master) return '';
28
- return createHmac('sha256', master).update(`nextblock:${label}`).digest('hex');
29
- }
30
-
31
- /** Secret for the programmatic Draft Mode preview entry (`/api/draft?secret=`). */
32
- export function resolveDraftModeSecret(): string {
33
- return process.env.DRAFT_MODE_SECRET?.trim() || deriveFromServiceRole('draft-mode');
34
- }
35
-
36
- /** Shared secret a Supabase webhook sends to `/api/revalidate` (`x-revalidate-secret`). */
37
- export function resolveRevalidateSecret(): string {
38
- return process.env.REVALIDATE_SECRET_TOKEN?.trim() || deriveFromServiceRole('revalidate');
39
- }
1
+ import 'server-only';
2
+ import { createHmac } from 'node:crypto';
3
+
4
+ // Resolve the app's internal shared secrets WITHOUT requiring the operator to paste
5
+ // random strings at deploy time. When an explicit env var is set it always wins;
6
+ // otherwise the secret is derived deterministically from the always-present Supabase
7
+ // service-role key. This is what lets a one-click Vercel deploy work with zero env
8
+ // input while Draft Mode and on-demand revalidation still function out of the box.
9
+ //
10
+ // HMAC-SHA256 is one-way, so a leaked derived secret never exposes the service-role
11
+ // key. The derived value is stable for a given Supabase project; rotating the
12
+ // service-role key rotates these secrets too (set the explicit env var to pin one
13
+ // independently — e.g. to configure a Supabase revalidation webhook with a fixed
14
+ // token). `npm run setup` still writes explicit values locally, so dev is unchanged.
15
+ //
16
+ // CRON_SECRET is intentionally NOT derived here: Vercel Cron injects
17
+ // `Authorization: Bearer ${process.env.CRON_SECRET}` read from the env at invocation,
18
+ // so a derived value could never match it. The cron routes instead treat CRON_SECRET
19
+ // as optional (enforced only when set) — see app/api/cron/*/route.ts.
20
+
21
+ function deriveFromServiceRole(label: string): string {
22
+ // Accept the Marketplace integration's SUPABASE_SECRET_KEY alias too, so derivation
23
+ // still works on a one-click deploy that only injected the new key name.
24
+ const master = (
25
+ process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_SECRET_KEY
26
+ )?.trim();
27
+ if (!master) return '';
28
+ return createHmac('sha256', master).update(`nextblock:${label}`).digest('hex');
29
+ }
30
+
31
+ /** Secret for the programmatic Draft Mode preview entry (`/api/draft?secret=`). */
32
+ export function resolveDraftModeSecret(): string {
33
+ return process.env.DRAFT_MODE_SECRET?.trim() || deriveFromServiceRole('draft-mode');
34
+ }
35
+
36
+ /** Shared secret a Supabase webhook sends to `/api/revalidate` (`x-revalidate-secret`). */
37
+ export function resolveRevalidateSecret(): string {
38
+ return process.env.REVALIDATE_SECRET_TOKEN?.trim() || deriveFromServiceRole('revalidate');
39
+ }
@@ -1,47 +1,47 @@
1
- // Server-only cookie helpers for the 2FA / trusted-device flow.
2
- // All three cookies are HttpOnly so they are never readable from JS.
3
- import { cookies } from 'next/headers';
4
-
5
- /** Long-lived "remember this device" token (raw token; its SHA-256 is in the DB). */
6
- export const TRUSTED_DEVICE_COOKIE = 'nb_trusted_device';
7
- /** Signed marker proving the email second factor was satisfied this session. */
8
- export const TWO_FACTOR_COOKIE = 'nb_2fa_verified';
9
- /** Short-lived flag carrying the "remember me" checkbox from login to post-2FA. */
10
- export const REMEMBER_INTENT_COOKIE = 'nb_remember_intent';
11
-
12
- const isProd = process.env.NODE_ENV === 'production';
13
-
14
- export async function setSecureCookie(
15
- name: string,
16
- value: string,
17
- maxAgeSeconds: number,
18
- ): Promise<void> {
19
- const store = await cookies();
20
- store.set({
21
- name,
22
- value,
23
- httpOnly: true,
24
- secure: isProd,
25
- sameSite: 'lax',
26
- path: '/',
27
- maxAge: maxAgeSeconds,
28
- });
29
- }
30
-
31
- export async function getCookieValue(name: string): Promise<string | null> {
32
- const store = await cookies();
33
- return store.get(name)?.value ?? null;
34
- }
35
-
36
- export async function clearCookie(name: string): Promise<void> {
37
- const store = await cookies();
38
- store.set({
39
- name,
40
- value: '',
41
- httpOnly: true,
42
- secure: isProd,
43
- sameSite: 'lax',
44
- path: '/',
45
- maxAge: 0,
46
- });
47
- }
1
+ // Server-only cookie helpers for the 2FA / trusted-device flow.
2
+ // All three cookies are HttpOnly so they are never readable from JS.
3
+ import { cookies } from 'next/headers';
4
+
5
+ /** Long-lived "remember this device" token (raw token; its SHA-256 is in the DB). */
6
+ export const TRUSTED_DEVICE_COOKIE = 'nb_trusted_device';
7
+ /** Signed marker proving the email second factor was satisfied this session. */
8
+ export const TWO_FACTOR_COOKIE = 'nb_2fa_verified';
9
+ /** Short-lived flag carrying the "remember me" checkbox from login to post-2FA. */
10
+ export const REMEMBER_INTENT_COOKIE = 'nb_remember_intent';
11
+
12
+ const isProd = process.env.NODE_ENV === 'production';
13
+
14
+ export async function setSecureCookie(
15
+ name: string,
16
+ value: string,
17
+ maxAgeSeconds: number,
18
+ ): Promise<void> {
19
+ const store = await cookies();
20
+ store.set({
21
+ name,
22
+ value,
23
+ httpOnly: true,
24
+ secure: isProd,
25
+ sameSite: 'lax',
26
+ path: '/',
27
+ maxAge: maxAgeSeconds,
28
+ });
29
+ }
30
+
31
+ export async function getCookieValue(name: string): Promise<string | null> {
32
+ const store = await cookies();
33
+ return store.get(name)?.value ?? null;
34
+ }
35
+
36
+ export async function clearCookie(name: string): Promise<void> {
37
+ const store = await cookies();
38
+ store.set({
39
+ name,
40
+ value: '',
41
+ httpOnly: true,
42
+ secure: isProd,
43
+ sameSite: 'lax',
44
+ path: '/',
45
+ maxAge: 0,
46
+ });
47
+ }
@@ -1,45 +1,45 @@
1
- // Server-only crypto helpers for 2FA tokens, trusted-device hashing, and the
2
- // signed "second factor satisfied" session marker. Uses Node's crypto module.
3
- import crypto from 'node:crypto';
4
-
5
- /** SHA-256 hex digest. Used to store device/code hashes (never the raw value). */
6
- export function sha256Hex(input: string): string {
7
- return crypto.createHash('sha256').update(input).digest('hex');
8
- }
9
-
10
- /** Cryptographically random URL-safe token (default 32 bytes -> 43 chars). */
11
- export function randomToken(bytes = 32): string {
12
- return crypto.randomBytes(bytes).toString('base64url');
13
- }
14
-
15
- /** Random fixed-length numeric code, e.g. a 6-digit email 2FA code. */
16
- export function generateNumericCode(digits = 6): string {
17
- const max = 10 ** digits;
18
- return crypto.randomInt(0, max).toString().padStart(digits, '0');
19
- }
20
-
21
- function getSecret(): string {
22
- // Dedicated secret if provided, otherwise fall back to the service-role key
23
- // (server-only, never shipped to the client).
24
- const secret =
25
- process.env.NB_2FA_SECRET ||
26
- process.env.SUPABASE_SERVICE_ROLE_KEY ||
27
- process.env.SUPABASE_SECRET_KEY;
28
- if (!secret) {
29
- throw new Error('Missing NB_2FA_SECRET / SUPABASE_SERVICE_ROLE_KEY for 2FA signing.');
30
- }
31
- return secret;
32
- }
33
-
34
- /** HMAC-SHA256 signature (base64url) of an arbitrary payload string. */
35
- export function hmacSign(payload: string): string {
36
- return crypto.createHmac('sha256', getSecret()).update(payload).digest('base64url');
37
- }
38
-
39
- /** Constant-time string comparison that never throws on length mismatch. */
40
- export function safeEqual(a: string, b: string): boolean {
41
- const ab = Buffer.from(a);
42
- const bb = Buffer.from(b);
43
- if (ab.length !== bb.length) return false;
44
- return crypto.timingSafeEqual(ab, bb);
45
- }
1
+ // Server-only crypto helpers for 2FA tokens, trusted-device hashing, and the
2
+ // signed "second factor satisfied" session marker. Uses Node's crypto module.
3
+ import crypto from 'node:crypto';
4
+
5
+ /** SHA-256 hex digest. Used to store device/code hashes (never the raw value). */
6
+ export function sha256Hex(input: string): string {
7
+ return crypto.createHash('sha256').update(input).digest('hex');
8
+ }
9
+
10
+ /** Cryptographically random URL-safe token (default 32 bytes -> 43 chars). */
11
+ export function randomToken(bytes = 32): string {
12
+ return crypto.randomBytes(bytes).toString('base64url');
13
+ }
14
+
15
+ /** Random fixed-length numeric code, e.g. a 6-digit email 2FA code. */
16
+ export function generateNumericCode(digits = 6): string {
17
+ const max = 10 ** digits;
18
+ return crypto.randomInt(0, max).toString().padStart(digits, '0');
19
+ }
20
+
21
+ function getSecret(): string {
22
+ // Dedicated secret if provided, otherwise fall back to the service-role key
23
+ // (server-only, never shipped to the client).
24
+ const secret =
25
+ process.env.NB_2FA_SECRET ||
26
+ process.env.SUPABASE_SERVICE_ROLE_KEY ||
27
+ process.env.SUPABASE_SECRET_KEY;
28
+ if (!secret) {
29
+ throw new Error('Missing NB_2FA_SECRET / SUPABASE_SERVICE_ROLE_KEY for 2FA signing.');
30
+ }
31
+ return secret;
32
+ }
33
+
34
+ /** HMAC-SHA256 signature (base64url) of an arbitrary payload string. */
35
+ export function hmacSign(payload: string): string {
36
+ return crypto.createHmac('sha256', getSecret()).update(payload).digest('base64url');
37
+ }
38
+
39
+ /** Constant-time string comparison that never throws on length mismatch. */
40
+ export function safeEqual(a: string, b: string): boolean {
41
+ const ab = Buffer.from(a);
42
+ const bb = Buffer.from(b);
43
+ if (ab.length !== bb.length) return false;
44
+ return crypto.timingSafeEqual(ab, bb);
45
+ }