@nextsparkjs/core 0.1.0-beta.185 → 0.1.0-beta.187
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/app/guards/DeveloperGuard.d.ts.map +1 -1
- package/dist/components/app/guards/DeveloperGuard.js +8 -4
- package/dist/components/app/guards/SuperAdminGuard.d.ts.map +1 -1
- package/dist/components/app/guards/SuperAdminGuard.js +8 -4
- package/dist/components/app/layouts/PublicFooter.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicFooter.js +2 -2
- package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
- package/dist/components/app/layouts/PublicNavbar.js +2 -2
- package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
- package/dist/components/app/misc/ThemeToggle.js +4 -1
- package/dist/components/auth/DevKeyring.d.ts.map +1 -1
- package/dist/components/auth/DevKeyring.js +10 -2
- package/dist/components/auth/SessionCookieRefresher.d.ts +21 -0
- package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -0
- package/dist/components/auth/SessionCookieRefresher.js +11 -0
- package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
- package/dist/components/auth/forms/LoginForm.js +300 -6
- package/dist/components/auth/index.d.ts +1 -0
- package/dist/components/auth/index.d.ts.map +1 -1
- package/dist/components/auth/index.js +2 -0
- package/dist/components/billing/InvoicesTable.d.ts.map +1 -1
- package/dist/components/billing/InvoicesTable.js +4 -3
- package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/AuthGuard.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/AuthGuard.js +2 -2
- package/dist/components/dashboard/layouts/DashboardAuthLayout.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/DashboardAuthLayout.js +2 -2
- package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts +17 -0
- package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts.map +1 -0
- package/dist/components/dashboard/layouts/DashboardAuthSkeleton.js +52 -0
- package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/Sidebar.js +2 -3
- package/dist/components/dashboard/layouts/TopNavbar.js +2 -2
- package/dist/components/dashboard/layouts/index.d.ts +1 -0
- package/dist/components/dashboard/layouts/index.d.ts.map +1 -1
- package/dist/components/dashboard/layouts/index.js +2 -0
- package/dist/components/devtools/api-explorer/ApiExplorer.js +4 -4
- package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
- package/dist/components/entities/EntityFieldRenderer.js +3 -0
- package/dist/components/entities/EntityTable.d.ts.map +1 -1
- package/dist/components/entities/EntityTable.js +2 -1
- package/dist/components/entities/wrappers/EntityFormWrapper.d.ts.map +1 -1
- package/dist/components/entities/wrappers/EntityFormWrapper.js +7 -2
- package/dist/components/patterns/pages/PatternEditPage.d.ts +5 -1
- package/dist/components/patterns/pages/PatternEditPage.d.ts.map +1 -1
- package/dist/components/patterns/pages/PatternEditPage.js +16 -5
- package/dist/components/patterns/pages/PatternsCreatePage.d.ts +2 -1
- package/dist/components/patterns/pages/PatternsCreatePage.d.ts.map +1 -1
- package/dist/components/patterns/pages/PatternsCreatePage.js +17 -5
- package/dist/components/ui/combobox.d.ts +8 -1
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/combobox.js +37 -44
- package/dist/components/ui/country-select.d.ts +3 -1
- package/dist/components/ui/country-select.d.ts.map +1 -1
- package/dist/components/ui/country-select.js +3 -1
- package/dist/components/ui/currency-select.d.ts +3 -1
- package/dist/components/ui/currency-select.d.ts.map +1 -1
- package/dist/components/ui/currency-select.js +3 -1
- package/dist/components/ui/sheet.d.ts +5 -0
- package/dist/components/ui/sheet.d.ts.map +1 -1
- package/dist/components/ui/sheet.js +46 -26
- package/dist/components/ui/timezone-select.d.ts +3 -1
- package/dist/components/ui/timezone-select.d.ts.map +1 -1
- package/dist/components/ui/timezone-select.js +3 -1
- package/dist/contexts/TeamContext.d.ts +6 -0
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +8 -1
- package/dist/emails/otp-verification.d.ts.map +1 -1
- package/dist/emails/reset-password.d.ts.map +1 -1
- package/dist/emails/team-invitation.d.ts.map +1 -1
- package/dist/emails/team-invitation.js +3 -2
- package/dist/emails/verify-email.d.ts.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useAuth.d.ts +29 -0
- package/dist/hooks/useAuth.d.ts.map +1 -1
- package/dist/hooks/useAuth.js +24 -0
- package/dist/hooks/useEnsureUserMetadata.d.ts +22 -0
- package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
- package/dist/hooks/useEnsureUserMetadata.js +18 -5
- package/dist/hooks/useSessionCookieRefresh.d.ts +35 -0
- package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -0
- package/dist/hooks/useSessionCookieRefresh.js +49 -0
- package/dist/lib/api/api-error.d.ts +3 -1
- package/dist/lib/api/api-error.d.ts.map +1 -1
- package/dist/lib/api/api-error.js +4 -2
- package/dist/lib/api/auth/dual-auth.d.ts +38 -3
- package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
- package/dist/lib/api/auth/dual-auth.js +42 -7
- package/dist/lib/api/auth/permissions.d.ts +7 -2
- package/dist/lib/api/auth/permissions.d.ts.map +1 -1
- package/dist/lib/api/auth/permissions.js +2 -2
- package/dist/lib/api/auth/scope-policy.d.ts +71 -0
- package/dist/lib/api/auth/scope-policy.d.ts.map +1 -0
- package/dist/lib/api/auth/scope-policy.js +53 -0
- package/dist/lib/api/auth.d.ts +15 -0
- package/dist/lib/api/auth.d.ts.map +1 -1
- package/dist/lib/api/auth.js +17 -4
- package/dist/lib/api/entities.js +2 -1
- package/dist/lib/api/entity/audit-log.d.ts +35 -0
- package/dist/lib/api/entity/audit-log.d.ts.map +1 -0
- package/dist/lib/api/entity/audit-log.js +35 -0
- package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
- package/dist/lib/api/entity/generic-handler.js +333 -138
- package/dist/lib/api/entity-handler.js +2 -2
- package/dist/lib/api/helpers.d.ts +29 -4
- package/dist/lib/api/helpers.d.ts.map +1 -1
- package/dist/lib/api/helpers.js +30 -6
- package/dist/lib/api/keys.d.ts +16 -0
- package/dist/lib/api/keys.d.ts.map +1 -1
- package/dist/lib/api/keys.js +19 -1
- package/dist/lib/api/routes/patterns-usages.d.ts.map +1 -1
- package/dist/lib/api/routes/patterns-usages.js +3 -11
- package/dist/lib/auth/auth-methods.d.ts +52 -0
- package/dist/lib/auth/auth-methods.d.ts.map +1 -0
- package/dist/lib/auth/auth-methods.js +63 -0
- package/dist/lib/auth/registration-guard-plugin.d.ts.map +1 -1
- package/dist/lib/auth/registration-helpers.d.ts +9 -0
- package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
- package/dist/lib/auth/registration-helpers.js +8 -2
- package/dist/lib/auth/security-notifications/device-fingerprint.d.ts +52 -0
- package/dist/lib/auth/security-notifications/device-fingerprint.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/device-fingerprint.js +42 -0
- package/dist/lib/auth/security-notifications/dispatcher.d.ts +37 -0
- package/dist/lib/auth/security-notifications/dispatcher.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/dispatcher.js +157 -0
- package/dist/lib/auth/security-notifications/index.d.ts +20 -0
- package/dist/lib/auth/security-notifications/index.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/index.js +22 -0
- package/dist/lib/auth/security-notifications/registry.d.ts +36 -0
- package/dist/lib/auth/security-notifications/registry.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/registry.js +26 -0
- package/dist/lib/auth/security-notifications/templates/email-changed.d.ts +12 -0
- package/dist/lib/auth/security-notifications/templates/email-changed.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/templates/email-changed.js +43 -0
- package/dist/lib/auth/security-notifications/templates/new-device-login.d.ts +7 -0
- package/dist/lib/auth/security-notifications/templates/new-device-login.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/templates/new-device-login.js +46 -0
- package/dist/lib/auth/security-notifications/templates/password-changed.d.ts +7 -0
- package/dist/lib/auth/security-notifications/templates/password-changed.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/templates/password-changed.js +35 -0
- package/dist/lib/auth/security-notifications/templates/shared.d.ts +36 -0
- package/dist/lib/auth/security-notifications/templates/shared.d.ts.map +1 -0
- package/dist/lib/auth/security-notifications/templates/shared.js +68 -0
- package/dist/lib/auth/security-notifications/types.d.ts +74 -0
- package/dist/lib/auth/security-notifications/types.d.ts.map +1 -0
- package/dist/lib/auth/session-config.d.ts +37 -0
- package/dist/lib/auth/session-config.d.ts.map +1 -0
- package/dist/lib/auth/session-config.js +59 -0
- package/dist/lib/auth/session-refresh.d.ts +46 -0
- package/dist/lib/auth/session-refresh.d.ts.map +1 -0
- package/dist/lib/auth/session-refresh.js +11 -0
- package/dist/lib/auth-client.d.ts +1639 -0
- package/dist/lib/auth-client.d.ts.map +1 -0
- package/dist/lib/auth-client.js +13 -1
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +45 -11
- package/dist/lib/billing/gateways/factory.d.ts +8 -3
- package/dist/lib/billing/gateways/factory.d.ts.map +1 -1
- package/dist/lib/billing/gateways/factory.js +37 -23
- package/dist/lib/billing/stripe-webhook.d.ts.map +1 -1
- package/dist/lib/billing/stripe-webhook.js +2 -1
- package/dist/lib/config/app.config.d.ts.map +1 -1
- package/dist/lib/config/app.config.js +71 -0
- package/dist/lib/config/config-sync.d.ts +1 -4
- package/dist/lib/config/config-sync.d.ts.map +1 -1
- package/dist/lib/config/config-sync.js +6 -2
- package/dist/lib/config/types.d.ts +130 -0
- package/dist/lib/config/types.d.ts.map +1 -1
- package/dist/lib/email/templates.d.ts +3 -3
- package/dist/lib/email/templates.d.ts.map +1 -1
- package/dist/lib/entities/api-generator.js +5 -5
- package/dist/lib/entities/entity-hooks.d.ts +9 -1
- package/dist/lib/entities/entity-hooks.d.ts.map +1 -1
- package/dist/lib/entities/entity-hooks.js +77 -4
- package/dist/lib/entities/schema-generator.d.ts.map +1 -1
- package/dist/lib/entities/schema-generator.js +20 -4
- package/dist/lib/entities/serialization.d.ts +2 -2
- package/dist/lib/entities/serialization.d.ts.map +1 -1
- package/dist/lib/entities/serialization.js +3 -2
- package/dist/lib/entities/types.d.ts +20 -0
- package/dist/lib/entities/types.d.ts.map +1 -1
- package/dist/lib/locale.d.ts.map +1 -1
- package/dist/lib/locale.js +4 -1
- package/dist/lib/mcp/audit.d.ts +8 -4
- package/dist/lib/mcp/audit.d.ts.map +1 -1
- package/dist/lib/plugins/hook-system.d.ts +13 -0
- package/dist/lib/plugins/hook-system.d.ts.map +1 -1
- package/dist/lib/plugins/hook-system.js +32 -2
- package/dist/lib/scheduled-actions/handlers/index.d.ts +1 -0
- package/dist/lib/scheduled-actions/handlers/index.d.ts.map +1 -1
- package/dist/lib/scheduled-actions/handlers/index.js +3 -1
- package/dist/lib/scheduled-actions/handlers/security-notification.d.ts +26 -0
- package/dist/lib/scheduled-actions/handlers/security-notification.d.ts.map +1 -0
- package/dist/lib/scheduled-actions/handlers/security-notification.js +54 -0
- package/dist/lib/selectors/core-selectors.d.ts +12 -0
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.d.ts +12 -0
- package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/auth.selectors.js +14 -1
- package/dist/lib/selectors/selectors.d.ts +24 -0
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/lib/services/api-docs.service.d.ts +5 -1
- package/dist/lib/services/api-docs.service.d.ts.map +1 -1
- package/dist/lib/services/api-presets.service.d.ts +6 -1
- package/dist/lib/services/api-presets.service.d.ts.map +1 -1
- package/dist/lib/services/feature.service.d.ts +58 -4
- package/dist/lib/services/feature.service.d.ts.map +1 -1
- package/dist/lib/services/generic-entity.service.d.ts.map +1 -1
- package/dist/lib/services/generic-entity.service.js +16 -32
- package/dist/lib/services/membership.service.d.ts +10 -2
- package/dist/lib/services/membership.service.d.ts.map +1 -1
- package/dist/lib/services/membership.service.js +37 -16
- package/dist/lib/services/permission.service.d.ts +10 -4
- package/dist/lib/services/permission.service.d.ts.map +1 -1
- package/dist/lib/services/plugin.service.d.ts +1 -1
- package/dist/lib/services/plugin.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.d.ts.map +1 -1
- package/dist/lib/services/subscription.service.js +2 -1
- package/dist/lib/services/team-member.service.d.ts +15 -3
- package/dist/lib/services/team-member.service.d.ts.map +1 -1
- package/dist/lib/services/team-member.service.js +27 -6
- package/dist/lib/services/team.service.d.ts.map +1 -1
- package/dist/lib/teams/permissions.d.ts +3 -1
- package/dist/lib/teams/permissions.d.ts.map +1 -1
- package/dist/lib/teams/permissions.js +6 -0
- package/dist/lib/teams/schema.d.ts.map +1 -1
- package/dist/lib/teams/schema.js +3 -0
- package/dist/lib/template-resolver.d.ts +3 -3
- package/dist/lib/theme/forced-theme.d.ts +34 -0
- package/dist/lib/theme/forced-theme.d.ts.map +1 -0
- package/dist/lib/theme/forced-theme.js +27 -0
- package/dist/lib/theme/get-default-theme-mode.d.ts +3 -0
- package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
- package/dist/lib/theme/get-default-theme-mode.js +5 -3
- package/dist/lib/utils/cors.d.ts +13 -0
- package/dist/lib/utils/cors.d.ts.map +1 -1
- package/dist/lib/utils/cors.js +20 -0
- package/dist/messages/de/auth.json +25 -2
- package/dist/messages/de/index.d.ts +83 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/de/index.js +2 -0
- package/dist/messages/de/index.ts +2 -0
- package/dist/messages/de/navigation.json +3 -1
- package/dist/messages/en/auth.json +25 -2
- package/dist/messages/en/index.d.ts +83 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/en/index.js +2 -0
- package/dist/messages/en/index.ts +2 -0
- package/dist/messages/en/navigation.json +3 -1
- package/dist/messages/es/auth.json +25 -2
- package/dist/messages/es/index.d.ts +83 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/es/index.js +2 -0
- package/dist/messages/es/index.ts +2 -0
- package/dist/messages/es/navigation.json +3 -1
- package/dist/messages/fr/auth.json +25 -2
- package/dist/messages/fr/index.d.ts +83 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/fr/index.js +2 -0
- package/dist/messages/fr/index.ts +2 -0
- package/dist/messages/fr/navigation.json +3 -1
- package/dist/messages/it/auth.json +25 -2
- package/dist/messages/it/index.d.ts +83 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/it/index.js +2 -0
- package/dist/messages/it/index.ts +2 -0
- package/dist/messages/it/navigation.json +3 -1
- package/dist/messages/pt/auth.json +25 -2
- package/dist/messages/pt/index.d.ts +83 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/messages/pt/index.js +2 -0
- package/dist/messages/pt/index.ts +2 -0
- package/dist/messages/pt/navigation.json +3 -1
- package/dist/migrations/005_api_audit_log.sql +2 -1
- package/dist/migrations/025_api_audit_log_nullable_api_key.sql +12 -0
- package/dist/migrations/026_login_events.sql +91 -0
- package/dist/migrations/027_rls_bypass_developer_and_system_admin_team.sql +197 -0
- package/dist/nextspark-registries.d.ts +580 -236
- package/dist/providers/DashboardProviders.d.ts +12 -3
- package/dist/providers/DashboardProviders.d.ts.map +1 -1
- package/dist/providers/DashboardProviders.js +6 -2
- package/dist/providers/theme-provider.d.ts +19 -2
- package/dist/providers/theme-provider.d.ts.map +1 -1
- package/dist/providers/theme-provider.js +6 -2
- package/dist/templates/app/(auth)/signup/page.tsx +8 -0
- package/dist/templates/app/(public)/[...slug]/page.tsx +9 -14
- package/dist/templates/app/api/auth/[...all]/route.ts +23 -1
- package/dist/templates/app/api/health/route.ts +4 -2
- package/dist/templates/app/api/internal/user-metadata/route.ts +5 -3
- package/dist/templates/app/api/mcp/route.ts +4 -1
- package/dist/templates/app/api/superadmin/subscriptions/route.ts +2 -1
- package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +4 -3
- package/dist/templates/app/api/superadmin/users/[userId]/route.ts +10 -3
- package/dist/templates/app/api/v1/api-keys/[id]/route.ts +50 -71
- package/dist/templates/app/api/v1/api-keys/route.ts +21 -43
- package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +14 -14
- package/dist/templates/app/api/v1/billing/cancel/route.ts +7 -6
- package/dist/templates/app/api/v1/billing/change-plan/route.ts +5 -4
- package/dist/templates/app/api/v1/billing/check-action/route.ts +6 -4
- package/dist/templates/app/api/v1/billing/checkout/route.ts +7 -5
- package/dist/templates/app/api/v1/billing/plans/route.ts +8 -12
- package/dist/templates/app/api/v1/billing/portal/route.ts +7 -5
- package/dist/templates/app/api/v1/billing/webhooks/polar/route.ts +1 -1
- package/dist/templates/app/api/v1/devtools/blocks/route.ts +5 -4
- package/dist/templates/app/api/v1/devtools/features/route.ts +5 -4
- package/dist/templates/app/api/v1/devtools/flows/route.ts +5 -4
- package/dist/templates/app/api/v1/devtools/scheduled-actions/route.ts +9 -7
- package/dist/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +5 -4
- package/dist/templates/app/api/v1/devtools/testing/route.ts +5 -4
- package/dist/templates/app/api/v1/media/[id]/route.ts +13 -25
- package/dist/templates/app/api/v1/media/[id]/tags/route.ts +17 -25
- package/dist/templates/app/api/v1/media/check-duplicates/route.ts +5 -7
- package/dist/templates/app/api/v1/media/route.ts +5 -9
- package/dist/templates/app/api/v1/media/upload/route.ts +9 -21
- package/dist/templates/app/api/v1/media-tags/route.ts +9 -13
- package/dist/templates/app/api/v1/patterns/[id]/usages/route.ts +11 -19
- package/dist/templates/app/api/v1/post-categories/[id]/route.ts +9 -7
- package/dist/templates/app/api/v1/post-categories/route.ts +5 -4
- package/dist/templates/app/api/v1/team-invitations/[token]/accept/route.ts +16 -18
- package/dist/templates/app/api/v1/team-invitations/[token]/decline/route.ts +15 -17
- package/dist/templates/app/api/v1/team-invitations/[token]/route.ts +8 -8
- package/dist/templates/app/api/v1/team-invitations/route.ts +9 -11
- package/dist/templates/app/api/v1/teams/[teamId]/invitations/route.ts +41 -32
- package/dist/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +15 -16
- package/dist/templates/app/api/v1/teams/[teamId]/invoices/route.ts +14 -15
- package/dist/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +32 -36
- package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +33 -33
- package/dist/templates/app/api/v1/teams/[teamId]/route.ts +35 -41
- package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +5 -3
- package/dist/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +10 -6
- package/dist/templates/app/api/v1/teams/route.ts +33 -27
- package/dist/templates/app/api/v1/teams/switch/route.ts +11 -13
- package/dist/templates/app/api/v1/theme/[...path]/route.ts +23 -2
- package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +32 -77
- package/dist/templates/app/api/v1/users/[id]/route.ts +35 -68
- package/dist/templates/app/api/v1/users/route.ts +21 -25
- package/dist/templates/app/dashboard/layout.tsx +2 -6
- package/dist/templates/app/layout.ppr.tsx +15 -15
- package/dist/templates/app/layout.tsx +46 -20
- package/dist/templates/contents/themes/starter/config/app.config.ts +19 -0
- package/dist/templates/contents/themes/starter/config/theme.config.ts +6 -0
- package/dist/templates/contents/themes/starter/styles/globals.css +6 -2
- package/dist/templates/proxy.ts +46 -10
- package/dist/templates/tsconfig.json +4 -0
- package/dist/types/theme.d.ts +9 -0
- package/dist/types/theme.d.ts.map +1 -1
- package/migrations/005_api_audit_log.sql +2 -1
- package/migrations/025_api_audit_log_nullable_api_key.sql +12 -0
- package/migrations/026_login_events.sql +91 -0
- package/migrations/027_rls_bypass_developer_and_system_admin_team.sql +197 -0
- package/package.json +14 -11
- package/scripts/build/registry/__tests__/scope-registry.test.mjs +18 -0
- package/scripts/build/registry/generators/scope-registry.mjs +9 -2
- package/templates/app/(auth)/signup/page.tsx +8 -0
- package/templates/app/(public)/[...slug]/page.tsx +9 -14
- package/templates/app/api/auth/[...all]/route.ts +23 -1
- package/templates/app/api/health/route.ts +4 -2
- package/templates/app/api/internal/user-metadata/route.ts +5 -3
- package/templates/app/api/mcp/route.ts +4 -1
- package/templates/app/api/superadmin/subscriptions/route.ts +2 -1
- package/templates/app/api/superadmin/teams/[teamId]/route.ts +4 -3
- package/templates/app/api/superadmin/users/[userId]/route.ts +10 -3
- package/templates/app/api/v1/api-keys/[id]/route.ts +50 -71
- package/templates/app/api/v1/api-keys/route.ts +21 -43
- package/templates/app/api/v1/auth/signup-with-invite/route.ts +14 -14
- package/templates/app/api/v1/billing/cancel/route.ts +7 -6
- package/templates/app/api/v1/billing/change-plan/route.ts +5 -4
- package/templates/app/api/v1/billing/check-action/route.ts +6 -4
- package/templates/app/api/v1/billing/checkout/route.ts +7 -5
- package/templates/app/api/v1/billing/plans/route.ts +8 -12
- package/templates/app/api/v1/billing/portal/route.ts +7 -5
- package/templates/app/api/v1/billing/webhooks/polar/route.ts +1 -1
- package/templates/app/api/v1/devtools/blocks/route.ts +5 -4
- package/templates/app/api/v1/devtools/features/route.ts +5 -4
- package/templates/app/api/v1/devtools/flows/route.ts +5 -4
- package/templates/app/api/v1/devtools/scheduled-actions/route.ts +9 -7
- package/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +5 -4
- package/templates/app/api/v1/devtools/testing/route.ts +5 -4
- package/templates/app/api/v1/media/[id]/route.ts +13 -25
- package/templates/app/api/v1/media/[id]/tags/route.ts +17 -25
- package/templates/app/api/v1/media/check-duplicates/route.ts +5 -7
- package/templates/app/api/v1/media/route.ts +5 -9
- package/templates/app/api/v1/media/upload/route.ts +9 -21
- package/templates/app/api/v1/media-tags/route.ts +9 -13
- package/templates/app/api/v1/patterns/[id]/usages/route.ts +11 -19
- package/templates/app/api/v1/post-categories/[id]/route.ts +9 -7
- package/templates/app/api/v1/post-categories/route.ts +5 -4
- package/templates/app/api/v1/team-invitations/[token]/accept/route.ts +16 -18
- package/templates/app/api/v1/team-invitations/[token]/decline/route.ts +15 -17
- package/templates/app/api/v1/team-invitations/[token]/route.ts +8 -8
- package/templates/app/api/v1/team-invitations/route.ts +9 -11
- package/templates/app/api/v1/teams/[teamId]/invitations/route.ts +41 -32
- package/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +15 -16
- package/templates/app/api/v1/teams/[teamId]/invoices/route.ts +14 -15
- package/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +32 -36
- package/templates/app/api/v1/teams/[teamId]/members/route.ts +33 -33
- package/templates/app/api/v1/teams/[teamId]/route.ts +35 -41
- package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +5 -3
- package/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +10 -6
- package/templates/app/api/v1/teams/route.ts +33 -27
- package/templates/app/api/v1/teams/switch/route.ts +11 -13
- package/templates/app/api/v1/theme/[...path]/route.ts +23 -2
- package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +32 -77
- package/templates/app/api/v1/users/[id]/route.ts +35 -68
- package/templates/app/api/v1/users/route.ts +21 -25
- package/templates/app/dashboard/layout.tsx +2 -6
- package/templates/app/layout.ppr.tsx +15 -15
- package/templates/app/layout.tsx +46 -20
- package/templates/contents/themes/starter/config/app.config.ts +19 -0
- package/templates/contents/themes/starter/config/theme.config.ts +6 -0
- package/templates/contents/themes/starter/styles/globals.css +6 -2
- package/templates/proxy.ts +46 -10
- package/templates/tsconfig.json +4 -0
- package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +23 -0
- package/tests/jest/__mocks__/next-server.js +24 -0
- package/dist/components/teams/TeamSwitchModal.d.js +0 -0
- package/dist/components/ui/accordion.d.js +0 -0
- package/dist/components/ui/avatar.d.js +0 -0
- package/dist/components/ui/badge.d.js +0 -0
- package/dist/components/ui/button.d.js +0 -0
- package/dist/components/ui/card.d.js +0 -0
- package/dist/components/ui/dialog.d.js +0 -0
- package/dist/components/ui/dropdown-menu.d.js +0 -0
- package/dist/components/ui/input.d.js +0 -0
- package/dist/components/ui/progress.d.js +0 -0
- package/dist/components/ui/scroll-area.d.js +0 -0
- package/dist/components/ui/select.d.js +0 -0
- package/dist/components/ui/separator.d.js +0 -0
- package/dist/components/ui/table.d.js +0 -0
- package/dist/components/ui/textarea.d.js +0 -0
- package/dist/contexts/TeamContext.d.js +0 -0
- package/dist/hooks/useAuth.d.js +0 -0
- package/dist/hooks/useLastAuthMethod.d.js +0 -0
- package/dist/hooks/useOrigin.d.js +0 -0
- package/dist/lib/api/auth/dual-auth.d.js +0 -0
- package/dist/lib/api/auth.d.js +0 -0
- package/dist/lib/api/cache.d.js +0 -0
- package/dist/lib/api/keys.d.js +0 -0
- package/dist/lib/auth-client.d.js +0 -0
- package/dist/lib/auth-context.d.js +0 -0
- package/dist/lib/auth.d.js +0 -0
- package/dist/lib/billing/config-types.d.js +0 -0
- package/dist/lib/billing/enforcement.d.js +0 -0
- package/dist/lib/billing/helpers.d.js +0 -0
- package/dist/lib/billing/jobs.d.js +0 -0
- package/dist/lib/billing/types.d.js +0 -0
- package/dist/lib/blocks/loader.d.js +0 -0
- package/dist/lib/config/app.config.d.js +0 -0
- package/dist/lib/config/config-loader.d.js +0 -0
- package/dist/lib/config/config-sync.d.js +0 -0
- package/dist/lib/config/config-types.d.js +0 -0
- package/dist/lib/config/config-utils.d.js +0 -0
- package/dist/lib/config/dashboard-types.d.js +0 -0
- package/dist/lib/config/dashboard.config.d.js +0 -0
- package/dist/lib/config/icon-map.d.js +0 -0
- package/dist/lib/config/index.d.js +0 -7
- package/dist/lib/config/nextspark-types.d.js +0 -0
- package/dist/lib/config/roles-merge.d.js +0 -0
- package/dist/lib/config/types.d.js +0 -0
- package/dist/lib/db.d.js +0 -0
- package/dist/lib/email/factory.d.js +0 -0
- package/dist/lib/email/index.d.js +0 -3
- package/dist/lib/email/providers/console.d.js +0 -0
- package/dist/lib/email/providers/resend.d.js +0 -0
- package/dist/lib/email/templates.d.js +0 -0
- package/dist/lib/email/types.d.js +0 -0
- package/dist/lib/entities/types.d.js +0 -0
- package/dist/lib/permissions/system.d.js +0 -0
- package/dist/lib/permissions/types.d.js +0 -0
- package/dist/lib/plugins/hook-system.d.js +0 -0
- package/dist/lib/scheduled-actions/cleanup.d.js +0 -0
- package/dist/lib/scheduled-actions/index.d.js +0 -19
- package/dist/lib/scheduled-actions/initializer.d.js +0 -1
- package/dist/lib/scheduled-actions/processor.d.js +0 -0
- package/dist/lib/scheduled-actions/registry.d.js +0 -0
- package/dist/lib/scheduled-actions/scheduler.d.js +0 -0
- package/dist/lib/scheduled-actions/types.d.js +0 -0
- package/dist/lib/services/api-routes.service.d.js +0 -0
- package/dist/lib/services/entity-type.service.d.js +0 -0
- package/dist/lib/services/index.d.js +0 -40
- package/dist/lib/services/invoice.service.d.js +0 -0
- package/dist/lib/services/membership.service.d.js +0 -0
- package/dist/lib/services/meta.service.d.js +0 -0
- package/dist/lib/services/middleware.service.d.js +0 -0
- package/dist/lib/services/namespace.service.d.js +0 -0
- package/dist/lib/services/permission.service.d.js +0 -0
- package/dist/lib/services/plan.service.d.js +0 -0
- package/dist/lib/services/plugin.service.d.js +0 -0
- package/dist/lib/services/route-handler.service.d.js +0 -0
- package/dist/lib/services/scope.service.d.js +0 -0
- package/dist/lib/services/subscription.service.d.js +0 -0
- package/dist/lib/services/team-member.service.d.js +0 -0
- package/dist/lib/services/team.service.d.js +0 -0
- package/dist/lib/services/theme.service.d.js +0 -0
- package/dist/lib/services/usage.service.d.js +0 -0
- package/dist/lib/services/user-flags.service.d.js +0 -0
- package/dist/lib/services/user.service.d.js +0 -0
- package/dist/lib/teams/helpers.d.js +0 -0
- package/dist/lib/teams/permissions.d.js +0 -0
- package/dist/lib/teams/types.d.js +0 -0
- package/dist/lib/utils/config-merge.d.js +0 -0
- package/dist/lib/utils/file-logger.d.js +0 -0
- package/dist/lib/utils.d.js +0 -0
- package/dist/styles/classes.json +0 -1093
- package/dist/styles/ui.css +0 -2
- package/dist/types/auth.d.js +0 -0
- package/dist/types/blocks.d.js +0 -0
- package/dist/types/meta.types.d.js +0 -0
- package/dist/types/plugin.d.js +0 -0
- package/dist/types/testing.types.d.js +0 -0
- package/dist/types/theme.d.js +0 -0
- package/dist/types/user.types.d.js +0 -0
- package/scripts/build/build-ui-css.mjs +0 -351
- /package/dist/{components/app/layouts/PublicFooter.d.js → lib/auth/security-notifications/types.js} +0 -0
- /package/dist/{components/app/layouts/PublicNavbar.d.js → nextspark-registries.d.js} +0 -0
- /package/dist/{components/app/misc/ThemeToggle.d.js → types/use-intl-react-shim.d.js} +0 -0
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
-- Migration: 027_rls_bypass_developer_and_system_admin_team.sql
|
|
2
|
+
-- Description: Resolve the System Admin Team by a metadata flag instead of a
|
|
3
|
+
-- hardcoded team id, auto-enroll/unenroll developer/superadmin
|
|
4
|
+
-- users via a trigger, and fix 4 RLS policies that hardcoded
|
|
5
|
+
-- their own role check instead of calling can_bypass_rls().
|
|
6
|
+
-- Date: 2026-09-03
|
|
7
|
+
-- Issues: #108, #102
|
|
8
|
+
--
|
|
9
|
+
-- Why both issues in one migration: #102's fix (make a policy call
|
|
10
|
+
-- can_bypass_rls()) only makes 'developer' bypass actually reachable in a
|
|
11
|
+
-- real (non-seeded) deployment once #108's enrollment mechanism exists —
|
|
12
|
+
-- fixing one without the other leaves the combination still broken.
|
|
13
|
+
--
|
|
14
|
+
-- #108 — System Admin Team enrollment:
|
|
15
|
+
-- can_bypass_rls() grants 'developer' a conditional bypass: membership in
|
|
16
|
+
-- the System Admin Team. Nothing ever enrolled anyone into it outside of
|
|
17
|
+
-- 090_sample_data.sql's explicit INSERTs, and the team id was a literal
|
|
18
|
+
-- ('team-nextspark-001') duplicated in this function AND in
|
|
19
|
+
-- dual-auth.ts's SYSTEM_ADMIN_TEAM_ID constant. This migration:
|
|
20
|
+
-- 1. Resolves the System Admin Team by `teams.metadata.systemAdmin =
|
|
21
|
+
-- true` instead of a literal id — 090_sample_data.sql's team already
|
|
22
|
+
-- carries this flag, so seeded deployments keep working unchanged;
|
|
23
|
+
-- a real deployment flags its own team, no code change needed.
|
|
24
|
+
-- 2. Adds a trigger on users(role) that auto-enrolls a user into that
|
|
25
|
+
-- team (as 'owner' for superadmin, 'admin' for developer) when their
|
|
26
|
+
-- role becomes bypass-eligible, and removes the membership when it
|
|
27
|
+
-- stops being eligible. Framework-level (a Postgres trigger fires
|
|
28
|
+
-- regardless of which application code performed the UPDATE) rather
|
|
29
|
+
-- than an app-level hook, because no Server Action in core actually
|
|
30
|
+
-- assigns users.role today — the only code that does lives in
|
|
31
|
+
-- apps/dev, reimplementable by any consumer of this framework.
|
|
32
|
+
-- 3. Backfills existing developer/superadmin users into the team, for
|
|
33
|
+
-- deployments that already have such users predating this trigger.
|
|
34
|
+
-- Deliberately NOT included here (separate, larger concern — see #108):
|
|
35
|
+
-- POST /api/v1/users creating a "half" user (no account/team/subscription
|
|
36
|
+
-- row). That depends on patterns from the not-yet-approved #98 MCP work.
|
|
37
|
+
--
|
|
38
|
+
-- #102 (+ 3 more found while auditing the same pattern) — RLS policies that
|
|
39
|
+
-- hardcoded `role IN ('admin','superadmin')` or `role = 'superadmin'`
|
|
40
|
+
-- instead of calling can_bypass_rls() have drifted from it in both
|
|
41
|
+
-- directions. 'admin' is NOT a valid users.role value (see check_users_role
|
|
42
|
+
-- in 002_auth_tables.sql: only 'member' | 'superadmin' | 'developer'), so
|
|
43
|
+
-- that branch never matched any real row — removing it changes nothing for
|
|
44
|
+
-- existing behavior. All four also silently excluded 'developer', who
|
|
45
|
+
-- can_bypass_rls() already grants conditional bypass everywhere else.
|
|
46
|
+
-- Switching to can_bypass_rls() is a pure widening for 'developer' and an
|
|
47
|
+
-- exact match for 'superadmin' — no regression, only fixes a gap:
|
|
48
|
+
-- - users_metas_owner_or_admin_all (003_user_metas.sql)
|
|
49
|
+
-- - "API key owner or admin can do all" (004_api_key.sql)
|
|
50
|
+
-- - "API logs superadmin can select" (005_api_audit_log.sql)
|
|
51
|
+
-- - "Plans superadmin write" (012_billing_plans.sql)
|
|
52
|
+
|
|
53
|
+
-- ============================================
|
|
54
|
+
-- #108.1 — can_bypass_rls(): resolve System Admin Team by metadata flag
|
|
55
|
+
-- ============================================
|
|
56
|
+
|
|
57
|
+
CREATE OR REPLACE FUNCTION public.can_bypass_rls()
|
|
58
|
+
RETURNS BOOLEAN AS $$
|
|
59
|
+
DECLARE
|
|
60
|
+
current_user_id TEXT;
|
|
61
|
+
user_role TEXT;
|
|
62
|
+
admin_team_id TEXT;
|
|
63
|
+
is_system_admin_member BOOLEAN;
|
|
64
|
+
BEGIN
|
|
65
|
+
current_user_id := public.get_auth_user_id();
|
|
66
|
+
|
|
67
|
+
SELECT role INTO user_role
|
|
68
|
+
FROM public."users"
|
|
69
|
+
WHERE id = current_user_id;
|
|
70
|
+
|
|
71
|
+
IF user_role = 'superadmin' THEN
|
|
72
|
+
RETURN TRUE;
|
|
73
|
+
END IF;
|
|
74
|
+
|
|
75
|
+
IF user_role = 'developer' THEN
|
|
76
|
+
-- The System Admin Team is whichever team has metadata.systemAdmin =
|
|
77
|
+
-- true, not a hardcoded id — each deployment can flag its own team.
|
|
78
|
+
SELECT id INTO admin_team_id
|
|
79
|
+
FROM public."teams"
|
|
80
|
+
WHERE (metadata->>'systemAdmin')::boolean IS TRUE
|
|
81
|
+
LIMIT 1;
|
|
82
|
+
|
|
83
|
+
IF admin_team_id IS NULL THEN
|
|
84
|
+
RETURN FALSE;
|
|
85
|
+
END IF;
|
|
86
|
+
|
|
87
|
+
SELECT EXISTS(
|
|
88
|
+
SELECT 1 FROM public."team_members"
|
|
89
|
+
WHERE "userId" = current_user_id
|
|
90
|
+
AND "teamId" = admin_team_id
|
|
91
|
+
) INTO is_system_admin_member;
|
|
92
|
+
|
|
93
|
+
RETURN is_system_admin_member;
|
|
94
|
+
END IF;
|
|
95
|
+
|
|
96
|
+
RETURN FALSE;
|
|
97
|
+
END;
|
|
98
|
+
$$ LANGUAGE plpgsql STABLE SECURITY DEFINER SET search_path = public;
|
|
99
|
+
|
|
100
|
+
-- ============================================
|
|
101
|
+
-- #108.2 — auto-enroll/unenroll on role change
|
|
102
|
+
-- ============================================
|
|
103
|
+
|
|
104
|
+
CREATE OR REPLACE FUNCTION public.sync_system_admin_team_membership()
|
|
105
|
+
RETURNS TRIGGER
|
|
106
|
+
LANGUAGE plpgsql
|
|
107
|
+
SECURITY DEFINER
|
|
108
|
+
SET search_path = public
|
|
109
|
+
AS $$
|
|
110
|
+
DECLARE
|
|
111
|
+
admin_team_id TEXT;
|
|
112
|
+
new_team_role TEXT;
|
|
113
|
+
BEGIN
|
|
114
|
+
SELECT id INTO admin_team_id
|
|
115
|
+
FROM public."teams"
|
|
116
|
+
WHERE (metadata->>'systemAdmin')::boolean IS TRUE
|
|
117
|
+
LIMIT 1;
|
|
118
|
+
|
|
119
|
+
-- No team flagged as the System Admin Team in this deployment yet —
|
|
120
|
+
-- nothing to enroll into. Not an error: same as no bypass being possible.
|
|
121
|
+
IF admin_team_id IS NULL THEN
|
|
122
|
+
RETURN NEW;
|
|
123
|
+
END IF;
|
|
124
|
+
|
|
125
|
+
IF NEW.role IN ('developer', 'superadmin') THEN
|
|
126
|
+
new_team_role := CASE WHEN NEW.role = 'superadmin' THEN 'owner' ELSE 'admin' END;
|
|
127
|
+
|
|
128
|
+
INSERT INTO public."team_members" ("teamId", "userId", role)
|
|
129
|
+
VALUES (admin_team_id, NEW.id, new_team_role)
|
|
130
|
+
ON CONFLICT ("teamId", "userId") DO UPDATE SET role = EXCLUDED.role;
|
|
131
|
+
|
|
132
|
+
ELSIF TG_OP = 'UPDATE' AND OLD.role IN ('developer', 'superadmin') THEN
|
|
133
|
+
-- Role changed away from a bypass-eligible tier: revoke membership.
|
|
134
|
+
DELETE FROM public."team_members"
|
|
135
|
+
WHERE "teamId" = admin_team_id AND "userId" = NEW.id;
|
|
136
|
+
END IF;
|
|
137
|
+
|
|
138
|
+
RETURN NEW;
|
|
139
|
+
END;
|
|
140
|
+
$$;
|
|
141
|
+
|
|
142
|
+
DROP TRIGGER IF EXISTS trg_sync_system_admin_team_membership ON public."users";
|
|
143
|
+
CREATE TRIGGER trg_sync_system_admin_team_membership
|
|
144
|
+
AFTER INSERT OR UPDATE OF role ON public."users"
|
|
145
|
+
FOR EACH ROW
|
|
146
|
+
EXECUTE FUNCTION public.sync_system_admin_team_membership();
|
|
147
|
+
|
|
148
|
+
-- ============================================
|
|
149
|
+
-- #108.3 — backfill existing developer/superadmin users
|
|
150
|
+
-- ============================================
|
|
151
|
+
|
|
152
|
+
DO $$
|
|
153
|
+
DECLARE
|
|
154
|
+
admin_team_id TEXT;
|
|
155
|
+
BEGIN
|
|
156
|
+
SELECT id INTO admin_team_id
|
|
157
|
+
FROM public."teams"
|
|
158
|
+
WHERE (metadata->>'systemAdmin')::boolean IS TRUE
|
|
159
|
+
LIMIT 1;
|
|
160
|
+
|
|
161
|
+
IF admin_team_id IS NOT NULL THEN
|
|
162
|
+
INSERT INTO public."team_members" ("teamId", "userId", role)
|
|
163
|
+
SELECT admin_team_id, u.id, CASE WHEN u.role = 'superadmin' THEN 'owner' ELSE 'admin' END
|
|
164
|
+
FROM public."users" u
|
|
165
|
+
WHERE u.role IN ('developer', 'superadmin')
|
|
166
|
+
ON CONFLICT ("teamId", "userId") DO UPDATE SET role = EXCLUDED.role;
|
|
167
|
+
END IF;
|
|
168
|
+
END $$;
|
|
169
|
+
|
|
170
|
+
-- ============================================
|
|
171
|
+
-- #102 + siblings — switch drifted policies to can_bypass_rls()
|
|
172
|
+
-- ============================================
|
|
173
|
+
|
|
174
|
+
DROP POLICY IF EXISTS "users_metas_owner_or_admin_all" ON "users_metas";
|
|
175
|
+
CREATE POLICY "users_metas_owner_or_admin_all" ON "users_metas"
|
|
176
|
+
FOR ALL
|
|
177
|
+
TO authenticated
|
|
178
|
+
USING ("userId" = public.get_auth_user_id() OR public.can_bypass_rls())
|
|
179
|
+
WITH CHECK ("userId" = public.get_auth_user_id() OR public.can_bypass_rls());
|
|
180
|
+
|
|
181
|
+
DROP POLICY IF EXISTS "API key owner or admin can do all" ON "api_key";
|
|
182
|
+
CREATE POLICY "API key owner or admin can do all" ON "api_key"
|
|
183
|
+
FOR ALL TO authenticated
|
|
184
|
+
USING ("userId" = public.get_auth_user_id() OR public.can_bypass_rls())
|
|
185
|
+
WITH CHECK ("userId" = public.get_auth_user_id() OR public.can_bypass_rls());
|
|
186
|
+
|
|
187
|
+
DROP POLICY IF EXISTS "API logs superadmin can select" ON "api_audit_log";
|
|
188
|
+
CREATE POLICY "API logs superadmin can select" ON "api_audit_log"
|
|
189
|
+
FOR SELECT TO authenticated
|
|
190
|
+
USING (public.can_bypass_rls());
|
|
191
|
+
|
|
192
|
+
DROP POLICY IF EXISTS "Plans superadmin write" ON public."plans";
|
|
193
|
+
CREATE POLICY "Plans superadmin write"
|
|
194
|
+
ON public."plans"
|
|
195
|
+
FOR ALL TO authenticated
|
|
196
|
+
USING (public.can_bypass_rls())
|
|
197
|
+
WITH CHECK (public.can_bypass_rls());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nextsparkjs/core",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.187",
|
|
4
4
|
"description": "NextSpark - The complete SaaS framework for Next.js",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "NextSpark <hello@nextspark.dev>",
|
|
@@ -50,10 +50,6 @@
|
|
|
50
50
|
},
|
|
51
51
|
"./globals.css": "./globals.css",
|
|
52
52
|
"./theme-styles.css": "./theme-styles.css",
|
|
53
|
-
"./styles/ui.css": {
|
|
54
|
-
"style": "./dist/styles/ui.css",
|
|
55
|
-
"default": "./dist/styles/ui.css"
|
|
56
|
-
},
|
|
57
53
|
"./styles/utilities.css": "./styles/utilities.css",
|
|
58
54
|
"./styles/docs.css": "./styles/docs.css",
|
|
59
55
|
"./lib/middleware": {
|
|
@@ -112,6 +108,14 @@
|
|
|
112
108
|
"types": "./dist/lib/scheduled-actions/index.d.ts",
|
|
113
109
|
"import": "./dist/lib/scheduled-actions/index.js"
|
|
114
110
|
},
|
|
111
|
+
"./lib/scheduled-actions/handlers": {
|
|
112
|
+
"types": "./dist/lib/scheduled-actions/handlers/index.d.ts",
|
|
113
|
+
"import": "./dist/lib/scheduled-actions/handlers/index.js"
|
|
114
|
+
},
|
|
115
|
+
"./lib/auth/security-notifications": {
|
|
116
|
+
"types": "./dist/lib/auth/security-notifications/index.d.ts",
|
|
117
|
+
"import": "./dist/lib/auth/security-notifications/index.js"
|
|
118
|
+
},
|
|
115
119
|
"./lib/permissions": {
|
|
116
120
|
"types": "./dist/lib/permissions/index.d.ts",
|
|
117
121
|
"import": "./dist/lib/permissions/index.js"
|
|
@@ -405,7 +409,7 @@
|
|
|
405
409
|
"@dnd-kit/core": "^6.3.1",
|
|
406
410
|
"@dnd-kit/sortable": "^10.0.0",
|
|
407
411
|
"@dnd-kit/utilities": "^3.2.2",
|
|
408
|
-
"@hookform/resolvers": "^5.
|
|
412
|
+
"@hookform/resolvers": "^5.9.1",
|
|
409
413
|
"@inquirer/prompts": "^7.2.0",
|
|
410
414
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
411
415
|
"@nextsparkjs/ui": "^0.1.0-beta.2",
|
|
@@ -468,21 +472,20 @@
|
|
|
468
472
|
"remark-gfm": "^4.0.1",
|
|
469
473
|
"remark-rehype": "^11.1.2",
|
|
470
474
|
"resend": "^5.0.0",
|
|
471
|
-
"sharp": "^0.
|
|
475
|
+
"sharp": "^0.34.3 || ^0.35.3",
|
|
472
476
|
"shiki": "^3.20.0",
|
|
473
477
|
"sonner": "^2.0.7",
|
|
474
478
|
"stripe": "^18.5.0",
|
|
475
479
|
"tailwind-merge": "^3.3.1",
|
|
476
480
|
"uuid": "^13.0.0",
|
|
477
|
-
"zod": "^4.
|
|
478
|
-
"@nextsparkjs/testing": "0.1.0-beta.
|
|
481
|
+
"zod": "^4.3.6",
|
|
482
|
+
"@nextsparkjs/testing": "0.1.0-beta.187"
|
|
479
483
|
},
|
|
480
484
|
"scripts": {
|
|
481
485
|
"postinstall": "node scripts/postinstall.mjs || true",
|
|
482
|
-
"build": "tsup && pnpm build:dts
|
|
486
|
+
"build": "tsup && pnpm build:dts",
|
|
483
487
|
"build:js": "tsup",
|
|
484
488
|
"build:dts": "tsc -p tsconfig.dts.json || echo '⚠️ DTS generation completed with some type errors (partial coverage)'",
|
|
485
|
-
"build:ui-css": "node scripts/build/build-ui-css.mjs",
|
|
486
489
|
"dev": "tsup --watch",
|
|
487
490
|
"test": "jest",
|
|
488
491
|
"test:watch": "jest --watch",
|
|
@@ -86,3 +86,21 @@ test('is a pure function of its output shape — always emits both SCOPE_CONFIG
|
|
|
86
86
|
assert.match(out, /export const SCOPE_CONFIG: ScopeConfig = \{/)
|
|
87
87
|
assert.match(out, /export const API_CONFIG: ApiConfig = \{/)
|
|
88
88
|
})
|
|
89
|
+
|
|
90
|
+
// Regression for the npm-mode bug: this generator hardcoded the two `@/core/*`
|
|
91
|
+
// type-only imports instead of routing them through convertCorePath() like
|
|
92
|
+
// every sibling generator does, so a scaffolded (non-monorepo) app's tsconfig
|
|
93
|
+
// — which maps `@/*` to its own `./*`, not to core — failed `tsc --noEmit`
|
|
94
|
+
// with TS2307 on both. See https://github.com/NextSpark-js/nextspark/issues/133
|
|
95
|
+
test('monorepo mode (isNpmMode: false or unset): @/core/* type imports are left as-is', () => {
|
|
96
|
+
const out = generateScopeRegistry([], { isNpmMode: false })
|
|
97
|
+
assert.match(out, /import type \{ Permission \} from '@\/core\/lib\/permissions\/types'/)
|
|
98
|
+
assert.match(out, /import type \{ EntityConfig \} from '@\/core\/lib\/entities\/types'/)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('npm mode: @/core/* type imports are converted to @nextsparkjs/core/*, like every sibling generator', () => {
|
|
102
|
+
const out = generateScopeRegistry([], { isNpmMode: true, outputDir: '/project/.nextspark/registries' })
|
|
103
|
+
assert.match(out, /import type \{ Permission \} from '@nextsparkjs\/core\/lib\/permissions\/types'/)
|
|
104
|
+
assert.match(out, /import type \{ EntityConfig \} from '@nextsparkjs\/core\/lib\/entities\/types'/)
|
|
105
|
+
assert.doesNotMatch(out, /from '@\/core\//)
|
|
106
|
+
})
|
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
* Scope Registry Generator
|
|
3
3
|
*
|
|
4
4
|
* Generates scope-registry.ts
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { join } from 'path'
|
|
8
|
+
import { convertCorePath } from '../config.mjs'
|
|
9
|
+
|
|
10
|
+
/**
|
|
5
11
|
*
|
|
6
12
|
* IMPORTANT: unlike most registry generators, the role→scope computation does
|
|
7
13
|
* NOT happen here at generation time. It happens at IMPORT TIME inside the
|
|
@@ -58,6 +64,7 @@ const SCOPE_RESTRICTIONS = {
|
|
|
58
64
|
* @returns {string} Generated TypeScript content
|
|
59
65
|
*/
|
|
60
66
|
export function generateScopeRegistry(entities, config) {
|
|
67
|
+
const outputFilePath = config.outputDir ? join(config.outputDir, 'scope-registry.ts') : 'scope-registry.ts'
|
|
61
68
|
return `/**
|
|
62
69
|
* Auto-generated API Scope Registry
|
|
63
70
|
*
|
|
@@ -76,8 +83,8 @@ export function generateScopeRegistry(entities, config) {
|
|
|
76
83
|
|
|
77
84
|
import { ENTITY_REGISTRY } from './entity-registry'
|
|
78
85
|
import { AVAILABLE_ROLES, PERMISSIONS_BY_ROLE } from './permissions-registry'
|
|
79
|
-
import type { Permission } from '@/core/lib/permissions/types'
|
|
80
|
-
import type { EntityConfig } from '@/core/lib/entities/types'
|
|
86
|
+
import type { Permission } from '${convertCorePath('@/core/lib/permissions/types', outputFilePath, config)}'
|
|
87
|
+
import type { EntityConfig } from '${convertCorePath('@/core/lib/entities/types', outputFilePath, config)}'
|
|
81
88
|
|
|
82
89
|
export interface ScopeConfig {
|
|
83
90
|
base: string[]
|
|
@@ -4,6 +4,7 @@ import { redirect } from 'next/navigation'
|
|
|
4
4
|
import { SignupForm } from '@nextsparkjs/core/components/auth/forms/SignupForm'
|
|
5
5
|
import { getTemplateOrDefault, getMetadataOrDefault } from '@nextsparkjs/core/lib/template-resolver'
|
|
6
6
|
import { AUTH_CONFIG } from '@nextsparkjs/core/lib/config'
|
|
7
|
+
import { resolveAuthMethods } from '@nextsparkjs/core/lib/auth/auth-methods'
|
|
7
8
|
import { TeamService } from '@nextsparkjs/core/lib/services'
|
|
8
9
|
|
|
9
10
|
// This page reads DB state (TeamService.hasGlobal) and redirect()s during render,
|
|
@@ -23,6 +24,13 @@ export const metadata: Metadata = getMetadataOrDefault(
|
|
|
23
24
|
async function SignupPageContent() {
|
|
24
25
|
const registrationMode = AUTH_CONFIG?.registration?.mode ?? 'open'
|
|
25
26
|
|
|
27
|
+
// Passwordless preset (no 'email-password' in auth.methods): the account is
|
|
28
|
+
// created by the first one-time-code sign-in, so there is no password signup
|
|
29
|
+
// form to show — send people to /login instead.
|
|
30
|
+
if (!resolveAuthMethods(AUTH_CONFIG).includes('email-password')) {
|
|
31
|
+
redirect('/login')
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
// In invitation-only mode, allow the first user to register
|
|
27
35
|
// (when no global team exists yet). Subsequent users need invitations.
|
|
28
36
|
if (registrationMode === 'invitation-only') {
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
* 2. Falls back to default PageRenderer if no template
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import { Suspense } from 'react'
|
|
17
16
|
import { notFound } from 'next/navigation'
|
|
18
17
|
import { query } from '@nextsparkjs/core/lib/db'
|
|
19
18
|
import { PageRenderer } from '@nextsparkjs/core/components/public/pageBuilder'
|
|
@@ -249,9 +248,16 @@ export async function generateMetadata({
|
|
|
249
248
|
}
|
|
250
249
|
|
|
251
250
|
/**
|
|
252
|
-
* Main catch-all page
|
|
251
|
+
* Main catch-all page component
|
|
252
|
+
*
|
|
253
|
+
* Not wrapped in Suspense: this route's entire content depends on whether the
|
|
254
|
+
* slug resolves to a published item, so notFound() must be able to run before
|
|
255
|
+
* any part of the response commits to a 200. A Suspense boundary here would
|
|
256
|
+
* let Next.js flush the (null) fallback with a 200 status ahead of the
|
|
257
|
+
* DB-backed lookup, so a later notFound() inside the boundary could no longer
|
|
258
|
+
* change the status code — see #129.
|
|
253
259
|
*/
|
|
254
|
-
async function
|
|
260
|
+
export default async function DynamicPublicPage({
|
|
255
261
|
params,
|
|
256
262
|
searchParams,
|
|
257
263
|
}: PageProps) {
|
|
@@ -378,14 +384,3 @@ async function DynamicPublicPageContent({
|
|
|
378
384
|
// No match found
|
|
379
385
|
notFound()
|
|
380
386
|
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Main catch-all page component — wraps async content in Suspense for PPR compatibility
|
|
384
|
-
*/
|
|
385
|
-
export default function DynamicPublicPage(props: PageProps) {
|
|
386
|
-
return (
|
|
387
|
-
<Suspense fallback={null}>
|
|
388
|
-
<DynamicPublicPageContent {...props} />
|
|
389
|
-
</Suspense>
|
|
390
|
-
)
|
|
391
|
-
}
|
|
@@ -9,6 +9,7 @@ import { TeamService } from "@nextsparkjs/core/lib/services";
|
|
|
9
9
|
import { wrapAuthHandlerWithCors, handleCorsPreflightRequest, addCorsHeaders } from "@nextsparkjs/core/lib/api/helpers";
|
|
10
10
|
import { checkDistributedRateLimit } from "@nextsparkjs/core/lib/api/rate-limit";
|
|
11
11
|
import { withSignupContext } from "@nextsparkjs/core/lib/auth-context";
|
|
12
|
+
import { dispatchSecurityNotificationsForRequest } from "@nextsparkjs/core/lib/auth/security-notifications";
|
|
12
13
|
|
|
13
14
|
const handlers = toNextJsHandler(auth);
|
|
14
15
|
|
|
@@ -181,11 +182,32 @@ export async function POST(req: NextRequest) {
|
|
|
181
182
|
? (req.cookies.get('signup-intent')?.value || undefined)
|
|
182
183
|
: undefined;
|
|
183
184
|
|
|
185
|
+
// Clone the request BEFORE the handler consumes its body. The
|
|
186
|
+
// security-notifications dispatcher (below) needs the original request's
|
|
187
|
+
// headers (UA/IP) and, for change-email, its body (newEmail) — but
|
|
188
|
+
// handlers.POST(req) reads req's body exactly once.
|
|
189
|
+
const securityReq = req.clone() as NextRequest;
|
|
190
|
+
|
|
184
191
|
// Wrap with CORS headers for cross-origin requests (mobile apps, etc.)
|
|
185
|
-
|
|
192
|
+
const response = await wrapAuthHandlerWithCors(
|
|
186
193
|
signupIntent
|
|
187
194
|
? () => withSignupContext({ signupIntent }, () => handlers.POST(req))
|
|
188
195
|
: () => handlers.POST(req),
|
|
189
196
|
req
|
|
190
197
|
);
|
|
198
|
+
|
|
199
|
+
// Built-in security email notifications (issue #75): after a successful
|
|
200
|
+
// sign-in / change-password / change-email, queue the matching security
|
|
201
|
+
// email. Guarded by AUTH_CONFIG.securityNotifications.enabled and wrapped in
|
|
202
|
+
// try/catch — a notification failure must NEVER change the auth response
|
|
203
|
+
// status (the dispatcher is itself best-effort, this is defense in depth).
|
|
204
|
+
if (AUTH_CONFIG.securityNotifications?.enabled) {
|
|
205
|
+
try {
|
|
206
|
+
await dispatchSecurityNotificationsForRequest(securityReq, response);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error("[auth] security-notifications dispatch error:", error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
return response;
|
|
191
213
|
}
|
|
@@ -24,8 +24,10 @@ export const GET = withRateLimitTier(async (request: NextRequest) => {
|
|
|
24
24
|
timestamp: new Date().toISOString(),
|
|
25
25
|
};
|
|
26
26
|
|
|
27
|
-
// Check if caller is authenticated for detailed info
|
|
28
|
-
|
|
27
|
+
// Check if caller is authenticated for detailed info. Public endpoint: any
|
|
28
|
+
// valid API key (whatever its scopes) may see the detailed status, so the
|
|
29
|
+
// scope-agnostic opt-out is explicit here (#93).
|
|
30
|
+
const authResult = await authenticateRequest(request, { allowAnyScope: true });
|
|
29
31
|
const isAuthenticated = authResult.success && authResult.user;
|
|
30
32
|
|
|
31
33
|
if (!isAuthenticated) {
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { NextRequest, NextResponse } from 'next/server'
|
|
2
2
|
import { MetaService } from '@nextsparkjs/core/lib/services/meta.service'
|
|
3
3
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
4
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
4
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
5
5
|
|
|
6
6
|
// Endpoint interno para crear metadata default después del signup
|
|
7
7
|
export const POST = withRateLimitTier(async (req: NextRequest) => {
|
|
8
8
|
try {
|
|
9
|
-
|
|
9
|
+
// The API-key scope is declared at the entry point, which fails closed
|
|
10
|
+
// for keys that lack it (#93).
|
|
11
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:write' })
|
|
10
12
|
if (!authResult.success || !authResult.user) {
|
|
11
|
-
return
|
|
13
|
+
return createAuthFailureResponse(authResult)
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
const body = await req.json()
|
|
@@ -106,7 +106,10 @@ async function handleMcpPost(request: NextRequest): Promise<NextResponse> {
|
|
|
106
106
|
return jsonRpcError(403, -32000, 'Origin not allowed')
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
|
|
109
|
+
// Transport-level auth only: per-tool scopes (`<entity>:read/write/delete`)
|
|
110
|
+
// are enforced by the generic entity handlers the executor invokes for each
|
|
111
|
+
// tool call, so this entry point accepts any valid key explicitly (#93).
|
|
112
|
+
const authResult = await authenticateRequest(request, { allowAnyScope: true })
|
|
110
113
|
if (!authResult.success || authResult.type !== 'api-key' || !authResult.user) {
|
|
111
114
|
return jsonRpcError(401, -32001, API_KEY_HELP)
|
|
112
115
|
}
|
|
@@ -230,6 +230,7 @@ export const GET = withRateLimitTier(async (request: NextRequest) => {
|
|
|
230
230
|
const totalPages = Math.ceil(total / limit);
|
|
231
231
|
|
|
232
232
|
// Format subscriptions
|
|
233
|
+
const billingGateway = await getBillingGateway()
|
|
233
234
|
const subscriptions = subscriptionsResult.map(sub => ({
|
|
234
235
|
id: sub.id,
|
|
235
236
|
team: {
|
|
@@ -257,7 +258,7 @@ export const GET = withRateLimitTier(async (request: NextRequest) => {
|
|
|
257
258
|
cancelAtPeriodEnd: sub.cancelAtPeriodEnd,
|
|
258
259
|
externalSubscriptionId: sub.externalSubscriptionId,
|
|
259
260
|
paymentProvider: sub.paymentProvider,
|
|
260
|
-
providerDashboardUrl:
|
|
261
|
+
providerDashboardUrl: billingGateway.getSubscriptionDashboardUrl(sub.externalSubscriptionId),
|
|
261
262
|
createdAt: sub.createdAt
|
|
262
263
|
}));
|
|
263
264
|
|
|
@@ -204,6 +204,7 @@ export const GET = withRateLimitTier(async (
|
|
|
204
204
|
const subscription = subscriptionResult[0] || null;
|
|
205
205
|
|
|
206
206
|
// Prepare response data
|
|
207
|
+
const billingGateway = subscription ? await getBillingGateway() : null
|
|
207
208
|
const responseData = {
|
|
208
209
|
team: {
|
|
209
210
|
id: team.id,
|
|
@@ -225,7 +226,7 @@ export const GET = withRateLimitTier(async (
|
|
|
225
226
|
role: member.role,
|
|
226
227
|
joinedAt: member.joinedAt
|
|
227
228
|
})),
|
|
228
|
-
subscription: subscription ? {
|
|
229
|
+
subscription: subscription && billingGateway ? {
|
|
229
230
|
id: subscription.id,
|
|
230
231
|
plan: {
|
|
231
232
|
id: subscription.planId,
|
|
@@ -246,8 +247,8 @@ export const GET = withRateLimitTier(async (
|
|
|
246
247
|
externalSubscriptionId: subscription.externalSubscriptionId,
|
|
247
248
|
externalCustomerId: subscription.externalCustomerId,
|
|
248
249
|
paymentProvider: subscription.paymentProvider,
|
|
249
|
-
providerName:
|
|
250
|
-
providerDashboardUrl:
|
|
250
|
+
providerName: billingGateway.getProviderName(),
|
|
251
|
+
providerDashboardUrl: billingGateway.getSubscriptionDashboardUrl(subscription.externalSubscriptionId),
|
|
251
252
|
createdAt: subscription.createdAt
|
|
252
253
|
} : null,
|
|
253
254
|
billingHistory: billingEventsResult.map((event) => ({
|
|
@@ -129,11 +129,18 @@ export const GET = withRateLimitTier(async (request: NextRequest, { params }: Ro
|
|
|
129
129
|
ORDER BY "metaKey"
|
|
130
130
|
`;
|
|
131
131
|
|
|
132
|
-
// Execute all queries in parallel
|
|
132
|
+
// Execute all queries in parallel.
|
|
133
|
+
//
|
|
134
|
+
// The team_members queries run on the service (RLS-bypass) pool: team_members
|
|
135
|
+
// has no superadmin/developer bypass policy, so with the acting admin's own
|
|
136
|
+
// id as RLS context the SELECT policy silently ANDs "teams the actor belongs
|
|
137
|
+
// to" on top of WHERE "userId" = $1 and under-reports multi-team users.
|
|
138
|
+
// Authorization is already enforced above (superadmin/developer role check)
|
|
139
|
+
// and the WHERE clause scopes the rows to the subject user.
|
|
133
140
|
const [userResults, teamsResults, countsResults, metasResults] = await Promise.all([
|
|
134
141
|
queryWithRLS(userQuery, [userId], session.user.id) as Promise<UserResult[]>,
|
|
135
|
-
queryWithRLS(teamsQuery, [userId], session.user.id) as Promise<TeamMembershipResult[]>,
|
|
136
|
-
queryWithRLS(countsQuery, [userId], session.user.id) as Promise<{
|
|
142
|
+
queryWithRLS(teamsQuery, [userId], session.user.id, { service: true }) as Promise<TeamMembershipResult[]>,
|
|
143
|
+
queryWithRLS(countsQuery, [userId], session.user.id, { service: true }) as Promise<{
|
|
137
144
|
totalTeams: number;
|
|
138
145
|
ownedTeams: number;
|
|
139
146
|
}[]>,
|