@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
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `copyFileSync` from a project's `projectFiles`, from a FIFO source into a
|
|
3
|
+
* destination that the parent process swaps for a symlink while this process is
|
|
4
|
+
* blocked opening that FIFO - after safe-fs's own check already ran.
|
|
5
|
+
*/
|
|
6
|
+
import { projectFiles } from '../../safe-fs.mjs'
|
|
7
|
+
|
|
8
|
+
const [, , root, source, destination] = process.argv
|
|
9
|
+
try {
|
|
10
|
+
projectFiles(root).copyFileSync(source, destination)
|
|
11
|
+
process.stdout.write(JSON.stringify({ ok: true }))
|
|
12
|
+
} catch (error) {
|
|
13
|
+
process.stdout.write(JSON.stringify({ code: error.code }))
|
|
14
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Finds where a source file can change the file system without going through
|
|
3
|
+
* core's safe-fs: an fs module imported whole, a named import of anything
|
|
4
|
+
* other than a call that only reads, an fs module re-exported, and an fs module
|
|
5
|
+
* named as the argument of a call - require, import(), createRequire(...)(),
|
|
6
|
+
* process.binding - whose result can't be followed. Reads are listed by name,
|
|
7
|
+
* so a call fs adds that changes things is found without being listed.
|
|
8
|
+
*
|
|
9
|
+
* And which files are the generator's: the ones under the directories given,
|
|
10
|
+
* less tests, and every file they import from under the same package, however
|
|
11
|
+
* deep, so a module added to what those files load is looked at too.
|
|
12
|
+
*
|
|
13
|
+
* @module core/scripts/build/registry/__tests__/direct-fs-writes
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'fs'
|
|
17
|
+
import { dirname, join, relative, resolve, sep } from 'path'
|
|
18
|
+
import ts from 'typescript'
|
|
19
|
+
|
|
20
|
+
/** The modules that reach the file system. */
|
|
21
|
+
export const FS_MODULES = new Set(['fs', 'node:fs', 'fs/promises', 'node:fs/promises', 'fs-extra', 'graceful-fs'])
|
|
22
|
+
|
|
23
|
+
/** What may be imported by name from them: calls and values that read, and nothing that writes, creates, renames or removes. */
|
|
24
|
+
export const READ_ONLY = new Set([
|
|
25
|
+
'access',
|
|
26
|
+
'accessSync',
|
|
27
|
+
'constants',
|
|
28
|
+
'createReadStream',
|
|
29
|
+
'Dirent',
|
|
30
|
+
'existsSync',
|
|
31
|
+
'lstat',
|
|
32
|
+
'lstatSync',
|
|
33
|
+
'opendir',
|
|
34
|
+
'opendirSync',
|
|
35
|
+
'pathExists',
|
|
36
|
+
'pathExistsSync',
|
|
37
|
+
'readdir',
|
|
38
|
+
'readdirSync',
|
|
39
|
+
'readFile',
|
|
40
|
+
'readFileSync',
|
|
41
|
+
'readJson',
|
|
42
|
+
'readJsonSync',
|
|
43
|
+
'readlink',
|
|
44
|
+
'readlinkSync',
|
|
45
|
+
'realpath',
|
|
46
|
+
'realpathSync',
|
|
47
|
+
'stat',
|
|
48
|
+
'Stats',
|
|
49
|
+
'statSync',
|
|
50
|
+
'unwatchFile',
|
|
51
|
+
'watch',
|
|
52
|
+
'watchFile',
|
|
53
|
+
])
|
|
54
|
+
|
|
55
|
+
const SOURCE_EXTENSIONS = ['.mjs', '.js', '.cjs', '.ts', '.mts', '.cts']
|
|
56
|
+
|
|
57
|
+
function scriptKind(fileName) {
|
|
58
|
+
return fileName.endsWith('ts') ? ts.ScriptKind.TS : ts.ScriptKind.JS
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function parse(source, fileName) {
|
|
62
|
+
return ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true, scriptKind(fileName))
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function moduleName(node) {
|
|
66
|
+
return node && (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) ? node.text : null
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Each place in `source` that can change the file system without safe-fs, by
|
|
71
|
+
* line, with what it is.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} source - The file's text
|
|
74
|
+
* @param {string} fileName - Its name, for its language
|
|
75
|
+
* @returns {{ line: number, what: string }[]}
|
|
76
|
+
*/
|
|
77
|
+
export function directFsWrites(source, fileName) {
|
|
78
|
+
const file = parse(source, fileName)
|
|
79
|
+
const found = []
|
|
80
|
+
const add = (node, what) => {
|
|
81
|
+
found.push({ line: file.getLineAndCharacterOfPosition(node.getStart(file)).line + 1, what })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const visit = node => {
|
|
85
|
+
if (ts.isImportDeclaration(node) && FS_MODULES.has(moduleName(node.moduleSpecifier))) {
|
|
86
|
+
const clause = node.importClause
|
|
87
|
+
const from = moduleName(node.moduleSpecifier)
|
|
88
|
+
if (clause && !clause.isTypeOnly) {
|
|
89
|
+
if (clause.name) add(node, `imports ${from} whole, as ${clause.name.text}`)
|
|
90
|
+
const bindings = clause.namedBindings
|
|
91
|
+
if (bindings && ts.isNamespaceImport(bindings)) add(node, `imports ${from} whole, as ${bindings.name.text}`)
|
|
92
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
93
|
+
for (const element of bindings.elements) {
|
|
94
|
+
const name = (element.propertyName ?? element.name).text
|
|
95
|
+
if (!element.isTypeOnly && !READ_ONLY.has(name)) add(element, `imports ${name} from ${from}`)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
} else if (ts.isExportDeclaration(node) && FS_MODULES.has(moduleName(node.moduleSpecifier))) {
|
|
100
|
+
add(node, `re-exports ${moduleName(node.moduleSpecifier)}`)
|
|
101
|
+
} else if (
|
|
102
|
+
ts.isImportEqualsDeclaration(node) &&
|
|
103
|
+
ts.isExternalModuleReference(node.moduleReference) &&
|
|
104
|
+
FS_MODULES.has(moduleName(node.moduleReference.expression))
|
|
105
|
+
) {
|
|
106
|
+
add(node, `imports ${moduleName(node.moduleReference.expression)} whole, as ${node.name.text}`)
|
|
107
|
+
} else if (ts.isCallExpression(node)) {
|
|
108
|
+
for (const argument of node.arguments) {
|
|
109
|
+
const name = moduleName(argument)
|
|
110
|
+
if (FS_MODULES.has(name)) add(node, `loads ${name} with a call`)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
ts.forEachChild(node, visit)
|
|
114
|
+
}
|
|
115
|
+
visit(file)
|
|
116
|
+
return found
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/** The relative module specifiers `source` imports, re-exports or loads with import(). */
|
|
120
|
+
function localSpecifiers(source, fileName) {
|
|
121
|
+
const file = parse(source, fileName)
|
|
122
|
+
const specifiers = []
|
|
123
|
+
const visit = node => {
|
|
124
|
+
if ((ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && moduleName(node.moduleSpecifier)?.startsWith('.')) {
|
|
125
|
+
specifiers.push(moduleName(node.moduleSpecifier))
|
|
126
|
+
} else if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
127
|
+
const name = moduleName(node.arguments[0])
|
|
128
|
+
if (name?.startsWith('.')) specifiers.push(name)
|
|
129
|
+
}
|
|
130
|
+
ts.forEachChild(node, visit)
|
|
131
|
+
}
|
|
132
|
+
visit(file)
|
|
133
|
+
return specifiers
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** The file a relative specifier names: as written, a TypeScript source for a .js name, or with an extension added. */
|
|
137
|
+
function resolveSpecifier(fromFile, specifier) {
|
|
138
|
+
const base = resolve(dirname(fromFile), specifier)
|
|
139
|
+
const candidates = [
|
|
140
|
+
base,
|
|
141
|
+
base.replace(/\.js$/, '.ts'),
|
|
142
|
+
base.replace(/\.mjs$/, '.mts'),
|
|
143
|
+
...SOURCE_EXTENSIONS.map(extension => `${base}${extension}`),
|
|
144
|
+
...SOURCE_EXTENSIONS.map(extension => join(base, `index${extension}`)),
|
|
145
|
+
]
|
|
146
|
+
return candidates.find(candidate => existsSync(candidate) && statSync(candidate).isFile()) ?? null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function isTest(path) {
|
|
150
|
+
return path.split(sep).includes('__tests__') || /\.test\.[cm]?[jt]s$/.test(path)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function sourcesUnder(directory) {
|
|
154
|
+
const files = []
|
|
155
|
+
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
|
156
|
+
const path = join(directory, entry.name)
|
|
157
|
+
if (entry.isDirectory()) {
|
|
158
|
+
if (entry.name !== 'node_modules' && entry.name !== '__tests__') files.push(...sourcesUnder(path))
|
|
159
|
+
} else if (entry.isFile() && SOURCE_EXTENSIONS.some(extension => entry.name.endsWith(extension)) && !isTest(path)) {
|
|
160
|
+
files.push(path)
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
return files
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* The generator's files: every source under `directories` that is not a test,
|
|
168
|
+
* `entries`, and whatever those import from under `within`, followed to the end.
|
|
169
|
+
*
|
|
170
|
+
* @param {{ directories?: string[], entries?: string[], within: string }} options
|
|
171
|
+
* @returns {string[]} Absolute paths, sorted
|
|
172
|
+
*/
|
|
173
|
+
export function generatorFiles({ directories = [], entries = [], within }) {
|
|
174
|
+
const seen = new Set()
|
|
175
|
+
const pending = [...directories.flatMap(sourcesUnder), ...entries.map(entry => resolve(entry))]
|
|
176
|
+
while (pending.length > 0) {
|
|
177
|
+
const file = pending.pop()
|
|
178
|
+
if (seen.has(file)) continue
|
|
179
|
+
seen.add(file)
|
|
180
|
+
for (const specifier of localSpecifiers(readFileSync(file, 'utf8'), file)) {
|
|
181
|
+
const target = resolveSpecifier(file, specifier)
|
|
182
|
+
if (target && !relative(within, target).startsWith('..') && !isTest(target)) pending.push(target)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return [...seen].sort()
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Each place, in each of `files` other than `allowed`, that can change the file
|
|
190
|
+
* system without safe-fs, as `path:line what` from `base`.
|
|
191
|
+
*
|
|
192
|
+
* @param {string[]} files - Absolute paths
|
|
193
|
+
* @param {{ base: string, allowed?: string[] }} options
|
|
194
|
+
* @returns {string[]}
|
|
195
|
+
*/
|
|
196
|
+
export function directFsWritesIn(files, { base, allowed = [] }) {
|
|
197
|
+
const exempt = new Set(allowed.map(path => resolve(path)))
|
|
198
|
+
return files
|
|
199
|
+
.filter(file => !exempt.has(file))
|
|
200
|
+
.flatMap(file =>
|
|
201
|
+
directFsWrites(readFileSync(file, 'utf8'), file).map(({ line, what }) => `${relative(base, file)}:${line} ${what}`)
|
|
202
|
+
)
|
|
203
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for how the registry build keeps app/globals.css's generated tag when it
|
|
3
|
+
* points the file's import at another theme: a file sync:app tagged and nobody
|
|
4
|
+
* changed since keeps an intact tag, and a file the project changed keeps the
|
|
5
|
+
* tag it had, which no longer matches.
|
|
6
|
+
*
|
|
7
|
+
* Run: node --test packages/core/scripts/build/registry/__tests__/globals-css-tag.test.mjs
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { test } from 'node:test'
|
|
11
|
+
import assert from 'node:assert/strict'
|
|
12
|
+
import { createHash } from 'node:crypto'
|
|
13
|
+
import { mkdtemp, mkdir, writeFile, readFile, rm } from 'node:fs/promises'
|
|
14
|
+
import { tmpdir } from 'node:os'
|
|
15
|
+
import { join } from 'node:path'
|
|
16
|
+
|
|
17
|
+
import { syncAppGlobalsCss } from '../../theme.mjs'
|
|
18
|
+
|
|
19
|
+
const hashOf = text => createHash('sha256').update(text.replace(/\r\n/g, '\n')).digest('hex')
|
|
20
|
+
|
|
21
|
+
/** A globals.css as sync:app writes it: the tag line, then the file. */
|
|
22
|
+
function taggedGlobals(body, hash = hashOf(body)) {
|
|
23
|
+
return `/* @nextspark-generated core@1.0.0 path=app/globals.css sha256=${hash} */\n${body}`
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** A project with two themes, whose app/globals.css is `content`. */
|
|
27
|
+
async function projectWith(content) {
|
|
28
|
+
const root = await mkdtemp(join(tmpdir(), 'nextspark-globals-css-tag-'))
|
|
29
|
+
for (const theme of ['acme', 'other']) {
|
|
30
|
+
await mkdir(join(root, 'contents/themes', theme, 'styles'), { recursive: true })
|
|
31
|
+
await writeFile(join(root, 'contents/themes', theme, 'styles/globals.css'), 'body {}\n')
|
|
32
|
+
}
|
|
33
|
+
await mkdir(join(root, 'app'), { recursive: true })
|
|
34
|
+
await writeFile(join(root, 'app/globals.css'), content)
|
|
35
|
+
return { root, config: { projectRoot: root, themesDir: join(root, 'contents/themes') } }
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
test('pointing an intact tagged globals.css at another theme leaves its tag intact', async () => {
|
|
39
|
+
const body = '@import "../contents/themes/acme/styles/globals.css";\n\n.custom {}\n'
|
|
40
|
+
const { root, config } = await projectWith(taggedGlobals(body))
|
|
41
|
+
try {
|
|
42
|
+
assert.equal(syncAppGlobalsCss(config, 'other'), true)
|
|
43
|
+
|
|
44
|
+
const [tagLine, ...rest] = (await readFile(join(root, 'app/globals.css'), 'utf8')).split('\n')
|
|
45
|
+
const newBody = rest.join('\n')
|
|
46
|
+
assert.match(newBody, /@import "\.\.\/contents\/themes\/other\/styles\/globals\.css";/)
|
|
47
|
+
assert.equal(tagLine, `/* @nextspark-generated core@1.0.0 path=app/globals.css sha256=${hashOf(newBody)} */`)
|
|
48
|
+
} finally {
|
|
49
|
+
await rm(root, { recursive: true, force: true })
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
test('pointing a customized globals.css at another theme leaves its tag as it was', async () => {
|
|
54
|
+
const body = '@import "../contents/themes/acme/styles/globals.css";\n\n.custom {}\n'
|
|
55
|
+
const staleTag = taggedGlobals(body, hashOf('what sync wrote before the project changed it\n'))
|
|
56
|
+
const { root, config } = await projectWith(staleTag)
|
|
57
|
+
try {
|
|
58
|
+
assert.equal(syncAppGlobalsCss(config, 'other'), true)
|
|
59
|
+
|
|
60
|
+
const content = await readFile(join(root, 'app/globals.css'), 'utf8')
|
|
61
|
+
assert.equal(content.split('\n')[0], staleTag.split('\n')[0])
|
|
62
|
+
assert.match(content, /@import "\.\.\/contents\/themes\/other\/styles\/globals\.css";/)
|
|
63
|
+
} finally {
|
|
64
|
+
await rm(root, { recursive: true, force: true })
|
|
65
|
+
}
|
|
66
|
+
})
|