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,246 +1,246 @@
|
|
|
1
|
-
'use server';
|
|
2
|
-
|
|
3
|
-
import { revalidatePath } from 'next/cache';
|
|
4
|
-
import { redirect } from 'next/navigation';
|
|
5
|
-
|
|
6
|
-
import { createClient, verifyPackageOnline } from '@nextblock-cms/db/server';
|
|
7
|
-
|
|
8
|
-
import {
|
|
9
|
-
CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
10
|
-
CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
11
|
-
CORTEX_AI_PACKAGE_ID,
|
|
12
|
-
createCortexAiStoredModelSelection,
|
|
13
|
-
encryptStoredOpenRouterApiKey,
|
|
14
|
-
getCortexAiEnvConfig,
|
|
15
|
-
getEnvOpenRouterKeyStatus,
|
|
16
|
-
getStoredOpenRouterKeyStatus,
|
|
17
|
-
listCortexAiCompatibleOpenRouterModels,
|
|
18
|
-
safeParseCortexAiModelSelection,
|
|
19
|
-
type CortexAiStoredModelSelection,
|
|
20
|
-
} from '@nextblock-cms/cortex';
|
|
21
|
-
|
|
22
|
-
const CORTEX_AI_SETTINGS_PATH = '/cms/settings/cortex-ai';
|
|
23
|
-
|
|
24
|
-
type CortexAiSettingsStatus = {
|
|
25
|
-
activeKeySource: 'env' | 'stored' | 'none';
|
|
26
|
-
hasEncryptionKey: boolean;
|
|
27
|
-
hasEnvOpenRouterKey: boolean;
|
|
28
|
-
hasStoredOpenRouterKey: boolean;
|
|
29
|
-
isPackageActive: boolean;
|
|
30
|
-
maskedEnvOpenRouterKey: string | null;
|
|
31
|
-
maskedStoredOpenRouterKey: string | null;
|
|
32
|
-
selectedModel: CortexAiStoredModelSelection | null;
|
|
33
|
-
storedOpenRouterKeyUpdatedAt: string | null;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
function redirectWithStatus(status: 'success' | 'error', message: string): never {
|
|
37
|
-
redirect(`${CORTEX_AI_SETTINGS_PATH}?${status}=${encodeURIComponent(message)}`);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
async function requireAdminSupabaseClient() {
|
|
41
|
-
const supabase = createClient();
|
|
42
|
-
const {
|
|
43
|
-
data: { user },
|
|
44
|
-
error: userError,
|
|
45
|
-
} = await supabase.auth.getUser();
|
|
46
|
-
|
|
47
|
-
if (userError || !user) {
|
|
48
|
-
throw new Error('You must be logged in to manage Cortex AI settings.');
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
const { data: profile, error: profileError } = await supabase
|
|
52
|
-
.from('profiles')
|
|
53
|
-
.select('role')
|
|
54
|
-
.eq('id', user.id)
|
|
55
|
-
.single();
|
|
56
|
-
|
|
57
|
-
if (profileError || !profile || profile.role !== 'ADMIN') {
|
|
58
|
-
throw new Error('You do not have permission to manage Cortex AI settings.');
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return supabase;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export async function getCortexAiSettingsStatus(): Promise<CortexAiSettingsStatus> {
|
|
65
|
-
const supabase = await requireAdminSupabaseClient();
|
|
66
|
-
const env = getCortexAiEnvConfig();
|
|
67
|
-
const envKeyStatus = getEnvOpenRouterKeyStatus();
|
|
68
|
-
|
|
69
|
-
const [{ data: storedKeyRow }, { data: selectedModelRow }, isPackageActive] = await Promise.all([
|
|
70
|
-
supabase
|
|
71
|
-
.from('site_settings')
|
|
72
|
-
.select('value')
|
|
73
|
-
.eq('key', CORTEX_AI_OPENROUTER_SETTING_KEY)
|
|
74
|
-
.maybeSingle(),
|
|
75
|
-
supabase
|
|
76
|
-
.from('site_settings')
|
|
77
|
-
.select('value')
|
|
78
|
-
.eq('key', CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY)
|
|
79
|
-
.maybeSingle(),
|
|
80
|
-
verifyPackageOnline(CORTEX_AI_PACKAGE_ID).catch(() => false),
|
|
81
|
-
]);
|
|
82
|
-
|
|
83
|
-
const storedKeyStatus = getStoredOpenRouterKeyStatus(storedKeyRow?.value);
|
|
84
|
-
const selectedModel = safeParseCortexAiModelSelection(selectedModelRow?.value);
|
|
85
|
-
|
|
86
|
-
return {
|
|
87
|
-
activeKeySource: storedKeyStatus.hasStoredKey
|
|
88
|
-
? 'stored'
|
|
89
|
-
: env.hasOpenRouterEnvKey
|
|
90
|
-
? 'env'
|
|
91
|
-
: 'none',
|
|
92
|
-
hasEncryptionKey: env.hasEncryptionKey,
|
|
93
|
-
hasEnvOpenRouterKey: env.hasOpenRouterEnvKey,
|
|
94
|
-
hasStoredOpenRouterKey: storedKeyStatus.hasStoredKey,
|
|
95
|
-
isPackageActive,
|
|
96
|
-
maskedEnvOpenRouterKey: envKeyStatus.maskedEnvOpenRouterKey,
|
|
97
|
-
maskedStoredOpenRouterKey: storedKeyStatus.maskedKey,
|
|
98
|
-
selectedModel: storedKeyStatus.hasStoredKey ? selectedModel : null,
|
|
99
|
-
storedOpenRouterKeyUpdatedAt: storedKeyStatus.updatedAt,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
export async function saveOpenRouterApiKeyAction(formData: FormData) {
|
|
104
|
-
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
105
|
-
throw new Error('Sandbox environment cannot save keys to the database.');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
const supabase = await requireAdminSupabaseClient();
|
|
110
|
-
const apiKey = String(formData.get('openrouter_api_key') || '').trim();
|
|
111
|
-
|
|
112
|
-
if (!apiKey) {
|
|
113
|
-
throw new Error('OpenRouter API key is required.');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const encryptedKey = encryptStoredOpenRouterApiKey(apiKey);
|
|
117
|
-
const { error } = await supabase.from('site_settings').upsert({
|
|
118
|
-
key: CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
119
|
-
value: encryptedKey,
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
if (error) {
|
|
123
|
-
throw new Error(error.message);
|
|
124
|
-
}
|
|
125
|
-
} catch (error) {
|
|
126
|
-
redirectWithStatus(
|
|
127
|
-
'error',
|
|
128
|
-
error instanceof Error ? error.message : 'Failed to save OpenRouter key.'
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
133
|
-
redirectWithStatus('success', 'OpenRouter key saved.');
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export async function clearOpenRouterApiKeyAction() {
|
|
137
|
-
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
138
|
-
throw new Error('Sandbox environment cannot clear keys from the database.');
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
try {
|
|
142
|
-
const supabase = await requireAdminSupabaseClient();
|
|
143
|
-
const { error } = await supabase
|
|
144
|
-
.from('site_settings')
|
|
145
|
-
.delete()
|
|
146
|
-
.in('key', [
|
|
147
|
-
CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
148
|
-
CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
149
|
-
]);
|
|
150
|
-
|
|
151
|
-
if (error) {
|
|
152
|
-
throw new Error(error.message);
|
|
153
|
-
}
|
|
154
|
-
} catch (error) {
|
|
155
|
-
redirectWithStatus(
|
|
156
|
-
'error',
|
|
157
|
-
error instanceof Error ? error.message : 'Failed to clear OpenRouter key.'
|
|
158
|
-
);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
162
|
-
redirectWithStatus('success', 'Stored OpenRouter key cleared.');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export async function saveCortexAiModelSelectionAction(formData: FormData) {
|
|
166
|
-
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
167
|
-
throw new Error('Sandbox environment cannot save model selection to the database.');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
const supabase = await requireAdminSupabaseClient();
|
|
172
|
-
const modelId = String(formData.get('openrouter_model_id') || '').trim();
|
|
173
|
-
|
|
174
|
-
if (!modelId) {
|
|
175
|
-
throw new Error('Choose an OpenRouter model before saving.');
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
const { data: storedKeyRow, error: storedKeyError } = await supabase
|
|
179
|
-
.from('site_settings')
|
|
180
|
-
.select('value')
|
|
181
|
-
.eq('key', CORTEX_AI_OPENROUTER_SETTING_KEY)
|
|
182
|
-
.maybeSingle();
|
|
183
|
-
|
|
184
|
-
if (storedKeyError) {
|
|
185
|
-
throw new Error(storedKeyError.message);
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
const storedKeyStatus = getStoredOpenRouterKeyStatus(storedKeyRow?.value);
|
|
189
|
-
|
|
190
|
-
if (!storedKeyStatus.hasStoredKey) {
|
|
191
|
-
throw new Error('Save a stored OpenRouter BYOK before choosing a paid model.');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
const compatibleModels = await listCortexAiCompatibleOpenRouterModels();
|
|
195
|
-
const selectedModel = compatibleModels.find((model) => model.id === modelId);
|
|
196
|
-
|
|
197
|
-
if (!selectedModel) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
'The selected model is no longer eligible for Cortex AI structured output and tool calling.'
|
|
200
|
-
);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const { error } = await supabase.from('site_settings').upsert({
|
|
204
|
-
key: CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
205
|
-
value: createCortexAiStoredModelSelection(selectedModel),
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
if (error) {
|
|
209
|
-
throw new Error(error.message);
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
redirectWithStatus(
|
|
213
|
-
'error',
|
|
214
|
-
error instanceof Error ? error.message : 'Failed to save Cortex AI model selection.'
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
219
|
-
redirectWithStatus('success', 'Cortex AI model selection saved.');
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
export async function clearCortexAiModelSelectionAction() {
|
|
223
|
-
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
224
|
-
throw new Error('Sandbox environment cannot clear model selection from the database.');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
try {
|
|
228
|
-
const supabase = await requireAdminSupabaseClient();
|
|
229
|
-
const { error } = await supabase
|
|
230
|
-
.from('site_settings')
|
|
231
|
-
.delete()
|
|
232
|
-
.eq('key', CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY);
|
|
233
|
-
|
|
234
|
-
if (error) {
|
|
235
|
-
throw new Error(error.message);
|
|
236
|
-
}
|
|
237
|
-
} catch (error) {
|
|
238
|
-
redirectWithStatus(
|
|
239
|
-
'error',
|
|
240
|
-
error instanceof Error ? error.message : 'Failed to clear Cortex AI model selection.'
|
|
241
|
-
);
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
245
|
-
redirectWithStatus('success', 'Cortex AI model selection cleared.');
|
|
246
|
-
}
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { revalidatePath } from 'next/cache';
|
|
4
|
+
import { redirect } from 'next/navigation';
|
|
5
|
+
|
|
6
|
+
import { createClient, verifyPackageOnline } from '@nextblock-cms/db/server';
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
10
|
+
CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
11
|
+
CORTEX_AI_PACKAGE_ID,
|
|
12
|
+
createCortexAiStoredModelSelection,
|
|
13
|
+
encryptStoredOpenRouterApiKey,
|
|
14
|
+
getCortexAiEnvConfig,
|
|
15
|
+
getEnvOpenRouterKeyStatus,
|
|
16
|
+
getStoredOpenRouterKeyStatus,
|
|
17
|
+
listCortexAiCompatibleOpenRouterModels,
|
|
18
|
+
safeParseCortexAiModelSelection,
|
|
19
|
+
type CortexAiStoredModelSelection,
|
|
20
|
+
} from '@nextblock-cms/cortex';
|
|
21
|
+
|
|
22
|
+
const CORTEX_AI_SETTINGS_PATH = '/cms/settings/cortex-ai';
|
|
23
|
+
|
|
24
|
+
type CortexAiSettingsStatus = {
|
|
25
|
+
activeKeySource: 'env' | 'stored' | 'none';
|
|
26
|
+
hasEncryptionKey: boolean;
|
|
27
|
+
hasEnvOpenRouterKey: boolean;
|
|
28
|
+
hasStoredOpenRouterKey: boolean;
|
|
29
|
+
isPackageActive: boolean;
|
|
30
|
+
maskedEnvOpenRouterKey: string | null;
|
|
31
|
+
maskedStoredOpenRouterKey: string | null;
|
|
32
|
+
selectedModel: CortexAiStoredModelSelection | null;
|
|
33
|
+
storedOpenRouterKeyUpdatedAt: string | null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
function redirectWithStatus(status: 'success' | 'error', message: string): never {
|
|
37
|
+
redirect(`${CORTEX_AI_SETTINGS_PATH}?${status}=${encodeURIComponent(message)}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function requireAdminSupabaseClient() {
|
|
41
|
+
const supabase = createClient();
|
|
42
|
+
const {
|
|
43
|
+
data: { user },
|
|
44
|
+
error: userError,
|
|
45
|
+
} = await supabase.auth.getUser();
|
|
46
|
+
|
|
47
|
+
if (userError || !user) {
|
|
48
|
+
throw new Error('You must be logged in to manage Cortex AI settings.');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const { data: profile, error: profileError } = await supabase
|
|
52
|
+
.from('profiles')
|
|
53
|
+
.select('role')
|
|
54
|
+
.eq('id', user.id)
|
|
55
|
+
.single();
|
|
56
|
+
|
|
57
|
+
if (profileError || !profile || profile.role !== 'ADMIN') {
|
|
58
|
+
throw new Error('You do not have permission to manage Cortex AI settings.');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return supabase;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export async function getCortexAiSettingsStatus(): Promise<CortexAiSettingsStatus> {
|
|
65
|
+
const supabase = await requireAdminSupabaseClient();
|
|
66
|
+
const env = getCortexAiEnvConfig();
|
|
67
|
+
const envKeyStatus = getEnvOpenRouterKeyStatus();
|
|
68
|
+
|
|
69
|
+
const [{ data: storedKeyRow }, { data: selectedModelRow }, isPackageActive] = await Promise.all([
|
|
70
|
+
supabase
|
|
71
|
+
.from('site_settings')
|
|
72
|
+
.select('value')
|
|
73
|
+
.eq('key', CORTEX_AI_OPENROUTER_SETTING_KEY)
|
|
74
|
+
.maybeSingle(),
|
|
75
|
+
supabase
|
|
76
|
+
.from('site_settings')
|
|
77
|
+
.select('value')
|
|
78
|
+
.eq('key', CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY)
|
|
79
|
+
.maybeSingle(),
|
|
80
|
+
verifyPackageOnline(CORTEX_AI_PACKAGE_ID).catch(() => false),
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
const storedKeyStatus = getStoredOpenRouterKeyStatus(storedKeyRow?.value);
|
|
84
|
+
const selectedModel = safeParseCortexAiModelSelection(selectedModelRow?.value);
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
activeKeySource: storedKeyStatus.hasStoredKey
|
|
88
|
+
? 'stored'
|
|
89
|
+
: env.hasOpenRouterEnvKey
|
|
90
|
+
? 'env'
|
|
91
|
+
: 'none',
|
|
92
|
+
hasEncryptionKey: env.hasEncryptionKey,
|
|
93
|
+
hasEnvOpenRouterKey: env.hasOpenRouterEnvKey,
|
|
94
|
+
hasStoredOpenRouterKey: storedKeyStatus.hasStoredKey,
|
|
95
|
+
isPackageActive,
|
|
96
|
+
maskedEnvOpenRouterKey: envKeyStatus.maskedEnvOpenRouterKey,
|
|
97
|
+
maskedStoredOpenRouterKey: storedKeyStatus.maskedKey,
|
|
98
|
+
selectedModel: storedKeyStatus.hasStoredKey ? selectedModel : null,
|
|
99
|
+
storedOpenRouterKeyUpdatedAt: storedKeyStatus.updatedAt,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export async function saveOpenRouterApiKeyAction(formData: FormData) {
|
|
104
|
+
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
105
|
+
throw new Error('Sandbox environment cannot save keys to the database.');
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
try {
|
|
109
|
+
const supabase = await requireAdminSupabaseClient();
|
|
110
|
+
const apiKey = String(formData.get('openrouter_api_key') || '').trim();
|
|
111
|
+
|
|
112
|
+
if (!apiKey) {
|
|
113
|
+
throw new Error('OpenRouter API key is required.');
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const encryptedKey = encryptStoredOpenRouterApiKey(apiKey);
|
|
117
|
+
const { error } = await supabase.from('site_settings').upsert({
|
|
118
|
+
key: CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
119
|
+
value: encryptedKey,
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (error) {
|
|
123
|
+
throw new Error(error.message);
|
|
124
|
+
}
|
|
125
|
+
} catch (error) {
|
|
126
|
+
redirectWithStatus(
|
|
127
|
+
'error',
|
|
128
|
+
error instanceof Error ? error.message : 'Failed to save OpenRouter key.'
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
133
|
+
redirectWithStatus('success', 'OpenRouter key saved.');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function clearOpenRouterApiKeyAction() {
|
|
137
|
+
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
138
|
+
throw new Error('Sandbox environment cannot clear keys from the database.');
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
try {
|
|
142
|
+
const supabase = await requireAdminSupabaseClient();
|
|
143
|
+
const { error } = await supabase
|
|
144
|
+
.from('site_settings')
|
|
145
|
+
.delete()
|
|
146
|
+
.in('key', [
|
|
147
|
+
CORTEX_AI_OPENROUTER_SETTING_KEY,
|
|
148
|
+
CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
if (error) {
|
|
152
|
+
throw new Error(error.message);
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
redirectWithStatus(
|
|
156
|
+
'error',
|
|
157
|
+
error instanceof Error ? error.message : 'Failed to clear OpenRouter key.'
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
162
|
+
redirectWithStatus('success', 'Stored OpenRouter key cleared.');
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
export async function saveCortexAiModelSelectionAction(formData: FormData) {
|
|
166
|
+
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
167
|
+
throw new Error('Sandbox environment cannot save model selection to the database.');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const supabase = await requireAdminSupabaseClient();
|
|
172
|
+
const modelId = String(formData.get('openrouter_model_id') || '').trim();
|
|
173
|
+
|
|
174
|
+
if (!modelId) {
|
|
175
|
+
throw new Error('Choose an OpenRouter model before saving.');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const { data: storedKeyRow, error: storedKeyError } = await supabase
|
|
179
|
+
.from('site_settings')
|
|
180
|
+
.select('value')
|
|
181
|
+
.eq('key', CORTEX_AI_OPENROUTER_SETTING_KEY)
|
|
182
|
+
.maybeSingle();
|
|
183
|
+
|
|
184
|
+
if (storedKeyError) {
|
|
185
|
+
throw new Error(storedKeyError.message);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
const storedKeyStatus = getStoredOpenRouterKeyStatus(storedKeyRow?.value);
|
|
189
|
+
|
|
190
|
+
if (!storedKeyStatus.hasStoredKey) {
|
|
191
|
+
throw new Error('Save a stored OpenRouter BYOK before choosing a paid model.');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const compatibleModels = await listCortexAiCompatibleOpenRouterModels();
|
|
195
|
+
const selectedModel = compatibleModels.find((model) => model.id === modelId);
|
|
196
|
+
|
|
197
|
+
if (!selectedModel) {
|
|
198
|
+
throw new Error(
|
|
199
|
+
'The selected model is no longer eligible for Cortex AI structured output and tool calling.'
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const { error } = await supabase.from('site_settings').upsert({
|
|
204
|
+
key: CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY,
|
|
205
|
+
value: createCortexAiStoredModelSelection(selectedModel),
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
if (error) {
|
|
209
|
+
throw new Error(error.message);
|
|
210
|
+
}
|
|
211
|
+
} catch (error) {
|
|
212
|
+
redirectWithStatus(
|
|
213
|
+
'error',
|
|
214
|
+
error instanceof Error ? error.message : 'Failed to save Cortex AI model selection.'
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
219
|
+
redirectWithStatus('success', 'Cortex AI model selection saved.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
export async function clearCortexAiModelSelectionAction() {
|
|
223
|
+
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
224
|
+
throw new Error('Sandbox environment cannot clear model selection from the database.');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
try {
|
|
228
|
+
const supabase = await requireAdminSupabaseClient();
|
|
229
|
+
const { error } = await supabase
|
|
230
|
+
.from('site_settings')
|
|
231
|
+
.delete()
|
|
232
|
+
.eq('key', CORTEX_AI_OPENROUTER_MODEL_SELECTION_SETTING_KEY);
|
|
233
|
+
|
|
234
|
+
if (error) {
|
|
235
|
+
throw new Error(error.message);
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
redirectWithStatus(
|
|
239
|
+
'error',
|
|
240
|
+
error instanceof Error ? error.message : 'Failed to clear Cortex AI model selection.'
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
revalidatePath(CORTEX_AI_SETTINGS_PATH);
|
|
245
|
+
redirectWithStatus('success', 'Cortex AI model selection cleared.');
|
|
246
|
+
}
|
|
@@ -1,80 +1,80 @@
|
|
|
1
|
-
import { listCortexAiCompatibleOpenRouterModels } from '@nextblock-cms/cortex';
|
|
2
|
-
import { getCortexAiSettingsStatus } from './actions';
|
|
3
|
-
import { SandboxCortexAiSettingsClient } from './SandboxCortexAiSettingsClient';
|
|
4
|
-
import { StoredCortexAiSettingsClient } from './StoredCortexAiSettingsClient';
|
|
5
|
-
import { redirect } from 'next/navigation';
|
|
6
|
-
|
|
7
|
-
type CortexAiSettingsPageProps = {
|
|
8
|
-
searchParams?: Promise<{
|
|
9
|
-
error?: string;
|
|
10
|
-
success?: string;
|
|
11
|
-
}>;
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
function formatDate(value: string | null) {
|
|
15
|
-
if (!value) {
|
|
16
|
-
return null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return new Intl.DateTimeFormat('en', {
|
|
20
|
-
dateStyle: 'medium',
|
|
21
|
-
timeStyle: 'short',
|
|
22
|
-
}).format(new Date(value));
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default async function CortexAiSettingsPage({
|
|
26
|
-
searchParams,
|
|
27
|
-
}: CortexAiSettingsPageProps) {
|
|
28
|
-
const status = await getCortexAiSettingsStatus();
|
|
29
|
-
|
|
30
|
-
if (!status.isPackageActive) {
|
|
31
|
-
redirect('/cms/dashboard');
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const params: { error?: string; success?: string } = searchParams
|
|
35
|
-
? await searchParams
|
|
36
|
-
: {};
|
|
37
|
-
const storedKeyUpdatedAt = formatDate(status.storedOpenRouterKeyUpdatedAt);
|
|
38
|
-
const selectedModelUpdatedAt = formatDate(status.selectedModel?.updatedAt || null);
|
|
39
|
-
let compatibleModels: Awaited<ReturnType<typeof listCortexAiCompatibleOpenRouterModels>> = [];
|
|
40
|
-
let modelCatalogError: string | null = null;
|
|
41
|
-
|
|
42
|
-
if (status.hasStoredOpenRouterKey || process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
43
|
-
try {
|
|
44
|
-
compatibleModels = await listCortexAiCompatibleOpenRouterModels();
|
|
45
|
-
} catch (error) {
|
|
46
|
-
modelCatalogError =
|
|
47
|
-
error instanceof Error ? error.message : 'Failed to load compatible OpenRouter models.';
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
52
|
-
return (
|
|
53
|
-
<SandboxCortexAiSettingsClient
|
|
54
|
-
compatibleModels={compatibleModels as any}
|
|
55
|
-
isPackageActive={status.isPackageActive}
|
|
56
|
-
hasEnvOpenRouterKey={status.hasEnvOpenRouterKey}
|
|
57
|
-
maskedEnvOpenRouterKey={status.maskedEnvOpenRouterKey}
|
|
58
|
-
modelCatalogError={modelCatalogError}
|
|
59
|
-
/>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return (
|
|
64
|
-
<StoredCortexAiSettingsClient
|
|
65
|
-
compatibleModels={compatibleModels as any}
|
|
66
|
-
isPackageActive={status.isPackageActive}
|
|
67
|
-
hasEnvOpenRouterKey={status.hasEnvOpenRouterKey}
|
|
68
|
-
maskedEnvOpenRouterKey={status.maskedEnvOpenRouterKey}
|
|
69
|
-
hasStoredOpenRouterKey={status.hasStoredOpenRouterKey}
|
|
70
|
-
maskedStoredOpenRouterKey={status.maskedStoredOpenRouterKey}
|
|
71
|
-
storedKeyUpdatedAt={storedKeyUpdatedAt}
|
|
72
|
-
selectedModel={status.selectedModel}
|
|
73
|
-
selectedModelUpdatedAt={selectedModelUpdatedAt}
|
|
74
|
-
hasEncryptionKey={status.hasEncryptionKey}
|
|
75
|
-
modelCatalogError={modelCatalogError}
|
|
76
|
-
successMessage={params.success}
|
|
77
|
-
errorMessage={params.error}
|
|
78
|
-
/>
|
|
79
|
-
);
|
|
80
|
-
}
|
|
1
|
+
import { listCortexAiCompatibleOpenRouterModels } from '@nextblock-cms/cortex';
|
|
2
|
+
import { getCortexAiSettingsStatus } from './actions';
|
|
3
|
+
import { SandboxCortexAiSettingsClient } from './SandboxCortexAiSettingsClient';
|
|
4
|
+
import { StoredCortexAiSettingsClient } from './StoredCortexAiSettingsClient';
|
|
5
|
+
import { redirect } from 'next/navigation';
|
|
6
|
+
|
|
7
|
+
type CortexAiSettingsPageProps = {
|
|
8
|
+
searchParams?: Promise<{
|
|
9
|
+
error?: string;
|
|
10
|
+
success?: string;
|
|
11
|
+
}>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function formatDate(value: string | null) {
|
|
15
|
+
if (!value) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return new Intl.DateTimeFormat('en', {
|
|
20
|
+
dateStyle: 'medium',
|
|
21
|
+
timeStyle: 'short',
|
|
22
|
+
}).format(new Date(value));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default async function CortexAiSettingsPage({
|
|
26
|
+
searchParams,
|
|
27
|
+
}: CortexAiSettingsPageProps) {
|
|
28
|
+
const status = await getCortexAiSettingsStatus();
|
|
29
|
+
|
|
30
|
+
if (!status.isPackageActive) {
|
|
31
|
+
redirect('/cms/dashboard');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const params: { error?: string; success?: string } = searchParams
|
|
35
|
+
? await searchParams
|
|
36
|
+
: {};
|
|
37
|
+
const storedKeyUpdatedAt = formatDate(status.storedOpenRouterKeyUpdatedAt);
|
|
38
|
+
const selectedModelUpdatedAt = formatDate(status.selectedModel?.updatedAt || null);
|
|
39
|
+
let compatibleModels: Awaited<ReturnType<typeof listCortexAiCompatibleOpenRouterModels>> = [];
|
|
40
|
+
let modelCatalogError: string | null = null;
|
|
41
|
+
|
|
42
|
+
if (status.hasStoredOpenRouterKey || process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
43
|
+
try {
|
|
44
|
+
compatibleModels = await listCortexAiCompatibleOpenRouterModels();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
modelCatalogError =
|
|
47
|
+
error instanceof Error ? error.message : 'Failed to load compatible OpenRouter models.';
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (process.env.NEXT_PUBLIC_IS_SANDBOX === 'true') {
|
|
52
|
+
return (
|
|
53
|
+
<SandboxCortexAiSettingsClient
|
|
54
|
+
compatibleModels={compatibleModels as any}
|
|
55
|
+
isPackageActive={status.isPackageActive}
|
|
56
|
+
hasEnvOpenRouterKey={status.hasEnvOpenRouterKey}
|
|
57
|
+
maskedEnvOpenRouterKey={status.maskedEnvOpenRouterKey}
|
|
58
|
+
modelCatalogError={modelCatalogError}
|
|
59
|
+
/>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<StoredCortexAiSettingsClient
|
|
65
|
+
compatibleModels={compatibleModels as any}
|
|
66
|
+
isPackageActive={status.isPackageActive}
|
|
67
|
+
hasEnvOpenRouterKey={status.hasEnvOpenRouterKey}
|
|
68
|
+
maskedEnvOpenRouterKey={status.maskedEnvOpenRouterKey}
|
|
69
|
+
hasStoredOpenRouterKey={status.hasStoredOpenRouterKey}
|
|
70
|
+
maskedStoredOpenRouterKey={status.maskedStoredOpenRouterKey}
|
|
71
|
+
storedKeyUpdatedAt={storedKeyUpdatedAt}
|
|
72
|
+
selectedModel={status.selectedModel}
|
|
73
|
+
selectedModelUpdatedAt={selectedModelUpdatedAt}
|
|
74
|
+
hasEncryptionKey={status.hasEncryptionKey}
|
|
75
|
+
modelCatalogError={modelCatalogError}
|
|
76
|
+
successMessage={params.success}
|
|
77
|
+
errorMessage={params.error}
|
|
78
|
+
/>
|
|
79
|
+
);
|
|
80
|
+
}
|