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.
- package/docker-template/.dockerignore +23 -23
- package/docker-template/.env.docker.example +69 -69
- package/docker-template/docker/db/init/99-jwt.sql +6 -6
- package/docker-template/docker/db/init/99-roles.sql +25 -25
- package/docker-template/docker/kong/kong.yml +112 -112
- package/docker-template/scripts/docker-setup.mjs +310 -310
- package/libs/db/tsconfig.lib.json +3 -3
- package/libs/editor/tsconfig.lib.json +3 -3
- package/libs/ui/tsconfig.lib.json +3 -3
- package/libs/utils/tsconfig.json +3 -3
- package/package.json +1 -1
- package/project.json +19 -19
- package/templates/nextblock-template/.browserslistrc +11 -11
- package/templates/nextblock-template/.dockerignore +23 -23
- package/templates/nextblock-template/README.md +34 -34
- package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -9
- package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +27 -27
- package/templates/nextblock-template/app/(auth-pages)/sign-up/SignUpForm.tsx +141 -141
- package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +46 -46
- package/templates/nextblock-template/app/(auth-pages)/two-factor/actions.ts +91 -91
- package/templates/nextblock-template/app/(auth-pages)/two-factor/components/TwoFactorForm.tsx +123 -123
- package/templates/nextblock-template/app/(auth-pages)/two-factor/page.tsx +51 -51
- package/templates/nextblock-template/app/ToasterProvider.tsx +17 -17
- package/templates/nextblock-template/app/[slug]/pageClientActions.ts +7 -7
- package/templates/nextblock-template/app/actions/consent.ts +57 -57
- package/templates/nextblock-template/app/actions/interactions.test.ts +301 -301
- package/templates/nextblock-template/app/actions/interactions.ts +373 -373
- package/templates/nextblock-template/app/actions/postActions.ts +146 -146
- package/templates/nextblock-template/app/actions/twoFactorEmail.ts +22 -22
- package/templates/nextblock-template/app/api/ai/cortex/build-widget/route.ts +153 -153
- package/templates/nextblock-template/app/api/ai/generate-blocks/route.ts +96 -96
- package/templates/nextblock-template/app/api/ai/global-agent/route.ts +964 -964
- package/templates/nextblock-template/app/api/brand/email-logo/route.ts +48 -48
- package/templates/nextblock-template/app/api/cms/check-updates/route.ts +44 -44
- package/templates/nextblock-template/app/api/cms/full-backup/export/route.ts +33 -33
- package/templates/nextblock-template/app/api/cms/full-backup/restore/route.ts +63 -63
- package/templates/nextblock-template/app/api/cron/reset-sandbox/route.ts +3490 -3490
- package/templates/nextblock-template/app/api/cron/reset-sandbox/sandboxResetSql.ts +5597 -5597
- package/templates/nextblock-template/app/api/cron/sync-currencies/route.ts +39 -39
- package/templates/nextblock-template/app/api/custom-blocks/db-relations/route.ts +92 -92
- package/templates/nextblock-template/app/api/custom-blocks/editor-definitions/route.ts +43 -43
- package/templates/nextblock-template/app/api/media/library/route.ts +69 -69
- package/templates/nextblock-template/app/api/media/r2-presigned/route.ts +53 -53
- package/templates/nextblock-template/app/api/media/record/route.ts +160 -160
- package/templates/nextblock-template/app/api/search/route.ts +43 -43
- package/templates/nextblock-template/app/article/[slug]/PostClientContent.tsx +441 -441
- package/templates/nextblock-template/app/auth/callback/route.ts +31 -31
- package/templates/nextblock-template/app/cart/page.tsx +7 -7
- package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -160
- package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +149 -149
- package/templates/nextblock-template/app/cms/blocks/editors/DynamicCustomBlockEditor.tsx +167 -167
- package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +29 -29
- package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +90 -90
- package/templates/nextblock-template/app/cms/components/ConnectGitHubButton.tsx +122 -122
- package/templates/nextblock-template/app/cms/components/CortexAiPageContext.tsx +58 -58
- package/templates/nextblock-template/app/cms/components/FeatureImageField.tsx +244 -244
- package/templates/nextblock-template/app/cms/components/FeedbackModal.tsx +36 -36
- package/templates/nextblock-template/app/cms/components/SystemAlertsBanner.tsx +112 -112
- package/templates/nextblock-template/app/cms/components/TwoFactorReminderBanner.tsx +45 -45
- package/templates/nextblock-template/app/cms/components/github-connect-actions.ts +102 -102
- package/templates/nextblock-template/app/cms/components/system-alerts-actions.ts +31 -31
- package/templates/nextblock-template/app/cms/custom-blocks/[id]/edit/page.tsx +66 -66
- package/templates/nextblock-template/app/cms/custom-blocks/actions.ts +519 -519
- package/templates/nextblock-template/app/cms/custom-blocks/components/BlockComposer.tsx +1522 -1522
- package/templates/nextblock-template/app/cms/custom-blocks/components/BlocksLibraryTransferControls.tsx +256 -256
- package/templates/nextblock-template/app/cms/custom-blocks/components/DBRelationSelect.tsx +384 -384
- package/templates/nextblock-template/app/cms/custom-blocks/components/ImageR2Picker.tsx +221 -221
- package/templates/nextblock-template/app/cms/custom-blocks/new/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/custom-blocks/page.tsx +438 -438
- package/templates/nextblock-template/app/cms/dashboard/actions.ts +228 -228
- package/templates/nextblock-template/app/cms/dashboard/components/DashboardOnboarding.tsx +130 -130
- package/templates/nextblock-template/app/cms/import-export/ContentTransferControls.tsx +431 -391
- package/templates/nextblock-template/app/cms/import-export/actions.ts +226 -226
- package/templates/nextblock-template/app/cms/interactions/InteractionsModerationClient.tsx +408 -408
- package/templates/nextblock-template/app/cms/interactions/page.tsx +51 -51
- package/templates/nextblock-template/app/cms/layout.tsx +73 -73
- package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -273
- package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -122
- package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +26 -26
- package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +69 -69
- package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +149 -158
- package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +101 -101
- package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +3 -3
- package/templates/nextblock-template/app/cms/pages/page.tsx +18 -17
- package/templates/nextblock-template/app/cms/posts/page.tsx +19 -18
- package/templates/nextblock-template/app/cms/products/[id]/edit/page.tsx +12 -0
- package/templates/nextblock-template/app/cms/products/attributes/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/products/categories/page.tsx +12 -12
- package/templates/nextblock-template/app/cms/products/inventory/page.tsx +13 -13
- package/templates/nextblock-template/app/cms/products/new/page.tsx +135 -135
- package/templates/nextblock-template/app/cms/products/page.tsx +39 -27
- package/templates/nextblock-template/app/cms/products/productFormData.ts +133 -133
- package/templates/nextblock-template/app/cms/products/settings/page.tsx +5 -5
- package/templates/nextblock-template/app/cms/promotions/PromotionsWorkspace.tsx +456 -456
- package/templates/nextblock-template/app/cms/promotions/actions.ts +115 -115
- package/templates/nextblock-template/app/cms/promotions/page.tsx +31 -31
- package/templates/nextblock-template/app/cms/revisions/service.ts +19 -19
- package/templates/nextblock-template/app/cms/revisions/utils.ts +132 -132
- package/templates/nextblock-template/app/cms/settings/backup-restore/BackupRestoreWorkspace.tsx +1004 -1004
- package/templates/nextblock-template/app/cms/settings/backup-restore/page.tsx +29 -29
- package/templates/nextblock-template/app/cms/settings/bot-protection/actions.ts +93 -93
- package/templates/nextblock-template/app/cms/settings/bot-protection/components/BotProtectionForm.tsx +129 -129
- package/templates/nextblock-template/app/cms/settings/bot-protection/page.tsx +24 -24
- package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +497 -497
- package/templates/nextblock-template/app/cms/settings/cortex-ai/StoredCortexAiSettingsClient.tsx +410 -410
- package/templates/nextblock-template/app/cms/settings/cortex-ai/actions.ts +246 -246
- package/templates/nextblock-template/app/cms/settings/cortex-ai/page.tsx +80 -80
- package/templates/nextblock-template/app/cms/settings/currencies/actions.ts +331 -331
- package/templates/nextblock-template/app/cms/settings/currencies/page.tsx +494 -494
- package/templates/nextblock-template/app/cms/settings/email/actions.ts +64 -64
- package/templates/nextblock-template/app/cms/settings/email/components/EmailForm.tsx +181 -181
- package/templates/nextblock-template/app/cms/settings/email/page.tsx +28 -28
- package/templates/nextblock-template/app/cms/settings/extra-translations/ExtraTranslationsWorkspace.tsx +767 -767
- package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +93 -93
- package/templates/nextblock-template/app/cms/settings/google-analytics/actions.ts +60 -60
- package/templates/nextblock-template/app/cms/settings/google-analytics/components/GoogleAnalyticsForm.tsx +129 -129
- package/templates/nextblock-template/app/cms/settings/google-analytics/page.tsx +26 -26
- package/templates/nextblock-template/app/cms/settings/languages/actions.ts +16 -16
- package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +7 -7
- package/templates/nextblock-template/app/cms/settings/logos/components/BrandingSettingsForm.tsx +339 -339
- package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +21 -21
- package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +20 -20
- package/templates/nextblock-template/app/cms/settings/logos/components/SetActiveLogoButton.tsx +42 -42
- package/templates/nextblock-template/app/cms/settings/logos/components/SiteSeoSettingsForm.tsx +133 -133
- package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +8 -8
- package/templates/nextblock-template/app/cms/settings/packages/package-card.tsx +122 -122
- package/templates/nextblock-template/app/cms/settings/privacy/actions.ts +52 -52
- package/templates/nextblock-template/app/cms/settings/privacy/components/PrivacyForm.tsx +148 -148
- package/templates/nextblock-template/app/cms/settings/privacy/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/registration/actions.ts +44 -44
- package/templates/nextblock-template/app/cms/settings/registration/components/RegistrationForm.tsx +65 -65
- package/templates/nextblock-template/app/cms/settings/registration/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/security/actions.ts +284 -284
- package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +522 -522
- package/templates/nextblock-template/app/cms/settings/security/page.tsx +33 -33
- package/templates/nextblock-template/app/cms/settings/taxes/page.tsx +21 -21
- package/templates/nextblock-template/app/cms/shipping/page.tsx +20 -20
- package/templates/nextblock-template/app/cms/users/actions.ts +222 -222
- package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +12 -12
- package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +44 -44
- package/templates/nextblock-template/app/lib/site-settings.ts +105 -105
- package/templates/nextblock-template/app/lib/sitemap-utils.ts +253 -253
- package/templates/nextblock-template/app/profile/ProfileAccountSidebar.tsx +73 -73
- package/templates/nextblock-template/app/profile/ProfilePageHeader.tsx +16 -16
- package/templates/nextblock-template/app/profile/ProfilePageMissingState.tsx +9 -9
- package/templates/nextblock-template/app/profile/account-data.ts +37 -37
- package/templates/nextblock-template/app/profile/account-links.ts +22 -22
- package/templates/nextblock-template/app/profile/account-types.ts +11 -11
- package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
- package/templates/nextblock-template/app/profile/orders/[id]/CustomerOrderDetailPageClient.tsx +79 -79
- package/templates/nextblock-template/app/profile/orders/[id]/page.tsx +32 -32
- package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
- package/templates/nextblock-template/app/profile/page.tsx +42 -42
- package/templates/nextblock-template/app/profile/password/PasswordSettingsPageClient.tsx +128 -128
- package/templates/nextblock-template/app/profile/password/actions.ts +59 -59
- package/templates/nextblock-template/app/profile/password/page.tsx +27 -27
- package/templates/nextblock-template/app/setup/SetupWizard.tsx +678 -678
- package/templates/nextblock-template/app/setup/layout.tsx +13 -13
- package/templates/nextblock-template/app/setup/page.tsx +111 -111
- package/templates/nextblock-template/app/sitemap.ts +130 -130
- package/templates/nextblock-template/components/CartDrawerLoader.tsx +7 -7
- package/templates/nextblock-template/components/DeferredCartDrawer.tsx +23 -23
- package/templates/nextblock-template/components/DeferredGoogleAnalytics.tsx +70 -70
- package/templates/nextblock-template/components/DeferredGoogleTagManager.tsx +70 -70
- package/templates/nextblock-template/components/DeferredSpeedInsights.tsx +69 -69
- package/templates/nextblock-template/components/FeatureImageHero.tsx +47 -47
- package/templates/nextblock-template/components/FooterNavigation.tsx +32 -32
- package/templates/nextblock-template/components/GitHubLoginButton.tsx +15 -15
- package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -47
- package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
- package/templates/nextblock-template/components/PostCommentsSection.tsx +369 -369
- package/templates/nextblock-template/components/ProductReviewsSection.tsx +419 -419
- package/templates/nextblock-template/components/PublicEnvBootstrap.tsx +30 -30
- package/templates/nextblock-template/components/ResponsiveNav.tsx +14 -14
- package/templates/nextblock-template/components/auth/AuthBotProtection.tsx +182 -182
- package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +12 -12
- package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +12 -12
- package/templates/nextblock-template/components/blocks/ecommerceRendererLoaders.ts +23 -23
- package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +249 -249
- package/templates/nextblock-template/components/blocks/types.ts +7 -7
- package/templates/nextblock-template/components/env-var-warning.tsx +3 -3
- package/templates/nextblock-template/components/form-message.tsx +32 -32
- package/templates/nextblock-template/components/privacy/ConsentBanner.tsx +170 -170
- package/templates/nextblock-template/components/privacy/ConsentGatedAnalytics.tsx +70 -70
- package/templates/nextblock-template/components/renderers/CachedDynamicLayoutEngine.tsx +28 -28
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.test.tsx +166 -166
- package/templates/nextblock-template/components/renderers/DynamicLayoutEngine.tsx +464 -464
- package/templates/nextblock-template/components/submit-button.tsx +23 -23
- package/templates/nextblock-template/components/theme-switcher.tsx +8 -8
- package/templates/nextblock-template/components/visual-editing/DeferredVisualEditing.tsx +21 -21
- package/templates/nextblock-template/context/AuthContext.tsx +23 -23
- package/templates/nextblock-template/context/LanguageContext.tsx +16 -16
- package/templates/nextblock-template/context/language-rest-client.ts +32 -32
- package/templates/nextblock-template/docker/db/init/99-jwt.sql +6 -6
- package/templates/nextblock-template/docker/db/init/99-roles.sql +25 -25
- package/templates/nextblock-template/docker/kong/kong.yml +112 -112
- package/templates/nextblock-template/docs/01-PROJECT-OVERVIEW.md +94 -94
- package/templates/nextblock-template/docs/02-ECOMMERCE-CAPABILITIES.md +364 -364
- package/templates/nextblock-template/docs/03-CMS-AND-EDITOR.md +202 -202
- package/templates/nextblock-template/docs/04-DATABASE-AND-AUTH.md +246 -246
- package/templates/nextblock-template/docs/06-CLI-AND-SCAFFOLDING.md +176 -176
- package/templates/nextblock-template/docs/07-BLOCK-SDK-AND-EXTENSIBILITY.md +146 -146
- package/templates/nextblock-template/docs/08-NEXTBLOCK-CORTEX-AI-ARCHITECTURE.md +1319 -1319
- package/templates/nextblock-template/docs/10-CUSTOM-BLOCKS.md +222 -222
- package/templates/nextblock-template/docs/11-SELF-HOSTED-DOCKER.md +173 -173
- package/templates/nextblock-template/docs/12-VERCEL-DEPLOYMENT.md +170 -170
- package/templates/nextblock-template/docs/13-STAYING-UP-TO-DATE.md +151 -151
- package/templates/nextblock-template/docs/README.md +39 -39
- package/templates/nextblock-template/docs/TECHNICAL_SPECIFICATION.md +12505 -12505
- package/templates/nextblock-template/hooks/use-hotkeys.ts +21 -21
- package/templates/nextblock-template/hooks/useGlobalSearch.ts +101 -101
- package/templates/nextblock-template/index.d.ts +7 -7
- package/templates/nextblock-template/lib/app-secrets.ts +39 -39
- package/templates/nextblock-template/lib/auth/cookies.ts +47 -47
- package/templates/nextblock-template/lib/auth/crypto.ts +45 -45
- package/templates/nextblock-template/lib/auth/trustedDevices.ts +92 -92
- package/templates/nextblock-template/lib/auth/twoFactor.ts +208 -208
- package/templates/nextblock-template/lib/auth-redirects.ts +46 -46
- package/templates/nextblock-template/lib/blocks/README.md +13 -13
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +6 -6
- package/templates/nextblock-template/lib/blocks/blockTypes.ts +18 -18
- package/templates/nextblock-template/lib/botProtection/verify.ts +134 -134
- package/templates/nextblock-template/lib/cms-transfer/csv.test.ts +100 -77
- package/templates/nextblock-template/lib/cms-transfer/csv.ts +403 -399
- package/templates/nextblock-template/lib/cms-transfer/server.ts +2243 -2243
- package/templates/nextblock-template/lib/cms-transfer/types.ts +145 -145
- package/templates/nextblock-template/lib/config/email-settings.ts +217 -217
- package/templates/nextblock-template/lib/custom-block-definitions.ts +87 -87
- package/templates/nextblock-template/lib/custom-block-r2-upload-shared.ts +178 -178
- package/templates/nextblock-template/lib/custom-block-r2-upload.test.ts +140 -140
- package/templates/nextblock-template/lib/custom-block-r2-upload.ts +88 -88
- package/templates/nextblock-template/lib/custom-block-relation-registry.ts +256 -256
- package/templates/nextblock-template/lib/custom-block-relations.test.ts +227 -227
- package/templates/nextblock-template/lib/custom-block-relations.ts +279 -279
- package/templates/nextblock-template/lib/custom-block-safelist.ts +14 -14
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.test.ts +172 -172
- package/templates/nextblock-template/lib/editor/dynamic-extension-core.ts +213 -213
- package/templates/nextblock-template/lib/editor/dynamic-extension-loader.ts +22 -22
- package/templates/nextblock-template/lib/editor/dynamic-extensions.tsx +193 -193
- package/templates/nextblock-template/lib/email/branding-format.test.ts +133 -133
- package/templates/nextblock-template/lib/email/branding-format.ts +123 -123
- package/templates/nextblock-template/lib/email/branding.ts +76 -76
- package/templates/nextblock-template/lib/full-backup/manifest.test.ts +121 -121
- package/templates/nextblock-template/lib/full-backup/manifest.ts +206 -206
- package/templates/nextblock-template/lib/full-backup/server.ts +743 -743
- package/templates/nextblock-template/lib/logos/active-logo.ts +53 -53
- package/templates/nextblock-template/lib/media/resolveMediaUrl.ts +54 -54
- package/templates/nextblock-template/lib/onboarding/actions.ts +31 -31
- package/templates/nextblock-template/lib/onboarding/status.ts +222 -222
- package/templates/nextblock-template/lib/posts/readTime.ts +60 -60
- package/templates/nextblock-template/lib/privacy/consent-client.ts +57 -57
- package/templates/nextblock-template/lib/privacy/contact-emails.ts +64 -64
- package/templates/nextblock-template/lib/privacy/settings.ts +115 -115
- package/templates/nextblock-template/lib/privacy/types.ts +69 -69
- package/templates/nextblock-template/lib/promotions/server.test.ts +74 -74
- package/templates/nextblock-template/lib/promotions/server.ts +741 -741
- package/templates/nextblock-template/lib/resolve-block-relations.test.ts +142 -142
- package/templates/nextblock-template/lib/resolve-block-relations.ts +255 -255
- package/templates/nextblock-template/lib/search/server.ts +585 -585
- package/templates/nextblock-template/lib/search/types.ts +27 -27
- package/templates/nextblock-template/lib/setup/actions.ts +460 -460
- package/templates/nextblock-template/lib/setup/env-status.ts +125 -125
- package/templates/nextblock-template/lib/setup/env-write.ts +111 -111
- package/templates/nextblock-template/lib/setup/migrations-bundle.ts +37 -37
- package/templates/nextblock-template/lib/setup/provisioning.ts +59 -59
- package/templates/nextblock-template/lib/setup/schema-apply.ts +408 -408
- package/templates/nextblock-template/lib/setup/system-config.ts +105 -105
- package/templates/nextblock-template/lib/setup/types.ts +18 -18
- package/templates/nextblock-template/lib/site-url.ts +48 -48
- package/templates/nextblock-template/lib/storage/provider.ts +66 -66
- package/templates/nextblock-template/lib/storage/supabase-storage.ts +103 -103
- package/templates/nextblock-template/lib/updates/check-upstream.ts +441 -441
- package/templates/nextblock-template/lib/updates/github-device.ts +206 -206
- package/templates/nextblock-template/lib/updates/repo-identity.ts +56 -56
- package/templates/nextblock-template/package.json +1 -1
- package/templates/nextblock-template/postcss.config.js +6 -6
- package/templates/nextblock-template/scripts/backup.js +115 -115
- package/templates/nextblock-template/scripts/docker-setup.mjs +310 -310
- package/templates/nextblock-template/scripts/restore.js +385 -385
- package/templates/nextblock-template/scripts/verify-cortex-ai-build-widget.tsx +98 -98
- package/templates/nextblock-template/scripts/verify-cortex-ai-generate-blocks.ts +62 -62
- package/templates/nextblock-template/scripts/verify-cortex-ai-global-tools.ts +537 -537
- package/templates/nextblock-template/scripts/verify-cortex-ai-routing.ts +58 -58
- package/templates/nextblock-template/scripts/verify-custom-block-definitions.ts +188 -188
- package/templates/nextblock-template/scripts/verify-dynamic-custom-block-extensions.ts +123 -123
- package/templates/nextblock-template/scripts/verify-dynamic-layout-engine.tsx +133 -133
- package/templates/nextblock-template/scripts/verify-milestone-2-custom-blocks.ts +65 -65
- package/templates/nextblock-template/tailwind.config.js +25 -25
- package/templates/nextblock-template/tools/build-migrate.mjs +209 -209
- package/templates/nextblock-template/tools/configure-supabase-auth.js +282 -282
- package/templates/nextblock-template/types/jsdom.d.ts +6 -6
- package/tsconfig.base.json +3 -3
- package/templates/nextblock-template/tsconfig.tsbuildinfo +0 -1
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
import { createClient, verifyPackageOnline } from "@nextblock-cms/db/server";
|
|
2
|
-
import { redirect } from "next/navigation";
|
|
3
|
-
|
|
4
|
-
import { BackupRestoreWorkspace } from "./BackupRestoreWorkspace";
|
|
5
|
-
|
|
6
|
-
export default async function BackupRestorePage() {
|
|
7
|
-
const supabase = createClient();
|
|
8
|
-
const {
|
|
9
|
-
data: { user },
|
|
10
|
-
} = await supabase.auth.getUser();
|
|
11
|
-
|
|
12
|
-
if (!user) {
|
|
13
|
-
redirect("/sign-in?redirect=/cms/settings/backup-restore");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
const { data: profile } = await supabase
|
|
17
|
-
.from("profiles")
|
|
18
|
-
.select("role")
|
|
19
|
-
.eq("id", user.id)
|
|
20
|
-
.single();
|
|
21
|
-
|
|
22
|
-
if (profile?.role !== "ADMIN") {
|
|
23
|
-
redirect("/unauthorized?reason=admin_required");
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const isEcommerceActive = await verifyPackageOnline("ecommerce").catch(() => false);
|
|
27
|
-
|
|
28
|
-
return <BackupRestoreWorkspace isEcommerceActive={isEcommerceActive} />;
|
|
29
|
-
}
|
|
1
|
+
import { createClient, verifyPackageOnline } from "@nextblock-cms/db/server";
|
|
2
|
+
import { redirect } from "next/navigation";
|
|
3
|
+
|
|
4
|
+
import { BackupRestoreWorkspace } from "./BackupRestoreWorkspace";
|
|
5
|
+
|
|
6
|
+
export default async function BackupRestorePage() {
|
|
7
|
+
const supabase = createClient();
|
|
8
|
+
const {
|
|
9
|
+
data: { user },
|
|
10
|
+
} = await supabase.auth.getUser();
|
|
11
|
+
|
|
12
|
+
if (!user) {
|
|
13
|
+
redirect("/sign-in?redirect=/cms/settings/backup-restore");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const { data: profile } = await supabase
|
|
17
|
+
.from("profiles")
|
|
18
|
+
.select("role")
|
|
19
|
+
.eq("id", user.id)
|
|
20
|
+
.single();
|
|
21
|
+
|
|
22
|
+
if (profile?.role !== "ADMIN") {
|
|
23
|
+
redirect("/unauthorized?reason=admin_required");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const isEcommerceActive = await verifyPackageOnline("ecommerce").catch(() => false);
|
|
27
|
+
|
|
28
|
+
return <BackupRestoreWorkspace isEcommerceActive={isEcommerceActive} />;
|
|
29
|
+
}
|
|
@@ -1,93 +1,93 @@
|
|
|
1
|
-
// app/cms/settings/bot-protection/actions.ts
|
|
2
|
-
'use server';
|
|
3
|
-
|
|
4
|
-
import { createClient } from '@nextblock-cms/db/server';
|
|
5
|
-
import { revalidatePath } from 'next/cache';
|
|
6
|
-
|
|
7
|
-
export type BotProtectionSettings = {
|
|
8
|
-
provider: 'none' | 'turnstile' | 'recaptcha';
|
|
9
|
-
siteKey: string;
|
|
10
|
-
secretKey?: string;
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
export async function getBotProtectionSettings(): Promise<BotProtectionSettings> {
|
|
14
|
-
const supabase = createClient();
|
|
15
|
-
|
|
16
|
-
// Fetch public settings
|
|
17
|
-
const { data: publicData } = await supabase
|
|
18
|
-
.from('site_settings')
|
|
19
|
-
.select('value')
|
|
20
|
-
.eq('key', 'bot_protection_public')
|
|
21
|
-
.maybeSingle();
|
|
22
|
-
|
|
23
|
-
// Fetch secret settings (only accessible by ADMIN role due to our RLS policy)
|
|
24
|
-
const { data: secretData } = await supabase
|
|
25
|
-
.from('site_settings')
|
|
26
|
-
.select('value')
|
|
27
|
-
.eq('key', 'bot_protection_secret')
|
|
28
|
-
.maybeSingle();
|
|
29
|
-
|
|
30
|
-
const publicVal = (publicData?.value || {}) as Record<string, any>;
|
|
31
|
-
const secretVal = (secretData?.value || {}) as Record<string, any>;
|
|
32
|
-
|
|
33
|
-
return {
|
|
34
|
-
provider: (publicVal.provider as any) || 'none',
|
|
35
|
-
siteKey: publicVal.siteKey || '',
|
|
36
|
-
secretKey: secretVal.secretKey || '',
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export async function updateBotProtectionSettings(formData: FormData) {
|
|
41
|
-
const supabase = createClient();
|
|
42
|
-
|
|
43
|
-
// Verify auth and role
|
|
44
|
-
const { data: { user } } = await supabase.auth.getUser();
|
|
45
|
-
if (!user) {
|
|
46
|
-
throw new Error('You must be logged in to update settings.');
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const { data: profile, error: profileError } = await supabase
|
|
50
|
-
.from('profiles')
|
|
51
|
-
.select('role')
|
|
52
|
-
.eq('id', user.id)
|
|
53
|
-
.single();
|
|
54
|
-
|
|
55
|
-
if (profileError || !profile || profile.role !== 'ADMIN') {
|
|
56
|
-
throw new Error('You do not have permission to perform this action.');
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
const provider = formData.get('provider') as 'none' | 'turnstile' | 'recaptcha';
|
|
60
|
-
const siteKey = formData.get('siteKey') as string;
|
|
61
|
-
const secretKey = formData.get('secretKey') as string;
|
|
62
|
-
|
|
63
|
-
// Update public settings (provider and siteKey)
|
|
64
|
-
const { error: publicError } = await supabase
|
|
65
|
-
.from('site_settings')
|
|
66
|
-
.upsert({
|
|
67
|
-
key: 'bot_protection_public',
|
|
68
|
-
value: { provider, siteKey },
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
if (publicError) {
|
|
72
|
-
console.error('Error updating public bot protection settings:', publicError);
|
|
73
|
-
throw new Error('Failed to update bot protection settings.');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Update secret settings (secretKey)
|
|
77
|
-
const { error: secretError } = await supabase
|
|
78
|
-
.from('site_settings')
|
|
79
|
-
.upsert({
|
|
80
|
-
key: 'bot_protection_secret',
|
|
81
|
-
value: { secretKey },
|
|
82
|
-
});
|
|
83
|
-
|
|
84
|
-
if (secretError) {
|
|
85
|
-
console.error('Error updating secret bot protection settings:', secretError);
|
|
86
|
-
throw new Error('Failed to update bot protection secrets.');
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Revalidate root layout so scripts update instantly
|
|
90
|
-
revalidatePath('/', 'layout');
|
|
91
|
-
|
|
92
|
-
return { success: true, message: 'Bot protection settings updated successfully.' };
|
|
93
|
-
}
|
|
1
|
+
// app/cms/settings/bot-protection/actions.ts
|
|
2
|
+
'use server';
|
|
3
|
+
|
|
4
|
+
import { createClient } from '@nextblock-cms/db/server';
|
|
5
|
+
import { revalidatePath } from 'next/cache';
|
|
6
|
+
|
|
7
|
+
export type BotProtectionSettings = {
|
|
8
|
+
provider: 'none' | 'turnstile' | 'recaptcha';
|
|
9
|
+
siteKey: string;
|
|
10
|
+
secretKey?: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export async function getBotProtectionSettings(): Promise<BotProtectionSettings> {
|
|
14
|
+
const supabase = createClient();
|
|
15
|
+
|
|
16
|
+
// Fetch public settings
|
|
17
|
+
const { data: publicData } = await supabase
|
|
18
|
+
.from('site_settings')
|
|
19
|
+
.select('value')
|
|
20
|
+
.eq('key', 'bot_protection_public')
|
|
21
|
+
.maybeSingle();
|
|
22
|
+
|
|
23
|
+
// Fetch secret settings (only accessible by ADMIN role due to our RLS policy)
|
|
24
|
+
const { data: secretData } = await supabase
|
|
25
|
+
.from('site_settings')
|
|
26
|
+
.select('value')
|
|
27
|
+
.eq('key', 'bot_protection_secret')
|
|
28
|
+
.maybeSingle();
|
|
29
|
+
|
|
30
|
+
const publicVal = (publicData?.value || {}) as Record<string, any>;
|
|
31
|
+
const secretVal = (secretData?.value || {}) as Record<string, any>;
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
provider: (publicVal.provider as any) || 'none',
|
|
35
|
+
siteKey: publicVal.siteKey || '',
|
|
36
|
+
secretKey: secretVal.secretKey || '',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function updateBotProtectionSettings(formData: FormData) {
|
|
41
|
+
const supabase = createClient();
|
|
42
|
+
|
|
43
|
+
// Verify auth and role
|
|
44
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
45
|
+
if (!user) {
|
|
46
|
+
throw new Error('You must be logged in to update settings.');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const { data: profile, error: profileError } = await supabase
|
|
50
|
+
.from('profiles')
|
|
51
|
+
.select('role')
|
|
52
|
+
.eq('id', user.id)
|
|
53
|
+
.single();
|
|
54
|
+
|
|
55
|
+
if (profileError || !profile || profile.role !== 'ADMIN') {
|
|
56
|
+
throw new Error('You do not have permission to perform this action.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const provider = formData.get('provider') as 'none' | 'turnstile' | 'recaptcha';
|
|
60
|
+
const siteKey = formData.get('siteKey') as string;
|
|
61
|
+
const secretKey = formData.get('secretKey') as string;
|
|
62
|
+
|
|
63
|
+
// Update public settings (provider and siteKey)
|
|
64
|
+
const { error: publicError } = await supabase
|
|
65
|
+
.from('site_settings')
|
|
66
|
+
.upsert({
|
|
67
|
+
key: 'bot_protection_public',
|
|
68
|
+
value: { provider, siteKey },
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
if (publicError) {
|
|
72
|
+
console.error('Error updating public bot protection settings:', publicError);
|
|
73
|
+
throw new Error('Failed to update bot protection settings.');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Update secret settings (secretKey)
|
|
77
|
+
const { error: secretError } = await supabase
|
|
78
|
+
.from('site_settings')
|
|
79
|
+
.upsert({
|
|
80
|
+
key: 'bot_protection_secret',
|
|
81
|
+
value: { secretKey },
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
if (secretError) {
|
|
85
|
+
console.error('Error updating secret bot protection settings:', secretError);
|
|
86
|
+
throw new Error('Failed to update bot protection secrets.');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Revalidate root layout so scripts update instantly
|
|
90
|
+
revalidatePath('/', 'layout');
|
|
91
|
+
|
|
92
|
+
return { success: true, message: 'Bot protection settings updated successfully.' };
|
|
93
|
+
}
|
|
@@ -1,129 +1,129 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { useState, useTransition, useRef } from 'react';
|
|
4
|
-
import { Label } from '@nextblock-cms/ui';
|
|
5
|
-
import { Input } from '@nextblock-cms/ui';
|
|
6
|
-
import { Button } from '@nextblock-cms/ui';
|
|
7
|
-
import { Alert, AlertDescription, Spinner } from '@nextblock-cms/ui';
|
|
8
|
-
import { Message } from '../../../../../components/form-message';
|
|
9
|
-
import { useHotkeys } from '../../../../../hooks/use-hotkeys';
|
|
10
|
-
import { BotProtectionSettings, updateBotProtectionSettings } from '../actions';
|
|
11
|
-
|
|
12
|
-
interface BotProtectionFormProps {
|
|
13
|
-
initialSettings: BotProtectionSettings;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export default function BotProtectionForm({ initialSettings }: BotProtectionFormProps) {
|
|
17
|
-
const [isPending, startTransition] = useTransition();
|
|
18
|
-
const [message, setMessage] = useState<Message | null>(null);
|
|
19
|
-
|
|
20
|
-
const [provider, setProvider] = useState<'none' | 'turnstile' | 'recaptcha'>(initialSettings.provider);
|
|
21
|
-
const [siteKey, setSiteKey] = useState<string>(initialSettings.siteKey);
|
|
22
|
-
const [secretKey, setSecretKey] = useState<string>(initialSettings.secretKey || '');
|
|
23
|
-
|
|
24
|
-
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
25
|
-
event.preventDefault();
|
|
26
|
-
setMessage(null);
|
|
27
|
-
|
|
28
|
-
const formData = new FormData();
|
|
29
|
-
formData.append('provider', provider);
|
|
30
|
-
formData.append('siteKey', siteKey);
|
|
31
|
-
formData.append('secretKey', secretKey);
|
|
32
|
-
|
|
33
|
-
startTransition(async () => {
|
|
34
|
-
try {
|
|
35
|
-
const result = await updateBotProtectionSettings(formData);
|
|
36
|
-
if (result.success) {
|
|
37
|
-
setMessage({ success: result.message });
|
|
38
|
-
} else {
|
|
39
|
-
setMessage({ error: 'An unexpected error occurred.' });
|
|
40
|
-
}
|
|
41
|
-
} catch (error) {
|
|
42
|
-
setMessage({ error: error instanceof Error ? error.message : 'An unknown error occurred.' });
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const formRef = useRef<HTMLFormElement>(null);
|
|
48
|
-
useHotkeys('ctrl+s', () => formRef.current?.requestSubmit());
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
<form ref={formRef} onSubmit={handleSubmit} className="space-y-6">
|
|
52
|
-
<div className="space-y-4">
|
|
53
|
-
<div className="space-y-2">
|
|
54
|
-
<Label htmlFor="provider">Protection Provider</Label>
|
|
55
|
-
<select
|
|
56
|
-
id="provider"
|
|
57
|
-
name="provider"
|
|
58
|
-
value={provider}
|
|
59
|
-
onChange={(e) => setProvider(e.target.value as any)}
|
|
60
|
-
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
61
|
-
>
|
|
62
|
-
<option value="none">None (Honeypot Only)</option>
|
|
63
|
-
<option value="turnstile">Cloudflare Turnstile (Recommended)</option>
|
|
64
|
-
<option value="recaptcha">Google reCAPTCHA v3</option>
|
|
65
|
-
</select>
|
|
66
|
-
<p className="text-xs text-slate-500">
|
|
67
|
-
NextBlock always renders a hidden Honeypot field in form blocks by default. Setting a provider adds an additional cryptographic verification layer.
|
|
68
|
-
</p>
|
|
69
|
-
</div>
|
|
70
|
-
|
|
71
|
-
{provider !== 'none' && (
|
|
72
|
-
<>
|
|
73
|
-
<div className="space-y-2">
|
|
74
|
-
<Label htmlFor="siteKey">
|
|
75
|
-
{provider === 'turnstile' ? 'Turnstile Site Key' : 'reCAPTCHA Site Key'}
|
|
76
|
-
</Label>
|
|
77
|
-
<Input
|
|
78
|
-
id="siteKey"
|
|
79
|
-
name="siteKey"
|
|
80
|
-
value={siteKey}
|
|
81
|
-
onChange={(e) => setSiteKey(e.target.value)}
|
|
82
|
-
placeholder={provider === 'turnstile' ? 'e.g., 0x4AAAAAAAB...' : 'e.g., 6LdGP...'}
|
|
83
|
-
required
|
|
84
|
-
/>
|
|
85
|
-
<p className="text-xs text-slate-500">
|
|
86
|
-
The public key used to initialize the widget or API script on the client side.
|
|
87
|
-
</p>
|
|
88
|
-
</div>
|
|
89
|
-
|
|
90
|
-
<div className="space-y-2">
|
|
91
|
-
<Label htmlFor="secretKey">
|
|
92
|
-
{provider === 'turnstile' ? 'Turnstile Secret Key' : 'reCAPTCHA Secret Key'}
|
|
93
|
-
</Label>
|
|
94
|
-
<Input
|
|
95
|
-
id="secretKey"
|
|
96
|
-
name="secretKey"
|
|
97
|
-
type="password"
|
|
98
|
-
value={secretKey}
|
|
99
|
-
onChange={(e) => setSecretKey(e.target.value)}
|
|
100
|
-
placeholder="••••••••••••••••••••••••••••••••"
|
|
101
|
-
required
|
|
102
|
-
/>
|
|
103
|
-
<p className="text-xs text-slate-500">
|
|
104
|
-
The private key used to sign server-to-server validation requests. Stored securely on the server.
|
|
105
|
-
</p>
|
|
106
|
-
</div>
|
|
107
|
-
</>
|
|
108
|
-
)}
|
|
109
|
-
</div>
|
|
110
|
-
|
|
111
|
-
<div className="flex items-center gap-4">
|
|
112
|
-
<Button type="submit" disabled={isPending}>
|
|
113
|
-
{isPending ? (
|
|
114
|
-
<>
|
|
115
|
-
<Spinner className="mr-2 h-4 w-4 animate-spin" /> Saving...
|
|
116
|
-
</>
|
|
117
|
-
) : (
|
|
118
|
-
'Save Settings'
|
|
119
|
-
)}
|
|
120
|
-
</Button>
|
|
121
|
-
{message && (
|
|
122
|
-
<Alert variant={'success' in message ? 'success' : 'destructive'} className="py-2 px-4 w-auto inline-flex items-center">
|
|
123
|
-
<AlertDescription>{'success' in message ? (message as any).success : (message as any).error}</AlertDescription>
|
|
124
|
-
</Alert>
|
|
125
|
-
)}
|
|
126
|
-
</div>
|
|
127
|
-
</form>
|
|
128
|
-
);
|
|
129
|
-
}
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useTransition, useRef } from 'react';
|
|
4
|
+
import { Label } from '@nextblock-cms/ui';
|
|
5
|
+
import { Input } from '@nextblock-cms/ui';
|
|
6
|
+
import { Button } from '@nextblock-cms/ui';
|
|
7
|
+
import { Alert, AlertDescription, Spinner } from '@nextblock-cms/ui';
|
|
8
|
+
import { Message } from '../../../../../components/form-message';
|
|
9
|
+
import { useHotkeys } from '../../../../../hooks/use-hotkeys';
|
|
10
|
+
import { BotProtectionSettings, updateBotProtectionSettings } from '../actions';
|
|
11
|
+
|
|
12
|
+
interface BotProtectionFormProps {
|
|
13
|
+
initialSettings: BotProtectionSettings;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default function BotProtectionForm({ initialSettings }: BotProtectionFormProps) {
|
|
17
|
+
const [isPending, startTransition] = useTransition();
|
|
18
|
+
const [message, setMessage] = useState<Message | null>(null);
|
|
19
|
+
|
|
20
|
+
const [provider, setProvider] = useState<'none' | 'turnstile' | 'recaptcha'>(initialSettings.provider);
|
|
21
|
+
const [siteKey, setSiteKey] = useState<string>(initialSettings.siteKey);
|
|
22
|
+
const [secretKey, setSecretKey] = useState<string>(initialSettings.secretKey || '');
|
|
23
|
+
|
|
24
|
+
const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
|
|
25
|
+
event.preventDefault();
|
|
26
|
+
setMessage(null);
|
|
27
|
+
|
|
28
|
+
const formData = new FormData();
|
|
29
|
+
formData.append('provider', provider);
|
|
30
|
+
formData.append('siteKey', siteKey);
|
|
31
|
+
formData.append('secretKey', secretKey);
|
|
32
|
+
|
|
33
|
+
startTransition(async () => {
|
|
34
|
+
try {
|
|
35
|
+
const result = await updateBotProtectionSettings(formData);
|
|
36
|
+
if (result.success) {
|
|
37
|
+
setMessage({ success: result.message });
|
|
38
|
+
} else {
|
|
39
|
+
setMessage({ error: 'An unexpected error occurred.' });
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
setMessage({ error: error instanceof Error ? error.message : 'An unknown error occurred.' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const formRef = useRef<HTMLFormElement>(null);
|
|
48
|
+
useHotkeys('ctrl+s', () => formRef.current?.requestSubmit());
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<form ref={formRef} onSubmit={handleSubmit} className="space-y-6">
|
|
52
|
+
<div className="space-y-4">
|
|
53
|
+
<div className="space-y-2">
|
|
54
|
+
<Label htmlFor="provider">Protection Provider</Label>
|
|
55
|
+
<select
|
|
56
|
+
id="provider"
|
|
57
|
+
name="provider"
|
|
58
|
+
value={provider}
|
|
59
|
+
onChange={(e) => setProvider(e.target.value as any)}
|
|
60
|
+
className="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
|
|
61
|
+
>
|
|
62
|
+
<option value="none">None (Honeypot Only)</option>
|
|
63
|
+
<option value="turnstile">Cloudflare Turnstile (Recommended)</option>
|
|
64
|
+
<option value="recaptcha">Google reCAPTCHA v3</option>
|
|
65
|
+
</select>
|
|
66
|
+
<p className="text-xs text-slate-500">
|
|
67
|
+
NextBlock always renders a hidden Honeypot field in form blocks by default. Setting a provider adds an additional cryptographic verification layer.
|
|
68
|
+
</p>
|
|
69
|
+
</div>
|
|
70
|
+
|
|
71
|
+
{provider !== 'none' && (
|
|
72
|
+
<>
|
|
73
|
+
<div className="space-y-2">
|
|
74
|
+
<Label htmlFor="siteKey">
|
|
75
|
+
{provider === 'turnstile' ? 'Turnstile Site Key' : 'reCAPTCHA Site Key'}
|
|
76
|
+
</Label>
|
|
77
|
+
<Input
|
|
78
|
+
id="siteKey"
|
|
79
|
+
name="siteKey"
|
|
80
|
+
value={siteKey}
|
|
81
|
+
onChange={(e) => setSiteKey(e.target.value)}
|
|
82
|
+
placeholder={provider === 'turnstile' ? 'e.g., 0x4AAAAAAAB...' : 'e.g., 6LdGP...'}
|
|
83
|
+
required
|
|
84
|
+
/>
|
|
85
|
+
<p className="text-xs text-slate-500">
|
|
86
|
+
The public key used to initialize the widget or API script on the client side.
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<div className="space-y-2">
|
|
91
|
+
<Label htmlFor="secretKey">
|
|
92
|
+
{provider === 'turnstile' ? 'Turnstile Secret Key' : 'reCAPTCHA Secret Key'}
|
|
93
|
+
</Label>
|
|
94
|
+
<Input
|
|
95
|
+
id="secretKey"
|
|
96
|
+
name="secretKey"
|
|
97
|
+
type="password"
|
|
98
|
+
value={secretKey}
|
|
99
|
+
onChange={(e) => setSecretKey(e.target.value)}
|
|
100
|
+
placeholder="••••••••••••••••••••••••••••••••"
|
|
101
|
+
required
|
|
102
|
+
/>
|
|
103
|
+
<p className="text-xs text-slate-500">
|
|
104
|
+
The private key used to sign server-to-server validation requests. Stored securely on the server.
|
|
105
|
+
</p>
|
|
106
|
+
</div>
|
|
107
|
+
</>
|
|
108
|
+
)}
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
<div className="flex items-center gap-4">
|
|
112
|
+
<Button type="submit" disabled={isPending}>
|
|
113
|
+
{isPending ? (
|
|
114
|
+
<>
|
|
115
|
+
<Spinner className="mr-2 h-4 w-4 animate-spin" /> Saving...
|
|
116
|
+
</>
|
|
117
|
+
) : (
|
|
118
|
+
'Save Settings'
|
|
119
|
+
)}
|
|
120
|
+
</Button>
|
|
121
|
+
{message && (
|
|
122
|
+
<Alert variant={'success' in message ? 'success' : 'destructive'} className="py-2 px-4 w-auto inline-flex items-center">
|
|
123
|
+
<AlertDescription>{'success' in message ? (message as any).success : (message as any).error}</AlertDescription>
|
|
124
|
+
</Alert>
|
|
125
|
+
)}
|
|
126
|
+
</div>
|
|
127
|
+
</form>
|
|
128
|
+
);
|
|
129
|
+
}
|
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
// app/cms/settings/bot-protection/page.tsx
|
|
2
|
-
import { getBotProtectionSettings } from './actions';
|
|
3
|
-
import BotProtectionForm from './components/BotProtectionForm';
|
|
4
|
-
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@nextblock-cms/ui';
|
|
5
|
-
|
|
6
|
-
export default async function BotProtectionSettingsPage() {
|
|
7
|
-
const settings = await getBotProtectionSettings();
|
|
8
|
-
|
|
9
|
-
return (
|
|
10
|
-
<div className="max-w-4xl mx-auto">
|
|
11
|
-
<Card>
|
|
12
|
-
<CardHeader>
|
|
13
|
-
<CardTitle>Bot Protection Settings</CardTitle>
|
|
14
|
-
<CardDescription>
|
|
15
|
-
Configure bot and spam protection settings for all form blocks on your site. NextBlock supports lightweight Honeypots, Google reCAPTCHA v3, and Cloudflare Turnstile.
|
|
16
|
-
</CardDescription>
|
|
17
|
-
</CardHeader>
|
|
18
|
-
<CardContent>
|
|
19
|
-
<BotProtectionForm initialSettings={settings} />
|
|
20
|
-
</CardContent>
|
|
21
|
-
</Card>
|
|
22
|
-
</div>
|
|
23
|
-
);
|
|
24
|
-
}
|
|
1
|
+
// app/cms/settings/bot-protection/page.tsx
|
|
2
|
+
import { getBotProtectionSettings } from './actions';
|
|
3
|
+
import BotProtectionForm from './components/BotProtectionForm';
|
|
4
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@nextblock-cms/ui';
|
|
5
|
+
|
|
6
|
+
export default async function BotProtectionSettingsPage() {
|
|
7
|
+
const settings = await getBotProtectionSettings();
|
|
8
|
+
|
|
9
|
+
return (
|
|
10
|
+
<div className="max-w-4xl mx-auto">
|
|
11
|
+
<Card>
|
|
12
|
+
<CardHeader>
|
|
13
|
+
<CardTitle>Bot Protection Settings</CardTitle>
|
|
14
|
+
<CardDescription>
|
|
15
|
+
Configure bot and spam protection settings for all form blocks on your site. NextBlock supports lightweight Honeypots, Google reCAPTCHA v3, and Cloudflare Turnstile.
|
|
16
|
+
</CardDescription>
|
|
17
|
+
</CardHeader>
|
|
18
|
+
<CardContent>
|
|
19
|
+
<BotProtectionForm initialSettings={settings} />
|
|
20
|
+
</CardContent>
|
|
21
|
+
</Card>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|