@nextsparkjs/core 0.1.0-beta.193 → 0.1.0-beta.195
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/README.md +2 -2
- package/dist/components/app/guards/DeveloperGuard.d.ts +8 -1
- package/dist/components/app/guards/DeveloperGuard.d.ts.map +1 -1
- package/dist/components/app/guards/DeveloperGuard.js +2 -1
- package/dist/components/app/guards/SuperAdminGuard.d.ts +8 -1
- package/dist/components/app/guards/SuperAdminGuard.d.ts.map +1 -1
- package/dist/components/app/guards/SuperAdminGuard.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 +39 -23
- 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/AuthGuard.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/AuthGuard.js +3 -4
- package/dist/components/dashboard/layouts/AuthenticatedDashboardLayout.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/AuthenticatedDashboardLayout.js +9 -10
- package/dist/components/dashboard/layouts/DashboardAuthLayout.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/DashboardAuthLayout.js +3 -4
- package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts +2 -2
- package/dist/components/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -2
- package/dist/components/entities/wrappers/EntityFormWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityFormWrapper.js +5 -2
- package/dist/components/entities/wrappers/EntityListWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityListWrapper.js +5 -2
- package/dist/components/ui/relation-display.d.ts.map +1 -1
- package/dist/components/ui/relation-display.js +2 -1
- package/dist/components/ui/user-display.d.ts.map +1 -1
- package/dist/components/ui/user-display.js +2 -1
- package/dist/emails/otp-verification.d.ts.map +1 -1
- package/dist/emails/otp-verification.js +5 -3
- package/dist/emails/reset-password.d.ts.map +1 -1
- package/dist/emails/reset-password.js +5 -3
- package/dist/emails/team-invitation.d.ts.map +1 -1
- package/dist/emails/team-invitation.js +3 -2
- package/dist/emails/verify-email.d.ts.map +1 -1
- package/dist/emails/verify-email.js +5 -3
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +21 -4
- package/dist/hooks/usePatternUsages.d.ts.map +1 -1
- package/dist/hooks/usePatternUsages.js +3 -2
- package/dist/lib/api/auth/permissions.d.ts +10 -0
- package/dist/lib/api/auth/permissions.d.ts.map +1 -1
- package/dist/lib/api/auth/permissions.js +7 -0
- package/dist/lib/api/auth.d.ts +2 -0
- package/dist/lib/api/auth.d.ts.map +1 -1
- package/dist/lib/api/auth.js +10 -10
- package/dist/lib/api/client-headers.d.ts +11 -0
- package/dist/lib/api/client-headers.d.ts.map +1 -0
- package/dist/lib/api/client-headers.js +12 -0
- package/dist/lib/api/client-ip.d.ts +59 -0
- package/dist/lib/api/client-ip.d.ts.map +1 -0
- package/dist/lib/api/client-ip.js +91 -0
- package/dist/lib/api/cors-response.d.ts +54 -0
- package/dist/lib/api/cors-response.d.ts.map +1 -0
- package/dist/lib/api/cors-response.js +88 -0
- package/dist/lib/api/entities.d.ts.map +1 -1
- package/dist/lib/api/entities.js +4 -3
- package/dist/lib/api/entity/audit-log.d.ts.map +1 -1
- package/dist/lib/api/entity/audit-log.js +2 -1
- package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
- package/dist/lib/api/entity/generic-handler.js +23 -5
- package/dist/lib/api/helpers.d.ts +8 -2
- package/dist/lib/api/helpers.d.ts.map +1 -1
- package/dist/lib/api/helpers.js +27 -81
- package/dist/lib/api/keys.d.ts +6 -0
- package/dist/lib/api/keys.d.ts.map +1 -1
- package/dist/lib/api/keys.js +7 -1
- package/dist/lib/api/rate-limit.d.ts +4 -0
- package/dist/lib/api/rate-limit.d.ts.map +1 -1
- package/dist/lib/api/rate-limit.js +17 -38
- package/dist/lib/api/request-origin.d.ts +35 -0
- package/dist/lib/api/request-origin.d.ts.map +1 -0
- package/dist/lib/api/request-origin.js +69 -0
- package/dist/lib/auth/load-login-page.d.ts +10 -0
- package/dist/lib/auth/load-login-page.d.ts.map +1 -0
- package/dist/lib/auth/load-login-page.js +7 -0
- package/dist/lib/auth/runtime-readiness.d.ts.map +1 -1
- package/dist/lib/auth/runtime-readiness.js +2 -0
- package/dist/lib/auth/security-notifications/device-fingerprint.d.ts +1 -8
- package/dist/lib/auth/security-notifications/device-fingerprint.d.ts.map +1 -1
- package/dist/lib/auth/security-notifications/device-fingerprint.js +2 -12
- package/dist/lib/auth-email-callbacks.js +3 -3
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +15 -14
- package/dist/lib/config/config-client.d.ts.map +1 -1
- package/dist/lib/config/config-client.js +1 -1
- package/dist/lib/config/config-sync.d.ts.map +1 -1
- package/dist/lib/config/config-sync.js +1 -1
- package/dist/lib/config/public-config-client.d.ts +1 -0
- package/dist/lib/config/public-config-client.d.ts.map +1 -1
- package/dist/lib/config/public-config-client.js +3 -1
- package/dist/lib/config/types.d.ts +2 -0
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/constants/reserved-slugs.d.ts +17 -8
- package/dist/lib/constants/reserved-slugs.d.ts.map +1 -1
- package/dist/lib/constants/reserved-slugs.js +16 -52
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +9 -3
- package/dist/lib/entities/external-api-generator.d.ts.map +1 -1
- package/dist/lib/entities/external-api-generator.js +5 -5
- package/dist/lib/entities/public-slug.d.ts +46 -0
- package/dist/lib/entities/public-slug.d.ts.map +1 -0
- package/dist/lib/entities/public-slug.js +39 -0
- package/dist/lib/services/subscription.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.js +3 -0
- package/dist/lib/utils/cors.d.ts +7 -0
- package/dist/lib/utils/cors.d.ts.map +1 -1
- package/dist/lib/utils/cors.js +8 -0
- package/dist/routes/(auth)/signup/page.cc.d.ts +3 -8
- package/dist/routes/(auth)/signup/page.cc.d.ts.map +1 -1
- package/dist/routes/(auth)/signup/page.cc.js +7 -1
- package/dist/routes/(auth)/verify-email/page.d.ts.map +1 -1
- package/dist/routes/(auth)/verify-email/page.js +2 -1
- package/dist/routes/(public)/page.cc.d.ts +3 -0
- package/dist/routes/(public)/page.cc.d.ts.map +1 -0
- package/dist/routes/(public)/page.cc.js +3 -0
- package/dist/routes/_internal/area-access.cc.d.ts +21 -0
- package/dist/routes/_internal/area-access.cc.d.ts.map +1 -0
- package/dist/routes/_internal/area-access.cc.js +19 -0
- package/dist/routes/_internal/auth-layout.d.ts.map +1 -1
- package/dist/routes/_internal/auth-layout.js +3 -2
- package/dist/routes/_internal/dashboard-main-shared.d.ts +7 -0
- package/dist/routes/_internal/dashboard-main-shared.d.ts.map +1 -0
- package/dist/routes/_internal/dashboard-main-shared.js +49 -0
- package/dist/routes/_internal/default-auth-layout.d.ts.map +1 -1
- package/dist/routes/_internal/default-auth-layout.js +3 -2
- package/dist/routes/_internal/devtools-layout.cc.d.ts +3 -2
- package/dist/routes/_internal/devtools-layout.cc.d.ts.map +1 -1
- package/dist/routes/_internal/devtools-layout.cc.js +1 -1
- package/dist/routes/_internal/devtools-layout.d.ts +7 -2
- package/dist/routes/_internal/devtools-layout.d.ts.map +1 -1
- package/dist/routes/_internal/devtools-layout.js +4 -4
- package/dist/routes/_internal/entity-detail-route.cc.d.ts +8 -0
- package/dist/routes/_internal/entity-detail-route.cc.d.ts.map +1 -0
- package/dist/routes/_internal/entity-detail-route.cc.js +5 -0
- package/dist/routes/_internal/entity-edit-route.cc.d.ts +8 -0
- package/dist/routes/_internal/entity-edit-route.cc.d.ts.map +1 -0
- package/dist/routes/_internal/entity-edit-route.cc.js +5 -0
- package/dist/routes/_internal/public-archive-route.d.ts +1 -1
- package/dist/routes/_internal/public-archive-route.d.ts.map +1 -1
- package/dist/routes/_internal/public-archive-route.js +8 -3
- package/dist/routes/_internal/public-item-route.cc.d.ts +5 -1
- package/dist/routes/_internal/public-item-route.cc.d.ts.map +1 -1
- package/dist/routes/_internal/public-item-route.cc.js +2 -1
- package/dist/routes/_internal/public-item-route.d.ts +7 -0
- package/dist/routes/_internal/public-item-route.d.ts.map +1 -1
- package/dist/routes/_internal/public-item-route.js +6 -1
- package/dist/routes/_internal/superadmin-layout.cc.d.ts +2 -1
- package/dist/routes/_internal/superadmin-layout.cc.d.ts.map +1 -1
- package/dist/routes/_internal/superadmin-layout.cc.js +1 -1
- package/dist/routes/_internal/superadmin-layout.d.ts +7 -2
- package/dist/routes/_internal/superadmin-layout.d.ts.map +1 -1
- package/dist/routes/_internal/superadmin-layout.js +6 -6
- package/dist/routes/_internal/suspended-route.d.ts +16 -0
- package/dist/routes/_internal/suspended-route.d.ts.map +1 -0
- package/dist/routes/_internal/suspended-route.js +7 -0
- package/dist/routes/api/auth/[...all]/route.d.ts.map +1 -1
- package/dist/routes/api/auth/[...all]/route.js +4 -12
- package/dist/routes/api/csp-report/route.d.ts.map +1 -1
- package/dist/routes/api/csp-report/route.js +2 -13
- package/dist/routes/api/devtools/config/entities/route.d.ts +2 -0
- package/dist/routes/api/devtools/config/entities/route.d.ts.map +1 -1
- package/dist/routes/api/devtools/config/entities/route.js +2 -0
- package/dist/routes/api/devtools/config/theme/route.d.ts +2 -0
- package/dist/routes/api/devtools/config/theme/route.d.ts.map +1 -1
- package/dist/routes/api/devtools/config/theme/route.js +2 -0
- package/dist/routes/api/devtools/tests/[...path]/route.d.ts +2 -0
- package/dist/routes/api/devtools/tests/[...path]/route.d.ts.map +1 -1
- package/dist/routes/api/devtools/tests/[...path]/route.js +2 -0
- package/dist/routes/api/devtools/tests/route.d.ts +2 -0
- package/dist/routes/api/devtools/tests/route.d.ts.map +1 -1
- package/dist/routes/api/devtools/tests/route.js +2 -0
- package/dist/routes/api/health/route.d.ts +2 -0
- package/dist/routes/api/health/route.d.ts.map +1 -1
- package/dist/routes/api/health/route.js +2 -0
- package/dist/routes/api/internal/user-metadata/route.d.ts +2 -0
- package/dist/routes/api/internal/user-metadata/route.d.ts.map +1 -1
- package/dist/routes/api/internal/user-metadata/route.js +2 -0
- package/dist/routes/api/mcp/route.d.ts +2 -0
- package/dist/routes/api/mcp/route.d.ts.map +1 -1
- package/dist/routes/api/mcp/route.js +2 -0
- package/dist/routes/api/superadmin/subscriptions/route.d.ts +2 -0
- package/dist/routes/api/superadmin/subscriptions/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/subscriptions/route.js +2 -0
- package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts +2 -0
- package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/teams/[teamId]/route.js +2 -0
- package/dist/routes/api/superadmin/teams/route.d.ts +2 -0
- package/dist/routes/api/superadmin/teams/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/teams/route.js +2 -0
- package/dist/routes/api/superadmin/users/[userId]/route.d.ts +2 -0
- package/dist/routes/api/superadmin/users/[userId]/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/users/[userId]/route.js +2 -0
- package/dist/routes/api/superadmin/users/route.d.ts +2 -0
- package/dist/routes/api/superadmin/users/route.d.ts.map +1 -1
- package/dist/routes/api/superadmin/users/route.js +2 -0
- package/dist/routes/api/user/delete-account/route.d.ts +2 -0
- package/dist/routes/api/user/delete-account/route.d.ts.map +1 -1
- package/dist/routes/api/user/delete-account/route.js +2 -0
- package/dist/routes/api/user/plan-flags/route.d.ts +2 -0
- package/dist/routes/api/user/plan-flags/route.d.ts.map +1 -1
- package/dist/routes/api/user/plan-flags/route.js +2 -0
- package/dist/routes/api/user/profile/route.d.ts +2 -0
- package/dist/routes/api/user/profile/route.d.ts.map +1 -1
- package/dist/routes/api/user/profile/route.js +4 -3
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts +2 -0
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.js +2 -0
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts +2 -0
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.js +2 -0
- package/dist/routes/api/v1/billing/cancel/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/cancel/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/cancel/route.js +2 -0
- package/dist/routes/api/v1/billing/change-plan/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/change-plan/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/change-plan/route.js +2 -0
- package/dist/routes/api/v1/billing/check-action/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/check-action/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/check-action/route.js +2 -0
- package/dist/routes/api/v1/billing/checkout/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/checkout/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/checkout/route.js +2 -0
- package/dist/routes/api/v1/billing/plans/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/plans/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/plans/route.js +2 -0
- package/dist/routes/api/v1/billing/portal/route.d.ts +2 -0
- package/dist/routes/api/v1/billing/portal/route.d.ts.map +1 -1
- package/dist/routes/api/v1/billing/portal/route.js +2 -0
- package/dist/routes/api/v1/blocks/[slug]/route.d.ts +2 -0
- package/dist/routes/api/v1/blocks/[slug]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/blocks/[slug]/route.js +2 -0
- package/dist/routes/api/v1/blocks/route.d.ts +2 -0
- package/dist/routes/api/v1/blocks/route.d.ts.map +1 -1
- package/dist/routes/api/v1/blocks/route.js +2 -0
- package/dist/routes/api/v1/blocks/validate/route.d.ts +2 -0
- package/dist/routes/api/v1/blocks/validate/route.d.ts.map +1 -1
- package/dist/routes/api/v1/blocks/validate/route.js +2 -0
- package/dist/routes/api/v1/devtools/blocks/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/blocks/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/blocks/route.js +2 -9
- package/dist/routes/api/v1/devtools/docs/route.d.ts +2 -0
- package/dist/routes/api/v1/devtools/docs/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/docs/route.js +2 -0
- package/dist/routes/api/v1/devtools/features/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/features/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/features/route.js +2 -9
- package/dist/routes/api/v1/devtools/flows/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/flows/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/flows/route.js +2 -9
- package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/scheduled-actions/route.js +2 -9
- package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/scheduled-actions/run/route.js +2 -9
- package/dist/routes/api/v1/devtools/testing/route.d.ts +2 -1
- package/dist/routes/api/v1/devtools/testing/route.d.ts.map +1 -1
- package/dist/routes/api/v1/devtools/testing/route.js +2 -9
- package/dist/routes/api/v1/media/[id]/route.d.ts +2 -0
- package/dist/routes/api/v1/media/[id]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media/[id]/route.js +2 -0
- package/dist/routes/api/v1/media/[id]/tags/route.d.ts +2 -0
- package/dist/routes/api/v1/media/[id]/tags/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media/[id]/tags/route.js +2 -0
- package/dist/routes/api/v1/media/check-duplicates/route.d.ts +2 -0
- package/dist/routes/api/v1/media/check-duplicates/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media/check-duplicates/route.js +2 -0
- package/dist/routes/api/v1/media/route.d.ts +2 -0
- package/dist/routes/api/v1/media/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media/route.js +2 -0
- package/dist/routes/api/v1/media/upload/route.d.ts +2 -0
- package/dist/routes/api/v1/media/upload/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media/upload/route.js +2 -0
- package/dist/routes/api/v1/media-tags/route.d.ts +2 -0
- package/dist/routes/api/v1/media-tags/route.d.ts.map +1 -1
- package/dist/routes/api/v1/media-tags/route.js +2 -0
- package/dist/routes/api/v1/post-categories/[id]/route.d.ts +2 -0
- package/dist/routes/api/v1/post-categories/[id]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/post-categories/[id]/route.js +2 -0
- package/dist/routes/api/v1/post-categories/route.d.ts +2 -0
- package/dist/routes/api/v1/post-categories/route.d.ts.map +1 -1
- package/dist/routes/api/v1/post-categories/route.js +2 -0
- package/dist/routes/api/v1/teams/[teamId]/members/route.js +2 -2
- package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts +2 -0
- package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts.map +1 -1
- package/dist/routes/api/v1/teams/[teamId]/subscription/route.js +2 -0
- package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts +2 -0
- package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.js +2 -0
- package/dist/routes/api/v1/users/[id]/meta/[key]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/users/[id]/meta/[key]/route.js +13 -0
- package/dist/routes/api/v1/users/[id]/route.d.ts.map +1 -1
- package/dist/routes/api/v1/users/[id]/route.js +20 -2
- package/dist/routes/api/v1/users/docs.md +34 -19
- package/dist/routes/api/v1/users/me/route.d.ts +6 -0
- package/dist/routes/api/v1/users/me/route.d.ts.map +1 -0
- package/dist/routes/api/v1/users/me/route.js +5 -0
- package/dist/routes/api/v1/users/presets.ts +2 -2
- package/dist/routes/dashboard/(main)/layout.cc.d.ts +4 -0
- package/dist/routes/dashboard/(main)/layout.cc.d.ts.map +1 -0
- package/dist/routes/dashboard/(main)/layout.cc.js +10 -0
- package/dist/routes/dashboard/(main)/layout.d.ts.map +1 -1
- package/dist/routes/dashboard/(main)/layout.js +3 -44
- package/dist/routes/dashboard/permission-denied/page.d.ts +1 -1
- package/dist/routes/dashboard/permission-denied/page.d.ts.map +1 -1
- package/dist/routes/dashboard/permission-denied/page.js +5 -1
- package/dist/routes/devtools/layout.cc.d.ts.map +1 -1
- package/dist/routes/devtools/layout.cc.js +5 -1
- package/dist/routes/manifest.json +10 -0
- package/dist/routes/robots.d.ts +10 -0
- package/dist/routes/robots.d.ts.map +1 -0
- package/dist/routes/robots.js +10 -0
- package/dist/routes/superadmin/layout.cc.d.ts.map +1 -1
- package/dist/routes/superadmin/layout.cc.js +5 -1
- package/dist/routes/variants.json +12 -2
- package/dist/templates/next.config.mjs +2 -29
- package/dist/templates/projects/blog/api/authors/[username]/route.ts +3 -0
- package/dist/templates/projects/blog/api/authors/route.ts +3 -0
- package/dist/templates/projects/blog/api/posts/public/route.ts +3 -0
- package/dist/templates/projects/blog/package.json +3 -3
- package/dist/templates/projects/crm/package.json +3 -3
- package/dist/templates/projects/productivity/package.json +3 -3
- package/dist/templates/proxy.ts +12 -1
- package/dist/templates/public/favicon.ico +0 -0
- package/package.json +8 -5
- package/scripts/build/auth-readiness.mjs +4 -0
- package/scripts/build/registry/__tests__/api-docs-colocated.test.mjs +3 -0
- package/scripts/build/registry/__tests__/billing-registry.test.mjs +50 -1
- package/scripts/build/registry/__tests__/block-registry.test.mjs +3 -0
- package/scripts/build/registry/__tests__/build-output.test.mjs +1 -1
- package/scripts/build/registry/__tests__/icons-discovery.test.mjs +3 -0
- package/scripts/build/registry/__tests__/project-mode-root-first.test.mjs +6 -6
- package/scripts/build/registry/__tests__/quiet-console.mjs +17 -0
- package/scripts/build/registry/__tests__/safe-fs.test.mjs +3 -0
- package/scripts/build/registry/__tests__/team-roles.test.mjs +3 -0
- package/scripts/build/registry/__tests__/write-places.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts-wire.test.mjs +1 -1
- package/scripts/build/registry/contracts/__tests__/contracts.test.mjs +1 -1
- package/scripts/build/registry/contracts/render.mjs +3 -3
- package/scripts/build/registry/discovery/permissions.test.mjs +3 -0
- package/scripts/build/registry/discovery/plugin-capabilities.mjs +2 -2
- package/scripts/build/registry/generators/billing-registry.mjs +7 -3
- package/scripts/build/registry/host/README.md +27 -3
- package/scripts/build/registry/host/__tests__/facade-emitter.test.mjs +9 -9
- package/scripts/build/registry/host/__tests__/host-area-access.test.mjs +32 -0
- package/scripts/build/registry/host/__tests__/host-entities.test.mjs +32 -1
- package/scripts/build/registry/host/__tests__/host-mode.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-plan.test.mjs +12 -2
- package/scripts/build/registry/host/__tests__/host-project-composition.test.mjs +1 -1
- package/scripts/build/registry/host/__tests__/host-project.test.mjs +2 -2
- package/scripts/build/registry/host/__tests__/host-robustness.test.mjs +65 -2
- package/scripts/build/registry/host/entity-routes.mjs +9 -3
- package/scripts/build/registry/host/facade-emitter.mjs +2 -2
- package/scripts/build/registry/host/generation.mjs +54 -0
- package/scripts/build/registry/host/next-route-exports.json +2 -2
- package/scripts/build/registry/host/prepare.mjs +3 -0
- package/scripts/build/registry/host/static-imports.mjs +4 -0
- package/scripts/build/routes-manifest.mjs +13 -1
- package/scripts/db/migration-time-limit.mjs +216 -34
- package/scripts/db/run-migrations.mjs +11 -179
- package/scripts/db/ssl-config.mjs +12 -1
- package/scripts/db/verify-theme-migrations.mjs +1 -1
- package/templates/next.config.mjs +2 -29
- package/templates/projects/blog/api/authors/[username]/route.ts +3 -0
- package/templates/projects/blog/api/authors/route.ts +3 -0
- package/templates/projects/blog/api/posts/public/route.ts +3 -0
- package/templates/projects/blog/package.json +3 -3
- package/templates/projects/crm/package.json +3 -3
- package/templates/projects/productivity/package.json +3 -3
- package/templates/proxy.ts +12 -1
- package/templates/public/favicon.ico +0 -0
|
@@ -17,7 +17,7 @@ const PREPARE_CLI = join(CORE_ROOT, 'scripts/build/registry/host/prepare-cli.mjs
|
|
|
17
17
|
function project({ legacyApp = false } = {}) {
|
|
18
18
|
const root = mkdtempSync(join(tmpdir(), 'nextspark-host-mode-'))
|
|
19
19
|
write(root, 'nextspark.config.ts', 'export default { plugins: [] }\n')
|
|
20
|
-
write(root, 'package.json', JSON.stringify({ name: 'host-mode', dependencies: { next: '16.3.
|
|
20
|
+
write(root, 'package.json', JSON.stringify({ name: 'host-mode', dependencies: { next: '16.3.6' } }))
|
|
21
21
|
write(root, 'templates/pricing/page.tsx', PAGE('Pricing'))
|
|
22
22
|
if (legacyApp) write(root, 'src/app/layout.tsx', 'export default function Layout({ children }) { return children }\n')
|
|
23
23
|
return { root, cleanup: () => rmSync(root, { recursive: true, force: true }) }
|
|
@@ -53,6 +53,16 @@ test('core < plugin < project: a higher layer replaces a lower one at the same r
|
|
|
53
53
|
}
|
|
54
54
|
})
|
|
55
55
|
|
|
56
|
+
test('a project robots.ts replaces the robots route core ships (#214)', () => {
|
|
57
|
+
const { root, cleanup } = project({ 'templates/robots.ts': 'export default function robots() { return { rules: { userAgent: "*", disallow: "/" } } }\n' })
|
|
58
|
+
try {
|
|
59
|
+
const routes = resolveHostPlan({ coreRoutes: [core('robots.ts', 'robots')], plugins: [], project: { root } })
|
|
60
|
+
assert.deepEqual(summary(routes), ['robots.ts <- project:@/templates/robots (overrides core route @nextsparkjs/core/routes/robots)'])
|
|
61
|
+
} finally {
|
|
62
|
+
cleanup()
|
|
63
|
+
}
|
|
64
|
+
})
|
|
65
|
+
|
|
56
66
|
test('the extension does not decide the slot: templates/about/page.ts replaces core about/page.tsx', () => {
|
|
57
67
|
const { root, cleanup } = project({ 'templates/about/page.ts': PAGE })
|
|
58
68
|
try {
|
|
@@ -330,8 +340,8 @@ test('core\'s routes carry their protection level, so a composed layout can be t
|
|
|
330
340
|
assert.equal(withCc.routes.find(route => route.target === 'layout.tsx').compose.specifier, '@nextsparkjs/core/routes/_internal/root-layout.ppr')
|
|
331
341
|
assert.equal(withCc.routes.find(route => route.target === '(auth)/login/page.tsx').specifier, '@nextsparkjs/core/routes/(auth)/login/page.cc')
|
|
332
342
|
assert.deepEqual(withCc.variantsApplied.sort(), [
|
|
333
|
-
'(auth)/layout.tsx', '(auth)/login/page.tsx', '(auth)/signup/page.tsx', '(public)/docs/[section]/[page]/page.tsx', '(public)/layout.tsx',
|
|
334
|
-
'dashboard/layout.tsx', 'devtools/layout.tsx', 'layout.tsx', 'superadmin/docs/[section]/[page]/page.tsx', 'superadmin/layout.tsx',
|
|
343
|
+
'(auth)/layout.tsx', '(auth)/login/page.tsx', '(auth)/signup/page.tsx', '(public)/docs/[section]/[page]/page.tsx', '(public)/layout.tsx', '(public)/page.tsx',
|
|
344
|
+
'dashboard/(main)/layout.tsx', 'dashboard/layout.tsx', 'devtools/layout.tsx', 'layout.tsx', 'superadmin/docs/[section]/[page]/page.tsx', 'superadmin/layout.tsx',
|
|
335
345
|
])
|
|
336
346
|
// The layouts that load messages keep their wrapper (from the Cache Components module) and their protection level
|
|
337
347
|
const ccLevel = target => withCc.routes.find(route => route.target === target)
|
|
@@ -36,7 +36,7 @@ const LAYOUT = 'export default function Layout({ children }: { children: React.R
|
|
|
36
36
|
function project(extra = {}) {
|
|
37
37
|
const root = mkdtempSync(join(tmpdir(), 'nextspark-host-composition-'))
|
|
38
38
|
write(root, 'nextspark.config.ts', "export default { plugins: [], billing: { webhookExtensions: { stripe: './lib/billing/stripe-webhook-extensions' } } }\n")
|
|
39
|
-
write(root, 'package.json', JSON.stringify({ name: 'composition', dependencies: { next: '16.3.
|
|
39
|
+
write(root, 'package.json', JSON.stringify({ name: 'composition', dependencies: { next: '16.3.6' } }))
|
|
40
40
|
write(root, 'config/theme.config.ts', "export const compositionThemeConfig = { name: 'composition' }\n")
|
|
41
41
|
write(root, 'styles/globals.css', '@import "tailwindcss";\n')
|
|
42
42
|
write(root, 'lib/billing/stripe-webhook-extensions.ts', 'export const stripeWebhookExtensions = {}\n')
|
|
@@ -16,7 +16,7 @@ const PREPARE_CLI = join(CORE_ROOT, 'scripts/build/registry/host/prepare-cli.mjs
|
|
|
16
16
|
function project() {
|
|
17
17
|
const root = mkdtempSync(join(tmpdir(), 'nextspark-host-project-'))
|
|
18
18
|
write(root, 'nextspark.config.ts', 'export default { plugins: [] }\n')
|
|
19
|
-
write(root, 'package.json', JSON.stringify({ name: 'host-project', dependencies: { next: '16.3.
|
|
19
|
+
write(root, 'package.json', JSON.stringify({ name: 'host-project', dependencies: { next: '16.3.6' } }))
|
|
20
20
|
write(root, 'templates/pricing/page.tsx', PAGE('Pricing'))
|
|
21
21
|
write(root, 'api/ping/route.ts', ROUTE)
|
|
22
22
|
return { root, cleanup: () => rmSync(root, { recursive: true, force: true }) }
|
|
@@ -41,7 +41,7 @@ test('a real project: the registry build is staged and published with the host,
|
|
|
41
41
|
|
|
42
42
|
const record = readGeneration(root)
|
|
43
43
|
assert.equal(Object.keys(record.files).length, first.files.length)
|
|
44
|
-
assert.ok(record.versions.core && record.versions.next === '16.3.
|
|
44
|
+
assert.ok(record.versions.core && record.versions.next === '16.3.6')
|
|
45
45
|
assert.ok(record.inputs.files['nextspark.config.ts'] && record.inputs.files['templates/pricing/page.tsx'])
|
|
46
46
|
assert.deepEqual(await checkHost(config), { ok: true, problems: [] })
|
|
47
47
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { test } from 'node:test'
|
|
2
2
|
import assert from 'node:assert/strict'
|
|
3
3
|
import { spawn } from 'node:child_process'
|
|
4
|
-
import { existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
4
|
+
import { chmodSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
5
5
|
import { hostname, tmpdir } from 'node:os'
|
|
6
6
|
import { join } from 'node:path'
|
|
7
7
|
|
|
@@ -139,6 +139,69 @@ test('crash mid-publish (SIGKILL): --check reports the host as not fresh, and th
|
|
|
139
139
|
}
|
|
140
140
|
})
|
|
141
141
|
|
|
142
|
+
test('what a killed writer leaves (temporary files, a staging directory) is swept by the next prepare instead of blocking it or piling up', async () => {
|
|
143
|
+
const host = tempHost({ 'templates/about/page.tsx': PAGE('About') })
|
|
144
|
+
try {
|
|
145
|
+
const config = hostConfig(host.root)
|
|
146
|
+
await prepareHost(config, { mode: 'production' })
|
|
147
|
+
const leftovers = [
|
|
148
|
+
'src/app/(public)/.page.tsx.4242.0a1b2c3d.nextspark-tmp',
|
|
149
|
+
'.nextspark/registries/.example.ts.4242.0a1b2c3d.nextspark-tmp',
|
|
150
|
+
'.nextspark/contracts/index.ts.nextspark-tmp',
|
|
151
|
+
'.nextspark/staging-AbC123/registries/example.ts',
|
|
152
|
+
]
|
|
153
|
+
const kept = ['.nextspark/my-notes.txt', '.nextspark/staging-notes/keep.txt']
|
|
154
|
+
for (const path of [...leftovers, ...kept]) write(host.hostRoot, path, 'x\n')
|
|
155
|
+
|
|
156
|
+
// A temporary file in src/app used to read as "a file NextSpark did not generate": prepare refused to run
|
|
157
|
+
const published = await prepareHost(config, { mode: 'production' })
|
|
158
|
+
assert.deepEqual(published.written, [])
|
|
159
|
+
for (const path of leftovers) assert.equal(existsSync(join(host.hostRoot, path)), false, `${path} is swept`)
|
|
160
|
+
assert.equal(existsSync(join(host.hostRoot, '.nextspark/staging-AbC123')), false)
|
|
161
|
+
// Only the writers' own names go: anything else is the user's
|
|
162
|
+
for (const path of kept) assert.equal(existsSync(join(host.hostRoot, path)), true, `${path} stays`)
|
|
163
|
+
write(host.hostRoot, 'src/app/(public)/page.tsx.nextspark-tmp', 'x\n')
|
|
164
|
+
await assert.rejects(() => prepareHost(config, { mode: 'production' }), error => error instanceof PrepareError && codes(error).includes(GENERATION_DIAGNOSTICS.FOREIGN))
|
|
165
|
+
assert.equal(existsSync(join(host.hostRoot, 'src/app/(public)/page.tsx.nextspark-tmp')), true)
|
|
166
|
+
} finally {
|
|
167
|
+
host.cleanup()
|
|
168
|
+
}
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
test('a scratch registry file a killed writer left is swept and the next prepare completes', async () => {
|
|
172
|
+
const host = tempHost({ 'templates/about/page.tsx': PAGE('About') })
|
|
173
|
+
try {
|
|
174
|
+
const config = hostConfig(host.root, { registries: manyRegistries(20, 'old') })
|
|
175
|
+
await prepareHost(config, { mode: 'production' })
|
|
176
|
+
const scratch = '.nextspark/registries/.r00003.ts.4242.0a1b2c3d.nextspark-tmp'
|
|
177
|
+
write(host.hostRoot, scratch, 'half written')
|
|
178
|
+
const fresh = hostConfig(host.root, { registries: manyRegistries(20, 'new') })
|
|
179
|
+
await prepareHost(fresh, { mode: 'production' })
|
|
180
|
+
assert.equal(existsSync(join(host.hostRoot, scratch)), false)
|
|
181
|
+
assert.deepEqual(await checkHost(fresh), { ok: true, problems: [] })
|
|
182
|
+
} finally {
|
|
183
|
+
host.cleanup()
|
|
184
|
+
}
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
test('the sweep never enters backups or migrate-rollback, and an unreadable directory under .nextspark does not crash prepare', async () => {
|
|
188
|
+
const host = tempHost({ 'templates/about/page.tsx': PAGE('About') })
|
|
189
|
+
const locked = join(host.hostRoot, '.nextspark/unreadable')
|
|
190
|
+
try {
|
|
191
|
+
const config = hostConfig(host.root)
|
|
192
|
+
await prepareHost(config, { mode: 'production' })
|
|
193
|
+
const kept = ['.nextspark/backups/20260101/src/app/.page.tsx.1.0a1b2c3d.nextspark-tmp', '.nextspark/backups/20260101/x.nextspark-tmp', '.nextspark/migrate-rollback/y.nextspark-tmp']
|
|
194
|
+
for (const path of kept) write(host.hostRoot, path, 'x\n')
|
|
195
|
+
write(host.hostRoot, '.nextspark/unreadable/z.nextspark-tmp', 'x\n')
|
|
196
|
+
if (process.getuid?.() !== 0) chmodSync(locked, 0)
|
|
197
|
+
await prepareHost(config, { mode: 'production' })
|
|
198
|
+
for (const path of kept) assert.equal(existsSync(join(host.hostRoot, path)), true, `${path} stays`)
|
|
199
|
+
} finally {
|
|
200
|
+
try { chmodSync(locked, 0o755) } catch {}
|
|
201
|
+
host.cleanup()
|
|
202
|
+
}
|
|
203
|
+
})
|
|
204
|
+
|
|
142
205
|
test('registries: a file in place of a generated registry is adopted only when a NextSpark registry build wrote it', async () => {
|
|
143
206
|
const cases = [
|
|
144
207
|
['byte-identical', REGISTRY, 'adopted'],
|
|
@@ -251,7 +314,7 @@ test('an npm-installed core ships only dist/: the manifest, variants and route m
|
|
|
251
314
|
test('the project config is read again for every generation: enabling a plugin in nextspark.config.ts adds its routes', async () => {
|
|
252
315
|
const root = mkdtempSync(join(tmpdir(), 'nextspark-config-reload-'))
|
|
253
316
|
try {
|
|
254
|
-
write(root, 'package.json', JSON.stringify({ name: 'reload', dependencies: { next: '16.3.
|
|
317
|
+
write(root, 'package.json', JSON.stringify({ name: 'reload', dependencies: { next: '16.3.6' } }))
|
|
255
318
|
write(root, 'nextspark.config.ts', 'export default { plugins: [] }\n')
|
|
256
319
|
write(root, 'plugins/search/plugin.config.ts', 'export const searchPluginConfig = {}\n')
|
|
257
320
|
write(root, 'plugins/search/templates/search/page.tsx', PAGE('Search'))
|
|
@@ -54,6 +54,9 @@ export const ENTITY_MODULES = Object.freeze({
|
|
|
54
54
|
detail: `${CORE_ROUTES_SPECIFIER}_internal/entity-detail-route`,
|
|
55
55
|
create: `${CORE_ROUTES_SPECIFIER}_internal/entity-create-route`,
|
|
56
56
|
edit: `${CORE_ROUTES_SPECIFIER}_internal/entity-edit-route`,
|
|
57
|
+
// The detail and edit pages of a host with `cacheComponents` on: the same routes behind a Suspense boundary (they await `params`).
|
|
58
|
+
detailCc: `${CORE_ROUTES_SPECIFIER}_internal/entity-detail-route.cc`,
|
|
59
|
+
editCc: `${CORE_ROUTES_SPECIFIER}_internal/entity-edit-route.cc`,
|
|
57
60
|
publicItem: `${CORE_ROUTES_SPECIFIER}_internal/public-item-route`,
|
|
58
61
|
// The item pages of a host with `cacheComponents` on: same factories, `'use cache'` reads instead of `revalidate`.
|
|
59
62
|
publicItemCc: `${CORE_ROUTES_SPECIFIER}_internal/public-item-route.cc`,
|
|
@@ -207,7 +210,10 @@ export function planEntityRoutes({ entities, facts, coreRoutes, resolveFile, cac
|
|
|
207
210
|
const revalidates = cacheComponents !== true && !modes.includes('cc')
|
|
208
211
|
// A host that builds in Cache Components mode only gets the cached item source; one that builds both (the
|
|
209
212
|
// conformance fixture) or does not know keeps the module that works in either.
|
|
210
|
-
const
|
|
213
|
+
const ccOnly = cacheComponents === true && modes.length === 0
|
|
214
|
+
const publicItemModule = ccOnly && modules.publicItemCc ? modules.publicItemCc : modules.publicItem
|
|
215
|
+
const detailModule = ccOnly && modules.detailCc ? modules.detailCc : modules.detail
|
|
216
|
+
const editModule = ccOnly && modules.editCc ? modules.editCc : modules.edit
|
|
211
217
|
|
|
212
218
|
const coreFacade = (kind, target, specifier) => ({
|
|
213
219
|
kind,
|
|
@@ -275,8 +281,8 @@ export function planEntityRoutes({ entities, facts, coreRoutes, resolveFile, cac
|
|
|
275
281
|
coreFacade('loading', `${base}/loading.tsx`, modules.loading),
|
|
276
282
|
composed('page', `${base}/page.tsx`, 'createEntityListRoute', modules.list, [config, arg.template()], { acceptsTemplate: true, reexport: [{ names: ['metadata'], specifier: modules.listMetadata }] }),
|
|
277
283
|
composed('page', `${base}/create/page.tsx`, 'createEntityCreateRoute', modules.create, [config, arg.template()], { acceptsTemplate: true }),
|
|
278
|
-
composed('page', `${base}/[id]/page.tsx`, 'createEntityDetailRoute',
|
|
279
|
-
composed('page', `${base}/[id]/edit/page.tsx`, 'createEntityEditRoute',
|
|
284
|
+
composed('page', `${base}/[id]/page.tsx`, 'createEntityDetailRoute', detailModule, [config, arg.literal(children), arg.template()], { acceptsTemplate: true, reexport: [{ names: ['metadata'], specifier: modules.detailMetadata }] }),
|
|
285
|
+
composed('page', `${base}/[id]/edit/page.tsx`, 'createEntityEditRoute', editModule, [config, arg.template()], { acceptsTemplate: true })
|
|
280
286
|
)
|
|
281
287
|
}
|
|
282
288
|
|
|
@@ -284,8 +284,8 @@ export function resolveNextPackage(projectRoot = process.cwd()) {
|
|
|
284
284
|
/**
|
|
285
285
|
* Whether `version` is a Next.js the table applies to: the table's `next` is the verified
|
|
286
286
|
* baseline, and core pins `next` to `~<baseline>`, so any stable patch of the same minor at or
|
|
287
|
-
* above the baseline is accepted (16.3.
|
|
288
|
-
* patches and prereleases (16.3.
|
|
287
|
+
* above the baseline is accepted (16.3.6, 16.3.9, 16.3.6+build.1), while other minors/majors, lower
|
|
288
|
+
* patches and prereleases (16.3.7-canary.0) are refused.
|
|
289
289
|
*/
|
|
290
290
|
export function isSupportedNextVersion(version, baseline = ROUTE_EXPORT_TABLE.next) {
|
|
291
291
|
// Stable versions only; build metadata (`+build.1`) is allowed, as npm's `~` range allows it.
|
|
@@ -438,6 +438,60 @@ export function acquireLock(hostRoot, { staleAfterMs = DEFAULT_STALE_LOCK_MS, at
|
|
|
438
438
|
throw lockedError(path)
|
|
439
439
|
}
|
|
440
440
|
|
|
441
|
+
// ---------------------------------------------------------------------------
|
|
442
|
+
// What a killed writer leaves behind
|
|
443
|
+
// ---------------------------------------------------------------------------
|
|
444
|
+
|
|
445
|
+
// The names of the scratch files and directories the writers create: `writeAtomically` (below),
|
|
446
|
+
// the contracts publisher (`<file>.nextspark-tmp`) and the registry build's staging directory
|
|
447
|
+
// (`fs.mkdtempSync('.nextspark/staging-')`).
|
|
448
|
+
const TEMPORARY_FILE = /^\..+\.\d+\.[0-9a-f]{8}\.nextspark-tmp$/
|
|
449
|
+
const CONTRACTS_TEMPORARY_FILE = /\.nextspark-tmp$/
|
|
450
|
+
const STAGING_DIR = /^staging-[A-Za-z0-9]{6}$/
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Remove what a writer that was killed (SIGKILL, power loss) between creating a scratch file and
|
|
454
|
+
* renaming it leaves behind: its temporary files under `src/app` and `.nextspark`, and a registry
|
|
455
|
+
* build's staging directory. Call it with the lock held, when no live writer can own one of them.
|
|
456
|
+
* Without it a temporary file in `src/app` is a file "NextSpark did not generate", so the next
|
|
457
|
+
* prepare refuses to run until someone deletes it by hand, and the others stay forever.
|
|
458
|
+
* Only names the writers use are touched, never through a symlink; returns the paths removed.
|
|
459
|
+
*/
|
|
460
|
+
export function sweepInterruptedWrites(hostRoot, { app = true } = {}) {
|
|
461
|
+
const fs = projectFiles(hostRoot)
|
|
462
|
+
const removed = []
|
|
463
|
+
const entries = dir => {
|
|
464
|
+
try {
|
|
465
|
+
return lstatOrNull(join(hostRoot, dir))?.isDirectory() ? readdirSync(join(hostRoot, dir), { withFileTypes: true }) : []
|
|
466
|
+
} catch {
|
|
467
|
+
return [] // an unreadable directory is skipped: the build reports it
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
const visit = (dir, isTemporary, recursive) => {
|
|
471
|
+
for (const entry of entries(dir)) {
|
|
472
|
+
const path = `${dir}/${entry.name}`
|
|
473
|
+
if (entry.isDirectory()) {
|
|
474
|
+
if (recursive) visit(path, isTemporary, true)
|
|
475
|
+
} else if (entry.isFile() && isTemporary.test(entry.name)) {
|
|
476
|
+
fs.unlinkSync(join(hostRoot, path))
|
|
477
|
+
removed.push(path)
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
// Only the places the writers use; never `.nextspark/backups` or `.nextspark/migrate-rollback`.
|
|
482
|
+
// src/app belongs to the host only when it generates it (prepareContractsOnly leaves it alone).
|
|
483
|
+
if (app) visit(APP_DIR, TEMPORARY_FILE, true)
|
|
484
|
+
visit('.nextspark', TEMPORARY_FILE, false)
|
|
485
|
+
visit(REGISTRIES_DIR, TEMPORARY_FILE, true)
|
|
486
|
+
visit('.nextspark/contracts', CONTRACTS_TEMPORARY_FILE, true)
|
|
487
|
+
for (const entry of entries('.nextspark')) {
|
|
488
|
+
if (!entry.isDirectory() || !STAGING_DIR.test(entry.name)) continue
|
|
489
|
+
fs.rmSync(join(hostRoot, '.nextspark', entry.name), { recursive: true, force: true })
|
|
490
|
+
removed.push(`.nextspark/${entry.name}`)
|
|
491
|
+
}
|
|
492
|
+
return removed
|
|
493
|
+
}
|
|
494
|
+
|
|
441
495
|
// ---------------------------------------------------------------------------
|
|
442
496
|
// Publication
|
|
443
497
|
// ---------------------------------------------------------------------------
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$comment": "Route file kinds x exports x emitted facade form, for the generated host (#203). Source of truth for host/facade-emitter.mjs; README.md renders it. Verified against the installed Next.js source listed in verifiedAgainst and by the probe builds recorded in README.md. Re-verify and bump `next` when upgrading Next.js: host/__tests__/facade-emitter.test.mjs fails when the installed version differs.",
|
|
3
|
-
"next": "16.3.
|
|
4
|
-
"supportedNext": "~16.3.
|
|
3
|
+
"next": "16.3.6",
|
|
4
|
+
"supportedNext": "~16.3.6 (same major.minor, stable patch >= the verified baseline in \"next\"; enforced by isSupportedNextVersion)",
|
|
5
5
|
"verifiedAgainst": [
|
|
6
6
|
"next/dist/build/segment-config/app/app-segment-config.js (AppSegmentConfigSchemaKeys, parseAppSegmentConfig)",
|
|
7
7
|
"next/dist/build/analysis/get-page-static-info.js (checkExports, getAppPageStaticInfo)",
|
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
preflight,
|
|
59
59
|
publishGeneration,
|
|
60
60
|
readGeneration,
|
|
61
|
+
sweepInterruptedWrites,
|
|
61
62
|
validateFiles,
|
|
62
63
|
writeOwnedFile,
|
|
63
64
|
} from './generation.mjs'
|
|
@@ -209,6 +210,7 @@ export async function predictHost(config, { devStatus = false } = {}) {
|
|
|
209
210
|
export async function prepareHost(config, { mode = 'development', devStatus = false, cache, staleAfterMs, reportFailure = false, changed = [] } = {}) {
|
|
210
211
|
const release = acquireLock(config.hostRoot, { staleAfterMs })
|
|
211
212
|
try {
|
|
213
|
+
sweepInterruptedWrites(config.hostRoot)
|
|
212
214
|
return await generateAndPublish(config, { mode, devStatus, cache })
|
|
213
215
|
} catch (error) {
|
|
214
216
|
// `nextspark dev`: the failure goes to the browser under the same lock, so no other writer's
|
|
@@ -283,6 +285,7 @@ export async function prepareContractsOnly(config, { staleAfterMs } = {}) {
|
|
|
283
285
|
if (!config.contracts) throw new PrepareError([{ code: 'NS_CONTRACTS_UNAVAILABLE', message: 'this project has no contracts step' }])
|
|
284
286
|
const release = acquireLock(config.hostRoot, { staleAfterMs })
|
|
285
287
|
try {
|
|
288
|
+
sweepInterruptedWrites(config.hostRoot, { app: false })
|
|
286
289
|
const contracts = await planContractsStep(config)
|
|
287
290
|
return publishContractsStep(config, contracts)
|
|
288
291
|
} catch (error) {
|
|
@@ -80,11 +80,15 @@ export const CORE_COMPOSITION_WRAPPERS = Object.freeze({
|
|
|
80
80
|
[`${INTERNAL}devtools-layout.cc`]: ['withDevtoolsGuard'],
|
|
81
81
|
// Every page and layout under /superadmin and /devtools (the manifest's `access`).
|
|
82
82
|
[`${INTERNAL}area-access`]: ['withSuperadminAccess', 'withDevtoolsAccess', 'withSuperadminMetadata', 'withDevtoolsMetadata', 'withSuperadminRouteAccess', 'withDevtoolsRouteAccess'],
|
|
83
|
+
// The same, for a Cache Components host (each segment checks inside its own Suspense boundary).
|
|
84
|
+
[`${INTERNAL}area-access.cc`]: ['withSuperadminAccess', 'withDevtoolsAccess', 'withSuperadminMetadata', 'withDevtoolsMetadata', 'withSuperadminRouteAccess', 'withDevtoolsRouteAccess'],
|
|
83
85
|
[`${INTERNAL}entity-layout-route`]: ['createEntityLayoutRoute'],
|
|
84
86
|
[`${INTERNAL}entity-list-route`]: ['createEntityListRoute'],
|
|
85
87
|
[`${INTERNAL}entity-detail-route`]: ['createEntityDetailRoute'],
|
|
86
88
|
[`${INTERNAL}entity-create-route`]: ['createEntityCreateRoute'],
|
|
87
89
|
[`${INTERNAL}entity-edit-route`]: ['createEntityEditRoute'],
|
|
90
|
+
[`${INTERNAL}entity-detail-route.cc`]: ['createEntityDetailRoute'],
|
|
91
|
+
[`${INTERNAL}entity-edit-route.cc`]: ['createEntityEditRoute'],
|
|
88
92
|
[`${INTERNAL}public-item-route`]: ['createPublicItemRoute', 'createPublicItemMetadata'],
|
|
89
93
|
[`${INTERNAL}public-item-route.cc`]: ['createPublicItemRoute', 'createPublicItemMetadata'],
|
|
90
94
|
[`${INTERNAL}public-archive-route`]: ['createPublicArchiveRoute', 'createPublicArchiveMetadata'],
|
|
@@ -66,6 +66,8 @@ export const VARIANT_FILES = Object.freeze({
|
|
|
66
66
|
'superadmin/layout.cc.tsx': 'superadmin/layout.tsx',
|
|
67
67
|
'devtools/layout.cc.tsx': 'devtools/layout.tsx',
|
|
68
68
|
'dashboard/layout.cc.tsx': 'dashboard/layout.tsx',
|
|
69
|
+
'dashboard/(main)/layout.cc.tsx': 'dashboard/(main)/layout.tsx',
|
|
70
|
+
'(public)/page.cc.tsx': '(public)/page.tsx',
|
|
69
71
|
'(auth)/login/page.cc.tsx': '(auth)/login/page.tsx',
|
|
70
72
|
'(auth)/signup/page.cc.tsx': '(auth)/signup/page.tsx',
|
|
71
73
|
'(public)/docs/[section]/[page]/page.cc.tsx': '(public)/docs/[section]/[page]/page.tsx',
|
|
@@ -105,6 +107,15 @@ export const VARIANT_COMPOSE = Object.freeze({
|
|
|
105
107
|
'devtools/layout.cc.tsx': { wrapper: 'withDevtoolsGuard', specifier: `${ROUTES_SUBPATH}/_internal/devtools-layout.cc` },
|
|
106
108
|
})
|
|
107
109
|
|
|
110
|
+
/**
|
|
111
|
+
* The per-segment access check of a variant, when it differs from its base route's: in Cache Components mode every
|
|
112
|
+
* page and layout under an area checks the role inside its own Suspense boundary (area-access.cc).
|
|
113
|
+
*/
|
|
114
|
+
export const VARIANT_ACCESS = Object.freeze({
|
|
115
|
+
'superadmin/layout.cc.tsx': { ...ACCESS_ROUTES['superadmin/layout.tsx'], specifier: `${ROUTES_SUBPATH}/_internal/area-access.cc` },
|
|
116
|
+
'devtools/layout.cc.tsx': { ...ACCESS_ROUTES['devtools/layout.tsx'], specifier: `${ROUTES_SUBPATH}/_internal/area-access.cc` },
|
|
117
|
+
})
|
|
118
|
+
|
|
108
119
|
/**
|
|
109
120
|
* Files that live next to a route without being one: the API explorer's presets, read as text by the
|
|
110
121
|
* registry build (registry/discovery/api-presets.mjs), and its docs.md.
|
|
@@ -168,7 +179,8 @@ export function buildRoutesManifest(routesDir = ROUTES_DIR) {
|
|
|
168
179
|
const replaced = manifest.find(entry => entry.target === target)
|
|
169
180
|
if (!replaced) throw new Error(`Variant ${file} (${mode}) replaces ${target}, which is not a core route`)
|
|
170
181
|
const compose = VARIANT_COMPOSE[file] ?? replaced.compose
|
|
171
|
-
|
|
182
|
+
const access = VARIANT_ACCESS[file] ?? replaced.access
|
|
183
|
+
return { kind: replaced.kind, target, specifier: specifierForRouteFile(file), ...(compose ? { compose } : {}), ...(access ? { access } : {}) }
|
|
172
184
|
})
|
|
173
185
|
}
|
|
174
186
|
return { manifest, variants }
|