create-nextblock 0.14.1 → 0.14.4
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/page.tsx +46 -46
- 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/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/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 +5881 -5623
- 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/CmsClientLayout.tsx +2 -2
- package/templates/nextblock-template/app/cms/blocks/components/ColumnEditor.tsx +17 -22
- package/templates/nextblock-template/app/cms/blocks/components/CustomBlockEditorPreview.tsx +160 -160
- package/templates/nextblock-template/app/cms/blocks/components/EditableBlock.tsx +13 -19
- 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/HeadingBlockEditor.tsx +45 -34
- package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +4 -2
- 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/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/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/actions.ts +226 -226
- 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/navigation/components/NavigationMenuDnd.tsx +3 -3
- 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/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/page.tsx +24 -24
- package/templates/nextblock-template/app/cms/settings/cortex-ai/SandboxCortexAiSettingsClient.tsx +688 -688
- 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/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/global-css/components/ThemeEditor.tsx +382 -0
- package/templates/nextblock-template/app/cms/settings/global-css/components/ThemeManager.tsx +267 -0
- package/templates/nextblock-template/app/cms/settings/global-css/page.tsx +40 -24
- package/templates/nextblock-template/app/cms/settings/global-css/theme-actions.ts +259 -0
- package/templates/nextblock-template/app/cms/settings/google-analytics/page.tsx +26 -26
- 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 +23 -21
- 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/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/registration/page.tsx +27 -27
- package/templates/nextblock-template/app/cms/settings/security/components/SecurityPanel.tsx +9 -7
- 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/components/DeleteUserButton.tsx +12 -12
- package/templates/nextblock-template/app/layout.tsx +49 -0
- package/templates/nextblock-template/app/lib/site-settings.ts +105 -105
- 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-links.ts +22 -22
- package/templates/nextblock-template/app/profile/orders/CustomerOrdersPageClient.tsx +124 -124
- package/templates/nextblock-template/app/profile/orders/page.tsx +19 -19
- 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/providers.tsx +16 -4
- 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/HtmlScriptExecutor.tsx +47 -47
- package/templates/nextblock-template/components/LanguageSwitcher.tsx +2 -2
- 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/renderers/HeadingBlockRenderer.tsx +7 -10
- 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/media/YouTubeFacade.tsx +105 -105
- package/templates/nextblock-template/components/media/youtube-embed-replace.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 +471 -471
- package/templates/nextblock-template/components/submit-button.tsx +23 -23
- package/templates/nextblock-template/components/theme-icon.tsx +78 -0
- package/templates/nextblock-template/components/theme-switcher.tsx +77 -82
- 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/ThemeCatalogContext.tsx +44 -0
- 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 +279 -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/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/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-redirects.ts +46 -46
- package/templates/nextblock-template/lib/blocks/README.md +13 -13
- package/templates/nextblock-template/lib/blocks/blockColors.test.ts +114 -0
- package/templates/nextblock-template/lib/blocks/blockColors.ts +132 -0
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +17 -1
- package/templates/nextblock-template/lib/botProtection/verify.ts +134 -134
- 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/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-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/media/youtube.ts +99 -99
- 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/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 +15 -10
- 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/themes/buildThemeCss.test.ts +163 -0
- package/templates/nextblock-template/lib/themes/buildThemeCss.ts +124 -0
- package/templates/nextblock-template/lib/themes/tokenColor.ts +31 -0
- package/templates/nextblock-template/lib/themes/tokens.ts +143 -0
- 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/next-env.d.ts +2 -2
- 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/scripts/verify-site-themes.ts +63 -0
- 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/tsconfig.tsbuildinfo +1 -1
- package/templates/nextblock-template/types/jsdom.d.ts +6 -6
- package/tsconfig.base.json +3 -3
|
@@ -1,102 +1,102 @@
|
|
|
1
|
-
'use server';
|
|
2
|
-
|
|
3
|
-
import { cookies } from 'next/headers';
|
|
4
|
-
import { revalidatePath } from 'next/cache';
|
|
5
|
-
import { createClient } from '@nextblock-cms/db/server';
|
|
6
|
-
import {
|
|
7
|
-
startDeviceFlow,
|
|
8
|
-
pollDeviceFlowOnce,
|
|
9
|
-
installSyncWorkflow,
|
|
10
|
-
} from '../../../lib/updates/github-device';
|
|
11
|
-
import { markSyncWorkflowInstalled } from '../../../lib/updates/check-upstream';
|
|
12
|
-
|
|
13
|
-
const DEVICE_COOKIE = 'nb_gh_device';
|
|
14
|
-
|
|
15
|
-
/** ADMIN gate, mirroring the rest of the CMS server entry points. */
|
|
16
|
-
async function isAdmin(): Promise<boolean> {
|
|
17
|
-
const supabase = createClient();
|
|
18
|
-
const {
|
|
19
|
-
data: { user },
|
|
20
|
-
} = await supabase.auth.getUser();
|
|
21
|
-
if (!user) return false;
|
|
22
|
-
const { data: profile, error } = await supabase
|
|
23
|
-
.from('profiles')
|
|
24
|
-
.select('role')
|
|
25
|
-
.eq('id', user.id)
|
|
26
|
-
.single();
|
|
27
|
-
return !error && profile?.role === 'ADMIN';
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export interface StartConnectResult {
|
|
31
|
-
ok: boolean;
|
|
32
|
-
userCode?: string;
|
|
33
|
-
verificationUri?: string;
|
|
34
|
-
interval?: number;
|
|
35
|
-
expiresIn?: number;
|
|
36
|
-
error?: string;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/** Begin the device flow; stash the device code in an httpOnly cookie for polling. */
|
|
40
|
-
export async function startGithubConnect(): Promise<StartConnectResult> {
|
|
41
|
-
if (!(await isAdmin())) return { ok: false, error: 'Administrator role required.' };
|
|
42
|
-
|
|
43
|
-
try {
|
|
44
|
-
const flow = await startDeviceFlow();
|
|
45
|
-
const store = await cookies();
|
|
46
|
-
store.set(DEVICE_COOKIE, flow.deviceCode, {
|
|
47
|
-
httpOnly: true,
|
|
48
|
-
secure: process.env.NODE_ENV === 'production',
|
|
49
|
-
sameSite: 'lax',
|
|
50
|
-
path: '/cms',
|
|
51
|
-
maxAge: flow.expiresIn,
|
|
52
|
-
});
|
|
53
|
-
return {
|
|
54
|
-
ok: true,
|
|
55
|
-
userCode: flow.userCode,
|
|
56
|
-
verificationUri: flow.verificationUri,
|
|
57
|
-
interval: flow.interval,
|
|
58
|
-
expiresIn: flow.expiresIn,
|
|
59
|
-
};
|
|
60
|
-
} catch (caught) {
|
|
61
|
-
return { ok: false, error: caught instanceof Error ? caught.message : 'Could not start GitHub connect.' };
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export type PollConnectResult =
|
|
66
|
-
| { status: 'installed'; htmlUrl?: string }
|
|
67
|
-
| { status: 'pending'; slowDown?: boolean }
|
|
68
|
-
| { status: 'error'; error: string };
|
|
69
|
-
|
|
70
|
-
/** Poll once; on authorization, install the workflow and clear the device cookie. */
|
|
71
|
-
export async function pollGithubConnect(): Promise<PollConnectResult> {
|
|
72
|
-
if (!(await isAdmin())) return { status: 'error', error: 'Administrator role required.' };
|
|
73
|
-
|
|
74
|
-
const store = await cookies();
|
|
75
|
-
const deviceCode = store.get(DEVICE_COOKIE)?.value;
|
|
76
|
-
if (!deviceCode) {
|
|
77
|
-
return { status: 'error', error: 'Connect session expired — start again.' };
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const poll = await pollDeviceFlowOnce(deviceCode);
|
|
81
|
-
|
|
82
|
-
if (poll.status === 'pending') return { status: 'pending', slowDown: poll.slowDown };
|
|
83
|
-
|
|
84
|
-
if (poll.status === 'authorized') {
|
|
85
|
-
const install = await installSyncWorkflow(poll.token);
|
|
86
|
-
store.delete({ name: DEVICE_COOKIE, path: '/cms' });
|
|
87
|
-
if (install.ok) {
|
|
88
|
-
// We just installed the workflow — flip the onboarding state now instead of waiting
|
|
89
|
-
// for the throttled background poll / GitHub's registration lag.
|
|
90
|
-
await markSyncWorkflowInstalled();
|
|
91
|
-
revalidatePath('/cms', 'layout');
|
|
92
|
-
return { status: 'installed', htmlUrl: install.htmlUrl };
|
|
93
|
-
}
|
|
94
|
-
return { status: 'error', error: install.error ?? 'Could not install the workflow.' };
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// expired / denied / error — clear the session.
|
|
98
|
-
store.delete({ name: DEVICE_COOKIE, path: '/cms' });
|
|
99
|
-
if (poll.status === 'expired') return { status: 'error', error: 'Authorization timed out — start again.' };
|
|
100
|
-
if (poll.status === 'denied') return { status: 'error', error: 'Authorization was declined.' };
|
|
101
|
-
return { status: 'error', error: poll.error };
|
|
102
|
-
}
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { cookies } from 'next/headers';
|
|
4
|
+
import { revalidatePath } from 'next/cache';
|
|
5
|
+
import { createClient } from '@nextblock-cms/db/server';
|
|
6
|
+
import {
|
|
7
|
+
startDeviceFlow,
|
|
8
|
+
pollDeviceFlowOnce,
|
|
9
|
+
installSyncWorkflow,
|
|
10
|
+
} from '../../../lib/updates/github-device';
|
|
11
|
+
import { markSyncWorkflowInstalled } from '../../../lib/updates/check-upstream';
|
|
12
|
+
|
|
13
|
+
const DEVICE_COOKIE = 'nb_gh_device';
|
|
14
|
+
|
|
15
|
+
/** ADMIN gate, mirroring the rest of the CMS server entry points. */
|
|
16
|
+
async function isAdmin(): Promise<boolean> {
|
|
17
|
+
const supabase = createClient();
|
|
18
|
+
const {
|
|
19
|
+
data: { user },
|
|
20
|
+
} = await supabase.auth.getUser();
|
|
21
|
+
if (!user) return false;
|
|
22
|
+
const { data: profile, error } = await supabase
|
|
23
|
+
.from('profiles')
|
|
24
|
+
.select('role')
|
|
25
|
+
.eq('id', user.id)
|
|
26
|
+
.single();
|
|
27
|
+
return !error && profile?.role === 'ADMIN';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface StartConnectResult {
|
|
31
|
+
ok: boolean;
|
|
32
|
+
userCode?: string;
|
|
33
|
+
verificationUri?: string;
|
|
34
|
+
interval?: number;
|
|
35
|
+
expiresIn?: number;
|
|
36
|
+
error?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Begin the device flow; stash the device code in an httpOnly cookie for polling. */
|
|
40
|
+
export async function startGithubConnect(): Promise<StartConnectResult> {
|
|
41
|
+
if (!(await isAdmin())) return { ok: false, error: 'Administrator role required.' };
|
|
42
|
+
|
|
43
|
+
try {
|
|
44
|
+
const flow = await startDeviceFlow();
|
|
45
|
+
const store = await cookies();
|
|
46
|
+
store.set(DEVICE_COOKIE, flow.deviceCode, {
|
|
47
|
+
httpOnly: true,
|
|
48
|
+
secure: process.env.NODE_ENV === 'production',
|
|
49
|
+
sameSite: 'lax',
|
|
50
|
+
path: '/cms',
|
|
51
|
+
maxAge: flow.expiresIn,
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
ok: true,
|
|
55
|
+
userCode: flow.userCode,
|
|
56
|
+
verificationUri: flow.verificationUri,
|
|
57
|
+
interval: flow.interval,
|
|
58
|
+
expiresIn: flow.expiresIn,
|
|
59
|
+
};
|
|
60
|
+
} catch (caught) {
|
|
61
|
+
return { ok: false, error: caught instanceof Error ? caught.message : 'Could not start GitHub connect.' };
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type PollConnectResult =
|
|
66
|
+
| { status: 'installed'; htmlUrl?: string }
|
|
67
|
+
| { status: 'pending'; slowDown?: boolean }
|
|
68
|
+
| { status: 'error'; error: string };
|
|
69
|
+
|
|
70
|
+
/** Poll once; on authorization, install the workflow and clear the device cookie. */
|
|
71
|
+
export async function pollGithubConnect(): Promise<PollConnectResult> {
|
|
72
|
+
if (!(await isAdmin())) return { status: 'error', error: 'Administrator role required.' };
|
|
73
|
+
|
|
74
|
+
const store = await cookies();
|
|
75
|
+
const deviceCode = store.get(DEVICE_COOKIE)?.value;
|
|
76
|
+
if (!deviceCode) {
|
|
77
|
+
return { status: 'error', error: 'Connect session expired — start again.' };
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const poll = await pollDeviceFlowOnce(deviceCode);
|
|
81
|
+
|
|
82
|
+
if (poll.status === 'pending') return { status: 'pending', slowDown: poll.slowDown };
|
|
83
|
+
|
|
84
|
+
if (poll.status === 'authorized') {
|
|
85
|
+
const install = await installSyncWorkflow(poll.token);
|
|
86
|
+
store.delete({ name: DEVICE_COOKIE, path: '/cms' });
|
|
87
|
+
if (install.ok) {
|
|
88
|
+
// We just installed the workflow — flip the onboarding state now instead of waiting
|
|
89
|
+
// for the throttled background poll / GitHub's registration lag.
|
|
90
|
+
await markSyncWorkflowInstalled();
|
|
91
|
+
revalidatePath('/cms', 'layout');
|
|
92
|
+
return { status: 'installed', htmlUrl: install.htmlUrl };
|
|
93
|
+
}
|
|
94
|
+
return { status: 'error', error: install.error ?? 'Could not install the workflow.' };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// expired / denied / error — clear the session.
|
|
98
|
+
store.delete({ name: DEVICE_COOKIE, path: '/cms' });
|
|
99
|
+
if (poll.status === 'expired') return { status: 'error', error: 'Authorization timed out — start again.' };
|
|
100
|
+
if (poll.status === 'denied') return { status: 'error', error: 'Authorization was declined.' };
|
|
101
|
+
return { status: 'error', error: poll.error };
|
|
102
|
+
}
|
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
'use server';
|
|
2
|
-
|
|
3
|
-
import { revalidatePath } from 'next/cache';
|
|
4
|
-
import { createClient } from '@nextblock-cms/db/server';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Mark a system alert resolved (dismiss it from the dashboard banner). Runs as the
|
|
8
|
-
* signed-in user; the system_alerts UPDATE RLS policy restricts this to ADMINs, so a
|
|
9
|
-
* non-admin caller simply updates zero rows. Inserts are service-role only.
|
|
10
|
-
*/
|
|
11
|
-
export async function resolveSystemAlert(
|
|
12
|
-
id: string,
|
|
13
|
-
): Promise<{ ok: boolean; error?: string }> {
|
|
14
|
-
if (!id) return { ok: false, error: 'Missing alert id.' };
|
|
15
|
-
|
|
16
|
-
const supabase = createClient();
|
|
17
|
-
const {
|
|
18
|
-
data: { user },
|
|
19
|
-
} = await supabase.auth.getUser();
|
|
20
|
-
if (!user) return { ok: false, error: 'Not authenticated.' };
|
|
21
|
-
|
|
22
|
-
const { error } = await supabase
|
|
23
|
-
.from('system_alerts')
|
|
24
|
-
.update({ is_resolved: true, resolved_at: new Date().toISOString() })
|
|
25
|
-
.eq('id', id);
|
|
26
|
-
|
|
27
|
-
if (error) return { ok: false, error: error.message };
|
|
28
|
-
|
|
29
|
-
revalidatePath('/cms', 'layout');
|
|
30
|
-
return { ok: true };
|
|
31
|
-
}
|
|
1
|
+
'use server';
|
|
2
|
+
|
|
3
|
+
import { revalidatePath } from 'next/cache';
|
|
4
|
+
import { createClient } from '@nextblock-cms/db/server';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Mark a system alert resolved (dismiss it from the dashboard banner). Runs as the
|
|
8
|
+
* signed-in user; the system_alerts UPDATE RLS policy restricts this to ADMINs, so a
|
|
9
|
+
* non-admin caller simply updates zero rows. Inserts are service-role only.
|
|
10
|
+
*/
|
|
11
|
+
export async function resolveSystemAlert(
|
|
12
|
+
id: string,
|
|
13
|
+
): Promise<{ ok: boolean; error?: string }> {
|
|
14
|
+
if (!id) return { ok: false, error: 'Missing alert id.' };
|
|
15
|
+
|
|
16
|
+
const supabase = createClient();
|
|
17
|
+
const {
|
|
18
|
+
data: { user },
|
|
19
|
+
} = await supabase.auth.getUser();
|
|
20
|
+
if (!user) return { ok: false, error: 'Not authenticated.' };
|
|
21
|
+
|
|
22
|
+
const { error } = await supabase
|
|
23
|
+
.from('system_alerts')
|
|
24
|
+
.update({ is_resolved: true, resolved_at: new Date().toISOString() })
|
|
25
|
+
.eq('id', id);
|
|
26
|
+
|
|
27
|
+
if (error) return { ok: false, error: error.message };
|
|
28
|
+
|
|
29
|
+
revalidatePath('/cms', 'layout');
|
|
30
|
+
return { ok: true };
|
|
31
|
+
}
|
|
@@ -1,66 +1,66 @@
|
|
|
1
|
-
import React from "react";
|
|
2
|
-
import Link from "next/link";
|
|
3
|
-
import { ArrowLeft, AlertCircle } from "lucide-react";
|
|
4
|
-
import { Button } from "@nextblock-cms/ui";
|
|
5
|
-
import { BlockComposer } from "../../components/BlockComposer";
|
|
6
|
-
import { getCustomBlockDefinition } from "../../actions";
|
|
7
|
-
|
|
8
|
-
interface EditCustomBlockPageProps {
|
|
9
|
-
params: Promise<{
|
|
10
|
-
id: string;
|
|
11
|
-
}>;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const dynamic = "force-dynamic";
|
|
15
|
-
|
|
16
|
-
export default async function EditCustomBlockPage(props: EditCustomBlockPageProps) {
|
|
17
|
-
const params = await props.params;
|
|
18
|
-
const blockId = params.id;
|
|
19
|
-
|
|
20
|
-
try {
|
|
21
|
-
const res = await getCustomBlockDefinition(blockId);
|
|
22
|
-
|
|
23
|
-
if (!res.success || !res.data) {
|
|
24
|
-
return (
|
|
25
|
-
<div className="flex flex-col items-center justify-center text-center py-16 px-4 max-w-md mx-auto">
|
|
26
|
-
<div className="h-12 w-12 rounded-full bg-destructive/10 flex items-center justify-center text-destructive mb-4">
|
|
27
|
-
<AlertCircle className="h-6 w-6" />
|
|
28
|
-
</div>
|
|
29
|
-
<h3 className="text-lg font-semibold">Block Not Found</h3>
|
|
30
|
-
<p className="text-sm text-muted-foreground mt-2">
|
|
31
|
-
The custom block definition you are trying to edit could not be loaded. It may have been deleted or does not exist.
|
|
32
|
-
</p>
|
|
33
|
-
<Button asChild className="mt-6" variant="outline">
|
|
34
|
-
<Link href="/cms/custom-blocks">
|
|
35
|
-
<ArrowLeft className="mr-2 h-4 w-4" /> Back to Blocks
|
|
36
|
-
</Link>
|
|
37
|
-
</Button>
|
|
38
|
-
</div>
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return (
|
|
43
|
-
<div className="w-full">
|
|
44
|
-
<BlockComposer initialData={res.data} mode="edit" />
|
|
45
|
-
</div>
|
|
46
|
-
);
|
|
47
|
-
} catch (err) {
|
|
48
|
-
console.error("Error loading custom block definition for edit:", err);
|
|
49
|
-
return (
|
|
50
|
-
<div className="flex flex-col items-center justify-center text-center py-16 px-4 max-w-md mx-auto">
|
|
51
|
-
<div className="h-12 w-12 rounded-full bg-destructive/10 flex items-center justify-center text-destructive mb-4">
|
|
52
|
-
<AlertCircle className="h-6 w-6" />
|
|
53
|
-
</div>
|
|
54
|
-
<h3 className="text-lg font-semibold">Unexpected Error</h3>
|
|
55
|
-
<p className="text-sm text-muted-foreground mt-2">
|
|
56
|
-
An error occurred while trying to load the custom block definition. Please try again.
|
|
57
|
-
</p>
|
|
58
|
-
<Button asChild className="mt-6" variant="outline">
|
|
59
|
-
<Link href="/cms/custom-blocks">
|
|
60
|
-
<ArrowLeft className="mr-2 h-4 w-4" /> Back to Blocks
|
|
61
|
-
</Link>
|
|
62
|
-
</Button>
|
|
63
|
-
</div>
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
1
|
+
import React from "react";
|
|
2
|
+
import Link from "next/link";
|
|
3
|
+
import { ArrowLeft, AlertCircle } from "lucide-react";
|
|
4
|
+
import { Button } from "@nextblock-cms/ui";
|
|
5
|
+
import { BlockComposer } from "../../components/BlockComposer";
|
|
6
|
+
import { getCustomBlockDefinition } from "../../actions";
|
|
7
|
+
|
|
8
|
+
interface EditCustomBlockPageProps {
|
|
9
|
+
params: Promise<{
|
|
10
|
+
id: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const dynamic = "force-dynamic";
|
|
15
|
+
|
|
16
|
+
export default async function EditCustomBlockPage(props: EditCustomBlockPageProps) {
|
|
17
|
+
const params = await props.params;
|
|
18
|
+
const blockId = params.id;
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
const res = await getCustomBlockDefinition(blockId);
|
|
22
|
+
|
|
23
|
+
if (!res.success || !res.data) {
|
|
24
|
+
return (
|
|
25
|
+
<div className="flex flex-col items-center justify-center text-center py-16 px-4 max-w-md mx-auto">
|
|
26
|
+
<div className="h-12 w-12 rounded-full bg-destructive/10 flex items-center justify-center text-destructive mb-4">
|
|
27
|
+
<AlertCircle className="h-6 w-6" />
|
|
28
|
+
</div>
|
|
29
|
+
<h3 className="text-lg font-semibold">Block Not Found</h3>
|
|
30
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
31
|
+
The custom block definition you are trying to edit could not be loaded. It may have been deleted or does not exist.
|
|
32
|
+
</p>
|
|
33
|
+
<Button asChild className="mt-6" variant="outline">
|
|
34
|
+
<Link href="/cms/custom-blocks">
|
|
35
|
+
<ArrowLeft className="mr-2 h-4 w-4" /> Back to Blocks
|
|
36
|
+
</Link>
|
|
37
|
+
</Button>
|
|
38
|
+
</div>
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="w-full">
|
|
44
|
+
<BlockComposer initialData={res.data} mode="edit" />
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error("Error loading custom block definition for edit:", err);
|
|
49
|
+
return (
|
|
50
|
+
<div className="flex flex-col items-center justify-center text-center py-16 px-4 max-w-md mx-auto">
|
|
51
|
+
<div className="h-12 w-12 rounded-full bg-destructive/10 flex items-center justify-center text-destructive mb-4">
|
|
52
|
+
<AlertCircle className="h-6 w-6" />
|
|
53
|
+
</div>
|
|
54
|
+
<h3 className="text-lg font-semibold">Unexpected Error</h3>
|
|
55
|
+
<p className="text-sm text-muted-foreground mt-2">
|
|
56
|
+
An error occurred while trying to load the custom block definition. Please try again.
|
|
57
|
+
</p>
|
|
58
|
+
<Button asChild className="mt-6" variant="outline">
|
|
59
|
+
<Link href="/cms/custom-blocks">
|
|
60
|
+
<ArrowLeft className="mr-2 h-4 w-4" /> Back to Blocks
|
|
61
|
+
</Link>
|
|
62
|
+
</Button>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
}
|