@nextsparkjs/core 0.1.0-beta.187 → 0.1.0-beta.189
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/dist/components/api/keys/ApiKeyDisplay.js +19 -19
- package/dist/components/api/keys/CreateApiKeyDialog.js +21 -21
- package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicNavbar.js +34 -16
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +3 -4
- package/dist/components/auth/SessionCookieRefresher.d.ts +5 -0
- package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -1
- package/dist/components/auth/SessionCookieRefresher.js +7 -1
- package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
- package/dist/components/auth/forms/LoginForm.js +49 -12
- package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/forms/SignupForm.js +4 -3
- package/dist/components/dashboard/block-editor/block-settings-panel.js +1 -1
- package/dist/components/dashboard/block-editor/floating-block-toolbar.js +1 -1
- package/dist/components/dashboard/block-editor/sortable-block.js +1 -1
- package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/Sidebar.js +8 -6
- package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/TopNavbar.js +51 -54
- package/dist/components/dashboard/misc/NotificationsDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/NotificationsDropdown.js +17 -15
- package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/SearchDropdown.js +19 -22
- package/dist/components/dashboard/mobile/MobileBottomNav.js +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts +10 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts.map +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.js +4 -3
- package/dist/components/dashboard/navigation/DynamicNavigation.js +5 -5
- package/dist/components/devtools/BlockDetailViewer.js +1 -1
- package/dist/components/devtools/BlocksViewer.js +1 -1
- package/dist/components/entities/EntityChildManager.js +5 -5
- package/dist/components/entities/EntityDetailPage.d.ts.map +1 -1
- package/dist/components/entities/EntityDetailPage.js +16 -15
- package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
- package/dist/components/entities/EntityFieldRenderer.js +12 -7
- package/dist/components/entities/EntityPageHeader.js +5 -5
- package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/entities/ErrorBoundary.js +20 -21
- package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -5
- package/dist/components/entities/wrappers/EntityFormWrapper.js +2 -2
- package/dist/components/entities/wrappers/EntityListWrapper.js +3 -3
- package/dist/components/permissions/NoPermission.js +10 -10
- package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
- package/dist/components/public/pageBuilder/PageRenderer.js +2 -1
- package/dist/components/settings/SettingsPageSkeleton.js +4 -4
- package/dist/components/settings/layouts/SettingsSidebar.js +6 -6
- package/dist/components/shared/MultiSelectFilter.d.ts +3 -1
- package/dist/components/shared/MultiSelectFilter.d.ts.map +1 -1
- package/dist/components/shared/MultiSelectFilter.js +7 -3
- package/dist/components/shared/SearchInput.d.ts +2 -0
- package/dist/components/shared/SearchInput.d.ts.map +1 -1
- package/dist/components/shared/SearchInput.js +64 -6
- package/dist/components/ui/address-input.js +18 -18
- package/dist/components/ui/audio-upload.js +9 -9
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/combobox.js +4 -4
- package/dist/components/ui/country-select.d.ts.map +1 -1
- package/dist/components/ui/country-select.js +3 -3
- package/dist/components/ui/currency-select.d.ts.map +1 -1
- package/dist/components/ui/currency-select.js +3 -3
- package/dist/components/ui/dynamic-icon.d.ts.map +1 -1
- package/dist/components/ui/dynamic-icon.js +3 -2
- package/dist/components/ui/file-upload.js +7 -7
- package/dist/components/ui/image-upload.js +8 -8
- package/dist/components/ui/multi-select.d.ts +2 -1
- package/dist/components/ui/multi-select.d.ts.map +1 -1
- package/dist/components/ui/multi-select.js +4 -3
- package/dist/components/ui/phone-input.d.ts.map +1 -1
- package/dist/components/ui/phone-input.js +3 -3
- package/dist/components/ui/relation-display.js +1 -1
- package/dist/components/ui/simple-relation-select.d.ts +2 -1
- package/dist/components/ui/simple-relation-select.d.ts.map +1 -1
- package/dist/components/ui/simple-relation-select.js +7 -6
- package/dist/components/ui/tags-input.d.ts.map +1 -1
- package/dist/components/ui/tags-input.js +1 -1
- package/dist/components/ui/timezone-select.d.ts.map +1 -1
- package/dist/components/ui/timezone-select.js +3 -3
- package/dist/components/ui/user-display.js +4 -4
- package/dist/components/ui/user-select.d.ts.map +1 -1
- package/dist/components/ui/user-select.js +9 -9
- package/dist/components/ui/video-upload.js +9 -9
- package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
- package/dist/contexts/SubscriptionContext.js +5 -1
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +83 -26
- package/dist/emails/otp-verification.d.ts.map +1 -1
- package/dist/emails/otp-verification.js +3 -2
- package/dist/hooks/useAccountPreferencesSync.d.ts +13 -0
- package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -0
- package/dist/hooks/useAccountPreferencesSync.js +95 -0
- package/dist/hooks/useAuth.d.ts +202 -15
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +49 -13
- package/dist/hooks/useEntityConfig.js +2 -2
- package/dist/hooks/useEntitySearch.js +10 -10
- package/dist/hooks/useNotifications.js +12 -12
- package/dist/hooks/usePrefetch.d.ts.map +1 -1
- package/dist/hooks/usePrefetch.js +6 -2
- package/dist/hooks/useSearch.js +15 -15
- package/dist/hooks/useSessionCookieRefresh.d.ts +18 -1
- package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -1
- package/dist/hooks/useSessionCookieRefresh.js +17 -4
- package/dist/hooks/useSessionHint.d.ts +12 -0
- package/dist/hooks/useSessionHint.d.ts.map +1 -0
- package/dist/hooks/useSessionHint.js +15 -0
- package/dist/hooks/useTranslationPreload.js +6 -6
- package/dist/i18n.d.ts +13 -0
- package/dist/i18n.d.ts.map +1 -1
- package/dist/i18n.js +2 -27
- package/dist/lib/actions/entity.actions.d.ts.map +1 -1
- package/dist/lib/actions/entity.actions.js +3 -2
- package/dist/lib/api/auth/dual-auth.d.ts +4 -1
- package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
- package/dist/lib/api/auth/dual-auth.js +5 -16
- package/dist/lib/api/entities.js +33 -33
- package/dist/lib/api/keys.d.ts +27 -27
- package/dist/lib/api/keys.js +27 -27
- package/dist/lib/auth/callback-url.d.ts +11 -0
- package/dist/lib/auth/callback-url.d.ts.map +1 -0
- package/dist/lib/auth/callback-url.js +14 -0
- package/dist/lib/auth/otp-config.d.ts +55 -0
- package/dist/lib/auth/otp-config.d.ts.map +1 -0
- package/dist/lib/auth/otp-config.js +48 -0
- package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
- package/dist/lib/auth/registration-helpers.js +3 -1
- package/dist/lib/auth/session-hint.d.ts +31 -0
- package/dist/lib/auth/session-hint.d.ts.map +1 -0
- package/dist/lib/auth/session-hint.js +37 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +6 -4
- package/dist/lib/blocks/loader.d.ts +3 -11
- package/dist/lib/blocks/loader.d.ts.map +1 -1
- package/dist/lib/blocks/loader.js +1 -9
- package/dist/lib/blocks/loader.server.d.ts +18 -0
- package/dist/lib/blocks/loader.server.d.ts.map +1 -0
- package/dist/lib/blocks/loader.server.js +11 -0
- package/dist/lib/blocks/sanitize-html.d.ts +31 -0
- package/dist/lib/blocks/sanitize-html.d.ts.map +1 -0
- package/dist/lib/blocks/sanitize-html.js +60 -0
- package/dist/lib/config/config-sync.d.ts +1 -0
- package/dist/lib/config/config-sync.d.ts.map +1 -1
- package/dist/lib/config/config-sync.js +4 -1
- package/dist/lib/config/types.d.ts +48 -0
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/email/types.d.ts +6 -0
- package/dist/lib/email/types.d.ts.map +1 -1
- package/dist/lib/entities/serialization.d.ts.map +1 -1
- package/dist/lib/entities/serialization.js +3 -6
- package/dist/lib/icons.d.ts +12 -0
- package/dist/lib/icons.d.ts.map +1 -0
- package/dist/lib/icons.js +30 -0
- package/dist/lib/locale.d.ts +25 -1
- package/dist/lib/locale.d.ts.map +1 -1
- package/dist/lib/locale.js +49 -35
- package/dist/lib/mcp/engine.js +1 -1
- package/dist/lib/mcp/errors.js +17 -17
- package/dist/lib/mcp/schema-builder.js +16 -16
- package/dist/lib/mcp/tool-generator.js +18 -18
- package/dist/lib/search-highlighting.d.ts +7 -0
- package/dist/lib/search-highlighting.d.ts.map +1 -1
- package/dist/lib/search-highlighting.js +6 -2
- package/dist/lib/selectors/core-selectors.d.ts +2 -0
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.d.ts +1 -0
- package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.js +1 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts +2 -0
- package/dist/lib/selectors/domains/entities.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/entities.selectors.js +2 -0
- package/dist/lib/selectors/selectors.d.ts +4 -0
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/lib/services/block.service.js +1 -1
- package/dist/lib/teams/active-team-cookie.d.ts +24 -0
- package/dist/lib/teams/active-team-cookie.d.ts.map +1 -0
- package/dist/lib/teams/active-team-cookie.js +17 -0
- package/dist/lib/teams/dashboard-team.d.ts +20 -0
- package/dist/lib/teams/dashboard-team.d.ts.map +1 -0
- package/dist/lib/teams/dashboard-team.js +38 -0
- package/dist/lib/teams/schema.d.ts.map +1 -1
- package/dist/lib/teams/schema.js +1 -1
- package/dist/lib/template-resolver.d.ts.map +1 -1
- package/dist/lib/template-resolver.js +0 -1
- package/dist/lib/theme/get-default-theme-mode.d.ts +7 -4
- package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
- package/dist/lib/theme/get-default-theme-mode.js +2 -44
- package/dist/messages/de/auth.json +4 -2
- package/dist/messages/de/common.json +83 -3
- package/dist/messages/de/email.json +1 -1
- package/dist/messages/de/index.d.ts +87 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/de/settings.json +5 -0
- package/dist/messages/en/auth.json +4 -2
- package/dist/messages/en/common.json +83 -3
- package/dist/messages/en/email.json +1 -1
- package/dist/messages/en/index.d.ts +86 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/en/settings.json +4 -0
- package/dist/messages/es/auth.json +4 -2
- package/dist/messages/es/common.json +83 -3
- package/dist/messages/es/email.json +1 -1
- package/dist/messages/es/index.d.ts +86 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/es/settings.json +4 -0
- package/dist/messages/fr/auth.json +4 -2
- package/dist/messages/fr/common.json +83 -3
- package/dist/messages/fr/email.json +1 -1
- package/dist/messages/fr/index.d.ts +87 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/fr/settings.json +5 -0
- package/dist/messages/it/auth.json +4 -2
- package/dist/messages/it/common.json +83 -3
- package/dist/messages/it/email.json +1 -1
- package/dist/messages/it/index.d.ts +87 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/it/settings.json +5 -0
- package/dist/messages/pt/auth.json +4 -2
- package/dist/messages/pt/common.json +83 -3
- package/dist/messages/pt/email.json +1 -1
- package/dist/messages/pt/index.d.ts +87 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/messages/pt/settings.json +5 -0
- package/dist/nextspark-registries.d.ts +54 -0
- package/dist/providers/DashboardProviders.d.ts +13 -10
- package/dist/providers/DashboardProviders.d.ts.map +1 -1
- package/dist/providers/DashboardProviders.js +7 -1
- package/dist/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/dist/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/dist/templates/app/403/page.tsx +6 -6
- package/dist/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/dist/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/dist/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/dist/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/dist/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/dist/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/dist/templates/app/layout.ppr.tsx +8 -8
- package/dist/templates/app/layout.tsx +12 -17
- package/dist/templates/blocks/cta-section/component.tsx +5 -2
- package/dist/templates/blocks/cta-section/config.ts +3 -2
- package/dist/templates/blocks/cta-section/fields.ts +2 -2
- package/dist/templates/blocks/cta-section/schema.ts +2 -2
- package/dist/templates/blocks/features-grid/component.tsx +10 -2
- package/dist/templates/blocks/features-grid/config.ts +3 -2
- package/dist/templates/blocks/features-grid/fields.ts +2 -2
- package/dist/templates/blocks/features-grid/schema.ts +2 -2
- package/dist/templates/blocks/hero/component.tsx +6 -3
- package/dist/templates/blocks/hero/config.ts +3 -2
- package/dist/templates/blocks/hero/fields.ts +2 -2
- package/dist/templates/blocks/hero/schema.ts +2 -2
- package/dist/templates/blocks/testimonials/component.tsx +6 -3
- package/dist/templates/blocks/testimonials/config.ts +3 -2
- package/dist/templates/blocks/testimonials/fields.ts +2 -2
- package/dist/templates/blocks/testimonials/schema.ts +2 -2
- package/dist/templates/blocks/text-content/component.tsx +7 -3
- package/dist/templates/blocks/text-content/config.ts +3 -2
- package/dist/templates/blocks/text-content/fields.ts +2 -2
- package/dist/templates/blocks/text-content/schema.ts +2 -2
- package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/dist/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/dist/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/dist/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/dist/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/dist/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/dist/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/dist/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/dist/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/dist/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/dist/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/dist/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/dist/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/dist/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/dist/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/dist/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/dist/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/dist/templates/proxy.ts +138 -53
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/blocks.js +1 -1
- package/dist/types/task.types.d.ts +1 -1
- package/dist/types/task.types.js +7 -7
- package/dist/utils/dev/TranslationDebugger.js +2 -2
- package/package.json +14 -5
- package/scripts/build/registry/__tests__/block-registry.test.mjs +73 -0
- package/scripts/build/registry/__tests__/icons-discovery.test.mjs +130 -0
- package/scripts/build/registry/__tests__/identifier.test.mjs +65 -0
- package/scripts/build/registry/__tests__/page-generator.test.mjs +430 -0
- package/scripts/build/registry/__tests__/scheduled-actions-registry.test.mjs +41 -0
- package/scripts/build/registry/__tests__/template-registry.test.mjs +89 -0
- package/scripts/build/registry/discovery/icons.mjs +275 -0
- package/scripts/build/registry/discovery/index.mjs +1 -0
- package/scripts/build/registry/generators/block-registry.mjs +203 -55
- package/scripts/build/registry/generators/feature-registry.mjs +9 -2
- package/scripts/build/registry/generators/icon-registry.mjs +56 -0
- package/scripts/build/registry/generators/identifier.mjs +28 -0
- package/scripts/build/registry/generators/index.mjs +1 -0
- package/scripts/build/registry/generators/plugin-registry.mjs +4 -3
- package/scripts/build/registry/generators/scheduled-actions-registry.mjs +4 -2
- package/scripts/build/registry/generators/template-registry.mjs +49 -41
- package/scripts/build/registry/generators/theme-registry.mjs +6 -7
- package/scripts/build/registry/post-build/page-generator.mjs +380 -59
- package/scripts/build/registry.mjs +9 -1
- package/templates/app/(auth)/forgot-password/page.tsx +2 -2
- package/templates/app/(auth)/reset-password/page.tsx +6 -6
- package/templates/app/403/page.tsx +6 -6
- package/templates/app/api/v1/teams/switch/route.ts +24 -5
- package/templates/app/dashboard/(main)/[entity]/layout.tsx +9 -7
- package/templates/app/dashboard/(main)/layout.tsx +4 -3
- package/templates/app/dashboard/settings/api-keys/page.tsx +36 -34
- package/templates/app/dashboard/settings/profile/page.tsx +7 -6
- package/templates/app/dashboard/settings/security/page.tsx +5 -4
- package/templates/app/layout.ppr.tsx +8 -8
- package/templates/app/layout.tsx +12 -17
- package/templates/blocks/cta-section/component.tsx +5 -2
- package/templates/blocks/cta-section/config.ts +3 -2
- package/templates/blocks/cta-section/fields.ts +2 -2
- package/templates/blocks/cta-section/schema.ts +2 -2
- package/templates/blocks/features-grid/component.tsx +10 -2
- package/templates/blocks/features-grid/config.ts +3 -2
- package/templates/blocks/features-grid/fields.ts +2 -2
- package/templates/blocks/features-grid/schema.ts +2 -2
- package/templates/blocks/hero/component.tsx +6 -3
- package/templates/blocks/hero/config.ts +3 -2
- package/templates/blocks/hero/fields.ts +2 -2
- package/templates/blocks/hero/schema.ts +2 -2
- package/templates/blocks/testimonials/component.tsx +6 -3
- package/templates/blocks/testimonials/config.ts +3 -2
- package/templates/blocks/testimonials/fields.ts +2 -2
- package/templates/blocks/testimonials/schema.ts +2 -2
- package/templates/blocks/text-content/component.tsx +7 -3
- package/templates/blocks/text-content/config.ts +3 -2
- package/templates/blocks/text-content/fields.ts +2 -2
- package/templates/blocks/text-content/schema.ts +2 -2
- package/templates/contents/themes/starter/blocks/cta-section/component.tsx +102 -0
- package/templates/contents/themes/starter/blocks/cta-section/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/cta-section/fields.ts +89 -0
- package/templates/contents/themes/starter/blocks/cta-section/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/cta-section/schema.ts +32 -0
- package/templates/contents/themes/starter/blocks/cta-section/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/features-grid/component.tsx +119 -0
- package/templates/contents/themes/starter/blocks/features-grid/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/features-grid/fields.ts +97 -0
- package/templates/contents/themes/starter/blocks/features-grid/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/features-grid/schema.ts +40 -0
- package/templates/contents/themes/starter/blocks/features-grid/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/hero/component.tsx +105 -0
- package/templates/contents/themes/starter/blocks/hero/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/hero/fields.ts +60 -0
- package/templates/contents/themes/starter/blocks/hero/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/hero/schema.ts +33 -0
- package/templates/contents/themes/starter/blocks/hero/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/testimonials/component.tsx +116 -0
- package/templates/contents/themes/starter/blocks/testimonials/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/testimonials/fields.ts +105 -0
- package/templates/contents/themes/starter/blocks/testimonials/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/testimonials/schema.ts +41 -0
- package/templates/contents/themes/starter/blocks/testimonials/thumbnail.png +0 -0
- package/templates/contents/themes/starter/blocks/text-content/component.tsx +100 -0
- package/templates/contents/themes/starter/blocks/text-content/config.ts +11 -0
- package/templates/contents/themes/starter/blocks/text-content/fields.ts +88 -0
- package/templates/contents/themes/starter/blocks/text-content/index.ts +6 -0
- package/templates/contents/themes/starter/blocks/text-content/schema.ts +30 -0
- package/templates/contents/themes/starter/blocks/text-content/thumbnail.png +0 -0
- package/templates/contents/themes/starter/config/app.config.ts +8 -0
- package/templates/contents/themes/starter/entities/tasks/tasks.config.ts +7 -0
- package/templates/contents/themes/starter/tests/cypress/e2e/_utils/devtools/access.cy.ts +9 -1
- package/templates/contents/themes/starter/tests/cypress/e2e/api/entities/tasks/TaskAPIController.js +2 -2
- package/templates/contents/themes/starter/tests/cypress/e2e/uat/entities/tasks/tasks-crud.cy.ts +45 -38
- package/templates/contents/themes/starter/tests/cypress/fixtures/entities.json +16 -0
- package/templates/contents/themes/starter/tests/cypress/src/components/DevKeyringPOM.ts +3 -1
- package/templates/contents/themes/starter/tests/cypress/src/core/BlockEditorBasePOM.ts +3 -3
- package/templates/contents/themes/starter/tests/cypress/src/entities/PagesPOM.ts +137 -0
- package/templates/contents/themes/starter/tests/cypress/src/entities/index.ts +2 -0
- package/templates/contents/themes/starter/tests/cypress/src/index.ts +1 -0
- package/templates/contents/themes/starter/tests/cypress/src/session-helpers.ts +42 -11
- package/templates/contents/themes/starter/tests/cypress/support/commands.ts +29 -18
- package/templates/features/blog/blocks/post-content/component.tsx +5 -1
- package/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/templates/features/pages/blocks/hero/component.tsx +3 -0
- package/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/templates/proxy.ts +138 -53
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.client.ts +9 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/block-registry.lazy.ts +5 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/icon-registry.ts +42 -0
- package/tests/jest/__mocks__/next-intl-server.js +85 -5
- package/tests/jest/__mocks__/next-server.js +32 -0
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module core/scripts/build/registry/post-build/page-generator
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
import { createRequire } from 'node:module'
|
|
9
10
|
import { existsSync } from 'fs'
|
|
10
11
|
import { readFile, writeFile, mkdir } from 'fs/promises'
|
|
11
12
|
import { join, dirname } from 'path'
|
|
@@ -31,46 +32,351 @@ function toPascalCase(str) {
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
/**
|
|
34
|
-
* Next.js route
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* Next.js route segment config keys (the `AppSegmentConfigSchema` keys from
|
|
36
|
+
* `next/dist/build/segment-config/app/app-segment-config`). Next.js only
|
|
37
|
+
* reads these when they're declared as a literal `export const` directly in
|
|
38
|
+
* the route file — a re-export doesn't work, so the generated route file
|
|
39
|
+
* must re-declare the value itself rather than forward it.
|
|
39
40
|
*/
|
|
40
|
-
const
|
|
41
|
-
'generateMetadata',
|
|
42
|
-
'generateStaticParams',
|
|
43
|
-
'generateViewport',
|
|
44
|
-
'metadata',
|
|
45
|
-
'viewport',
|
|
41
|
+
export const SEGMENT_CONFIG_EXPORTS = [
|
|
46
42
|
'revalidate',
|
|
47
|
-
'dynamic',
|
|
48
43
|
'dynamicParams',
|
|
44
|
+
'dynamic',
|
|
49
45
|
'fetchCache',
|
|
50
|
-
'runtime',
|
|
51
46
|
'preferredRegion',
|
|
47
|
+
'experimental_ppr',
|
|
48
|
+
'runtime',
|
|
52
49
|
'maxDuration',
|
|
53
50
|
]
|
|
54
51
|
|
|
55
52
|
/**
|
|
56
|
-
*
|
|
57
|
-
*
|
|
53
|
+
* Next.js module-level route exports that Next.js is happy to pick up
|
|
54
|
+
* through a re-export (`export { x } from '...'`), unlike segment config.
|
|
58
55
|
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
56
|
+
export const MODULE_LEVEL_EXPORTS = [
|
|
57
|
+
'generateMetadata',
|
|
58
|
+
'generateStaticParams',
|
|
59
|
+
'generateViewport',
|
|
60
|
+
'metadata',
|
|
61
|
+
'viewport',
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Per-key validators for the segment config schema. A value that parses as a
|
|
66
|
+
* literal but doesn't match here would still make Next.js throw at build
|
|
67
|
+
* time (via `parseAppSegmentConfig`), just later and with less context about
|
|
68
|
+
* which theme template caused it.
|
|
69
|
+
*/
|
|
70
|
+
const SEGMENT_CONFIG_VALIDATORS = {
|
|
71
|
+
revalidate: value => value === false || (typeof value === 'number' && Number.isInteger(value) && value >= 0),
|
|
72
|
+
dynamicParams: value => typeof value === 'boolean',
|
|
73
|
+
dynamic: value => ['auto', 'error', 'force-static', 'force-dynamic'].includes(value),
|
|
74
|
+
fetchCache: value =>
|
|
75
|
+
['auto', 'default-cache', 'only-cache', 'force-cache', 'force-no-store', 'default-no-store', 'only-no-store'].includes(value),
|
|
76
|
+
preferredRegion: value => typeof value === 'string' || (Array.isArray(value) && value.every(item => typeof item === 'string')),
|
|
77
|
+
experimental_ppr: value => typeof value === 'boolean',
|
|
78
|
+
runtime: value => ['edge', 'nodejs'].includes(value),
|
|
79
|
+
maxDuration: value => typeof value === 'number' && Number.isInteger(value) && value >= 0,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Loaded lazily (and only once) since not every consumer of this module needs
|
|
83
|
+
// to parse a template - npm-mode builds without a template needing this path
|
|
84
|
+
// shouldn't pay for loading a TypeScript compiler up front.
|
|
85
|
+
let typescriptModulePromise = null
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The TypeScript compiler, resolved from core first and then from the project:
|
|
89
|
+
* it is a devDependency of core, so an installed core finds it through the
|
|
90
|
+
* project that builds it, which has it to compile its own `.tsx` files.
|
|
91
|
+
*/
|
|
92
|
+
function loadTypeScript() {
|
|
93
|
+
if (!typescriptModulePromise) {
|
|
94
|
+
typescriptModulePromise = import('typescript')
|
|
95
|
+
.catch(() => createRequire(join(rootDir, 'package.json'))('typescript'))
|
|
96
|
+
.then(
|
|
97
|
+
module => module.default ?? module,
|
|
98
|
+
error => {
|
|
99
|
+
throw new Error(
|
|
100
|
+
'Parsing route-level exports out of a theme template requires the "typescript" package, but it could not be loaded ' +
|
|
101
|
+
`from @nextsparkjs/core or from the project at ${rootDir}. Add "typescript" to the project's devDependencies. (${error.message})`
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
return typescriptModulePromise
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
let nextParseModulePromise = null
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Next.js's own module parser (SWC), resolved from the project and then from
|
|
113
|
+
* core, or null when neither has Next.js.
|
|
114
|
+
*/
|
|
115
|
+
function loadNextParseModule() {
|
|
116
|
+
if (!nextParseModulePromise) {
|
|
117
|
+
const path = 'next/dist/build/analysis/parse-module'
|
|
118
|
+
nextParseModulePromise = Promise.resolve()
|
|
119
|
+
.then(() => createRequire(join(rootDir, 'package.json'))(path))
|
|
120
|
+
.catch(() => createRequire(import.meta.url)(path))
|
|
121
|
+
.then(module => module.parseModule, () => null)
|
|
122
|
+
}
|
|
123
|
+
return nextParseModulePromise
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Whether Next.js parses `source`; its parser answers null for a module it cannot. */
|
|
127
|
+
async function nextParses(filePath, source) {
|
|
128
|
+
const parseModule = await loadNextParseModule()
|
|
129
|
+
return Boolean(parseModule && (await parseModule(filePath, source)))
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Unwrap the syntactic wrappers around a literal that don't change its
|
|
134
|
+
* runtime value: parentheses, `as const`, and `satisfies`.
|
|
135
|
+
*/
|
|
136
|
+
function unwrapExpression(expression, ts) {
|
|
137
|
+
let current = expression
|
|
138
|
+
while (true) {
|
|
139
|
+
if (ts.isParenthesizedExpression(current)) {
|
|
140
|
+
current = current.expression
|
|
141
|
+
} else if (ts.isAsExpression(current) || ts.isSatisfiesExpression(current)) {
|
|
142
|
+
current = current.expression
|
|
143
|
+
} else {
|
|
144
|
+
return current
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Evaluate an expression node as a JSON-compatible literal. Returns
|
|
151
|
+
* `{ ok: false }` for anything that isn't a literal Next.js could read
|
|
152
|
+
* statically - an expression, an identifier reference, a call, etc.
|
|
153
|
+
*/
|
|
154
|
+
function evaluateLiteral(expression, ts) {
|
|
155
|
+
const node = unwrapExpression(expression, ts)
|
|
156
|
+
|
|
157
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) return { ok: true, value: true }
|
|
158
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) return { ok: true, value: false }
|
|
159
|
+
if (ts.isNumericLiteral(node)) return { ok: true, value: Number(node.text.replace(/_/g, '')) }
|
|
160
|
+
if (ts.isStringLiteralLike(node)) return { ok: true, value: node.text }
|
|
161
|
+
|
|
162
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.MinusToken) {
|
|
163
|
+
const operand = evaluateLiteral(node.operand, ts)
|
|
164
|
+
return operand.ok && typeof operand.value === 'number' ? { ok: true, value: -operand.value } : { ok: false }
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (ts.isArrayLiteralExpression(node)) {
|
|
168
|
+
const values = []
|
|
169
|
+
for (const element of node.elements) {
|
|
170
|
+
const item = evaluateLiteral(element, ts)
|
|
171
|
+
if (!item.ok) return { ok: false }
|
|
172
|
+
values.push(item.value)
|
|
173
|
+
}
|
|
174
|
+
return { ok: true, value: values }
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { ok: false }
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function isExported(node, ts) {
|
|
181
|
+
return Boolean(node.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.ExportKeyword))
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Whether a module has a runtime default export: `export default <expr>`,
|
|
186
|
+
* `export default function`/`class`, or `default` named in an export clause
|
|
187
|
+
* (`export { Layout as default }`, `export { default } from './shell'`).
|
|
188
|
+
* Type-only exports give the route no component.
|
|
189
|
+
*/
|
|
190
|
+
function declaresDefaultExport(sourceFile, ts) {
|
|
191
|
+
return sourceFile.statements.some(statement => {
|
|
192
|
+
if (ts.isExportAssignment(statement)) return !statement.isExportEquals
|
|
193
|
+
if (ts.isFunctionDeclaration(statement) || ts.isClassDeclaration(statement)) {
|
|
194
|
+
return isExported(statement, ts) && Boolean(statement.modifiers?.some(modifier => modifier.kind === ts.SyntaxKind.DefaultKeyword))
|
|
195
|
+
}
|
|
196
|
+
if (ts.isExportDeclaration(statement) && !statement.isTypeOnly && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
197
|
+
return statement.exportClause.elements.some(element => !element.isTypeOnly && element.name.text === 'default')
|
|
198
|
+
}
|
|
199
|
+
return false
|
|
200
|
+
})
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parse a theme template's source and split its route-level exports into:
|
|
205
|
+
* - `segmentConfig`: segment config keys that resolve to a literal value the
|
|
206
|
+
* generated route file can re-declare (`{ name: value }`).
|
|
207
|
+
* - `moduleExports`: exported names (functions, `metadata`, etc.) the
|
|
208
|
+
* generated route file can safely forward with `export { ... } from`.
|
|
209
|
+
* - `hasDefaultExport`: whether it exports a component as default, read from
|
|
210
|
+
* the syntax tree so a comment or string mentioning `export default` doesn't
|
|
211
|
+
* count and `export { Layout as default }` does.
|
|
212
|
+
*
|
|
213
|
+
* A segment config key that IS exported but not as a literal `export const`
|
|
214
|
+
* (an expression, an identifier, `let`/`var`, a re-export, or a value the
|
|
215
|
+
* Next.js schema rejects) throws instead of silently dropping it - Next.js
|
|
216
|
+
* would otherwise ignore the value and fall back to its default, and nothing
|
|
217
|
+
* in the build would say so beyond a console warning.
|
|
218
|
+
*/
|
|
219
|
+
export async function extractRouteExports(source, filePath) {
|
|
220
|
+
const ts = await loadTypeScript()
|
|
221
|
+
// Parsed as its own kind of file: a TSX parse reads TypeScript-only syntax in a
|
|
222
|
+
// .ts template (`<T>(props) => ...`, `<Props>value`) as JSX and loses what follows
|
|
223
|
+
const sourceFile = ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.getScriptKindFromFileName(filePath))
|
|
224
|
+
|
|
225
|
+
// The parser recovers from a syntax error by skipping code, exports included. A
|
|
226
|
+
// template Next.js cannot parse either is reported rather than read in part. One
|
|
227
|
+
// it can is read from what TypeScript recovered, with a warning: Next.js compiles
|
|
228
|
+
// templates with SWC, which may know syntax the installed TypeScript does not (a
|
|
229
|
+
// source phase import, for one).
|
|
230
|
+
const [parseError] = sourceFile.parseDiagnostics ?? []
|
|
231
|
+
if (parseError) {
|
|
232
|
+
const { line } = sourceFile.getLineAndCharacterOfPosition(parseError.start ?? 0)
|
|
233
|
+
const where = `${filePath}:${line + 1}`
|
|
234
|
+
const reason = ts.flattenDiagnosticMessageText(parseError.messageText, ' ')
|
|
235
|
+
if (!(await nextParses(filePath, source))) {
|
|
236
|
+
throw new Error(`${where}: the template does not parse (${reason}), so its route-level exports cannot be read.`)
|
|
237
|
+
}
|
|
238
|
+
console.warn(
|
|
239
|
+
`${where}: TypeScript cannot parse the template (${reason}) but Next.js can; its route-level exports are read from what TypeScript parsed.`
|
|
70
240
|
)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
const segmentConfig = {}
|
|
244
|
+
const moduleExports = []
|
|
245
|
+
const seenModuleExports = new Set()
|
|
246
|
+
const errors = []
|
|
247
|
+
|
|
248
|
+
const lineOf = node => sourceFile.getLineAndCharacterOfPosition(node.getStart(sourceFile)).line + 1
|
|
249
|
+
|
|
250
|
+
const addModuleExport = name => {
|
|
251
|
+
if (!seenModuleExports.has(name)) {
|
|
252
|
+
seenModuleExports.add(name)
|
|
253
|
+
moduleExports.push(name)
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const recordSegmentError = (name, node, reason) => {
|
|
258
|
+
errors.push(
|
|
259
|
+
`${filePath}:${lineOf(node)}: segment config export "${name}" ${reason}. ` +
|
|
260
|
+
`Next.js only reads segment config when it's a literal declared directly in the route file ` +
|
|
261
|
+
`(\`export const ${name} = ...\`) - anything else is silently ignored and the default is used instead. ` +
|
|
262
|
+
`Use a literal.`
|
|
263
|
+
)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const statement of sourceFile.statements) {
|
|
267
|
+
if (ts.isVariableStatement(statement) && isExported(statement, ts)) {
|
|
268
|
+
const isConst = (statement.declarationList.flags & ts.NodeFlags.Const) !== 0
|
|
269
|
+
|
|
270
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
271
|
+
if (!ts.isIdentifier(declaration.name)) continue
|
|
272
|
+
const name = declaration.name.text
|
|
273
|
+
|
|
274
|
+
if (SEGMENT_CONFIG_EXPORTS.includes(name)) {
|
|
275
|
+
if (!isConst) {
|
|
276
|
+
recordSegmentError(name, declaration, 'is declared with "let" or "var"')
|
|
277
|
+
continue
|
|
278
|
+
}
|
|
279
|
+
if (!declaration.initializer) {
|
|
280
|
+
recordSegmentError(name, declaration, 'has no initializer')
|
|
281
|
+
continue
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const literal = evaluateLiteral(declaration.initializer, ts)
|
|
285
|
+
if (!literal.ok) {
|
|
286
|
+
recordSegmentError(name, declaration, 'is not a literal (an expression or identifier)')
|
|
287
|
+
continue
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
const validate = SEGMENT_CONFIG_VALIDATORS[name]
|
|
291
|
+
if (!validate(literal.value)) {
|
|
292
|
+
recordSegmentError(name, declaration, `has a value (${JSON.stringify(literal.value)}) outside what Next.js accepts for "${name}"`)
|
|
293
|
+
continue
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
segmentConfig[name] = literal.value
|
|
297
|
+
} else if (MODULE_LEVEL_EXPORTS.includes(name)) {
|
|
298
|
+
addModuleExport(name)
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
} else if (ts.isFunctionDeclaration(statement) && statement.name && isExported(statement, ts)) {
|
|
302
|
+
const name = statement.name.text
|
|
303
|
+
if (SEGMENT_CONFIG_EXPORTS.includes(name)) {
|
|
304
|
+
recordSegmentError(name, statement, 'is declared as a function, not a literal')
|
|
305
|
+
} else if (MODULE_LEVEL_EXPORTS.includes(name)) {
|
|
306
|
+
addModuleExport(name)
|
|
307
|
+
}
|
|
308
|
+
} else if (ts.isExportDeclaration(statement) && statement.exportClause && ts.isNamedExports(statement.exportClause)) {
|
|
309
|
+
for (const element of statement.exportClause.elements) {
|
|
310
|
+
const exportedName = element.name.text
|
|
311
|
+
|
|
312
|
+
if (SEGMENT_CONFIG_EXPORTS.includes(exportedName)) {
|
|
313
|
+
recordSegmentError(
|
|
314
|
+
exportedName,
|
|
315
|
+
element,
|
|
316
|
+
statement.moduleSpecifier
|
|
317
|
+
? 'is re-exported from another module'
|
|
318
|
+
: 'is exported via `export { }` instead of an inline `export const`'
|
|
319
|
+
)
|
|
320
|
+
} else if (MODULE_LEVEL_EXPORTS.includes(exportedName)) {
|
|
321
|
+
addModuleExport(exportedName)
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if (errors.length > 0) {
|
|
328
|
+
throw new Error(errors.join('\n'))
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return { segmentConfig, moduleExports, hasDefaultExport: declaresDefaultExport(sourceFile, ts) }
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
/**
|
|
335
|
+
* Resolve a `@/contents/...` template import path to its file on disk,
|
|
336
|
+
* trying both TSX and TS extensions.
|
|
337
|
+
*/
|
|
338
|
+
function resolveTemplateFilePath(templatePath) {
|
|
339
|
+
const baseTemplatePath = templatePath
|
|
340
|
+
.replace('@/', rootDir + '/')
|
|
341
|
+
.replace(/\.(tsx|ts)$/, '')
|
|
342
|
+
return existsSync(baseTemplatePath + '.tsx') ? baseTemplatePath + '.tsx' : baseTemplatePath + '.ts'
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Read a template file and extract its route-level exports. A missing file
|
|
347
|
+
* is treated as having none, since a build-time override may point at a
|
|
348
|
+
* template that hasn't been generated yet; a template that fails to parse
|
|
349
|
+
* its segment config is not swallowed the same way, and propagates instead.
|
|
350
|
+
*/
|
|
351
|
+
async function readRouteExports(templatePath) {
|
|
352
|
+
const absoluteTemplatePath = resolveTemplateFilePath(templatePath)
|
|
353
|
+
|
|
354
|
+
let templateContent
|
|
355
|
+
try {
|
|
356
|
+
templateContent = await readFile(absoluteTemplatePath, 'utf8')
|
|
71
357
|
} catch {
|
|
72
|
-
return []
|
|
358
|
+
return { segmentConfig: {}, moduleExports: [], hasDefaultExport: false }
|
|
73
359
|
}
|
|
360
|
+
|
|
361
|
+
return extractRouteExports(templateContent, absoluteTemplatePath)
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Render the segment config keys a template exports as re-declared literals.
|
|
366
|
+
*/
|
|
367
|
+
function renderSegmentConfigBlock(segmentConfig) {
|
|
368
|
+
return Object.entries(segmentConfig)
|
|
369
|
+
.map(([name, value]) => `export const ${name} = ${JSON.stringify(value)}\n`)
|
|
370
|
+
.join('')
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Render the module-level exports a template exports as a re-export from it.
|
|
375
|
+
*/
|
|
376
|
+
function renderModuleExportsBlock(moduleExports, templatePathWithoutExtension) {
|
|
377
|
+
return moduleExports.length > 0
|
|
378
|
+
? `export { ${moduleExports.join(', ')} } from '${templatePathWithoutExtension}'\n`
|
|
379
|
+
: ''
|
|
74
380
|
}
|
|
75
381
|
|
|
76
382
|
/**
|
|
@@ -80,9 +386,16 @@ async function generateRegularPageContent(appPath, templatePath) {
|
|
|
80
386
|
// Remove .tsx/.ts extension from import path (TypeScript doesn't allow file extensions in imports)
|
|
81
387
|
const templatePathWithoutExtension = templatePath.replace(/\.(tsx|ts)$/, '')
|
|
82
388
|
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
389
|
+
const { segmentConfig, moduleExports } = await readRouteExports(templatePath)
|
|
390
|
+
|
|
391
|
+
const segmentConfigBlock = renderSegmentConfigBlock(segmentConfig)
|
|
392
|
+
const segmentConfigSection = segmentConfigBlock
|
|
393
|
+
? `\n// Segment config re-declared as literals: Next.js only reads these when they're declared directly in the route file, not re-exported\n${segmentConfigBlock}`
|
|
394
|
+
: ''
|
|
395
|
+
|
|
396
|
+
const moduleExportsBlock = renderModuleExportsBlock(moduleExports, templatePathWithoutExtension)
|
|
397
|
+
const moduleExportsSection = moduleExportsBlock
|
|
398
|
+
? `\n// Re-export Next.js route-level exports from the theme template\n${moduleExportsBlock}`
|
|
86
399
|
: ''
|
|
87
400
|
|
|
88
401
|
return `/**
|
|
@@ -94,7 +407,7 @@ import TemplateComponent from '${templatePathWithoutExtension}'
|
|
|
94
407
|
|
|
95
408
|
// Direct export of the theme template (no fallback)
|
|
96
409
|
export default TemplateComponent
|
|
97
|
-
${
|
|
410
|
+
${segmentConfigSection}${moduleExportsSection}`
|
|
98
411
|
}
|
|
99
412
|
|
|
100
413
|
/**
|
|
@@ -104,32 +417,33 @@ async function generateLayoutPageContent(appPath, componentName, templatePath) {
|
|
|
104
417
|
if (templatePath) {
|
|
105
418
|
// Remove .tsx/.ts extension from import path (TypeScript doesn't allow file extensions in imports)
|
|
106
419
|
const templatePathWithoutExtension = templatePath.replace(/\.(tsx|ts)$/, '')
|
|
420
|
+
const absoluteTemplatePath = resolveTemplateFilePath(templatePath)
|
|
107
421
|
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
const baseTemplatePath = templatePath
|
|
112
|
-
.replace('@/', rootDir + '/')
|
|
113
|
-
.replace(/\.(tsx|ts)$/, '')
|
|
114
|
-
const absoluteTemplatePath = existsSync(baseTemplatePath + '.tsx')
|
|
115
|
-
? baseTemplatePath + '.tsx'
|
|
116
|
-
: baseTemplatePath + '.ts'
|
|
117
|
-
|
|
118
|
-
// Check if template file has a default export (component) or just metadata
|
|
119
|
-
let hasDefaultExport = false
|
|
120
|
-
let hasMetadata = false
|
|
121
|
-
|
|
422
|
+
// Check if template file has a default export (component), and what
|
|
423
|
+
// route-level exports it defines alongside (or instead of) it
|
|
424
|
+
let templateContent = null
|
|
122
425
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} catch (error) {
|
|
127
|
-
// If we can't read the file, assume it has a default export
|
|
128
|
-
hasDefaultExport = true
|
|
426
|
+
templateContent = await readFile(absoluteTemplatePath, 'utf8')
|
|
427
|
+
} catch {
|
|
428
|
+
// Can't read the file - fall through to the default-export assumption below
|
|
129
429
|
}
|
|
130
430
|
|
|
431
|
+
let hasDefaultExport = true
|
|
432
|
+
let segmentConfig = {}
|
|
433
|
+
let moduleExports = []
|
|
434
|
+
if (templateContent !== null) {
|
|
435
|
+
;({ segmentConfig, moduleExports, hasDefaultExport } = await extractRouteExports(templateContent, absoluteTemplatePath))
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
const segmentConfigBlock = renderSegmentConfigBlock(segmentConfig)
|
|
439
|
+
const moduleExportsBlock = renderModuleExportsBlock(moduleExports, templatePathWithoutExtension)
|
|
440
|
+
|
|
131
441
|
if (hasDefaultExport) {
|
|
132
|
-
// Template has a component - import and re-export it
|
|
442
|
+
// Template has a component - import and re-export it, plus any route-level exports it defines
|
|
443
|
+
const forwardedExportsSection = segmentConfigBlock || moduleExportsBlock
|
|
444
|
+
? `\n// Re-export Next.js route-level exports from the theme template\n${segmentConfigBlock}${moduleExportsBlock}`
|
|
445
|
+
: ''
|
|
446
|
+
|
|
133
447
|
return `/**
|
|
134
448
|
* Layout template - directly imports from theme
|
|
135
449
|
* Template: ${appPath}
|
|
@@ -139,9 +453,10 @@ import TemplateComponent from '${templatePathWithoutExtension}'
|
|
|
139
453
|
|
|
140
454
|
// Direct export of the theme template (no fallback)
|
|
141
455
|
export default TemplateComponent
|
|
142
|
-
`
|
|
143
|
-
} else if (
|
|
144
|
-
//
|
|
456
|
+
${forwardedExportsSection}`
|
|
457
|
+
} else if (segmentConfigBlock || moduleExportsBlock) {
|
|
458
|
+
// No component, but the template still defines segment config and/or metadata -
|
|
459
|
+
// re-export those and provide a pass-through component
|
|
145
460
|
return `/**
|
|
146
461
|
* Layout template - metadata-only (PROTECTED_RENDER)
|
|
147
462
|
* Template: ${appPath}
|
|
@@ -149,9 +464,8 @@ export default TemplateComponent
|
|
|
149
464
|
*/
|
|
150
465
|
import type { ReactNode } from 'react'
|
|
151
466
|
|
|
152
|
-
// Re-export
|
|
153
|
-
|
|
154
|
-
|
|
467
|
+
// Re-export Next.js route-level exports from the theme template
|
|
468
|
+
${segmentConfigBlock}${moduleExportsBlock}
|
|
155
469
|
// Pass-through component (actual rendering blocked by PROTECTED_RENDER)
|
|
156
470
|
interface ${componentName}Props {
|
|
157
471
|
children: ReactNode
|
|
@@ -275,6 +589,13 @@ async function duplicateLayoutDirect(sourcePath, targetPath, layoutPath, templat
|
|
|
275
589
|
const templatePathWithoutExtension = layoutOverride.templatePath.replace(/\.(tsx|ts)$/, '')
|
|
276
590
|
const componentName = `Layout${toPascalCase(layoutPath.replace(/[^\w]/g, '_'))}`
|
|
277
591
|
|
|
592
|
+
const { segmentConfig, moduleExports } = await readRouteExports(layoutOverride.templatePath)
|
|
593
|
+
const segmentConfigBlock = renderSegmentConfigBlock(segmentConfig)
|
|
594
|
+
const moduleExportsBlock = renderModuleExportsBlock(moduleExports, templatePathWithoutExtension)
|
|
595
|
+
const forwardedExportsSection = segmentConfigBlock || moduleExportsBlock
|
|
596
|
+
? `\n// Re-export Next.js route-level exports from the theme template\n${segmentConfigBlock}${moduleExportsBlock}`
|
|
597
|
+
: ''
|
|
598
|
+
|
|
278
599
|
const content = `/**
|
|
279
600
|
* Layout with template override - directly imports from theme
|
|
280
601
|
* Template: ${layoutPath}
|
|
@@ -284,7 +605,7 @@ async function duplicateLayoutDirect(sourcePath, targetPath, layoutPath, templat
|
|
|
284
605
|
import TemplateLayout from '${templatePathWithoutExtension}'
|
|
285
606
|
|
|
286
607
|
export default TemplateLayout
|
|
287
|
-
`
|
|
608
|
+
${forwardedExportsSection}`
|
|
288
609
|
await writeFile(targetPath, content, 'utf8')
|
|
289
610
|
verbose(`Generated layout with template override: ${layoutPath}`)
|
|
290
611
|
return
|
|
@@ -53,6 +53,7 @@ import { discoverMiddlewares } from './registry/discovery/middlewares.mjs'
|
|
|
53
53
|
import { discoverTemplates } from './registry/discovery/templates.mjs'
|
|
54
54
|
import { discoverEmails } from './registry/discovery/emails.mjs'
|
|
55
55
|
import { discoverBlocks } from './registry/discovery/blocks.mjs'
|
|
56
|
+
import { discoverIcons } from './registry/discovery/icons.mjs'
|
|
56
57
|
import { discoverCoreRoutes } from './registry/discovery/core-routes.mjs'
|
|
57
58
|
import { discoverApiPresets } from './registry/discovery/api-presets.mjs'
|
|
58
59
|
import { discoverMcpOverrides } from './registry/discovery/mcp-overrides.mjs'
|
|
@@ -63,7 +64,8 @@ import { generateEntityTypes } from './registry/generators/entity-types.mjs'
|
|
|
63
64
|
import { generateThemeRegistry } from './registry/generators/theme-registry.mjs'
|
|
64
65
|
import { generateTemplateRegistry, generateTemplateRegistryClient } from './registry/generators/template-registry.mjs'
|
|
65
66
|
import { generateEmailRegistry } from './registry/generators/email-registry.mjs'
|
|
66
|
-
import { generateBlockRegistry } from './registry/generators/block-registry.mjs'
|
|
67
|
+
import { generateBlockRegistry, generateBlockRegistryClient, generateBlockRegistryLazy } from './registry/generators/block-registry.mjs'
|
|
68
|
+
import { generateIconRegistry } from './registry/generators/icon-registry.mjs'
|
|
67
69
|
import { generateMiddlewareRegistry } from './registry/generators/middleware-registry.mjs'
|
|
68
70
|
import { generateRouteHandlersRegistry } from './registry/generators/route-handlers.mjs'
|
|
69
71
|
import { generateTranslationRegistry } from './registry/generators/translation-registry.mjs'
|
|
@@ -101,6 +103,9 @@ async function generateRegistryFiles(CONFIG, plugins, entities, themes, template
|
|
|
101
103
|
// Generate client template registry (async - needs to check for server exports)
|
|
102
104
|
const templateRegistryClientContent = await generateTemplateRegistryClient(templates, CONFIG)
|
|
103
105
|
|
|
106
|
+
// Collect the icon names configs can ask for by string (async - reads configs)
|
|
107
|
+
const iconNames = await discoverIcons(blocks, CONFIG)
|
|
108
|
+
|
|
104
109
|
// Generate individual registries (pass CONFIG to all generators)
|
|
105
110
|
const files = [
|
|
106
111
|
{ name: 'plugin-registry.ts', content: generatePluginRegistry(plugins, CONFIG) },
|
|
@@ -115,6 +120,9 @@ async function generateRegistryFiles(CONFIG, plugins, entities, themes, template
|
|
|
115
120
|
{ name: 'template-registry.client.ts', content: templateRegistryClientContent },
|
|
116
121
|
{ name: 'email-registry.ts', content: generateEmailRegistry(emails, CONFIG) },
|
|
117
122
|
{ name: 'block-registry.ts', content: generateBlockRegistry(blocks, CONFIG) },
|
|
123
|
+
{ name: 'block-registry.client.ts', content: generateBlockRegistryClient(blocks, CONFIG) },
|
|
124
|
+
{ name: 'block-registry.lazy.ts', content: generateBlockRegistryLazy(blocks) },
|
|
125
|
+
{ name: 'icon-registry.ts', content: generateIconRegistry(iconNames, CONFIG) },
|
|
118
126
|
{ name: 'billing-registry.ts', content: await generateBillingRegistry(CONFIG.activeTheme, CONFIG.contentsDir, CONFIG) },
|
|
119
127
|
{ name: 'middleware-registry.ts', content: generateMiddlewareRegistry(middlewares, CONFIG) },
|
|
120
128
|
{ name: 'scope-registry.ts', content: generateScopeRegistry(entities, CONFIG) },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { resetPasswordSchema, type ResetPasswordFormData } from '@nextsparkjs/core/lib/validation';
|
|
4
|
-
import {
|
|
4
|
+
import { useAuthActions } from '@nextsparkjs/core/hooks/useAuth';
|
|
5
5
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
6
6
|
import { AlertCircle, ArrowLeft, CheckCircle, Loader2, Mail } from 'lucide-react';
|
|
7
7
|
import Link from 'next/link';
|
|
@@ -18,7 +18,7 @@ import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-reg
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
function ForgotPasswordPage() {
|
|
21
|
-
const { resetPassword } =
|
|
21
|
+
const { resetPassword } = useAuthActions();
|
|
22
22
|
const [loading, setLoading] = useState(false);
|
|
23
23
|
const [error, setError] = useState<string | null>(null);
|
|
24
24
|
const [success, setSuccess] = useState(false);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { newPasswordSchema, type NewPasswordFormData } from "@nextsparkjs/core/lib/validation";
|
|
4
|
-
import {
|
|
4
|
+
import { useAuthActions } from "@nextsparkjs/core/hooks/useAuth";
|
|
5
5
|
import { zodResolver } from "@hookform/resolvers/zod";
|
|
6
6
|
import {
|
|
7
7
|
AlertCircle,
|
|
@@ -24,7 +24,7 @@ import { sel } from '@nextsparkjs/core/selectors'
|
|
|
24
24
|
function ResetPasswordContent() {
|
|
25
25
|
const searchParams = useSearchParams()!;
|
|
26
26
|
const token = searchParams.get("token") || "";
|
|
27
|
-
const { updatePassword } =
|
|
27
|
+
const { updatePassword } = useAuthActions();
|
|
28
28
|
|
|
29
29
|
const [loading, setLoading] = useState(false);
|
|
30
30
|
const [error, setError] = useState<string | null>(null);
|
|
@@ -57,13 +57,13 @@ function ResetPasswordContent() {
|
|
|
57
57
|
|
|
58
58
|
const onSubmit = useCallback(async (data: NewPasswordFormData) => {
|
|
59
59
|
if (!token) {
|
|
60
|
-
setError("
|
|
60
|
+
setError("Invalid recovery token");
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
setLoading(true);
|
|
65
65
|
setError(null);
|
|
66
|
-
console.log('
|
|
66
|
+
console.log('Updating password...');
|
|
67
67
|
|
|
68
68
|
try {
|
|
69
69
|
const result = await updatePassword(data.password, token);
|
|
@@ -73,10 +73,10 @@ function ResetPasswordContent() {
|
|
|
73
73
|
setError(errorMsg);
|
|
74
74
|
} else {
|
|
75
75
|
setSuccess(true);
|
|
76
|
-
console.log('
|
|
76
|
+
console.log('Password updated successfully');
|
|
77
77
|
}
|
|
78
78
|
} catch {
|
|
79
|
-
setError('
|
|
79
|
+
setError('Unexpected error updating password');
|
|
80
80
|
} finally {
|
|
81
81
|
setLoading(false);
|
|
82
82
|
}
|
|
@@ -10,7 +10,7 @@ import { getTemplateOrDefaultClient } from '@nextsparkjs/registries/template-reg
|
|
|
10
10
|
|
|
11
11
|
function ForbiddenContent() {
|
|
12
12
|
const searchParams = useSearchParams()!
|
|
13
|
-
const reason = searchParams.get('reason') || '
|
|
13
|
+
const reason = searchParams.get('reason') || 'You do not have permission to access this resource'
|
|
14
14
|
const upgrade = searchParams.get('upgrade') === 'true'
|
|
15
15
|
|
|
16
16
|
return (
|
|
@@ -21,7 +21,7 @@ function ForbiddenContent() {
|
|
|
21
21
|
<AlertTriangle className="h-8 w-8 text-yellow-600" />
|
|
22
22
|
</div>
|
|
23
23
|
<CardTitle className="text-2xl">
|
|
24
|
-
⚠️
|
|
24
|
+
⚠️ Oops, you do not have permission to do this
|
|
25
25
|
</CardTitle>
|
|
26
26
|
<CardDescription className="text-gray-600">
|
|
27
27
|
{reason}
|
|
@@ -32,11 +32,11 @@ function ForbiddenContent() {
|
|
|
32
32
|
{upgrade && (
|
|
33
33
|
<div className="bg-blue-50 border border-blue-200 rounded-lg p-4">
|
|
34
34
|
<p className="text-sm text-blue-800">
|
|
35
|
-
|
|
35
|
+
This feature requires an upgrade to your current plan.
|
|
36
36
|
</p>
|
|
37
37
|
<Link href="/dashboard/settings/billing" className="block mt-2">
|
|
38
38
|
<Button variant="outline" size="sm" className="w-full">
|
|
39
|
-
|
|
39
|
+
View plans
|
|
40
40
|
</Button>
|
|
41
41
|
</Link>
|
|
42
42
|
</div>
|
|
@@ -49,7 +49,7 @@ function ForbiddenContent() {
|
|
|
49
49
|
onClick={() => window.history.back()}
|
|
50
50
|
>
|
|
51
51
|
<ArrowLeft className="h-4 w-4 mr-2" />
|
|
52
|
-
|
|
52
|
+
Back
|
|
53
53
|
</Button>
|
|
54
54
|
|
|
55
55
|
<Link href="/dashboard" className="flex-1">
|
|
@@ -75,7 +75,7 @@ function ForbiddenPage() {
|
|
|
75
75
|
<AlertTriangle className="h-8 w-8 text-yellow-600" />
|
|
76
76
|
</div>
|
|
77
77
|
<CardTitle className="text-2xl">
|
|
78
|
-
⚠️
|
|
78
|
+
⚠️ Oops, you do not have permission to do this
|
|
79
79
|
</CardTitle>
|
|
80
80
|
</CardHeader>
|
|
81
81
|
</Card>
|