@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
|
@@ -8,13 +8,28 @@
|
|
|
8
8
|
* Sources are exactly what resolveIcon can be handed, and all of them are
|
|
9
9
|
* source files (never the database):
|
|
10
10
|
* - entity configs (`icon: Users` — an identifier imported from lucide-react)
|
|
11
|
-
* - a theme
|
|
11
|
+
* - any `config/*.config.ts` of a theme or a plugin (`icon: 'Grid'`,
|
|
12
|
+
* `iconName: Users` — sidebar sections, dashboard menus, feature and flow
|
|
13
|
+
* definitions, all of a theme's or plugin's config surface)
|
|
12
14
|
* - block configs (`icon: 'Grid'` — the block's own icon in the editor)
|
|
15
|
+
* - a literal name handed to DynamicIcon's `name` prop or to resolveIcon's
|
|
16
|
+
* first argument in a theme's or plugin's own component code
|
|
13
17
|
*
|
|
14
18
|
* What a block RENDERS is not here: page content names those icons in the page
|
|
15
19
|
* builder, so they live in the database. Those blocks keep resolving through
|
|
16
20
|
* the lucide namespace — deliberately, see themes' features-grid component.
|
|
17
21
|
*
|
|
22
|
+
* A name that is not a string literal — a variable, a prop, a template
|
|
23
|
+
* expression — cannot be resolved while building, so it is left out of the
|
|
24
|
+
* registry rather than guessed; that is the same limit that makes the
|
|
25
|
+
* unresolved-reference warning below necessary for config files.
|
|
26
|
+
*
|
|
27
|
+
* Every source is read as a syntax tree (core's own TypeScript, #195), not as
|
|
28
|
+
* raw text: a name that only exists inside a comment or a docblock is not
|
|
29
|
+
* code the app can run, so it must not reach the registry either. Test files
|
|
30
|
+
* are skipped for the same reason from the other direction — an icon named
|
|
31
|
+
* only inside a test is never rendered in production.
|
|
32
|
+
*
|
|
18
33
|
* @module core/scripts/build/registry/discovery/icons
|
|
19
34
|
*/
|
|
20
35
|
|
|
@@ -24,6 +39,7 @@ import { createRequire } from 'module'
|
|
|
24
39
|
import { join, dirname } from 'path'
|
|
25
40
|
|
|
26
41
|
import { verbose, log } from '../../../utils/index.mjs'
|
|
42
|
+
import { loadTypeScriptFor } from '../shared/typescript-compiler.mjs'
|
|
27
43
|
|
|
28
44
|
/**
|
|
29
45
|
* Icons the resolver falls back to when a name doesn't resolve. They are
|
|
@@ -32,6 +48,15 @@ import { verbose, log } from '../../../utils/index.mjs'
|
|
|
32
48
|
*/
|
|
33
49
|
const FALLBACK_ICONS = ['Box', 'Circle', 'Folder', 'LayoutGrid']
|
|
34
50
|
|
|
51
|
+
/** A bare identifier-shaped name, the only shape the generated registry can
|
|
52
|
+
* safely turn into a named import or a lucide-react lookup key. */
|
|
53
|
+
const SAFE_NAME = /^[A-Za-z][\w$-]*$/
|
|
54
|
+
|
|
55
|
+
/** The property keys a config's icon can be written under — the plain
|
|
56
|
+
* `icon: X` shape and `iconName: X`, the one a theme's sidebar, dashboard,
|
|
57
|
+
* feature and flow configs use. */
|
|
58
|
+
const ICON_KEYS = new Set(['icon', 'iconName'])
|
|
59
|
+
|
|
35
60
|
/**
|
|
36
61
|
* Names lucide-react actually exports, read from its own barrel.
|
|
37
62
|
* A name that isn't there would become a broken named import in the
|
|
@@ -63,6 +88,10 @@ async function readLucideExportNames(config) {
|
|
|
63
88
|
/**
|
|
64
89
|
* Which config files hold icons resolveIcon can be handed. Exported for tests.
|
|
65
90
|
*
|
|
91
|
+
* Every file directly under a `config/` directory and named `*.config.ts`
|
|
92
|
+
* counts, not only `app.config.ts`: a theme's dashboard, features and flows
|
|
93
|
+
* configs name icons by string the same way its app config does.
|
|
94
|
+
*
|
|
66
95
|
* Separators are normalised first: the generator also runs on Windows, where
|
|
67
96
|
* join() produces '\\' and a '/'-shaped match would silently find nothing —
|
|
68
97
|
* leaving a registry with only its fallbacks, and every entity icon rendering
|
|
@@ -73,53 +102,195 @@ export function isIconSourcePath(filePath) {
|
|
|
73
102
|
return (
|
|
74
103
|
(normalised.includes('/entities/') && normalised.endsWith('.config.ts')) ||
|
|
75
104
|
(normalised.includes('/blocks/') && normalised.endsWith('/config.ts')) ||
|
|
76
|
-
|
|
105
|
+
/\/config\/[^/]+\.config\.ts$/.test(normalised)
|
|
77
106
|
)
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Whether a file is component source a theme or plugin could name an icon
|
|
111
|
+
* from at runtime — anything DynamicIcon or resolveIcon could be called
|
|
112
|
+
* from. Exported for tests. Same Windows-separator normalisation as
|
|
113
|
+
* isIconSourcePath, for the same reason.
|
|
114
|
+
*/
|
|
115
|
+
export function isIconCallSourcePath(filePath) {
|
|
116
|
+
return /\.tsx?$/.test(filePath.replace(/\\/g, '/'))
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Whether a path is test code rather than the app's own source. Exported for
|
|
121
|
+
* tests. A name that a test hands to resolveIcon or DynamicIcon to exercise a
|
|
122
|
+
* component is never reached by a real request, so it would only bloat the
|
|
123
|
+
* registry with icons nothing in production resolves.
|
|
124
|
+
*/
|
|
125
|
+
export function isTestFilePath(filePath) {
|
|
126
|
+
const normalised = filePath.replace(/\\/g, '/')
|
|
127
|
+
return /\.(test|spec)\.tsx?$/.test(normalised) || /(^|\/)(__tests__|tests|cypress)\//.test(normalised)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Parse a source file into a TypeScript syntax tree. Exported for tests, so a
|
|
132
|
+
* test can build a tree once and hand it to more than one extractor.
|
|
133
|
+
*
|
|
134
|
+
* Parsed as its own kind of file: a TSX parse reads TypeScript-only syntax in
|
|
135
|
+
* a .ts file (`<T>(props) => ...`) as JSX and loses what follows, so the
|
|
136
|
+
* script kind is derived from `filePath` rather than assumed.
|
|
137
|
+
*/
|
|
138
|
+
export async function parseIconSource(content, filePath, projectRoot = process.cwd()) {
|
|
139
|
+
const ts = await loadTypeScriptFor(projectRoot)
|
|
140
|
+
const sourceFile = ts.createSourceFile(filePath, content, ts.ScriptTarget.Latest, true, ts.getScriptKindFromFileName(filePath))
|
|
141
|
+
return { ts, sourceFile }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** The property key of a `PropertyAssignment` node, whether written bare
|
|
145
|
+
* (`icon: X`), quoted (`'icon': X`) or computed with a literal (`['icon']: X`);
|
|
146
|
+
* anything else — a computed key that isn't a literal — has no static name. */
|
|
147
|
+
function propertyKeyName(nameNode, ts) {
|
|
148
|
+
if (ts.isIdentifier(nameNode) || ts.isStringLiteralLike(nameNode)) {
|
|
149
|
+
return nameNode.text
|
|
150
|
+
}
|
|
151
|
+
if (ts.isComputedPropertyName(nameNode)) {
|
|
152
|
+
const expression = unwrapTransparentExpression(nameNode.expression, ts)
|
|
153
|
+
return expression && ts.isStringLiteralLike(expression) ? expression.text : null
|
|
154
|
+
}
|
|
155
|
+
return null
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Peel off the TypeScript wrappers that change nothing about which value an
|
|
160
|
+
* expression is at runtime — `(expr)`, `expr as T`, `<T>expr`,
|
|
161
|
+
* `expr satisfies T`, `expr!` — so `icon: 'Wallet' as const`, `icon: <any>Wallet`
|
|
162
|
+
* and `icon: Wallet!` are read the same as `icon: 'Wallet'` and `icon: Wallet`.
|
|
163
|
+
* A regex-based scanner never saw these wrappers in the first place; reading
|
|
164
|
+
* syntax does, so it has to strip them explicitly instead of failing to match
|
|
165
|
+
* and dropping the icon silently.
|
|
166
|
+
*/
|
|
167
|
+
function unwrapTransparentExpression(expression, ts) {
|
|
168
|
+
let current = expression
|
|
169
|
+
while (current) {
|
|
170
|
+
if (
|
|
171
|
+
ts.isParenthesizedExpression(current) ||
|
|
172
|
+
ts.isAsExpression(current) ||
|
|
173
|
+
ts.isTypeAssertionExpression(current) ||
|
|
174
|
+
ts.isSatisfiesExpression(current) ||
|
|
175
|
+
ts.isNonNullExpression(current)
|
|
176
|
+
) {
|
|
177
|
+
current = current.expression
|
|
178
|
+
continue
|
|
179
|
+
}
|
|
180
|
+
return current
|
|
181
|
+
}
|
|
182
|
+
return current
|
|
183
|
+
}
|
|
184
|
+
|
|
80
185
|
/**
|
|
81
186
|
* Map of local name -> exported lucide name for a file's lucide imports.
|
|
82
187
|
* `import { Home as HouseIcon }` means the config's `icon: HouseIcon` is
|
|
83
|
-
* lucide's `Home`.
|
|
188
|
+
* lucide's `Home`. Read from the syntax tree, so an import mentioned only in
|
|
189
|
+
* a comment is not a real import.
|
|
84
190
|
*/
|
|
85
|
-
function parseLucideImports(
|
|
191
|
+
function parseLucideImports(sourceFile, ts) {
|
|
86
192
|
const imports = new Map()
|
|
87
193
|
|
|
88
|
-
for (const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
194
|
+
for (const statement of sourceFile.statements) {
|
|
195
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteralLike(statement.moduleSpecifier)) continue
|
|
196
|
+
if (statement.moduleSpecifier.text !== 'lucide-react') continue
|
|
197
|
+
|
|
198
|
+
const namedBindings = statement.importClause?.namedBindings
|
|
199
|
+
if (!namedBindings || !ts.isNamedImports(namedBindings)) continue
|
|
200
|
+
|
|
201
|
+
for (const element of namedBindings.elements) {
|
|
202
|
+
if (element.isTypeOnly) continue
|
|
203
|
+
imports.set(element.name.text, (element.propertyName ?? element.name).text)
|
|
96
204
|
}
|
|
97
205
|
}
|
|
98
206
|
|
|
99
207
|
return imports
|
|
100
208
|
}
|
|
101
209
|
|
|
210
|
+
/** The expression a `get icon()`-style accessor's body returns, when the
|
|
211
|
+
* body is exactly one `return <expr>` statement — the only shape simple
|
|
212
|
+
* enough to read a static icon name from. Anything else (no return,
|
|
213
|
+
* several statements, a conditional) has no single value to extract, so the
|
|
214
|
+
* caller falls back to the accessor node itself, which resolves as neither
|
|
215
|
+
* a literal nor a lucide import and is therefore reported as unresolved
|
|
216
|
+
* rather than silently dropped. */
|
|
217
|
+
function accessorReturnExpression(node, ts) {
|
|
218
|
+
const [statement] = node.body?.statements ?? []
|
|
219
|
+
return node.body?.statements.length === 1 && statement && ts.isReturnStatement(statement) && statement.expression
|
|
220
|
+
? statement.expression
|
|
221
|
+
: null
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Whether a `set icon(v)` accessor has a `get icon()` beside it in the same
|
|
225
|
+
* object literal or class, the member that actually supplies the value. */
|
|
226
|
+
function hasSiblingGetter(setter, ts) {
|
|
227
|
+
const siblings = setter.parent.properties ?? setter.parent.members ?? []
|
|
228
|
+
const key = propertyKeyName(setter.name, ts)
|
|
229
|
+
return siblings.some(sibling => ts.isGetAccessorDeclaration(sibling) && propertyKeyName(sibling.name, ts) === key)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Every icon-bearing property value in the tree, wherever it is nested —
|
|
234
|
+
* `icon` or `iconName` written plain, quoted or computed (`node.initializer`),
|
|
235
|
+
* as a class field with an initializer, the shorthand form `{ icon }`, where
|
|
236
|
+
* the property's own name doubles as the value (`node.name`), and a getter
|
|
237
|
+
* (`get icon() { return 'Wallet' }`), an accessor object configs use the same
|
|
238
|
+
* as a plain property.
|
|
239
|
+
*
|
|
240
|
+
* A member under an icon key that holds no name to read — a method
|
|
241
|
+
* (`icon() { ... }`, whose value is the function itself) or a setter with no
|
|
242
|
+
* getter beside it (whose value reads as undefined) — is collected as the
|
|
243
|
+
* member node, which resolves as neither a literal nor a lucide import and is
|
|
244
|
+
* therefore reported as unresolved rather than silently dropped.
|
|
245
|
+
*/
|
|
246
|
+
function findIconPropertyValues(sourceFile, ts) {
|
|
247
|
+
const values = []
|
|
248
|
+
|
|
249
|
+
const visit = node => {
|
|
250
|
+
if ((ts.isPropertyAssignment(node) || (ts.isPropertyDeclaration(node) && node.initializer)) && ICON_KEYS.has(propertyKeyName(node.name, ts))) {
|
|
251
|
+
values.push(node.initializer)
|
|
252
|
+
} else if (ts.isShorthandPropertyAssignment(node) && ICON_KEYS.has(node.name.text)) {
|
|
253
|
+
values.push(node.name)
|
|
254
|
+
} else if (ts.isGetAccessorDeclaration(node) && ICON_KEYS.has(propertyKeyName(node.name, ts))) {
|
|
255
|
+
values.push(accessorReturnExpression(node, ts) ?? node)
|
|
256
|
+
} else if (ts.isMethodDeclaration(node) && ICON_KEYS.has(propertyKeyName(node.name, ts))) {
|
|
257
|
+
values.push(node)
|
|
258
|
+
} else if (ts.isSetAccessorDeclaration(node) && ICON_KEYS.has(propertyKeyName(node.name, ts)) && !hasSiblingGetter(node, ts)) {
|
|
259
|
+
values.push(node)
|
|
260
|
+
}
|
|
261
|
+
ts.forEachChild(node, visit)
|
|
262
|
+
}
|
|
263
|
+
visit(sourceFile)
|
|
264
|
+
|
|
265
|
+
return values
|
|
266
|
+
}
|
|
267
|
+
|
|
102
268
|
/**
|
|
103
269
|
* Icon names referenced by a single config file. Exported for tests.
|
|
104
270
|
*/
|
|
105
|
-
export function extractIconNames(content) {
|
|
106
|
-
const
|
|
271
|
+
export async function extractIconNames(content, filePath = 'icons.config.ts', projectRoot) {
|
|
272
|
+
const { ts, sourceFile } = await parseIconSource(content, filePath, projectRoot)
|
|
273
|
+
const lucideImports = parseLucideImports(sourceFile, ts)
|
|
107
274
|
const names = []
|
|
108
275
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
|
|
276
|
+
for (const value of findIconPropertyValues(sourceFile, ts)) {
|
|
277
|
+
const initializer = unwrapTransparentExpression(value, ts)
|
|
278
|
+
|
|
279
|
+
// `icon: Users` — only counts when the identifier came from lucide-react
|
|
280
|
+
if (ts.isIdentifier(initializer)) {
|
|
281
|
+
const exported = lucideImports.get(initializer.text)
|
|
282
|
+
if (exported) names.push(exported)
|
|
283
|
+
continue
|
|
115
284
|
}
|
|
116
|
-
}
|
|
117
285
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
286
|
+
// `icon: 'Users'` or `icon: 'pie-chart'` — a theme's sidebar sections and
|
|
287
|
+
// block configs use both spellings; the caller folds kebab-case into the
|
|
288
|
+
// lucide export name and validates the result against lucide's export
|
|
289
|
+
// list. The generated registry is TypeScript built from this string, so
|
|
290
|
+
// anything not shaped like a name is dropped rather than trusted.
|
|
291
|
+
if (ts.isStringLiteralLike(initializer) && SAFE_NAME.test(initializer.text)) {
|
|
292
|
+
names.push(initializer.text)
|
|
293
|
+
}
|
|
123
294
|
}
|
|
124
295
|
|
|
125
296
|
return names
|
|
@@ -131,26 +302,282 @@ export function extractIconNames(content) {
|
|
|
131
302
|
*
|
|
132
303
|
* Only a direct named import of lucide-react and a string literal reach the
|
|
133
304
|
* registry. Anything else — a namespace access (`I.Users`), an identifier
|
|
134
|
-
* aliased through another module, a component of the
|
|
135
|
-
* resolvable by reading this file, so it never enters
|
|
136
|
-
* resolveIcon falls back. That is silent, hence the warning
|
|
305
|
+
* aliased through another module, a call (`chooseIcon()`), a component of the
|
|
306
|
+
* project's own — is not resolvable by reading this file, so it never enters
|
|
307
|
+
* the registry and resolveIcon falls back. That is silent, hence the warning:
|
|
308
|
+
* whatever isn't one of the two resolvable shapes is reported, whatever kind
|
|
309
|
+
* of expression it is, rather than allowlisting the shapes worth warning about.
|
|
137
310
|
*/
|
|
138
|
-
export function findUnresolvedIconRefs(content) {
|
|
139
|
-
const
|
|
311
|
+
export async function findUnresolvedIconRefs(content, filePath = 'icons.config.ts', projectRoot) {
|
|
312
|
+
const { ts, sourceFile } = await parseIconSource(content, filePath, projectRoot)
|
|
313
|
+
const lucideImports = parseLucideImports(sourceFile, ts)
|
|
140
314
|
const unresolved = []
|
|
141
315
|
|
|
142
|
-
for (const
|
|
143
|
-
const
|
|
144
|
-
const isMember = reference.includes('.')
|
|
316
|
+
for (const value of findIconPropertyValues(sourceFile, ts)) {
|
|
317
|
+
const initializer = unwrapTransparentExpression(value, ts)
|
|
145
318
|
|
|
146
|
-
|
|
147
|
-
|
|
319
|
+
// A wrapper that resolved to a usable literal or a known lucide import is
|
|
320
|
+
// not unresolved — extractIconNames already has it. Quoting the source as
|
|
321
|
+
// written (wrapper included) so the warning points at what a developer
|
|
322
|
+
// would grep for.
|
|
323
|
+
const resolvedAsLiteral = ts.isStringLiteralLike(initializer) && SAFE_NAME.test(initializer.text)
|
|
324
|
+
const resolvedAsLucideImport = ts.isIdentifier(initializer) && lucideImports.has(initializer.text)
|
|
325
|
+
|
|
326
|
+
if (!resolvedAsLiteral && !resolvedAsLucideImport) {
|
|
327
|
+
unresolved.push(value.getText(sourceFile))
|
|
148
328
|
}
|
|
149
329
|
}
|
|
150
330
|
|
|
151
331
|
return unresolved
|
|
152
332
|
}
|
|
153
333
|
|
|
334
|
+
/** The string literal an expression evaluates to, unwrapping a JSX
|
|
335
|
+
* expression container (`{'pie-chart'}`) and any transparent TypeScript
|
|
336
|
+
* wrapper (`'pie-chart' satisfies string`) around it, or null when the
|
|
337
|
+
* expression isn't a literal — a runtime value that resolveIcon or
|
|
338
|
+
* DynamicIcon reads at render time, not a name this build can see. */
|
|
339
|
+
function literalTextOf(expression, ts) {
|
|
340
|
+
const unwrapped = unwrapTransparentExpression(ts.isJsxExpression(expression) ? expression.expression : expression, ts)
|
|
341
|
+
return unwrapped && ts.isStringLiteralLike(unwrapped) ? unwrapped.text : null
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/** Where a theme or plugin actually gets DynamicIcon and resolveIcon from —
|
|
345
|
+
* every subpath core publishes them under, via its `./lib/*` and
|
|
346
|
+
* `./components/*` export wildcards. Matched as a whole package name, not a
|
|
347
|
+
* string prefix: `@nextsparkjs/core-fake/lib/icons` starts with this string
|
|
348
|
+
* but is a different package entirely. */
|
|
349
|
+
const CORE_PACKAGE_PREFIX = '@nextsparkjs/core'
|
|
350
|
+
|
|
351
|
+
/** Whether a module specifier is core itself or one of its subpaths — the
|
|
352
|
+
* whole `@nextsparkjs/core` package segment, not merely a string prefix of it. */
|
|
353
|
+
function isCorePackageSpecifier(moduleSpecifierText) {
|
|
354
|
+
return moduleSpecifierText === CORE_PACKAGE_PREFIX || moduleSpecifierText.startsWith(`${CORE_PACKAGE_PREFIX}/`)
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Local bindings for whatever a file imports from core, so a call site is
|
|
359
|
+
* matched by what it actually refers to rather than by spelling: a named
|
|
360
|
+
* import tracks straight to its local name (aliased or not), a namespace
|
|
361
|
+
* import (`import * as Core from '@nextsparkjs/core/...'`) is tracked so
|
|
362
|
+
* `Core.resolveIcon(...)` resolves too.
|
|
363
|
+
*/
|
|
364
|
+
function parseCoreImports(sourceFile, ts) {
|
|
365
|
+
const named = new Map() // local name -> imported name
|
|
366
|
+
const namespaces = new Set() // local name bound to `import * as X`
|
|
367
|
+
|
|
368
|
+
for (const statement of sourceFile.statements) {
|
|
369
|
+
if (!ts.isImportDeclaration(statement) || !ts.isStringLiteralLike(statement.moduleSpecifier)) continue
|
|
370
|
+
if (!isCorePackageSpecifier(statement.moduleSpecifier.text)) continue
|
|
371
|
+
|
|
372
|
+
const namedBindings = statement.importClause?.namedBindings
|
|
373
|
+
if (!namedBindings) continue
|
|
374
|
+
|
|
375
|
+
if (ts.isNamedImports(namedBindings)) {
|
|
376
|
+
for (const element of namedBindings.elements) {
|
|
377
|
+
if (element.isTypeOnly) continue
|
|
378
|
+
named.set(element.name.text, (element.propertyName ?? element.name).text)
|
|
379
|
+
}
|
|
380
|
+
} else if (ts.isNamespaceImport(namedBindings)) {
|
|
381
|
+
namespaces.add(namedBindings.name.text)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
return { named, namespaces }
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/** The bare names a node declares in its own lexical scope: a function's
|
|
389
|
+
* parameters, a `let`/`const`/`var` declaration's bindings, a catch clause's
|
|
390
|
+
* binding. Destructured names are collected too, so `function f({ resolveIcon })`
|
|
391
|
+
* shadows the same as `function f(resolveIcon)`. */
|
|
392
|
+
function collectBindingNames(name, ts, into) {
|
|
393
|
+
if (ts.isIdentifier(name)) {
|
|
394
|
+
into.add(name.text)
|
|
395
|
+
} else if (ts.isObjectBindingPattern(name) || ts.isArrayBindingPattern(name)) {
|
|
396
|
+
for (const element of name.elements) {
|
|
397
|
+
if (ts.isBindingElement(element)) collectBindingNames(element.name, ts, into)
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/** Whether `node` starts its own `var` scope, one a hoisted `var` cannot
|
|
403
|
+
* escape: any function (declaration, expression, arrow, method, getter,
|
|
404
|
+
* setter, constructor), a class `static { }` block, or a TypeScript
|
|
405
|
+
* `namespace`, which compiles to a function of its own. This is where
|
|
406
|
+
* `collectHoistedVarNames` below stops recursing. */
|
|
407
|
+
function isVarScopeBoundary(node, ts) {
|
|
408
|
+
return ts.isFunctionLike(node) || ts.isClassStaticBlockDeclaration(node) || ts.isModuleDeclaration(node)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Every `var`-declared name nested anywhere under `node` — inside an `if`,
|
|
412
|
+
* a loop, a `switch`, as deep as it goes — except inside a nested `var`
|
|
413
|
+
* scope (see isVarScopeBoundary). Unlike `let`/`const`, `var` ignores block
|
|
414
|
+
* boundaries, so a single level of `node.statements` (what the block/module
|
|
415
|
+
* branch below reads for `let`/`const`) misses one declared inside a nested
|
|
416
|
+
* block; this walks the whole subtree instead, the way hoisting actually
|
|
417
|
+
* works. */
|
|
418
|
+
function collectHoistedVarNames(node, ts, into) {
|
|
419
|
+
if (isVarScopeBoundary(node, ts)) return
|
|
420
|
+
|
|
421
|
+
if (ts.isVariableStatement(node) && (node.declarationList.flags & ts.NodeFlags.BlockScoped) === 0) {
|
|
422
|
+
for (const declaration of node.declarationList.declarations) collectBindingNames(declaration.name, ts, into)
|
|
423
|
+
} else if (
|
|
424
|
+
(ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) &&
|
|
425
|
+
node.initializer &&
|
|
426
|
+
ts.isVariableDeclarationList(node.initializer) &&
|
|
427
|
+
(node.initializer.flags & ts.NodeFlags.BlockScoped) === 0
|
|
428
|
+
) {
|
|
429
|
+
for (const declaration of node.initializer.declarations) collectBindingNames(declaration.name, ts, into)
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
ts.forEachChild(node, child => collectHoistedVarNames(child, ts, into))
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/** The declarations directly in `statements` that introduce a name into
|
|
436
|
+
* their enclosing scope: function, class, `let`/`const`/`var` declarations,
|
|
437
|
+
* and TypeScript's value-bearing `enum`, `namespace` and `import x = ...`.
|
|
438
|
+
* Shared by a block/module's own statement list and by a `switch`'s case
|
|
439
|
+
* clauses, which — unlike a block per clause — all share one scope across
|
|
440
|
+
* the whole switch. */
|
|
441
|
+
function blockScopedBindingNames(statements, ts, into) {
|
|
442
|
+
for (const statement of statements) {
|
|
443
|
+
if (
|
|
444
|
+
(ts.isFunctionDeclaration(statement) ||
|
|
445
|
+
ts.isClassDeclaration(statement) ||
|
|
446
|
+
ts.isEnumDeclaration(statement) ||
|
|
447
|
+
ts.isModuleDeclaration(statement) ||
|
|
448
|
+
ts.isImportEqualsDeclaration(statement)) &&
|
|
449
|
+
statement.name &&
|
|
450
|
+
ts.isIdentifier(statement.name)
|
|
451
|
+
) {
|
|
452
|
+
into.add(statement.name.text)
|
|
453
|
+
} else if (ts.isVariableStatement(statement)) {
|
|
454
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
455
|
+
collectBindingNames(declaration.name, ts, into)
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/** The names `node` introduces into its own scope, or an empty set when it
|
|
462
|
+
* introduces none. Used while walking the tree to track which imported names
|
|
463
|
+
* are shadowed by a closer local declaration.
|
|
464
|
+
*
|
|
465
|
+
* A function's parameters — a getter's, a setter's and a constructor's as
|
|
466
|
+
* much as a method's or an arrow's — and a named function expression's own
|
|
467
|
+
* name are scoped to its parameter initializers and body. Its hoisted `var`
|
|
468
|
+
* names are added separately when the walk enters its body, because parameter
|
|
469
|
+
* initializers cannot see declarations from that body. A class expression's
|
|
470
|
+
* own name is scoped to itself, as is every `var` hoisted in a class `static
|
|
471
|
+
* { }` block or a `namespace` body. A block's (or the module's, or a
|
|
472
|
+
* namespace's) function, class and `let`/`const`/`var` declarations are
|
|
473
|
+
* scoped to the whole block, not merely to the statement that introduces
|
|
474
|
+
* them — a later sibling statement has to see the shadow too, the way it
|
|
475
|
+
* would at runtime. A `for`/`for-in`/`for-of` loop's own `let`/`const`
|
|
476
|
+
* initializer is scoped to the whole loop, not just to itself, and every
|
|
477
|
+
* clause of a `switch` shares one scope. */
|
|
478
|
+
function ownScopeBindingNames(node, ts) {
|
|
479
|
+
const names = new Set()
|
|
480
|
+
|
|
481
|
+
if (ts.isFunctionLike(node)) {
|
|
482
|
+
for (const parameter of node.parameters) collectBindingNames(parameter.name, ts, names)
|
|
483
|
+
if (ts.isFunctionExpression(node) && node.name) {
|
|
484
|
+
names.add(node.name.text)
|
|
485
|
+
}
|
|
486
|
+
} else if (ts.isClassExpression(node) && node.name) {
|
|
487
|
+
names.add(node.name.text)
|
|
488
|
+
} else if (ts.isClassStaticBlockDeclaration(node)) {
|
|
489
|
+
collectHoistedVarNames(node.body, ts, names)
|
|
490
|
+
} else if (ts.isModuleBlock(node)) {
|
|
491
|
+
blockScopedBindingNames(node.statements, ts, names)
|
|
492
|
+
for (const statement of node.statements) collectHoistedVarNames(statement, ts, names)
|
|
493
|
+
} else if (ts.isVariableDeclarationList(node)) {
|
|
494
|
+
for (const declaration of node.declarations) collectBindingNames(declaration.name, ts, names)
|
|
495
|
+
} else if ((ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) && node.initializer && ts.isVariableDeclarationList(node.initializer)) {
|
|
496
|
+
for (const declaration of node.initializer.declarations) collectBindingNames(declaration.name, ts, names)
|
|
497
|
+
} else if (ts.isCatchClause(node) && node.variableDeclaration) {
|
|
498
|
+
collectBindingNames(node.variableDeclaration.name, ts, names)
|
|
499
|
+
} else if (ts.isCaseBlock(node)) {
|
|
500
|
+
for (const clause of node.clauses) blockScopedBindingNames(clause.statements, ts, names)
|
|
501
|
+
} else if (ts.isBlock(node) || ts.isSourceFile(node)) {
|
|
502
|
+
blockScopedBindingNames(node.statements, ts, names)
|
|
503
|
+
if (ts.isSourceFile(node)) collectHoistedVarNames(node, ts, names)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return names
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* Whether `expression` — a JSX tag name or a call's callee — is the given
|
|
511
|
+
* core export, resolved through the file's own imports rather than by
|
|
512
|
+
* comparing text: `import { resolveIcon as ri }` still matches `ri(...)` and
|
|
513
|
+
* `ri!(...)`, `import * as Core from '@nextsparkjs/core/lib/icons'` still
|
|
514
|
+
* matches `Core.resolveIcon(...)`, and a same-named local that was never
|
|
515
|
+
* imported from core — a theme's own `resolveIcon` helper, or a function
|
|
516
|
+
* parameter that shadows the import — does not.
|
|
517
|
+
*/
|
|
518
|
+
function referencesCoreExport(expression, exportName, imports, ts, shadowStack) {
|
|
519
|
+
const unwrapped = unwrapTransparentExpression(expression, ts)
|
|
520
|
+
const isShadowed = name => shadowStack.some(scope => scope.has(name))
|
|
521
|
+
|
|
522
|
+
if (ts.isIdentifier(unwrapped)) {
|
|
523
|
+
return !isShadowed(unwrapped.text) && imports.named.get(unwrapped.text) === exportName
|
|
524
|
+
}
|
|
525
|
+
if (ts.isPropertyAccessExpression(unwrapped) && ts.isIdentifier(unwrapped.expression)) {
|
|
526
|
+
return !isShadowed(unwrapped.expression.text) && imports.namespaces.has(unwrapped.expression.text) && unwrapped.name.text === exportName
|
|
527
|
+
}
|
|
528
|
+
return false
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/**
|
|
532
|
+
* Icon names passed as a string literal to DynamicIcon's `name` prop or to
|
|
533
|
+
* resolveIcon's first argument. Exported for tests.
|
|
534
|
+
*
|
|
535
|
+
* Both accept a runtime variable too (`resolveIcon(item.icon)`, the normal
|
|
536
|
+
* way to render a value that came from the database) — that call is left
|
|
537
|
+
* alone, since there is no name in it to register.
|
|
538
|
+
*/
|
|
539
|
+
export async function extractLiteralIconCallNames(content, filePath = 'icons.tsx', projectRoot) {
|
|
540
|
+
const { ts, sourceFile } = await parseIconSource(content, filePath, projectRoot)
|
|
541
|
+
const imports = parseCoreImports(sourceFile, ts)
|
|
542
|
+
const names = []
|
|
543
|
+
|
|
544
|
+
// A local declaration (a function parameter, a `let`/`const`, a catch
|
|
545
|
+
// binding) shadows an import of the same name for the rest of its scope,
|
|
546
|
+
// the same way it would at runtime — so the stack of scopes entered so far
|
|
547
|
+
// travels with the walk instead of imports being looked up by name alone.
|
|
548
|
+
const visit = (node, shadowStack) => {
|
|
549
|
+
const ownNames = ownScopeBindingNames(node, ts)
|
|
550
|
+
const nextStack = ownNames.size > 0 ? [...shadowStack, ownNames] : shadowStack
|
|
551
|
+
|
|
552
|
+
if ((ts.isJsxSelfClosingElement(node) || ts.isJsxOpeningElement(node)) && referencesCoreExport(node.tagName, 'DynamicIcon', imports, ts, nextStack)) {
|
|
553
|
+
for (const attribute of node.attributes.properties) {
|
|
554
|
+
if (!ts.isJsxAttribute(attribute) || attribute.name.text !== 'name' || !attribute.initializer) continue
|
|
555
|
+
const name = literalTextOf(attribute.initializer, ts)
|
|
556
|
+
if (name && SAFE_NAME.test(name)) names.push(name)
|
|
557
|
+
}
|
|
558
|
+
} else if (ts.isCallExpression(node) && referencesCoreExport(node.expression, 'resolveIcon', imports, ts, nextStack)) {
|
|
559
|
+
const [firstArgument] = node.arguments
|
|
560
|
+
const name = firstArgument && literalTextOf(firstArgument, ts)
|
|
561
|
+
if (name && SAFE_NAME.test(name)) names.push(name)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
if (ts.isFunctionLike(node) && node.body) {
|
|
565
|
+
const bodyNames = new Set()
|
|
566
|
+
collectHoistedVarNames(node.body, ts, bodyNames)
|
|
567
|
+
const bodyStack = bodyNames.size > 0 ? [...nextStack, bodyNames] : nextStack
|
|
568
|
+
ts.forEachChild(node, child => {
|
|
569
|
+
const childStack = child === node.body ? bodyStack : node.parameters.includes(child) ? nextStack : shadowStack
|
|
570
|
+
visit(child, childStack)
|
|
571
|
+
})
|
|
572
|
+
} else {
|
|
573
|
+
ts.forEachChild(node, child => visit(child, nextStack))
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
visit(sourceFile, [])
|
|
577
|
+
|
|
578
|
+
return names
|
|
579
|
+
}
|
|
580
|
+
|
|
154
581
|
async function collectConfigFiles(dir, matcher, found = []) {
|
|
155
582
|
if (!existsSync(dir)) {
|
|
156
583
|
return found
|
|
@@ -195,12 +622,17 @@ function coreEntitiesDir(config) {
|
|
|
195
622
|
export async function discoverIcons(blocks, config) {
|
|
196
623
|
const candidates = new Set(FALLBACK_ICONS)
|
|
197
624
|
|
|
198
|
-
// Only the configs whose icons reach resolveIcon
|
|
199
|
-
//
|
|
625
|
+
// Only the configs whose icons reach resolveIcon: entity configs (core,
|
|
626
|
+
// themes and plugins), block configs, and every theme's or plugin's
|
|
627
|
+
// config/*.config.ts. Widening this further would put icons in the
|
|
628
|
+
// dashboard bundle that nothing can ask for. Test files are excluded even
|
|
629
|
+
// though a config rarely lives under one, for the same reason call sources
|
|
630
|
+
// exclude them below.
|
|
631
|
+
const isIconSource = filePath => isIconSourcePath(filePath) && !isTestFilePath(filePath)
|
|
200
632
|
const iconSources = [
|
|
201
|
-
...(await collectConfigFiles(coreEntitiesDir(config),
|
|
202
|
-
...(await collectConfigFiles(config.themesDir,
|
|
203
|
-
...(await collectConfigFiles(config.pluginsDir,
|
|
633
|
+
...(await collectConfigFiles(coreEntitiesDir(config), isIconSource)),
|
|
634
|
+
...(await collectConfigFiles(config.themesDir, isIconSource)),
|
|
635
|
+
...(await collectConfigFiles(config.pluginsDir, isIconSource))
|
|
204
636
|
]
|
|
205
637
|
|
|
206
638
|
const unresolved = []
|
|
@@ -208,10 +640,10 @@ export async function discoverIcons(blocks, config) {
|
|
|
208
640
|
for (const configPath of iconSources) {
|
|
209
641
|
try {
|
|
210
642
|
const content = await readFile(configPath, 'utf8')
|
|
211
|
-
for (const name of extractIconNames(content)) {
|
|
643
|
+
for (const name of await extractIconNames(content, configPath, config.projectRoot)) {
|
|
212
644
|
candidates.add(name)
|
|
213
645
|
}
|
|
214
|
-
for (const reference of findUnresolvedIconRefs(content)) {
|
|
646
|
+
for (const reference of await findUnresolvedIconRefs(content, configPath, config.projectRoot)) {
|
|
215
647
|
unresolved.push({ configPath, reference })
|
|
216
648
|
}
|
|
217
649
|
} catch {
|
|
@@ -226,6 +658,29 @@ export async function discoverIcons(blocks, config) {
|
|
|
226
658
|
)
|
|
227
659
|
}
|
|
228
660
|
|
|
661
|
+
// A theme or plugin can also name an icon directly in its own component
|
|
662
|
+
// code rather than through a config, so its trees are scanned for that too.
|
|
663
|
+
// Core is not: every core call site resolves a runtime value (item.icon,
|
|
664
|
+
// config.iconName), never a literal, so there is nothing to add here.
|
|
665
|
+
// Test files are excluded: a spec exercising DynamicIcon or resolveIcon
|
|
666
|
+
// with a literal name isn't a real call site the production bundle needs.
|
|
667
|
+
const isIconCallSource = filePath => isIconCallSourcePath(filePath) && !isTestFilePath(filePath)
|
|
668
|
+
const callSources = [
|
|
669
|
+
...(await collectConfigFiles(config.themesDir, isIconCallSource)),
|
|
670
|
+
...(await collectConfigFiles(config.pluginsDir, isIconCallSource))
|
|
671
|
+
]
|
|
672
|
+
|
|
673
|
+
for (const sourcePath of callSources) {
|
|
674
|
+
try {
|
|
675
|
+
const content = await readFile(sourcePath, 'utf8')
|
|
676
|
+
for (const name of await extractLiteralIconCallNames(content, sourcePath, config.projectRoot)) {
|
|
677
|
+
candidates.add(name)
|
|
678
|
+
}
|
|
679
|
+
} catch {
|
|
680
|
+
verbose(`[icons] Could not read ${sourcePath}`)
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
|
|
229
684
|
for (const block of blocks || []) {
|
|
230
685
|
if (block.icon) {
|
|
231
686
|
candidates.add(block.icon)
|
|
@@ -43,7 +43,7 @@ export async function discoverTemplates(config = DEFAULT_CONFIG) {
|
|
|
43
43
|
║ Or ensure your .env file has NEXT_PUBLIC_ACTIVE_THEME set correctly. ║
|
|
44
44
|
╚══════════════════════════════════════════════════════════════════════════════╝
|
|
45
45
|
`
|
|
46
|
-
console.error(
|
|
46
|
+
for (const line of errorMsg.split('\n')) console.error(line)
|
|
47
47
|
throw new Error('NEXT_PUBLIC_ACTIVE_THEME environment variable is required for template discovery')
|
|
48
48
|
}
|
|
49
49
|
|
|
@@ -140,7 +140,7 @@ export async function generateBillingRegistry(activeTheme, contentsDir, config)
|
|
|
140
140
|
let billingConfig
|
|
141
141
|
try {
|
|
142
142
|
// Use jiti to import .ts files at build time (Node.js can't import .ts natively)
|
|
143
|
-
const jiti = createJiti(import.meta.url, { interopDefault: true })
|
|
143
|
+
const jiti = createJiti(import.meta.url, { interopDefault: true, fsCache: false })
|
|
144
144
|
const module = await jiti.import(absolutePath)
|
|
145
145
|
billingConfig = module.billingConfig || module.default
|
|
146
146
|
} catch (error) {
|