@nextsparkjs/core 0.1.0-beta.189 → 0.1.0-beta.190
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/CreateApiKeyDialog.d.ts.map +1 -1
- package/dist/components/api/keys/CreateApiKeyDialog.js +2 -1
- package/dist/components/app/layouts/PublicFooter.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicFooter.js +2 -23
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +2 -1
- package/dist/components/auth/forms/LoginForm.js +1 -1
- package/dist/components/auth/forms/SignupForm.d.ts.map +1 -1
- package/dist/components/auth/forms/SignupForm.js +2 -1
- package/dist/components/auth/pages/AuthErrorPage.d.ts.map +1 -1
- package/dist/components/auth/pages/AuthErrorPage.js +2 -1
- package/dist/components/billing/ManageBillingButton.d.ts.map +1 -1
- package/dist/components/billing/ManageBillingButton.js +2 -1
- package/dist/components/dashboard/block-editor/array-field.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/array-field.js +2 -1
- package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/block-picker.js +2 -1
- package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/builder-editor-view.js +3 -2
- package/dist/components/dashboard/block-editor/config-panel.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/config-panel.js +3 -2
- package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/dynamic-form.js +2 -1
- package/dist/components/dashboard/block-editor/entity-fields-sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/entity-fields-sidebar.js +3 -2
- package/dist/components/dashboard/block-editor/pattern-reference-preview.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/pattern-reference-preview.js +2 -1
- package/dist/components/dashboard/layouts/TopNavbar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/TopNavbar.js +4 -3
- package/dist/components/dashboard/misc/SearchDropdown.d.ts.map +1 -1
- package/dist/components/dashboard/misc/SearchDropdown.js +2 -1
- package/dist/components/dashboard/mobile/MobileTopBar.d.ts.map +1 -1
- package/dist/components/dashboard/mobile/MobileTopBar.js +2 -1
- package/dist/components/devtools/BlockDetailViewer.d.ts.map +1 -1
- package/dist/components/devtools/BlockDetailViewer.js +2 -1
- package/dist/components/devtools/BlocksViewer.d.ts.map +1 -1
- package/dist/components/devtools/BlocksViewer.js +2 -1
- package/dist/components/devtools/ConfigViewer.d.ts.map +1 -1
- package/dist/components/devtools/ConfigViewer.js +3 -2
- package/dist/components/devtools/TestCasesViewer.d.ts.map +1 -1
- package/dist/components/devtools/TestCasesViewer.js +3 -2
- package/dist/components/devtools/TestCoverageDashboard.d.ts.map +1 -1
- package/dist/components/devtools/TestCoverageDashboard.js +2 -1
- package/dist/components/devtools/api-explorer/ApiDocsModal.d.ts.map +1 -1
- package/dist/components/devtools/api-explorer/ApiDocsModal.js +0 -0
- package/dist/components/devtools/api-explorer/ApiExplorer.d.ts.map +1 -1
- package/dist/components/devtools/api-explorer/ApiExplorer.js +2 -1
- package/dist/components/devtools/scheduled-actions/actions-table.d.ts.map +1 -1
- package/dist/components/devtools/scheduled-actions/actions-table.js +3 -2
- package/dist/components/docs/docs-sidebar.d.ts.map +1 -1
- package/dist/components/docs/docs-sidebar.js +3 -2
- package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
- package/dist/components/entities/EntityFieldRenderer.js +2 -1
- package/dist/components/entities/EntityList.d.ts.map +1 -1
- package/dist/components/entities/EntityList.js +2 -1
- package/dist/components/entities/EntityTable.d.ts.map +1 -1
- package/dist/components/entities/EntityTable.js +3 -2
- package/dist/components/entities/ErrorBoundary.d.ts.map +1 -1
- package/dist/components/entities/ErrorBoundary.js +2 -1
- package/dist/components/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityDetailWrapper.js +3 -2
- package/dist/components/media/MediaCard.d.ts.map +1 -1
- package/dist/components/media/MediaCard.js +2 -1
- package/dist/components/media/MediaDetailPanel.d.ts.map +1 -1
- package/dist/components/media/MediaDetailPanel.js +2 -1
- package/dist/components/media/MediaList.d.ts.map +1 -1
- package/dist/components/media/MediaList.js +2 -1
- package/dist/components/media/MediaSelector.d.ts.map +1 -1
- package/dist/components/media/MediaSelector.js +2 -1
- package/dist/components/media/MediaUploadZone.d.ts.map +1 -1
- package/dist/components/media/MediaUploadZone.js +2 -1
- package/dist/components/public/entities/PublicEntityDetail.d.ts.map +1 -1
- package/dist/components/public/entities/PublicEntityDetail.js +2 -1
- package/dist/components/teams/TeamPendingInvitations.d.ts.map +1 -1
- package/dist/components/teams/TeamPendingInvitations.js +3 -2
- package/dist/components/ui/accordion.js +1 -1
- package/dist/components/ui/audio-upload.d.ts.map +1 -1
- package/dist/components/ui/audio-upload.js +2 -1
- package/dist/components/ui/avatar.d.ts +17 -1
- package/dist/components/ui/avatar.d.ts.map +1 -1
- package/dist/components/ui/avatar.js +29 -2
- package/dist/components/ui/badge.js +1 -1
- package/dist/components/ui/breadcrumb.d.ts +13 -0
- package/dist/components/ui/breadcrumb.d.ts.map +1 -1
- package/dist/components/ui/breadcrumb.js +23 -10
- package/dist/components/ui/button.js +1 -1
- package/dist/components/ui/card.js +1 -1
- package/dist/components/ui/checkbox.js +1 -1
- package/dist/components/ui/file-upload.d.ts.map +1 -1
- package/dist/components/ui/file-upload.js +2 -1
- package/dist/components/ui/image-upload.d.ts.map +1 -1
- package/dist/components/ui/image-upload.js +4 -3
- package/dist/components/ui/input.js +1 -1
- package/dist/components/ui/label.js +1 -1
- package/dist/components/ui/optimized-image.d.ts.map +1 -1
- package/dist/components/ui/optimized-image.js +5 -0
- package/dist/components/ui/pagination.d.ts +1 -1
- package/dist/components/ui/pagination.d.ts.map +1 -1
- package/dist/components/ui/pagination.js +3 -0
- package/dist/components/ui/progress.js +1 -1
- package/dist/components/ui/relation-display.d.ts.map +1 -1
- package/dist/components/ui/relation-display.js +3 -2
- package/dist/components/ui/separator.js +1 -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/skeleton.js +1 -1
- package/dist/components/ui/slider.js +1 -1
- package/dist/components/ui/switch.js +1 -1
- package/dist/components/ui/tabs.js +1 -1
- package/dist/components/ui/textarea.js +1 -1
- package/dist/components/ui/user-display.d.ts.map +1 -1
- package/dist/components/ui/user-display.js +2 -1
- package/dist/components/ui/user-select.d.ts.map +1 -1
- package/dist/components/ui/user-select.js +2 -1
- package/dist/components/ui/video-upload.d.ts.map +1 -1
- package/dist/components/ui/video-upload.js +3 -2
- package/dist/components/users/tables/UsersTable.d.ts.map +1 -1
- package/dist/components/users/tables/UsersTable.js +3 -2
- package/dist/contexts/SubscriptionContext.d.ts.map +1 -1
- package/dist/contexts/SubscriptionContext.js +4 -3
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +3 -2
- package/dist/hooks/useAccountPreferencesSync.d.ts.map +1 -1
- package/dist/hooks/useAccountPreferencesSync.js +2 -1
- package/dist/hooks/useApiExplorerNavigation.d.ts.map +1 -1
- package/dist/hooks/useApiExplorerNavigation.js +2 -1
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +3 -2
- package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
- package/dist/hooks/useEnsureUserMetadata.js +3 -2
- package/dist/hooks/useEntityWithMeta.d.ts.map +1 -1
- package/dist/hooks/useEntityWithMeta.js +3 -2
- package/dist/hooks/useInvoice.d.ts.map +1 -1
- package/dist/hooks/useInvoice.js +2 -1
- package/dist/hooks/useInvoices.d.ts.map +1 -1
- package/dist/hooks/useInvoices.js +2 -1
- package/dist/hooks/useMedia.d.ts.map +1 -1
- package/dist/hooks/useMedia.js +10 -9
- package/dist/hooks/useMediaUpload.d.ts.map +1 -1
- package/dist/hooks/useMediaUpload.js +2 -1
- package/dist/hooks/useMembership.d.ts.map +1 -1
- package/dist/hooks/useMembership.js +3 -2
- package/dist/hooks/usePatternUsages.d.ts.map +1 -1
- package/dist/hooks/usePatternUsages.js +3 -2
- package/dist/hooks/usePrefetch.d.ts.map +1 -1
- package/dist/hooks/usePrefetch.js +3 -2
- package/dist/hooks/useQuota.d.ts.map +1 -1
- package/dist/hooks/useQuota.js +2 -1
- package/dist/hooks/useTeamInvitations.d.ts.map +1 -1
- package/dist/hooks/useTeamInvitations.js +4 -3
- package/dist/hooks/useTeamMembers.d.ts.map +1 -1
- package/dist/hooks/useTeamMembers.js +5 -4
- package/dist/hooks/useTeamUpdate.d.ts.map +1 -1
- package/dist/hooks/useTeamUpdate.js +2 -1
- package/dist/hooks/useUserProfile.d.ts.map +1 -1
- package/dist/hooks/useUserProfile.js +3 -2
- package/dist/hooks/useUserSettings.d.ts.map +1 -1
- package/dist/hooks/useUserSettings.js +3 -2
- package/dist/lib/actions/entity.actions.d.ts.map +1 -1
- package/dist/lib/actions/entity.actions.js +2 -1
- package/dist/lib/api/entities.d.ts.map +1 -1
- package/dist/lib/api/entities.js +4 -3
- package/dist/lib/auth/verify-email-link.d.ts +10 -0
- package/dist/lib/auth/verify-email-link.d.ts.map +1 -0
- package/dist/lib/auth/verify-email-link.js +14 -0
- package/dist/lib/auth-client.d.ts +2 -0
- package/dist/lib/auth-client.d.ts.map +1 -1
- package/dist/lib/auth-client.js +4 -0
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +10 -2
- package/dist/lib/base-path.d.ts +85 -0
- package/dist/lib/base-path.d.ts.map +1 -0
- package/dist/lib/base-path.js +79 -0
- package/dist/lib/billing/schema.d.ts +1 -1
- package/dist/lib/billing/schema.d.ts.map +1 -1
- package/dist/lib/billing/schema.js +1 -1
- package/dist/lib/blocks/sanitize-html.d.ts.map +1 -1
- package/dist/lib/blocks/sanitize-html.js +18 -2
- package/dist/lib/cache/revalidate-tag.d.ts +14 -0
- package/dist/lib/cache/revalidate-tag.d.ts.map +1 -0
- package/dist/lib/cache/revalidate-tag.js +8 -0
- package/dist/lib/config/dashboard-schema.d.ts +1 -1
- package/dist/lib/config/dashboard-schema.d.ts.map +1 -1
- package/dist/lib/config/dashboard-schema.js +1 -1
- package/dist/lib/config/types.d.ts +36 -16
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/docs/access.d.ts +28 -0
- package/dist/lib/docs/access.d.ts.map +1 -0
- package/dist/lib/docs/access.js +16 -0
- package/dist/lib/docs/parser.d.ts.map +1 -1
- package/dist/lib/docs/parser.js +2 -1
- package/dist/lib/docs/remark-doc-links.d.ts +14 -0
- package/dist/lib/docs/remark-doc-links.d.ts.map +1 -0
- package/dist/lib/docs/remark-doc-links.js +38 -0
- package/dist/lib/entities/api-generator.d.ts +1 -1
- package/dist/lib/entities/api-generator.d.ts.map +1 -1
- package/dist/lib/entities/api-generator.js +1 -1
- package/dist/lib/entities/schema-generator.d.ts +1 -1
- package/dist/lib/entities/schema-generator.d.ts.map +1 -1
- package/dist/lib/entities/schema-generator.js +1 -1
- package/dist/lib/mcp/engine.js +1 -1
- package/dist/lib/mcp/schema-builder.d.ts +1 -1
- package/dist/lib/mcp/schema-builder.d.ts.map +1 -1
- package/dist/lib/mcp/schema-builder.js +1 -1
- package/dist/lib/mcp/tool-generator.js +1 -1
- package/dist/lib/mcp/types.d.ts +1 -1
- package/dist/lib/mcp/types.d.ts.map +1 -1
- package/dist/lib/media/schemas.d.ts +1 -1
- package/dist/lib/media/schemas.d.ts.map +1 -1
- package/dist/lib/media/schemas.js +1 -1
- package/dist/lib/middleware/index.d.ts +5 -1
- package/dist/lib/middleware/index.d.ts.map +1 -1
- package/dist/lib/middleware/index.js +3 -2
- package/dist/lib/services/meta.service.d.ts +60 -0
- package/dist/lib/services/meta.service.d.ts.map +1 -1
- package/dist/lib/services/meta.service.js +132 -12
- package/dist/lib/services/middleware.service.d.ts.map +1 -1
- package/dist/lib/services/middleware.service.js +3 -2
- package/dist/lib/teams/schema.d.ts +1 -1
- package/dist/lib/teams/schema.d.ts.map +1 -1
- package/dist/lib/teams/schema.js +1 -1
- package/dist/lib/teams/teams.api.d.ts.map +1 -1
- package/dist/lib/teams/teams.api.js +4 -3
- package/dist/lib/user-data-client.d.ts.map +1 -1
- package/dist/lib/user-data-client.js +3 -2
- package/dist/lib/validation/invoices.d.ts +1 -1
- package/dist/lib/validation/invoices.d.ts.map +1 -1
- package/dist/lib/validation/invoices.js +1 -1
- package/dist/lib/validation-schemas.d.ts +1 -1
- package/dist/lib/validation-schemas.d.ts.map +1 -1
- package/dist/lib/validation-schemas.js +1 -1
- package/dist/lib/validation.d.ts +1 -1
- package/dist/lib/validation.d.ts.map +1 -1
- package/dist/lib/validation.js +1 -1
- package/dist/messages/de/footer.json +0 -1
- package/dist/messages/de/index.d.ts +0 -1
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/en/footer.json +0 -1
- package/dist/messages/en/index.d.ts +0 -1
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/es/footer.json +0 -1
- package/dist/messages/es/index.d.ts +0 -1
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/fr/footer.json +0 -1
- package/dist/messages/fr/index.d.ts +0 -1
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/it/footer.json +0 -1
- package/dist/messages/it/index.d.ts +0 -1
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/pt/footer.json +0 -1
- package/dist/messages/pt/index.d.ts +0 -1
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/templates/app/(auth)/accept-invite/[token]/page.tsx +4 -3
- package/dist/templates/app/(auth)/verify-email/page.tsx +4 -3
- package/dist/templates/app/(public)/docs/[section]/[page]/page.tsx +11 -0
- package/dist/templates/app/api/auth/[...all]/route.ts +15 -14
- package/dist/templates/app/api/internal/user-metadata/route.ts +6 -8
- package/dist/templates/app/api/user/plan-flags/route.ts +1 -1
- package/dist/templates/app/api/user/profile/route.ts +12 -17
- package/dist/templates/app/api/v1/api-keys/route.ts +1 -1
- package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +2 -1
- package/dist/templates/app/api/v1/billing/cancel/route.ts +1 -1
- package/dist/templates/app/api/v1/billing/change-plan/route.ts +1 -1
- package/dist/templates/app/api/v1/billing/check-action/route.ts +1 -1
- package/dist/templates/app/api/v1/billing/checkout/route.ts +1 -1
- package/dist/templates/app/api/v1/blocks/validate/route.ts +1 -1
- package/dist/templates/app/api/v1/media/[id]/tags/route.ts +1 -1
- package/dist/templates/app/api/v1/post-categories/[id]/route.ts +1 -1
- package/dist/templates/app/api/v1/post-categories/route.ts +1 -1
- package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +2 -1
- package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -5
- package/dist/templates/app/api/v1/teams/docs.md +4 -9
- package/dist/templates/app/api/v1/teams/switch/route.ts +1 -1
- package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +1 -1
- package/dist/templates/app/api/v1/users/[id]/route.ts +1 -1
- package/dist/templates/app/api/v1/users/route.ts +1 -1
- package/dist/templates/app/dashboard/(main)/media/page.tsx +3 -1
- package/dist/templates/app/dashboard/settings/api-keys/page.tsx +5 -4
- package/dist/templates/app/dashboard/settings/profile/page.tsx +3 -2
- package/dist/templates/app/devtools/scheduled-actions/page.tsx +2 -1
- package/dist/templates/app/superadmin/docs/[section]/[page]/page.tsx +16 -0
- package/dist/templates/app/superadmin/subscriptions/page.tsx +3 -2
- package/dist/templates/app/superadmin/teams/[teamId]/page.tsx +5 -4
- package/dist/templates/app/superadmin/users/[userId]/page.tsx +2 -1
- package/dist/templates/app/superadmin/users/page.tsx +2 -1
- package/dist/templates/blocks/cta-section/component.tsx +3 -2
- package/dist/templates/blocks/cta-section/schema.ts +1 -1
- package/dist/templates/blocks/features-grid/component.tsx +2 -1
- package/dist/templates/blocks/features-grid/schema.ts +1 -1
- package/dist/templates/blocks/hero/component.tsx +3 -2
- package/dist/templates/blocks/hero/schema.ts +1 -1
- package/dist/templates/blocks/testimonials/component.tsx +2 -1
- package/dist/templates/blocks/testimonials/schema.ts +1 -1
- package/dist/templates/blocks/text-content/component.tsx +2 -1
- package/dist/templates/blocks/text-content/schema.ts +1 -1
- package/dist/templates/ci-workflows/README.md +1 -1
- package/dist/templates/ci-workflows/github/cypress-regression.yml +1 -1
- package/dist/templates/ci-workflows/github/cypress-smoke.yml +1 -1
- package/dist/templates/contents/plugins/starter/plugin/api/example/route.ts.template +1 -1
- package/dist/templates/contents/themes/starter/blocks/cta-section/component.tsx +3 -2
- package/dist/templates/contents/themes/starter/blocks/cta-section/schema.ts +1 -1
- package/dist/templates/contents/themes/starter/blocks/features-grid/component.tsx +2 -1
- package/dist/templates/contents/themes/starter/blocks/features-grid/schema.ts +1 -1
- package/dist/templates/contents/themes/starter/blocks/hero/component.tsx +3 -2
- package/dist/templates/contents/themes/starter/blocks/hero/schema.ts +1 -1
- package/dist/templates/contents/themes/starter/blocks/testimonials/component.tsx +3 -2
- package/dist/templates/contents/themes/starter/blocks/testimonials/schema.ts +1 -1
- package/dist/templates/contents/themes/starter/blocks/text-content/component.tsx +2 -1
- package/dist/templates/contents/themes/starter/blocks/text-content/schema.ts +1 -1
- package/dist/templates/contents/themes/starter/entities/posts/components/post-header.tsx +2 -1
- package/dist/templates/contents/themes/starter/lib/hooks/useAnalyticsData.ts +2 -1
- package/dist/templates/contents/themes/starter/lib/hooks/useTaskStats.ts +2 -1
- package/dist/templates/eslint.config.mjs +133 -9
- package/dist/templates/features/blog/blocks/post-content/component.tsx +2 -1
- package/dist/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/dist/templates/features/blog/entities/posts/components/post-header.tsx +2 -1
- package/dist/templates/features/pages/blocks/hero/component.tsx +3 -2
- package/dist/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/dist/templates/next.config.mjs +50 -29
- package/dist/templates/proxy.ts +100 -21
- package/dist/templates/public/sw.js +2 -2
- package/dist/templates/scripts/cy-run-prod.cjs +5 -5
- package/dist/types/blocks.d.ts +1 -1
- package/dist/types/blocks.d.ts.map +1 -1
- package/dist/types/blocks.js +1 -1
- package/package.json +9 -5
- package/scripts/build/docs-registry.mjs +7 -7
- package/scripts/build/registry/__tests__/billing-registry.test.mjs +43 -0
- package/scripts/build/registry/__tests__/build-output.test.mjs +209 -0
- package/scripts/build/registry/__tests__/copy-race-child.mjs +14 -0
- package/scripts/build/registry/__tests__/direct-fs-writes.mjs +203 -0
- package/scripts/build/registry/__tests__/globals-css-tag.test.mjs +66 -0
- package/scripts/build/registry/__tests__/icons-discovery.test.mjs +530 -29
- package/scripts/build/registry/__tests__/page-generator.test.mjs +211 -37
- package/scripts/build/registry/__tests__/published-signatures.test.mjs +239 -0
- package/scripts/build/registry/__tests__/route-file-rule.test.mjs +170 -0
- package/scripts/build/registry/__tests__/safe-fs.test.mjs +333 -0
- package/scripts/build/registry/__tests__/template-analysis.test.mjs +142 -0
- package/scripts/build/registry/__tests__/template-registry.test.mjs +279 -9
- package/scripts/build/registry/__tests__/templates-plan.test.mjs +128 -0
- package/scripts/build/registry/__tests__/templates-tree.test.mjs +367 -0
- package/scripts/build/registry/__tests__/write-places.test.mjs +425 -0
- package/scripts/build/registry/config.mjs +6 -65
- package/scripts/build/registry/discovery/icons.mjs +498 -43
- package/scripts/build/registry/discovery/templates.mjs +1 -1
- package/scripts/build/registry/generators/billing-registry.mjs +1 -1
- package/scripts/build/registry/generators/docs-registry.mjs +3 -4
- package/scripts/build/registry/generators/feature-registry.mjs +1 -1
- package/scripts/build/registry/generators/permissions-registry.mjs +2 -2
- package/scripts/build/registry/generators/template-registry.mjs +65 -49
- package/scripts/build/registry/index.mjs +1 -2
- package/scripts/build/registry/post-build/index.mjs +1 -1
- package/scripts/build/registry/post-build/own-gitignores.mjs +220 -0
- package/scripts/build/registry/post-build/page-generator.mjs +512 -268
- package/scripts/build/registry/post-build/route-cleanup.mjs +16 -13
- package/scripts/build/registry/post-build/test-fixtures.mjs +26 -8
- package/scripts/build/registry/project-mode.mjs +76 -0
- package/scripts/build/registry/shared/typescript-compiler.mjs +77 -0
- package/scripts/build/registry/validate-env.test.mjs +12 -8
- package/scripts/build/registry/watch.mjs +3 -53
- package/scripts/build/registry/write-places.mjs +228 -0
- package/scripts/build/registry.mjs +53 -30
- package/scripts/build/safe-fs.mjs +279 -0
- package/scripts/build/templates-plan.mjs +44 -0
- package/scripts/build/theme.mjs +46 -42
- package/scripts/build/update-tsconfig.mjs +16 -15
- package/scripts/db/cluster-changes.mjs +205 -0
- package/scripts/db/connection-time-limits.mjs +53 -0
- package/scripts/db/inspect-server.mjs +108 -0
- package/scripts/db/migration-time-limit.mjs +695 -0
- package/scripts/db/run-migrations.mjs +46 -41
- package/scripts/db/ssl-config.mjs +194 -0
- package/scripts/db/theme-location.mjs +69 -0
- package/scripts/db/verify-tables.mjs +3 -8
- package/scripts/db/verify-teams.mjs +2 -6
- package/scripts/db/verify-theme-migrations.mjs +169 -0
- package/scripts/maintenance/core-updater.mjs +1003 -0
- package/scripts/maintenance/step-guard.mjs +74 -0
- package/scripts/maintenance/update-core.mjs +14 -831
- package/scripts/utils/console-guard.mjs +13 -0
- package/scripts/utils/generated-tag.mjs +66 -0
- package/scripts/utils/index.mjs +9 -1
- package/scripts/utils/logging.mjs +140 -0
- package/templates/app/(auth)/accept-invite/[token]/page.tsx +4 -3
- package/templates/app/(auth)/verify-email/page.tsx +4 -3
- package/templates/app/(public)/docs/[section]/[page]/page.tsx +11 -0
- package/templates/app/api/auth/[...all]/route.ts +15 -14
- package/templates/app/api/internal/user-metadata/route.ts +6 -8
- package/templates/app/api/user/plan-flags/route.ts +1 -1
- package/templates/app/api/user/profile/route.ts +12 -17
- package/templates/app/api/v1/api-keys/route.ts +1 -1
- package/templates/app/api/v1/auth/signup-with-invite/route.ts +2 -1
- package/templates/app/api/v1/billing/cancel/route.ts +1 -1
- package/templates/app/api/v1/billing/change-plan/route.ts +1 -1
- package/templates/app/api/v1/billing/check-action/route.ts +1 -1
- package/templates/app/api/v1/billing/checkout/route.ts +1 -1
- package/templates/app/api/v1/blocks/validate/route.ts +1 -1
- package/templates/app/api/v1/media/[id]/tags/route.ts +1 -1
- package/templates/app/api/v1/post-categories/[id]/route.ts +1 -1
- package/templates/app/api/v1/post-categories/route.ts +1 -1
- package/templates/app/api/v1/teams/[teamId]/members/route.ts +2 -1
- package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +3 -5
- package/templates/app/api/v1/teams/docs.md +4 -9
- package/templates/app/api/v1/teams/switch/route.ts +1 -1
- package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +1 -1
- package/templates/app/api/v1/users/[id]/route.ts +1 -1
- package/templates/app/api/v1/users/route.ts +1 -1
- package/templates/app/dashboard/(main)/media/page.tsx +3 -1
- package/templates/app/dashboard/settings/api-keys/page.tsx +5 -4
- package/templates/app/dashboard/settings/profile/page.tsx +3 -2
- package/templates/app/devtools/scheduled-actions/page.tsx +2 -1
- package/templates/app/superadmin/docs/[section]/[page]/page.tsx +16 -0
- package/templates/app/superadmin/subscriptions/page.tsx +3 -2
- package/templates/app/superadmin/teams/[teamId]/page.tsx +5 -4
- package/templates/app/superadmin/users/[userId]/page.tsx +2 -1
- package/templates/app/superadmin/users/page.tsx +2 -1
- package/templates/blocks/cta-section/component.tsx +3 -2
- package/templates/blocks/cta-section/schema.ts +1 -1
- package/templates/blocks/features-grid/component.tsx +2 -1
- package/templates/blocks/features-grid/schema.ts +1 -1
- package/templates/blocks/hero/component.tsx +3 -2
- package/templates/blocks/hero/schema.ts +1 -1
- package/templates/blocks/testimonials/component.tsx +2 -1
- package/templates/blocks/testimonials/schema.ts +1 -1
- package/templates/blocks/text-content/component.tsx +2 -1
- package/templates/blocks/text-content/schema.ts +1 -1
- package/templates/ci-workflows/README.md +1 -1
- package/templates/ci-workflows/github/cypress-regression.yml +1 -1
- package/templates/ci-workflows/github/cypress-smoke.yml +1 -1
- package/templates/contents/plugins/starter/plugin/api/example/route.ts.template +1 -1
- package/templates/contents/themes/starter/blocks/cta-section/component.tsx +3 -2
- package/templates/contents/themes/starter/blocks/cta-section/schema.ts +1 -1
- package/templates/contents/themes/starter/blocks/features-grid/component.tsx +2 -1
- package/templates/contents/themes/starter/blocks/features-grid/schema.ts +1 -1
- package/templates/contents/themes/starter/blocks/hero/component.tsx +3 -2
- package/templates/contents/themes/starter/blocks/hero/schema.ts +1 -1
- package/templates/contents/themes/starter/blocks/testimonials/component.tsx +3 -2
- package/templates/contents/themes/starter/blocks/testimonials/schema.ts +1 -1
- package/templates/contents/themes/starter/blocks/text-content/component.tsx +2 -1
- package/templates/contents/themes/starter/blocks/text-content/schema.ts +1 -1
- package/templates/contents/themes/starter/entities/posts/components/post-header.tsx +2 -1
- package/templates/contents/themes/starter/lib/hooks/useAnalyticsData.ts +2 -1
- package/templates/contents/themes/starter/lib/hooks/useTaskStats.ts +2 -1
- package/templates/eslint.config.mjs +133 -9
- package/templates/features/blog/blocks/post-content/component.tsx +2 -1
- package/templates/features/blog/blocks/post-content/schema.ts +1 -1
- package/templates/features/blog/entities/posts/components/post-header.tsx +2 -1
- package/templates/features/pages/blocks/hero/component.tsx +3 -2
- package/templates/features/pages/blocks/hero/schema.ts +1 -1
- package/templates/next.config.mjs +50 -29
- package/templates/proxy.ts +100 -21
- package/templates/public/sw.js +2 -2
- package/templates/scripts/cy-run-prod.cjs +5 -5
- package/tests/jest/__mocks__/@nextsparkjs/registries/template-registry.client.ts +11 -0
- package/tests/jest/__mocks__/next-server.js +10 -0
- package/scripts/build/docs.mjs +0 -392
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Badge } from '@nextsparkjs/core/components/ui/badge'
|
|
2
|
+
import { withBasePathIfInApp } from '@nextsparkjs/core/lib/base-path'
|
|
2
3
|
import Image from 'next/image'
|
|
3
4
|
|
|
4
5
|
interface Category {
|
|
@@ -24,7 +25,7 @@ export function PostHeader({ post }: PostHeaderProps) {
|
|
|
24
25
|
{post.featuredImage && (
|
|
25
26
|
<div className="relative w-full h-[400px] md:h-[500px] mb-8" data-cy="post-featured-image-display">
|
|
26
27
|
<Image
|
|
27
|
-
src={post.featuredImage}
|
|
28
|
+
src={withBasePathIfInApp(post.featuredImage)}
|
|
28
29
|
alt={post.title}
|
|
29
30
|
fill
|
|
30
31
|
className="object-cover rounded-lg"
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useQuery } from '@tanstack/react-query'
|
|
4
4
|
import { useTeamContext } from '@nextsparkjs/core/contexts/TeamContext'
|
|
5
|
+
import { withBasePath } from '@nextsparkjs/core/lib/base-path'
|
|
5
6
|
|
|
6
7
|
interface WeeklyProgress {
|
|
7
8
|
day: string
|
|
@@ -31,7 +32,7 @@ export function useAnalyticsData() {
|
|
|
31
32
|
return useQuery({
|
|
32
33
|
queryKey: ['analytics', currentTeam?.id],
|
|
33
34
|
queryFn: async (): Promise<AnalyticsData> => {
|
|
34
|
-
const res = await fetch(`/api/v1/analytics?teamId=${currentTeam?.id}`)
|
|
35
|
+
const res = await fetch(withBasePath(`/api/v1/analytics?teamId=${currentTeam?.id}`))
|
|
35
36
|
if (!res.ok) throw new Error('Failed to fetch analytics')
|
|
36
37
|
return res.json()
|
|
37
38
|
},
|
|
@@ -4,6 +4,7 @@ import { useMemo } from 'react'
|
|
|
4
4
|
import { useQuery } from '@tanstack/react-query'
|
|
5
5
|
import { useTeamContext } from '@nextsparkjs/core/contexts/TeamContext'
|
|
6
6
|
import { calculateTaskStats, type TaskStats } from '../utils'
|
|
7
|
+
import { withBasePath } from '@nextsparkjs/core/lib/base-path'
|
|
7
8
|
|
|
8
9
|
interface Task {
|
|
9
10
|
id: string
|
|
@@ -32,7 +33,7 @@ export function useTaskStats(): UseTaskStatsReturn {
|
|
|
32
33
|
} = useQuery({
|
|
33
34
|
queryKey: ['tasks', currentTeam?.id, 'stats'],
|
|
34
35
|
queryFn: async (): Promise<Task[]> => {
|
|
35
|
-
const response = await fetch(`/api/v1/tasks?teamId=${currentTeam?.id}&limit=1000`)
|
|
36
|
+
const response = await fetch(withBasePath(`/api/v1/tasks?teamId=${currentTeam?.id}&limit=1000`))
|
|
36
37
|
if (!response.ok) {
|
|
37
38
|
throw new Error('Failed to fetch tasks')
|
|
38
39
|
}
|
|
@@ -1,16 +1,140 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Next's presets from the eslint-config-next the project installs, as flat config.
|
|
10
|
+
*
|
|
11
|
+
* Version 16 publishes flat config arrays on these subpaths; reaching them through FlatCompat
|
|
12
|
+
* throws `Converting circular structure to JSON` before a single file is read. Version 15 declares
|
|
13
|
+
* no `exports` and publishes eslintrc presets, which FlatCompat is the only way to read: importing
|
|
14
|
+
* the subpaths throws ERR_MODULE_NOT_FOUND, or, under a loader that adds file extensions, returns
|
|
15
|
+
* eslintrc objects. That is what a Next 15 project gets when `nextspark init` drops this file next
|
|
16
|
+
* to its eslint-config-next. FlatCompat ships in @eslint/eslintrc, which ESLint itself depends on,
|
|
17
|
+
* so it is resolved from there.
|
|
18
|
+
*/
|
|
19
|
+
async function nextPresets() {
|
|
20
|
+
let presets;
|
|
21
|
+
try {
|
|
22
|
+
presets = await Promise.all([
|
|
23
|
+
import("eslint-config-next/core-web-vitals"),
|
|
24
|
+
import("eslint-config-next/typescript"),
|
|
25
|
+
]);
|
|
26
|
+
} catch (error) {
|
|
27
|
+
if (error?.code !== "ERR_MODULE_NOT_FOUND") throw error;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (presets?.every((preset) => Array.isArray(preset.default))) {
|
|
31
|
+
return presets.flatMap((preset) => preset.default);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { FlatCompat } = createRequire(require.resolve("eslint"))("@eslint/eslintrc");
|
|
35
|
+
return new FlatCompat({ baseDirectory: __dirname }).extends("next/core-web-vitals", "next/typescript");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** A config object holding nothing but `ignores` applies to every other object in the array. */
|
|
39
|
+
const isGlobalIgnore = (config) =>
|
|
40
|
+
Object.keys(config).every((key) => key === "ignores" || key === "name");
|
|
41
|
+
|
|
42
|
+
const presets = await nextPresets();
|
|
43
|
+
|
|
44
|
+
/** typescript-eslint's parser, which reads every syntax these trees use: JS, TS and JSX. */
|
|
45
|
+
const typescriptParser = presets
|
|
46
|
+
.map((config) => config.languageOptions?.parser)
|
|
47
|
+
.find((parser) => parser?.meta?.name === "typescript-eslint/parser");
|
|
48
|
+
|
|
49
|
+
const SOURCE_FILES = "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}";
|
|
50
|
+
|
|
51
|
+
// Tests and fixtures, the project's own and those every theme and plugin brings under contents/:
|
|
52
|
+
// they mock, stub and cast by design, so Next's presets skip them and only the zod rule reaches
|
|
53
|
+
// them. Everything else -- app/, contents/ and what the project adds -- gets the presets.
|
|
54
|
+
const TEST_FILES = [
|
|
55
|
+
"**/tests/**",
|
|
56
|
+
"**/__tests__/**",
|
|
57
|
+
"**/__mocks__/**",
|
|
58
|
+
"**/fixtures/**",
|
|
59
|
+
"**/cypress/**",
|
|
60
|
+
"**/*.{test,spec,cy}.{ts,tsx,mts,cts,js,jsx,mjs,cjs}",
|
|
61
|
+
"**/{jest,cypress}.{config,setup}.{ts,mts,cts,js,mjs,cjs}",
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
/** "error", 2 or ["error", ...]. */
|
|
65
|
+
const isError = (setting) => [setting, setting?.[0]].some((level) => level === "error" || level === 2);
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* The severity this project gives the rules Next's presets configure.
|
|
69
|
+
*
|
|
70
|
+
* `@next/next/no-img-element` is an error: the presets only warn, which leaves `eslint .` passing,
|
|
71
|
+
* and next/image is what serves an image resized and in a modern format.
|
|
72
|
+
*
|
|
73
|
+
* eslint-plugin-react-hooks 7, which Next 16's presets load, adds to rules-of-hooks and
|
|
74
|
+
* exhaustive-deps the rules that flag code the React Compiler cannot compile. A NextSpark project
|
|
75
|
+
* does not build with the React Compiler, and the components NextSpark ships in app/ and its themes
|
|
76
|
+
* and plugins break several of those rules, so they report as warnings. Version 5, which Next 15
|
|
77
|
+
* loads, has none of them.
|
|
78
|
+
*/
|
|
79
|
+
function projectSeverity(rule, setting) {
|
|
80
|
+
if (rule === "@next/next/no-img-element") return "error";
|
|
81
|
+
const compilerRule = rule.startsWith("react-hooks/") && !["react-hooks/rules-of-hooks", "react-hooks/exhaustive-deps"].includes(rule);
|
|
82
|
+
return compilerRule && isError(setting) ? "warn" : setting;
|
|
83
|
+
}
|
|
11
84
|
|
|
12
85
|
const eslintConfig = [
|
|
13
|
-
|
|
86
|
+
{
|
|
87
|
+
// Next writes next-env.d.ts itself; version 16's presets ignore it and version 15's do not.
|
|
88
|
+
ignores: [".next/**", ".nextspark/**", "next-env.d.ts"],
|
|
89
|
+
},
|
|
90
|
+
...presets.map((config) =>
|
|
91
|
+
isGlobalIgnore(config)
|
|
92
|
+
? config
|
|
93
|
+
: {
|
|
94
|
+
...config,
|
|
95
|
+
ignores: [...(config.ignores ?? []), ...TEST_FILES],
|
|
96
|
+
...(config.rules && {
|
|
97
|
+
rules: Object.fromEntries(Object.entries(config.rules).map(([rule, setting]) => [rule, projectSeverity(rule, setting)])),
|
|
98
|
+
}),
|
|
99
|
+
},
|
|
100
|
+
),
|
|
101
|
+
{
|
|
102
|
+
// A .cjs file is CommonJS by definition, so `require` is the only spelling it has.
|
|
103
|
+
files: ["**/*.cjs"],
|
|
104
|
+
ignores: TEST_FILES,
|
|
105
|
+
rules: { "@typescript-eslint/no-require-imports": "off" },
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
// The presets would have supplied the parser here. Their plugins are registered so the disable
|
|
109
|
+
// comments in tests resolve the rules they name, without turning any of those rules on.
|
|
110
|
+
files: TEST_FILES,
|
|
111
|
+
languageOptions: {
|
|
112
|
+
parser: typescriptParser,
|
|
113
|
+
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
114
|
+
},
|
|
115
|
+
plugins: Object.assign({}, ...presets.map((config) => config.plugins ?? {})),
|
|
116
|
+
linterOptions: { reportUnusedDisableDirectives: "off" },
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
// Spelled out rather than inherited: a block naming these extensions is what makes ESLint lint
|
|
120
|
+
// a .ts file at all.
|
|
121
|
+
files: [SOURCE_FILES],
|
|
122
|
+
rules: {
|
|
123
|
+
// `no-restricted-imports` with `importNames: ["z"]` also rejects `import * as z`, so the
|
|
124
|
+
// named specifier is matched by syntax instead.
|
|
125
|
+
"no-restricted-syntax": [
|
|
126
|
+
"error",
|
|
127
|
+
{
|
|
128
|
+
// `imported` is an Identifier for `{ z }` and a Literal for `{ "z" as zod }`, so the
|
|
129
|
+
// name lives under a different property in each.
|
|
130
|
+
selector:
|
|
131
|
+
"ImportDeclaration[source.value='zod'] > ImportSpecifier:matches([imported.name='z'], [imported.value='z']), ExportNamedDeclaration[source.value='zod'] > ExportSpecifier:matches([local.name='z'], [local.value='z'])",
|
|
132
|
+
message:
|
|
133
|
+
"Use `import * as z from 'zod'`. Turbopack doesn't tree-shake the named `z` import and bundles all of zod, its 63 locales included.",
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
},
|
|
137
|
+
},
|
|
14
138
|
];
|
|
15
139
|
|
|
16
140
|
export default eslintConfig;
|
|
@@ -4,6 +4,7 @@ import { buildSectionClasses } from '@nextsparkjs/core/types/blocks'
|
|
|
4
4
|
import { sanitizeBlockHtml } from '@nextsparkjs/core/lib/blocks/sanitize-html'
|
|
5
5
|
import { sel } from '../../lib/selectors'
|
|
6
6
|
import type { PostContentBlockProps } from './schema'
|
|
7
|
+
import { withBasePathIfInApp } from '@nextsparkjs/core/lib/base-path'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Post Content Block Component
|
|
@@ -182,7 +183,7 @@ export function PostContentBlock({
|
|
|
182
183
|
{cta && (
|
|
183
184
|
<div className={cn('mt-12 text-center', maxWidthClasses[maxWidth], 'mx-auto')}>
|
|
184
185
|
<a
|
|
185
|
-
href={cta.link}
|
|
186
|
+
href={withBasePathIfInApp(cta.link)}
|
|
186
187
|
target={cta.target}
|
|
187
188
|
rel={cta.target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
188
189
|
className="inline-flex items-center justify-center rounded-md bg-primary px-8 py-3 text-sm font-medium text-primary-foreground hover:bg-primary/90 transition-colors shadow-md hover:shadow-lg"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Badge } from '@nextsparkjs/core/components/ui/badge'
|
|
2
|
+
import { withBasePathIfInApp } from '@nextsparkjs/core/lib/base-path'
|
|
2
3
|
import Image from 'next/image'
|
|
3
4
|
|
|
4
5
|
interface Category {
|
|
@@ -24,7 +25,7 @@ export function PostHeader({ post }: PostHeaderProps) {
|
|
|
24
25
|
{post.featuredImage && (
|
|
25
26
|
<div className="relative w-full h-[400px] md:h-[500px] mb-8" data-cy="post-featured-image-display">
|
|
26
27
|
<Image
|
|
27
|
-
src={post.featuredImage}
|
|
28
|
+
src={withBasePathIfInApp(post.featuredImage)}
|
|
28
29
|
alt={post.title}
|
|
29
30
|
fill
|
|
30
31
|
className="object-cover rounded-lg"
|
|
@@ -4,6 +4,7 @@ import { cn } from '@nextsparkjs/core/lib/utils'
|
|
|
4
4
|
import { buildSectionClasses, resolveMediaUrl } from '@nextsparkjs/core/types/blocks'
|
|
5
5
|
import { sel } from '../../lib/selectors'
|
|
6
6
|
import type { HeroBlockProps } from './schema'
|
|
7
|
+
import { withBasePathIfInApp } from '@nextsparkjs/core/lib/base-path'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Hero Block Component
|
|
@@ -71,7 +72,7 @@ export function HeroBlock({
|
|
|
71
72
|
<div
|
|
72
73
|
className="absolute inset-0 z-0"
|
|
73
74
|
style={{
|
|
74
|
-
backgroundImage: `url(${backgroundImageUrl})`,
|
|
75
|
+
backgroundImage: `url(${withBasePathIfInApp(backgroundImageUrl)})`,
|
|
75
76
|
backgroundSize: 'cover',
|
|
76
77
|
backgroundPosition: 'center',
|
|
77
78
|
}}
|
|
@@ -100,7 +101,7 @@ export function HeroBlock({
|
|
|
100
101
|
{ctaConfig && (
|
|
101
102
|
<Button asChild size="lg" className="text-lg px-8 py-6">
|
|
102
103
|
<a
|
|
103
|
-
href={ctaConfig.link}
|
|
104
|
+
href={withBasePathIfInApp(ctaConfig.link)}
|
|
104
105
|
target={ctaConfig.target}
|
|
105
106
|
rel={ctaConfig.target === '_blank' ? 'noopener noreferrer' : undefined}
|
|
106
107
|
data-cy={sel('blocks.hero.cta')}
|
|
@@ -8,8 +8,52 @@ const __dirname = path.dirname(__filename);
|
|
|
8
8
|
// For npm mode, use local i18n.ts that re-exports from @nextsparkjs/core
|
|
9
9
|
const withNextIntl = createNextIntlPlugin('./i18n.ts');
|
|
10
10
|
|
|
11
|
+
// The app's Next.js basePath. Next.js adds it to routes and to <Link>, and to
|
|
12
|
+
// nothing a header names: the CSP report endpoints below are URLs the browser
|
|
13
|
+
// resolves against the origin, so they carry it from here.
|
|
14
|
+
const basePath = '';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Silences the Node built-ins that client bundles reach transitively, and points
|
|
18
|
+
* `@nextsparkjs/registries` at the generated directory.
|
|
19
|
+
*
|
|
20
|
+
* Only webpack reads this, and either major can build with it: Next 15 by
|
|
21
|
+
* default, Next 16 with `--webpack`. Turbopack resolves `@nextsparkjs/registries`
|
|
22
|
+
* through the `paths` of tsconfig.json, which Next's webpack skips for imports
|
|
23
|
+
* made from inside node_modules, as core's are, and leaves a Node built-in alone
|
|
24
|
+
* unless client code imports it for real.
|
|
25
|
+
*/
|
|
26
|
+
const applyWebpackFallbacks = (config, { isServer }) => {
|
|
27
|
+
if (!isServer) {
|
|
28
|
+
config.resolve.fallback = {
|
|
29
|
+
...config.resolve.fallback,
|
|
30
|
+
fs: false,
|
|
31
|
+
net: false,
|
|
32
|
+
tls: false,
|
|
33
|
+
crypto: false,
|
|
34
|
+
path: false,
|
|
35
|
+
os: false,
|
|
36
|
+
stream: false,
|
|
37
|
+
http: false,
|
|
38
|
+
https: false,
|
|
39
|
+
zlib: false,
|
|
40
|
+
dns: false,
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Add alias for @nextsparkjs/registries to fix ChunkLoadError
|
|
45
|
+
config.resolve.alias = {
|
|
46
|
+
...config.resolve.alias,
|
|
47
|
+
'pg-native': false,
|
|
48
|
+
'@nextsparkjs/registries': path.resolve(__dirname, '.nextspark/registries'),
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return config
|
|
52
|
+
}
|
|
53
|
+
|
|
11
54
|
/** @type {import('next').NextConfig} */
|
|
12
55
|
const nextConfig = {
|
|
56
|
+
basePath,
|
|
13
57
|
// Ignore TypeScript build errors - needed until DTS generation is enabled for @nextsparkjs/core
|
|
14
58
|
// Without this, production builds fail due to missing declaration files for deep imports
|
|
15
59
|
typescript: {
|
|
@@ -81,33 +125,10 @@ const nextConfig = {
|
|
|
81
125
|
},
|
|
82
126
|
],
|
|
83
127
|
},
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
fs: false,
|
|
89
|
-
net: false,
|
|
90
|
-
tls: false,
|
|
91
|
-
crypto: false,
|
|
92
|
-
path: false,
|
|
93
|
-
os: false,
|
|
94
|
-
stream: false,
|
|
95
|
-
http: false,
|
|
96
|
-
https: false,
|
|
97
|
-
zlib: false,
|
|
98
|
-
dns: false,
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Add alias for @nextsparkjs/registries to fix ChunkLoadError
|
|
103
|
-
config.resolve.alias = {
|
|
104
|
-
...config.resolve.alias,
|
|
105
|
-
'pg-native': false,
|
|
106
|
-
'@nextsparkjs/registries': path.resolve(__dirname, '.nextspark/registries'),
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return config
|
|
110
|
-
},
|
|
128
|
+
// Next.js sets TURBOPACK before it loads this file whenever Turbopack builds
|
|
129
|
+
// (on 15 with --turbopack, on 16 unless given --webpack), and next-intl picks
|
|
130
|
+
// its own webpack or Turbopack setup from the same variable.
|
|
131
|
+
...(process.env.TURBOPACK ? {} : { webpack: applyWebpackFallbacks }),
|
|
111
132
|
async headers() {
|
|
112
133
|
const isProduction = process.env.NODE_ENV === 'production';
|
|
113
134
|
|
|
@@ -158,7 +179,7 @@ const nextConfig = {
|
|
|
158
179
|
// CSP violation reporting - sends violations to /api/csp-report
|
|
159
180
|
// report-uri is deprecated but has wider browser support
|
|
160
181
|
// report-to is the modern replacement (configured via Reporting-Endpoints header)
|
|
161
|
-
|
|
182
|
+
`report-uri ${basePath}/api/csp-report`,
|
|
162
183
|
"report-to csp-endpoint",
|
|
163
184
|
];
|
|
164
185
|
|
|
@@ -167,7 +188,7 @@ const nextConfig = {
|
|
|
167
188
|
// Reporting API endpoint for modern browsers (used by report-to CSP directive)
|
|
168
189
|
{
|
|
169
190
|
key: 'Reporting-Endpoints',
|
|
170
|
-
value:
|
|
191
|
+
value: `csp-endpoint="${basePath}/api/csp-report"`
|
|
171
192
|
},
|
|
172
193
|
{
|
|
173
194
|
key: 'X-Content-Type-Options',
|
package/templates/proxy.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* then on sync reports it and leaves it alone.
|
|
2
|
+
* `nextspark sync:app` keeps this file up to date while its first line is the
|
|
3
|
+
* generated tag sync writes and the rest of the file is unchanged since then,
|
|
4
|
+
* which is how a release ships changes to it. Edit the file, or delete that
|
|
5
|
+
* line, to own it: from then on sync reports it and leaves it alone.
|
|
7
6
|
*
|
|
8
7
|
* NextSpark Proxy (Next.js 16+)
|
|
9
8
|
*
|
|
@@ -12,9 +11,10 @@
|
|
|
12
11
|
*
|
|
13
12
|
* Key responsibilities:
|
|
14
13
|
* 1. Theme middleware override support
|
|
15
|
-
* 2.
|
|
16
|
-
* 3.
|
|
17
|
-
* 4.
|
|
14
|
+
* 2. Redirecting historical 3-level docs URLs to their current route
|
|
15
|
+
* 3. Documentation access control
|
|
16
|
+
* 4. Protected route authentication, and the roles /superadmin and /devtools need
|
|
17
|
+
* 5. User header injection for downstream use (x-user-id, x-pathname, x-active-team-id)
|
|
18
18
|
*
|
|
19
19
|
* IMPORTANT: The EntityPermissionLayout depends on x-user-id and x-pathname
|
|
20
20
|
* headers being set here for server-side permission validation.
|
|
@@ -28,6 +28,8 @@ import {
|
|
|
28
28
|
} from '@nextsparkjs/core/lib/middleware'
|
|
29
29
|
import { ACTIVE_TEAM_COOKIE, activeTeamIdForSession } from '@nextsparkjs/core/lib/teams/active-team-cookie'
|
|
30
30
|
import { SESSION_HINT_COOKIE, SESSION_HINT_MAX_AGE, hasSessionCookie } from '@nextsparkjs/core/lib/auth/session-hint'
|
|
31
|
+
import { isDocsPublic, legacyDocsAccessMessage } from '@nextsparkjs/core/lib/docs/access'
|
|
32
|
+
import { DOCS_REGISTRY } from '@nextsparkjs/registries/docs-registry'
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
35
|
* Session type for proxy (inline definition)
|
|
@@ -91,6 +93,45 @@ function appUrl(request: NextRequest, pathname: string): NextRequest['nextUrl']
|
|
|
91
93
|
return url
|
|
92
94
|
}
|
|
93
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Whether `pathname` is a docs page route — `/docs/<section>/<page>` or
|
|
98
|
+
* `/superadmin/docs/<section>/<page>` — whose section and page the docs
|
|
99
|
+
* registry does not have together. Segments are compared decoded, the way the
|
|
100
|
+
* page reads its params.
|
|
101
|
+
*/
|
|
102
|
+
function isMissingDocsPage(pathname: string): boolean {
|
|
103
|
+
const match = pathname.match(/^(\/superadmin)?\/docs\/([^/]+)\/([^/]+)$/)
|
|
104
|
+
if (!match) return false
|
|
105
|
+
|
|
106
|
+
let sectionSlug: string
|
|
107
|
+
let pageSlug: string
|
|
108
|
+
try {
|
|
109
|
+
sectionSlug = decodeURIComponent(match[2])
|
|
110
|
+
pageSlug = decodeURIComponent(match[3])
|
|
111
|
+
} catch {
|
|
112
|
+
return true
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const sections = match[1] ? DOCS_REGISTRY.superadmin : DOCS_REGISTRY.public
|
|
116
|
+
return !sections.some(section => section.slug === sectionSlug && section.pages.some(page => page.slug === pageSlug))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Serve the app's not-found page with a 404 status for a docs page the
|
|
121
|
+
* registry does not have. The docs pages answer 404 on their own only where
|
|
122
|
+
* their `dynamicParams = false` has a list to check: in `next dev`, and for
|
|
123
|
+
* public docs prerendered by an app whose locale is fixed. Rendered on demand
|
|
124
|
+
* (superadmin docs always, public docs when the locale comes from the
|
|
125
|
+
* request), their notFound() runs inside the layouts' Suspense boundaries,
|
|
126
|
+
* after the response head has gone out with a 200. Deciding it here, before
|
|
127
|
+
* anything renders, gives those requests the 404.
|
|
128
|
+
*/
|
|
129
|
+
function rewriteToNotFound(request: NextRequest, requestHeaders: Headers): NextResponse {
|
|
130
|
+
return syncSessionHint(request, NextResponse.rewrite(appUrl(request, '/_not-found'), {
|
|
131
|
+
request: { headers: requestHeaders },
|
|
132
|
+
}))
|
|
133
|
+
}
|
|
134
|
+
|
|
94
135
|
/**
|
|
95
136
|
* Send a visitor without a session to login. LoginForm reads `callbackUrl` and
|
|
96
137
|
* returns them to the page they asked for, query included, once signed in.
|
|
@@ -178,6 +219,18 @@ function passThrough(request: NextRequest, requestHeaders: Headers): NextRespons
|
|
|
178
219
|
}))
|
|
179
220
|
}
|
|
180
221
|
|
|
222
|
+
let legacyDocsAccessWarned = false
|
|
223
|
+
|
|
224
|
+
/** Says once per server process what to change in an app config that still
|
|
225
|
+
* gates /docs with the older `docs.public` boolean. */
|
|
226
|
+
function warnLegacyDocsAccess(docsConfig: Parameters<typeof legacyDocsAccessMessage>[0]): void {
|
|
227
|
+
if (legacyDocsAccessWarned) return
|
|
228
|
+
const message = legacyDocsAccessMessage(docsConfig)
|
|
229
|
+
if (!message) return
|
|
230
|
+
legacyDocsAccessWarned = true
|
|
231
|
+
console.warn(`[NextSpark] ${message}`)
|
|
232
|
+
}
|
|
233
|
+
|
|
181
234
|
export async function proxy(request: NextRequest) {
|
|
182
235
|
const { pathname } = request.nextUrl
|
|
183
236
|
|
|
@@ -191,36 +244,58 @@ export async function proxy(request: NextRequest) {
|
|
|
191
244
|
if (themeResponse) return themeResponse
|
|
192
245
|
}
|
|
193
246
|
|
|
194
|
-
// 2. Redirect
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
247
|
+
// 2. Redirect historical 3-level docs URLs (/docs/<core|theme>/<section>/<page>)
|
|
248
|
+
// to the current route. That split predates this app's history: `core` and
|
|
249
|
+
// `theme` were the only two categories ever generated (a third, `plugins`,
|
|
250
|
+
// was scaffolded but never activated), and both were collapsed into a single
|
|
251
|
+
// docs tree per source - `public` (served at /docs) and `superadmin` (served
|
|
252
|
+
// at /superadmin/docs) - without renaming any section that survived the
|
|
253
|
+
// collapse. A section from that era can therefore only be in one of the two
|
|
254
|
+
// registries today, or in neither if its docs were dropped rather than
|
|
255
|
+
// moved; the redirect follows the section, not the old category. The page
|
|
256
|
+
// has to survive too - a section can live on with a different set of pages -
|
|
257
|
+
// so both are checked against the registry rather than only the section,
|
|
258
|
+
// which is the one thing this route can actually confirm still resolves.
|
|
259
|
+
const oldDocsMatch = pathname.match(/^\/docs\/(?:core|theme)\/([^/]+)\/([^/]+)$/)
|
|
198
260
|
if (oldDocsMatch) {
|
|
199
261
|
const [, sectionSlug, pageSlug] = oldDocsMatch
|
|
200
|
-
const themeSections = ['theme-overview', 'theme-features']
|
|
201
|
-
const category = themeSections.includes(sectionSlug) ? 'theme' : 'core'
|
|
202
|
-
const cleanSection = sectionSlug.replace(/^theme-/, '')
|
|
203
|
-
|
|
204
262
|
const newUrl = request.nextUrl.clone()
|
|
205
|
-
|
|
263
|
+
const superadminSection = DOCS_REGISTRY.superadmin.find((section) => section.slug === sectionSlug)
|
|
264
|
+
const publicSection = DOCS_REGISTRY.public.find((section) => section.slug === sectionSlug)
|
|
265
|
+
|
|
266
|
+
if (superadminSection?.pages.some((page) => page.slug === pageSlug)) {
|
|
267
|
+
newUrl.pathname = `/superadmin/docs/${sectionSlug}/${pageSlug}`
|
|
268
|
+
} else if (publicSection?.pages.some((page) => page.slug === pageSlug)) {
|
|
269
|
+
newUrl.pathname = `/docs/${sectionSlug}/${pageSlug}`
|
|
270
|
+
} else {
|
|
271
|
+
// The section is gone, or survived without this exact page - either way
|
|
272
|
+
// there is no page left to send this to, so it goes to the docs home
|
|
273
|
+
// instead of a dead link.
|
|
274
|
+
newUrl.pathname = '/docs'
|
|
275
|
+
}
|
|
206
276
|
return NextResponse.redirect(newUrl, 301)
|
|
207
277
|
}
|
|
208
278
|
|
|
209
|
-
// 3. Documentation access control
|
|
279
|
+
// 3. Documentation access control: docs.publicAccess, or the older
|
|
280
|
+
// docs.public boolean it replaced (see lib/docs/access)
|
|
210
281
|
if (isUnder(pathname, '/docs')) {
|
|
211
|
-
const
|
|
282
|
+
const docsConfig = getThemeAppConfig(activeTheme as string)?.docs
|
|
283
|
+
warnLegacyDocsAccess(docsConfig)
|
|
212
284
|
|
|
213
|
-
if (
|
|
285
|
+
if (!isDocsPublic(docsConfig)) {
|
|
214
286
|
try {
|
|
215
287
|
const { data: session } = await getSession(request)
|
|
216
288
|
|
|
217
289
|
if (!session) {
|
|
218
290
|
return redirectToLogin(request)
|
|
219
291
|
}
|
|
220
|
-
} catch
|
|
292
|
+
} catch {
|
|
221
293
|
return redirectToLogin(request)
|
|
222
294
|
}
|
|
223
295
|
}
|
|
296
|
+
if (isMissingDocsPage(pathname)) {
|
|
297
|
+
return rewriteToNotFound(request, requestHeaders)
|
|
298
|
+
}
|
|
224
299
|
return passThrough(request, requestHeaders)
|
|
225
300
|
}
|
|
226
301
|
|
|
@@ -290,6 +365,10 @@ export async function proxy(request: NextRequest) {
|
|
|
290
365
|
requestHeaders.set('x-active-team-id', activeTeamId)
|
|
291
366
|
}
|
|
292
367
|
|
|
368
|
+
if (isSuperadminRoute && isMissingDocsPage(pathname)) {
|
|
369
|
+
return rewriteToNotFound(request, requestHeaders)
|
|
370
|
+
}
|
|
371
|
+
|
|
293
372
|
return passThrough(request, requestHeaders)
|
|
294
373
|
} catch (error) {
|
|
295
374
|
console.error('Proxy error:', error)
|
package/templates/public/sw.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
// Empty service worker to prevent 404 errors
|
|
2
2
|
// This file exists only to stop browsers from requesting a non-existent service worker
|
|
3
3
|
|
|
4
|
-
self.addEventListener('install', function(
|
|
4
|
+
self.addEventListener('install', function() {
|
|
5
5
|
// No caching or special behavior
|
|
6
6
|
});
|
|
7
7
|
|
|
8
|
-
self.addEventListener('fetch', function(
|
|
8
|
+
self.addEventListener('fetch', function() {
|
|
9
9
|
// No fetch interception
|
|
10
10
|
});
|
|
@@ -83,7 +83,7 @@ function killPort(port) {
|
|
|
83
83
|
if (pid && /^\d+$/.test(pid)) {
|
|
84
84
|
try {
|
|
85
85
|
execSync(`taskkill /PID ${pid} /F`, { stdio: 'ignore' })
|
|
86
|
-
} catch
|
|
86
|
+
} catch {
|
|
87
87
|
// Process might already be dead
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -92,7 +92,7 @@ function killPort(port) {
|
|
|
92
92
|
execSync(`lsof -ti:${port} | xargs kill -9 2>/dev/null || true`, { stdio: 'ignore' })
|
|
93
93
|
}
|
|
94
94
|
console.log(`[cy:run:prod] Port ${port} cleared`)
|
|
95
|
-
} catch
|
|
95
|
+
} catch {
|
|
96
96
|
// No process on port, that's fine
|
|
97
97
|
console.log(`[cy:run:prod] Port ${port} was already free`)
|
|
98
98
|
}
|
|
@@ -206,16 +206,16 @@ function cleanup(server) {
|
|
|
206
206
|
// Kill process group
|
|
207
207
|
try {
|
|
208
208
|
process.kill(-server.pid, 'SIGKILL')
|
|
209
|
-
} catch
|
|
209
|
+
} catch {
|
|
210
210
|
// If process group kill fails, try direct kill
|
|
211
211
|
try {
|
|
212
212
|
server.kill('SIGKILL')
|
|
213
|
-
} catch
|
|
213
|
+
} catch {
|
|
214
214
|
// Process might already be dead
|
|
215
215
|
}
|
|
216
216
|
}
|
|
217
217
|
}
|
|
218
|
-
} catch
|
|
218
|
+
} catch {
|
|
219
219
|
// Process might already be dead
|
|
220
220
|
}
|
|
221
221
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mock Template Registry (client) for Jest tests
|
|
3
|
+
*
|
|
4
|
+
* No theme overrides a page in tests, so every page renders its default.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { ComponentType } from 'react'
|
|
8
|
+
|
|
9
|
+
export function getTemplateOrDefaultClient<P>(_path: string, defaultComponent: ComponentType<P>): ComponentType<P> {
|
|
10
|
+
return defaultComponent
|
|
11
|
+
}
|
|
@@ -98,6 +98,16 @@ class MockNextResponse {
|
|
|
98
98
|
return response
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
// Serves another URL of the app in place of the requested one, with the
|
|
102
|
+
// forwarded request headers kept for assertions like next() above.
|
|
103
|
+
static rewrite(url, init = {}) {
|
|
104
|
+
const response = new MockNextResponse(null, { status: 200, headers: init.headers })
|
|
105
|
+
response.type = 'rewrite'
|
|
106
|
+
response.rewriteUrl = String(url)
|
|
107
|
+
response.requestHeaders = init.request && init.request.headers ? init.request.headers : null
|
|
108
|
+
return response
|
|
109
|
+
}
|
|
110
|
+
|
|
101
111
|
static redirect(url, status = 307) {
|
|
102
112
|
const response = new MockNextResponse(null, { status, headers: { Location: String(url) } })
|
|
103
113
|
response.type = 'redirect'
|