@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
package/dist/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)
|
|
@@ -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
|
}
|
package/dist/types/blocks.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"blocks.d.ts","sourceRoot":"","sources":["../../src/types/blocks.ts"],"names":[],"mappings":"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"}
|
package/dist/types/blocks.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.190",
|
|
4
4
|
"description": "NextSpark - The complete SaaS framework for Next.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NextSpark <hello@nextspark.dev>",
|
|
@@ -31,6 +31,9 @@
|
|
|
31
31
|
"main": "./dist/index.js",
|
|
32
32
|
"module": "./dist/index.js",
|
|
33
33
|
"types": "./dist/index.d.ts",
|
|
34
|
+
"bin": {
|
|
35
|
+
"update-core": "./scripts/maintenance/update-core.mjs"
|
|
36
|
+
},
|
|
34
37
|
"exports": {
|
|
35
38
|
".": {
|
|
36
39
|
"types": "./dist/index.d.ts",
|
|
@@ -381,11 +384,12 @@
|
|
|
381
384
|
"scripts"
|
|
382
385
|
],
|
|
383
386
|
"peerDependencies": {
|
|
384
|
-
"next": ">=
|
|
387
|
+
"next": ">=15.0.0",
|
|
385
388
|
"react": ">=18.0.0",
|
|
386
389
|
"react-dom": ">=18.0.0"
|
|
387
390
|
},
|
|
388
391
|
"devDependencies": {
|
|
392
|
+
"@better-fetch/fetch": "1.3.1",
|
|
389
393
|
"@cypress/grep": "^5.0.1",
|
|
390
394
|
"@tailwindcss/cli": "^4",
|
|
391
395
|
"@testing-library/jest-dom": "^6.6.3",
|
|
@@ -405,8 +409,7 @@
|
|
|
405
409
|
"jest-environment-jsdom": "^29.7.0",
|
|
406
410
|
"tailwindcss": "^4",
|
|
407
411
|
"ts-jest": "^29.2.5",
|
|
408
|
-
"tsup": "^8.5.1"
|
|
409
|
-
"typescript": "^5"
|
|
412
|
+
"tsup": "^8.5.1"
|
|
410
413
|
},
|
|
411
414
|
"dependencies": {
|
|
412
415
|
"@babel/runtime": "^7.0.0",
|
|
@@ -484,9 +487,10 @@
|
|
|
484
487
|
"sonner": "^2.0.7",
|
|
485
488
|
"stripe": "^18.5.0",
|
|
486
489
|
"tailwind-merge": "^3.3.1",
|
|
490
|
+
"typescript": "^5 || ^6",
|
|
487
491
|
"uuid": "^13.0.0",
|
|
488
492
|
"zod": "^4.3.6",
|
|
489
|
-
"@nextsparkjs/testing": "0.1.0-beta.
|
|
493
|
+
"@nextsparkjs/testing": "0.1.0-beta.190"
|
|
490
494
|
},
|
|
491
495
|
"scripts": {
|
|
492
496
|
"postinstall": "node scripts/postinstall.mjs || true",
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
* Part of the registry system
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import
|
|
19
|
+
import { existsSync, readdirSync } from 'fs'
|
|
20
20
|
import path from 'path'
|
|
21
21
|
import { fileURLToPath } from 'url'
|
|
22
|
-
import {
|
|
22
|
+
import { projectFiles } from './safe-fs.mjs'
|
|
23
23
|
|
|
24
24
|
const __filename = fileURLToPath(import.meta.url)
|
|
25
25
|
const __dirname = path.dirname(__filename)
|
|
@@ -107,13 +107,13 @@ const PATH_PREFIX = IS_NPM_MODE ? '' : '../..'
|
|
|
107
107
|
* @returns {Array} Array of section metadata
|
|
108
108
|
*/
|
|
109
109
|
function scanDocsDirectory(docsPath, source) {
|
|
110
|
-
if (!
|
|
110
|
+
if (!existsSync(docsPath)) {
|
|
111
111
|
console.log(` No docs found at: ${docsPath}`)
|
|
112
112
|
return []
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
const sections = []
|
|
116
|
-
const items =
|
|
116
|
+
const items = readdirSync(docsPath, { withFileTypes: true })
|
|
117
117
|
|
|
118
118
|
for (const item of items) {
|
|
119
119
|
if (!item.isDirectory()) continue
|
|
@@ -124,7 +124,7 @@ function scanDocsDirectory(docsPath, source) {
|
|
|
124
124
|
const title = slugToTitle(slug)
|
|
125
125
|
|
|
126
126
|
const pages = []
|
|
127
|
-
const files =
|
|
127
|
+
const files = readdirSync(sectionPath)
|
|
128
128
|
|
|
129
129
|
for (const file of files) {
|
|
130
130
|
if (!file.endsWith('.md')) continue
|
|
@@ -301,12 +301,12 @@ export function findDocPage(sectionSlug: string, pageSlug: string): DocPageMeta
|
|
|
301
301
|
|
|
302
302
|
// Ensure output directory exists
|
|
303
303
|
if (!existsSync(OUTPUT_DIR)) {
|
|
304
|
-
mkdirSync(OUTPUT_DIR, { recursive: true })
|
|
304
|
+
projectFiles(PROJECT_ROOT).mkdirSync(OUTPUT_DIR, { recursive: true })
|
|
305
305
|
}
|
|
306
306
|
|
|
307
307
|
// Write registry file
|
|
308
308
|
const registryPath = path.join(OUTPUT_DIR, 'docs-registry.ts')
|
|
309
|
-
|
|
309
|
+
projectFiles(PROJECT_ROOT).writeFileSync(registryPath, registryContent, 'utf-8')
|
|
310
310
|
|
|
311
311
|
console.log('✅ Docs registry built successfully')
|
|
312
312
|
console.log(` Output: .nextspark/registries/docs-registry.ts`)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests that generateBillingRegistry's jiti instance keeps its module cache in
|
|
3
|
+
* memory instead of writing it to disk, since jiti's default cache directory
|
|
4
|
+
* falls outside the project whenever the nearest node_modules isn't writable.
|
|
5
|
+
*
|
|
6
|
+
* Run: node --test packages/core/scripts/build/registry/__tests__/billing-registry.test.mjs
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { test } from 'node:test'
|
|
10
|
+
import assert from 'node:assert/strict'
|
|
11
|
+
import { mkdtemp, readdir, rm } from 'node:fs/promises'
|
|
12
|
+
import { tmpdir } from 'node:os'
|
|
13
|
+
import { dirname, join } from 'node:path'
|
|
14
|
+
import { fileURLToPath } from 'node:url'
|
|
15
|
+
|
|
16
|
+
import { generateBillingRegistry } from '../generators/billing-registry.mjs'
|
|
17
|
+
|
|
18
|
+
const REPO_ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..', '..', '..')
|
|
19
|
+
|
|
20
|
+
async function directory(prefix) {
|
|
21
|
+
const root = await mkdtemp(join(tmpdir(), prefix))
|
|
22
|
+
return { root, cleanup: () => rm(root, { recursive: true, force: true }) }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
test("generateBillingRegistry's jiti import writes nothing under TMPDIR, even when it can't reach a writable node_modules", async () => {
|
|
26
|
+
const cacheRoot = await directory('nextspark-billing-registry-tmpdir-')
|
|
27
|
+
const originalTmpdir = process.env.TMPDIR
|
|
28
|
+
try {
|
|
29
|
+
process.env.TMPDIR = cacheRoot.root
|
|
30
|
+
const themesDir = join(REPO_ROOT, 'themes')
|
|
31
|
+
const config = { themesDir, outputDir: join(cacheRoot.root, 'lib/registries') }
|
|
32
|
+
|
|
33
|
+
const output = await generateBillingRegistry('default', join(REPO_ROOT, 'contents'), config)
|
|
34
|
+
|
|
35
|
+
assert.match(output, /Active theme: default/)
|
|
36
|
+
const strayEntries = await readdir(cacheRoot.root)
|
|
37
|
+
assert.deepEqual(strayEntries, [], `jiti must not write a module cache under TMPDIR, found: ${strayEntries.join(', ')}`)
|
|
38
|
+
} finally {
|
|
39
|
+
if (originalTmpdir === undefined) delete process.env.TMPDIR
|
|
40
|
+
else process.env.TMPDIR = originalTmpdir
|
|
41
|
+
await cacheRoot.cleanup()
|
|
42
|
+
}
|
|
43
|
+
})
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for what the registry build and its plan print: every call to the
|
|
3
|
+
* console is escaped where it prints, once the console is guarded - as the
|
|
4
|
+
* scripts that run the build guard it before anything loads - so a name that
|
|
5
|
+
* holds a character that breaks or reorders a line, in a file of the project
|
|
6
|
+
* or in the project's own path, starts no line of its own.
|
|
7
|
+
*
|
|
8
|
+
* Run: node --test packages/core/scripts/build/registry/__tests__/build-output.test.mjs
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { test } from 'node:test'
|
|
12
|
+
import assert from 'node:assert/strict'
|
|
13
|
+
import { spawnSync } from 'node:child_process'
|
|
14
|
+
import { copyFile, chmod, mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|
15
|
+
import { tmpdir } from 'node:os'
|
|
16
|
+
import { dirname, join } from 'node:path'
|
|
17
|
+
import { fileURLToPath } from 'node:url'
|
|
18
|
+
|
|
19
|
+
import { errorWithLines, guardConsole, logFailure, messageLines, shownLine, stackLines } from '../../../utils/index.mjs'
|
|
20
|
+
|
|
21
|
+
const CORE_DIR = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', '..')
|
|
22
|
+
|
|
23
|
+
/** A name that, printed raw, starts lines of its own - one reading as the build succeeding - erases a line, returns the carriage and separates or reorders lines. */
|
|
24
|
+
const FORGED = 'forged\n✅ Registry System built successfully!\n\u001b[2K\r\u2028\u0085\u202e'
|
|
25
|
+
const SHOWN = 'forged\\n✅ Registry System built successfully!\\n\\u001b[2K\\r\\u2028\\u0085\\u202e'
|
|
26
|
+
|
|
27
|
+
const RAW_CONTROL = /[\u0000-\u0009\u000b-\u001f\u007f-\u009f\u061c\u200e\u200f\u2028\u2029\u202a-\u202e\u2066-\u2069]/
|
|
28
|
+
|
|
29
|
+
async function createProject(parent = tmpdir(), name = 'nextspark-build-output-test-') {
|
|
30
|
+
const root = await mkdtemp(join(parent, name))
|
|
31
|
+
await writeFile(join(root, '.env'), 'NEXT_PUBLIC_ACTIVE_THEME=acme\n')
|
|
32
|
+
await writeFile(join(root, 'package.json'), '{}')
|
|
33
|
+
await mkdir(join(root, 'app'))
|
|
34
|
+
return root
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** What a script of core's build printed for the project, stdout and stderr, as lines, and its exit code. */
|
|
38
|
+
function run(script, root, args = [], env = {}) {
|
|
39
|
+
const result = spawnSync('node', [join('scripts', 'build', script), ...args], {
|
|
40
|
+
cwd: CORE_DIR,
|
|
41
|
+
env: { ...process.env, NEXTSPARK_PROJECT_ROOT: root, ...env },
|
|
42
|
+
encoding: 'utf8',
|
|
43
|
+
input: '{}',
|
|
44
|
+
})
|
|
45
|
+
return { status: result.status, lines: `${result.stdout}${result.stderr}`.split('\n') }
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** What is wrong with the lines a script printed: a raw control, or more lines reading as the build succeeding than it printed itself. */
|
|
49
|
+
function wrongLines(label, lines, successes = 0) {
|
|
50
|
+
return [
|
|
51
|
+
...lines.filter(line => RAW_CONTROL.test(line)).map(line => `${label}: ${JSON.stringify(line)} holds a raw control`),
|
|
52
|
+
...(lines.filter(line => line.trim() === '✅ Registry System built successfully!').length > successes ? [`${label}: a line reads as the build succeeding that it did not print`] : []),
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** Run `print` with the console captured and guarded, returning each line printed. */
|
|
57
|
+
function printedBy(print) {
|
|
58
|
+
const printed = []
|
|
59
|
+
const original = { log: console.log, error: console.error }
|
|
60
|
+
const capture = (...args) => { printed.push(args.join(' ')) }
|
|
61
|
+
console.log = capture
|
|
62
|
+
console.error = capture
|
|
63
|
+
guardConsole()
|
|
64
|
+
try {
|
|
65
|
+
print()
|
|
66
|
+
} finally {
|
|
67
|
+
Object.assign(console, original)
|
|
68
|
+
}
|
|
69
|
+
return printed.join('\n').split('\n')
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
test('a line the console prints is escaped whole, keeping the blank lines and the indent around it', () => {
|
|
73
|
+
assert.equal(shownLine(' plain line'), ' plain line')
|
|
74
|
+
assert.equal(shownLine('\n blank line before and after\n'), '\n blank line before and after\n')
|
|
75
|
+
assert.equal(shownLine(` named ${FORGED} here`), ` "named ${SHOWN} here"`)
|
|
76
|
+
assert.equal(shownLine(`\n✅ ${FORGED}\n`), `\n"✅ ${SHOWN}"\n`)
|
|
77
|
+
|
|
78
|
+
const lines = printedBy(() => {
|
|
79
|
+
console.log('📦 Output: %s', FORGED)
|
|
80
|
+
console.error(` ${FORGED}`)
|
|
81
|
+
console.log()
|
|
82
|
+
})
|
|
83
|
+
assert.deepEqual(lines, [`"📦 Output: ${SHOWN}"`, ` "${SHOWN}"`, ''])
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test("an error's own lines are printed one by one, and a newline anywhere else in its message, or in a path its stack names, stays on its line", async () => {
|
|
87
|
+
const multiline = errorWithLines(['permissions.config.ts has keys no entity matches:', ' ❌ "tasks" - No entity found with this slug', '\u001b[2Kerased'])
|
|
88
|
+
assert.deepEqual(messageLines(multiline), multiline.lines)
|
|
89
|
+
assert.deepEqual(messageLines(new Error(`one line ${FORGED}`)), [`one line ${FORGED}`])
|
|
90
|
+
assert.deepEqual(printedBy(() => logFailure('Build failed', multiline)), [
|
|
91
|
+
'❌ Build failed: permissions.config.ts has keys no entity matches:',
|
|
92
|
+
' ❌ "tasks" - No entity found with this slug',
|
|
93
|
+
'"\\u001b[2Kerased"',
|
|
94
|
+
])
|
|
95
|
+
|
|
96
|
+
const root = await mkdtemp(join(tmpdir(), 'nextspark-build-output-test-'))
|
|
97
|
+
try {
|
|
98
|
+
const error = await copyFile(join(root, `missing${FORGED}`), join(root, `copy\n${FORGED}`)).then(() => null, error => error)
|
|
99
|
+
assert.ok(error, 'copying a missing file fails')
|
|
100
|
+
const stack = stackLines(error)
|
|
101
|
+
assert.equal(stack[0], `Error: ${error.message}`)
|
|
102
|
+
assert.ok(stack.slice(1).every(line => line.startsWith(' at ')), 'each other line is a frame')
|
|
103
|
+
|
|
104
|
+
const lines = printedBy(() => logFailure('Build failed', error, true))
|
|
105
|
+
assert.deepEqual(lines.filter(line => RAW_CONTROL.test(line)), [])
|
|
106
|
+
assert.deepEqual(lines.filter(line => line.trim() === '✅ Registry System built successfully!'), [])
|
|
107
|
+
assert.equal(lines[0], `"❌ Build failed: ENOENT: no such file or directory, copyfile '${root}/missing${SHOWN}' -> '${root}/copy\\n${SHOWN}'"`)
|
|
108
|
+
assert.equal(lines[1], `"Error: ENOENT: no such file or directory, copyfile '${root}/missing${SHOWN}' -> '${root}/copy\\n${SHOWN}'"`)
|
|
109
|
+
} finally {
|
|
110
|
+
await rm(root, { recursive: true, force: true })
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
test('a directory in app/(templates) the build cannot read is named escaped where the build stops before writing and where its plan fails', { skip: process.getuid?.() === 0 }, async () => {
|
|
115
|
+
const root = await createProject()
|
|
116
|
+
const unreadable = join(root, 'app', '(templates)', FORGED)
|
|
117
|
+
try {
|
|
118
|
+
await mkdir(join(root, 'contents/themes/acme/templates/pricing'), { recursive: true })
|
|
119
|
+
await writeFile(join(root, 'contents/themes/acme/templates/pricing/page.tsx'), 'export default function Page() { return null }\n')
|
|
120
|
+
await mkdir(unreadable, { recursive: true })
|
|
121
|
+
await chmod(unreadable, 0)
|
|
122
|
+
|
|
123
|
+
const build = run('registry.mjs', root, ['--verbose'])
|
|
124
|
+
const plan = run('templates-plan.mjs', root)
|
|
125
|
+
|
|
126
|
+
const wrong = [...wrongLines('build', build.lines), ...wrongLines('plan', plan.lines)]
|
|
127
|
+
if (!build.lines.includes(` "app/(templates)/${SHOWN} can't be read"`)) wrong.push('build: the check does not name the directory escaped')
|
|
128
|
+
if (!plan.lines.some(line => line.startsWith('"EACCES: permission denied, scandir ') && line.endsWith(`/app/(templates)/${SHOWN}'"`))) wrong.push('plan: the failure does not name the directory escaped')
|
|
129
|
+
assert.equal(build.status, 1)
|
|
130
|
+
assert.equal(plan.status, 1)
|
|
131
|
+
assert.deepEqual(wrong, [])
|
|
132
|
+
} finally {
|
|
133
|
+
await chmod(unreadable, 0o755).catch(() => {})
|
|
134
|
+
await rm(root, { recursive: true, force: true })
|
|
135
|
+
}
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
test('a theme template the build rejects is named escaped where it is discovered and where the build and its plan reject it', async () => {
|
|
139
|
+
const root = await createProject()
|
|
140
|
+
try {
|
|
141
|
+
await mkdir(join(root, 'contents/themes/acme/templates', FORGED), { recursive: true })
|
|
142
|
+
await writeFile(join(root, 'contents/themes/acme/templates', FORGED, 'page.tsx'), 'export const metadata = { title: "no default export" }\n')
|
|
143
|
+
|
|
144
|
+
const build = run('registry.mjs', root, ['--verbose'])
|
|
145
|
+
const plan = run('templates-plan.mjs', root)
|
|
146
|
+
|
|
147
|
+
const wrong = [...wrongLines('build', build.lines), ...wrongLines('plan', plan.lines)]
|
|
148
|
+
const rejected = `@/contents/themes/acme/templates/${SHOWN}/page.tsx has no default export, and the app has no existing route at \\"app/${SHOWN}/page.tsx\\"`
|
|
149
|
+
if (!build.lines.includes(` "Template: app/${SHOWN}/page.tsx → @/contents/themes/acme/templates/${SHOWN}/page.tsx"`)) wrong.push('build: discovery does not name the template escaped')
|
|
150
|
+
if (!build.lines.some(line => line.startsWith(`"❌ Build failed: ${rejected}`))) wrong.push('build: the failure does not name the template escaped')
|
|
151
|
+
if (!plan.lines.some(line => line.startsWith(`"${rejected}`))) wrong.push('plan: the failure does not name the template escaped')
|
|
152
|
+
assert.equal(build.status, 1)
|
|
153
|
+
assert.equal(plan.status, 1)
|
|
154
|
+
assert.deepEqual(wrong, [])
|
|
155
|
+
} finally {
|
|
156
|
+
await rm(root, { recursive: true, force: true })
|
|
157
|
+
}
|
|
158
|
+
})
|
|
159
|
+
|
|
160
|
+
test('a theme template whose route-level exports the build cannot read is named escaped where the build and its plan reject it', async () => {
|
|
161
|
+
const sources = [
|
|
162
|
+
['segment config it would not read', 'export default function Page() { return null }\nconst revalidate = 60\nexport { revalidate }\n', ':3: segment config export \\"revalidate\\"'],
|
|
163
|
+
['source that does not parse', 'export default function Page( { return null\n', ':1: the template does not parse'],
|
|
164
|
+
]
|
|
165
|
+
const wrong = []
|
|
166
|
+
for (const [label, source, problem] of sources) {
|
|
167
|
+
const root = await createProject()
|
|
168
|
+
try {
|
|
169
|
+
await mkdir(join(root, 'contents/themes/acme/templates', FORGED), { recursive: true })
|
|
170
|
+
await writeFile(join(root, 'contents/themes/acme/templates', FORGED, 'page.tsx'), source)
|
|
171
|
+
|
|
172
|
+
const build = run('registry.mjs', root, ['--verbose'])
|
|
173
|
+
const plan = run('templates-plan.mjs', root)
|
|
174
|
+
|
|
175
|
+
wrong.push(...wrongLines(`${label}, build`, build.lines), ...wrongLines(`${label}, plan`, plan.lines))
|
|
176
|
+
const named = `${join(root, 'contents/themes/acme/templates')}/${SHOWN}/page.tsx${problem}`
|
|
177
|
+
if (!build.lines.some(line => line.startsWith(`"❌ Build failed: ${named}`))) wrong.push(`${label}, build: the failure does not name the template escaped`)
|
|
178
|
+
if (!plan.lines.some(line => line.startsWith(`"${named}`))) wrong.push(`${label}, plan: the failure does not name the template escaped`)
|
|
179
|
+
if (build.status !== 1 || plan.status !== 1) wrong.push(`${label}: build exited ${build.status} and plan ${plan.status}`)
|
|
180
|
+
} finally {
|
|
181
|
+
await rm(root, { recursive: true, force: true })
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
assert.deepEqual(wrong, [])
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test("a project whose own path holds characters that break or reorder a line starts no line of its own in what the build prints, built or refused for its environment", async () => {
|
|
188
|
+
const parent = await mkdtemp(join(tmpdir(), 'nextspark-build-output-test-'))
|
|
189
|
+
try {
|
|
190
|
+
const root = await createProject(parent, `${FORGED}-`)
|
|
191
|
+
await mkdir(join(root, 'contents/themes/acme/templates/pricing'), { recursive: true })
|
|
192
|
+
await writeFile(join(root, 'contents/themes/acme/templates/pricing/page.tsx'), 'export default function Page() { return null }\n')
|
|
193
|
+
|
|
194
|
+
const built = run('registry.mjs', root, ['--verbose'])
|
|
195
|
+
const wrong = wrongLines('built', built.lines, 1)
|
|
196
|
+
if (built.status !== 0) wrong.push(`built: exited ${built.status}`)
|
|
197
|
+
if (!built.lines.some(line => line.startsWith('"[dotenv@') && line.includes(SHOWN))) wrong.push("built: dotenv's line does not name the project escaped")
|
|
198
|
+
|
|
199
|
+
const bare = await mkdtemp(join(parent, `${FORGED}-bare-`))
|
|
200
|
+
const refused = run('registry.mjs', bare, [], { NEXT_PUBLIC_ACTIVE_THEME: '' })
|
|
201
|
+
wrong.push(...wrongLines('refused', refused.lines))
|
|
202
|
+
if (refused.status !== 1) wrong.push(`refused: exited ${refused.status}`)
|
|
203
|
+
if (!refused.lines.some(line => line.includes('Create a .env file in your project root: ') && line.includes(SHOWN))) wrong.push('refused: the fix does not name the project escaped')
|
|
204
|
+
|
|
205
|
+
assert.deepEqual(wrong, [])
|
|
206
|
+
} finally {
|
|
207
|
+
await rm(parent, { recursive: true, force: true })
|
|
208
|
+
}
|
|
209
|
+
})
|