@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
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
handleCorsPreflightRequest,
|
|
29
29
|
addCorsHeaders,
|
|
30
30
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
31
|
-
import { authenticateRequest,
|
|
31
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
32
32
|
import { z } from 'zod'
|
|
33
33
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
34
34
|
|
|
@@ -41,8 +41,8 @@ const metadataValueSchema = z.object({
|
|
|
41
41
|
})
|
|
42
42
|
|
|
43
43
|
// Handle CORS preflight
|
|
44
|
-
export async function OPTIONS() {
|
|
45
|
-
return handleCorsPreflightRequest()
|
|
44
|
+
export async function OPTIONS(request: NextRequest) {
|
|
45
|
+
return handleCorsPreflightRequest(request)
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
/**
|
|
@@ -62,44 +62,29 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
62
62
|
{ params }: { params: Promise<{ id: string; key: string }> }
|
|
63
63
|
): Promise<NextResponse> => {
|
|
64
64
|
try {
|
|
65
|
-
// Authenticate using dual auth
|
|
66
|
-
|
|
65
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
66
|
+
// point, which fails closed for keys that lack it (#93).
|
|
67
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:read' })
|
|
67
68
|
|
|
68
69
|
if (!authResult.success || !authResult.user) {
|
|
69
|
-
return
|
|
70
|
-
createApiError('Authentication required', 401, null, 'AUTHENTICATION_FAILED'),
|
|
71
|
-
{ status: 401 }
|
|
72
|
-
)
|
|
70
|
+
return createAuthFailureResponse(authResult)
|
|
73
71
|
}
|
|
74
72
|
|
|
75
73
|
if (authResult.rateLimitResponse) {
|
|
76
74
|
return authResult.rateLimitResponse as NextResponse
|
|
77
75
|
}
|
|
78
76
|
|
|
79
|
-
// Check required permissions
|
|
80
|
-
const hasPermission =
|
|
81
|
-
authResult.type === 'session' ||
|
|
82
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:read'))
|
|
83
|
-
|
|
84
|
-
if (!hasPermission) {
|
|
85
|
-
const response = createApiError(
|
|
86
|
-
'Insufficient permissions. Admin access required for user metadata.',
|
|
87
|
-
403
|
|
88
|
-
)
|
|
89
|
-
return addCorsHeaders(response)
|
|
90
|
-
}
|
|
91
|
-
|
|
92
77
|
const { id, key } = await params
|
|
93
78
|
|
|
94
79
|
// Validate parameters
|
|
95
80
|
if (!id || id.trim() === '') {
|
|
96
81
|
const response = createApiError('User ID is required', 400, null, 'MISSING_USER_ID')
|
|
97
|
-
return addCorsHeaders(response)
|
|
82
|
+
return addCorsHeaders(response, req)
|
|
98
83
|
}
|
|
99
84
|
|
|
100
85
|
if (!key || key.trim() === '') {
|
|
101
86
|
const response = createApiError('Metadata key is required', 400, null, 'MISSING_META_KEY')
|
|
102
|
-
return addCorsHeaders(response)
|
|
87
|
+
return addCorsHeaders(response, req)
|
|
103
88
|
}
|
|
104
89
|
|
|
105
90
|
// Validate key length
|
|
@@ -110,7 +95,7 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
110
95
|
null,
|
|
111
96
|
'INVALID_META_KEY'
|
|
112
97
|
)
|
|
113
|
-
return addCorsHeaders(response)
|
|
98
|
+
return addCorsHeaders(response, req)
|
|
114
99
|
}
|
|
115
100
|
|
|
116
101
|
// Get user metadata value using UserService
|
|
@@ -126,14 +111,14 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
126
111
|
key,
|
|
127
112
|
value: metaValue ?? null,
|
|
128
113
|
})
|
|
129
|
-
return addCorsHeaders(response)
|
|
114
|
+
return addCorsHeaders(response, req)
|
|
130
115
|
} catch (error) {
|
|
131
116
|
const response = createApiError(
|
|
132
117
|
'Failed to fetch user metadata',
|
|
133
118
|
500,
|
|
134
119
|
error instanceof Error ? error.message : undefined
|
|
135
120
|
)
|
|
136
|
-
return addCorsHeaders(response)
|
|
121
|
+
return addCorsHeaders(response, req)
|
|
137
122
|
}
|
|
138
123
|
}), 'read');
|
|
139
124
|
|
|
@@ -159,44 +144,29 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
159
144
|
{ params }: { params: Promise<{ id: string; key: string }> }
|
|
160
145
|
): Promise<NextResponse> => {
|
|
161
146
|
try {
|
|
162
|
-
// Authenticate using dual auth
|
|
163
|
-
|
|
147
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
148
|
+
// point, which fails closed for keys that lack it (#93).
|
|
149
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:write' })
|
|
164
150
|
|
|
165
151
|
if (!authResult.success || !authResult.user) {
|
|
166
|
-
return
|
|
167
|
-
createApiError('Authentication required', 401, null, 'AUTHENTICATION_FAILED'),
|
|
168
|
-
{ status: 401 }
|
|
169
|
-
)
|
|
152
|
+
return createAuthFailureResponse(authResult)
|
|
170
153
|
}
|
|
171
154
|
|
|
172
155
|
if (authResult.rateLimitResponse) {
|
|
173
156
|
return authResult.rateLimitResponse as NextResponse
|
|
174
157
|
}
|
|
175
158
|
|
|
176
|
-
// Check required permissions
|
|
177
|
-
const hasPermission =
|
|
178
|
-
authResult.type === 'session' ||
|
|
179
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:write'))
|
|
180
|
-
|
|
181
|
-
if (!hasPermission) {
|
|
182
|
-
const response = createApiError(
|
|
183
|
-
'Insufficient permissions. Admin access required for user metadata.',
|
|
184
|
-
403
|
|
185
|
-
)
|
|
186
|
-
return addCorsHeaders(response)
|
|
187
|
-
}
|
|
188
|
-
|
|
189
159
|
const { id, key } = await params
|
|
190
160
|
|
|
191
161
|
// Validate parameters
|
|
192
162
|
if (!id || id.trim() === '') {
|
|
193
163
|
const response = createApiError('User ID is required', 400, null, 'MISSING_USER_ID')
|
|
194
|
-
return addCorsHeaders(response)
|
|
164
|
+
return addCorsHeaders(response, req)
|
|
195
165
|
}
|
|
196
166
|
|
|
197
167
|
if (!key || key.trim() === '') {
|
|
198
168
|
const response = createApiError('Metadata key is required', 400, null, 'MISSING_META_KEY')
|
|
199
|
-
return addCorsHeaders(response)
|
|
169
|
+
return addCorsHeaders(response, req)
|
|
200
170
|
}
|
|
201
171
|
|
|
202
172
|
// Validate key length
|
|
@@ -207,7 +177,7 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
207
177
|
null,
|
|
208
178
|
'INVALID_META_KEY'
|
|
209
179
|
)
|
|
210
|
-
return addCorsHeaders(response)
|
|
180
|
+
return addCorsHeaders(response, req)
|
|
211
181
|
}
|
|
212
182
|
|
|
213
183
|
// Parse and validate request body
|
|
@@ -223,7 +193,7 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
223
193
|
null,
|
|
224
194
|
'VALUE_TOO_LARGE'
|
|
225
195
|
)
|
|
226
|
-
return addCorsHeaders(response)
|
|
196
|
+
return addCorsHeaders(response, req)
|
|
227
197
|
}
|
|
228
198
|
|
|
229
199
|
// Update metadata using UserService
|
|
@@ -245,7 +215,7 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
245
215
|
value: validatedData.value,
|
|
246
216
|
updated: true,
|
|
247
217
|
})
|
|
248
|
-
return addCorsHeaders(response)
|
|
218
|
+
return addCorsHeaders(response, req)
|
|
249
219
|
} catch (error) {
|
|
250
220
|
// Handle validation errors
|
|
251
221
|
if (error instanceof z.ZodError) {
|
|
@@ -255,7 +225,7 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
255
225
|
error.issues,
|
|
256
226
|
'VALIDATION_ERROR'
|
|
257
227
|
)
|
|
258
|
-
return addCorsHeaders(response)
|
|
228
|
+
return addCorsHeaders(response, req)
|
|
259
229
|
}
|
|
260
230
|
|
|
261
231
|
const response = createApiError(
|
|
@@ -263,7 +233,7 @@ export const PUT = withRateLimitTier(withApiLogging(async (
|
|
|
263
233
|
500,
|
|
264
234
|
error instanceof Error ? error.message : undefined
|
|
265
235
|
)
|
|
266
|
-
return addCorsHeaders(response)
|
|
236
|
+
return addCorsHeaders(response, req)
|
|
267
237
|
}
|
|
268
238
|
}), 'write');
|
|
269
239
|
|
|
@@ -287,44 +257,29 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
287
257
|
{ params }: { params: Promise<{ id: string; key: string }> }
|
|
288
258
|
): Promise<NextResponse> => {
|
|
289
259
|
try {
|
|
290
|
-
// Authenticate using dual auth
|
|
291
|
-
|
|
260
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
261
|
+
// point, which fails closed for keys that lack it (#93).
|
|
262
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:write' })
|
|
292
263
|
|
|
293
264
|
if (!authResult.success || !authResult.user) {
|
|
294
|
-
return
|
|
295
|
-
createApiError('Authentication required', 401, null, 'AUTHENTICATION_FAILED'),
|
|
296
|
-
{ status: 401 }
|
|
297
|
-
)
|
|
265
|
+
return createAuthFailureResponse(authResult)
|
|
298
266
|
}
|
|
299
267
|
|
|
300
268
|
if (authResult.rateLimitResponse) {
|
|
301
269
|
return authResult.rateLimitResponse as NextResponse
|
|
302
270
|
}
|
|
303
271
|
|
|
304
|
-
// Check required permissions
|
|
305
|
-
const hasPermission =
|
|
306
|
-
authResult.type === 'session' ||
|
|
307
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:write'))
|
|
308
|
-
|
|
309
|
-
if (!hasPermission) {
|
|
310
|
-
const response = createApiError(
|
|
311
|
-
'Insufficient permissions. Admin access required for user metadata.',
|
|
312
|
-
403
|
|
313
|
-
)
|
|
314
|
-
return addCorsHeaders(response)
|
|
315
|
-
}
|
|
316
|
-
|
|
317
272
|
const { id, key } = await params
|
|
318
273
|
|
|
319
274
|
// Validate parameters
|
|
320
275
|
if (!id || id.trim() === '') {
|
|
321
276
|
const response = createApiError('User ID is required', 400, null, 'MISSING_USER_ID')
|
|
322
|
-
return addCorsHeaders(response)
|
|
277
|
+
return addCorsHeaders(response, req)
|
|
323
278
|
}
|
|
324
279
|
|
|
325
280
|
if (!key || key.trim() === '') {
|
|
326
281
|
const response = createApiError('Metadata key is required', 400, null, 'MISSING_META_KEY')
|
|
327
|
-
return addCorsHeaders(response)
|
|
282
|
+
return addCorsHeaders(response, req)
|
|
328
283
|
}
|
|
329
284
|
|
|
330
285
|
// Validate key length
|
|
@@ -335,7 +290,7 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
335
290
|
null,
|
|
336
291
|
'INVALID_META_KEY'
|
|
337
292
|
)
|
|
338
|
-
return addCorsHeaders(response)
|
|
293
|
+
return addCorsHeaders(response, req)
|
|
339
294
|
}
|
|
340
295
|
|
|
341
296
|
// Delete metadata using UserService
|
|
@@ -346,13 +301,13 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
346
301
|
key,
|
|
347
302
|
deleted: true,
|
|
348
303
|
})
|
|
349
|
-
return addCorsHeaders(response)
|
|
304
|
+
return addCorsHeaders(response, req)
|
|
350
305
|
} catch (error) {
|
|
351
306
|
const response = createApiError(
|
|
352
307
|
'Failed to delete user metadata',
|
|
353
308
|
500,
|
|
354
309
|
error instanceof Error ? error.message : undefined
|
|
355
310
|
)
|
|
356
|
-
return addCorsHeaders(response)
|
|
311
|
+
return addCorsHeaders(response, req)
|
|
357
312
|
}
|
|
358
313
|
}), 'write');
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
handleEntityMetadataInResponse,
|
|
12
12
|
processEntityMetadata
|
|
13
13
|
} from '@nextsparkjs/core/lib/api/helpers';
|
|
14
|
-
import { authenticateRequest,
|
|
14
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth';
|
|
15
15
|
import { z } from 'zod';
|
|
16
16
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit';
|
|
17
17
|
|
|
@@ -24,8 +24,8 @@ const updateUserSchema = z.object({
|
|
|
24
24
|
});
|
|
25
25
|
|
|
26
26
|
// Handle CORS preflight
|
|
27
|
-
export async function OPTIONS() {
|
|
28
|
-
return handleCorsPreflightRequest();
|
|
27
|
+
export async function OPTIONS(request: NextRequest) {
|
|
28
|
+
return handleCorsPreflightRequest(request);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// GET /api/v1/users/:id - Get specific user
|
|
@@ -34,35 +34,24 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
34
34
|
{ params }: { params: Promise<{ id: string }> }
|
|
35
35
|
): Promise<NextResponse> => {
|
|
36
36
|
try {
|
|
37
|
-
// Authenticate using dual auth
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
38
|
+
// point, which fails closed for keys that lack it (#93).
|
|
39
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:read' });
|
|
40
|
+
|
|
40
41
|
if (!authResult.success) {
|
|
41
|
-
return
|
|
42
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
43
|
-
{ status: 401 }
|
|
44
|
-
);
|
|
42
|
+
return createAuthFailureResponse(authResult);
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
if (authResult.rateLimitResponse) {
|
|
48
46
|
return authResult.rateLimitResponse as NextResponse;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
// Check required permissions - session users need admin role, API key users need specific scope
|
|
52
|
-
const hasPermission = authResult.type === 'session' ||
|
|
53
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:read'));
|
|
54
|
-
|
|
55
|
-
if (!hasPermission) {
|
|
56
|
-
const response = createApiError('Insufficient permissions. Admin access required for user management.', 403);
|
|
57
|
-
return addCorsHeaders(response);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
49
|
const { id } = await params;
|
|
61
50
|
|
|
62
51
|
// Validate that id is not empty
|
|
63
52
|
if (!id || id.trim() === '') {
|
|
64
53
|
const response = createApiError('User ID or email is required', 400, null, 'MISSING_IDENTIFIER');
|
|
65
|
-
return addCorsHeaders(response);
|
|
54
|
+
return addCorsHeaders(response, req);
|
|
66
55
|
}
|
|
67
56
|
|
|
68
57
|
// Search by ID or email
|
|
@@ -74,7 +63,7 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
74
63
|
|
|
75
64
|
if (!user) {
|
|
76
65
|
const response = createApiError('User not found', 404, null, 'USER_NOT_FOUND');
|
|
77
|
-
return addCorsHeaders(response);
|
|
66
|
+
return addCorsHeaders(response, req);
|
|
78
67
|
}
|
|
79
68
|
|
|
80
69
|
// Handle metadata if requested (usando helper compartido)
|
|
@@ -82,11 +71,11 @@ export const GET = withRateLimitTier(withApiLogging(async (
|
|
|
82
71
|
const userWithMeta = await includeEntityMetadataForSingle('user', user as { id: string }, metaParams, authResult.user!.id);
|
|
83
72
|
|
|
84
73
|
const response = createApiResponse(userWithMeta);
|
|
85
|
-
return addCorsHeaders(response);
|
|
74
|
+
return addCorsHeaders(response, req);
|
|
86
75
|
} catch (error) {
|
|
87
76
|
console.error('Error fetching user:', error);
|
|
88
77
|
const response = createApiError('Internal server error', 500);
|
|
89
|
-
return addCorsHeaders(response);
|
|
78
|
+
return addCorsHeaders(response, req);
|
|
90
79
|
}
|
|
91
80
|
}), 'read');
|
|
92
81
|
|
|
@@ -96,35 +85,24 @@ export const PATCH = withRateLimitTier(withApiLogging(async (
|
|
|
96
85
|
{ params }: { params: Promise<{ id: string }> }
|
|
97
86
|
): Promise<NextResponse> => {
|
|
98
87
|
try {
|
|
99
|
-
// Authenticate using dual auth
|
|
100
|
-
|
|
101
|
-
|
|
88
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
89
|
+
// point, which fails closed for keys that lack it (#93).
|
|
90
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:write' });
|
|
91
|
+
|
|
102
92
|
if (!authResult.success) {
|
|
103
|
-
return
|
|
104
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
105
|
-
{ status: 401 }
|
|
106
|
-
);
|
|
93
|
+
return createAuthFailureResponse(authResult);
|
|
107
94
|
}
|
|
108
95
|
|
|
109
96
|
if (authResult.rateLimitResponse) {
|
|
110
97
|
return authResult.rateLimitResponse as NextResponse;
|
|
111
98
|
}
|
|
112
99
|
|
|
113
|
-
// Check required permissions - session users need admin role, API key users need specific scope
|
|
114
|
-
const hasPermission = authResult.type === 'session' ||
|
|
115
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:write'));
|
|
116
|
-
|
|
117
|
-
if (!hasPermission) {
|
|
118
|
-
const response = createApiError('Insufficient permissions. Admin access required for user management.', 403);
|
|
119
|
-
return addCorsHeaders(response);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
100
|
const { id } = await params;
|
|
123
101
|
|
|
124
102
|
// Validate that id is not empty
|
|
125
103
|
if (!id || id.trim() === '') {
|
|
126
104
|
const response = createApiError('User ID or email is required', 400, null, 'MISSING_IDENTIFIER');
|
|
127
|
-
return addCorsHeaders(response);
|
|
105
|
+
return addCorsHeaders(response, req);
|
|
128
106
|
}
|
|
129
107
|
|
|
130
108
|
const body = await req.json();
|
|
@@ -162,7 +140,7 @@ export const PATCH = withRateLimitTier(withApiLogging(async (
|
|
|
162
140
|
|
|
163
141
|
if (!hasEntityFieldsToUpdate && !hasMetadataToUpdate) {
|
|
164
142
|
const response = createApiError('No fields to update', 400, null, 'NO_FIELDS');
|
|
165
|
-
return addCorsHeaders(response);
|
|
143
|
+
return addCorsHeaders(response, req);
|
|
166
144
|
}
|
|
167
145
|
|
|
168
146
|
let updatedUser;
|
|
@@ -183,7 +161,7 @@ export const PATCH = withRateLimitTier(withApiLogging(async (
|
|
|
183
161
|
|
|
184
162
|
if (result.rows.length === 0) {
|
|
185
163
|
const response = createApiError('User not found', 404, null, 'USER_NOT_FOUND');
|
|
186
|
-
return addCorsHeaders(response);
|
|
164
|
+
return addCorsHeaders(response, req);
|
|
187
165
|
}
|
|
188
166
|
|
|
189
167
|
updatedUser = result.rows[0];
|
|
@@ -197,7 +175,7 @@ export const PATCH = withRateLimitTier(withApiLogging(async (
|
|
|
197
175
|
|
|
198
176
|
if (!user) {
|
|
199
177
|
const response = createApiError('User not found', 404, null, 'USER_NOT_FOUND');
|
|
200
|
-
return addCorsHeaders(response);
|
|
178
|
+
return addCorsHeaders(response, req);
|
|
201
179
|
}
|
|
202
180
|
|
|
203
181
|
updatedUser = user;
|
|
@@ -214,16 +192,16 @@ export const PATCH = withRateLimitTier(withApiLogging(async (
|
|
|
214
192
|
const responseData = await handleEntityMetadataInResponse('user', updatedUser as { id: string }, metadataWasProvided, authResult.user!.id);
|
|
215
193
|
|
|
216
194
|
const response = createApiResponse(responseData);
|
|
217
|
-
return addCorsHeaders(response);
|
|
195
|
+
return addCorsHeaders(response, req);
|
|
218
196
|
} catch (error) {
|
|
219
197
|
if (error instanceof z.ZodError) {
|
|
220
198
|
const response = createApiError('Validation error', 400, error.issues, 'VALIDATION_ERROR');
|
|
221
|
-
return addCorsHeaders(response);
|
|
199
|
+
return addCorsHeaders(response, req);
|
|
222
200
|
}
|
|
223
201
|
|
|
224
202
|
console.error('Error updating user:', error);
|
|
225
203
|
const response = createApiError('Internal server error', 500);
|
|
226
|
-
return addCorsHeaders(response);
|
|
204
|
+
return addCorsHeaders(response, req);
|
|
227
205
|
}
|
|
228
206
|
}), 'write');
|
|
229
207
|
|
|
@@ -233,35 +211,24 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
233
211
|
{ params }: { params: Promise<{ id: string }> }
|
|
234
212
|
): Promise<NextResponse> => {
|
|
235
213
|
try {
|
|
236
|
-
// Authenticate using dual auth
|
|
237
|
-
|
|
238
|
-
|
|
214
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
215
|
+
// point, which fails closed for keys that lack it (#93).
|
|
216
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:delete' });
|
|
217
|
+
|
|
239
218
|
if (!authResult.success) {
|
|
240
|
-
return
|
|
241
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
242
|
-
{ status: 401 }
|
|
243
|
-
);
|
|
219
|
+
return createAuthFailureResponse(authResult);
|
|
244
220
|
}
|
|
245
221
|
|
|
246
222
|
if (authResult.rateLimitResponse) {
|
|
247
223
|
return authResult.rateLimitResponse as NextResponse;
|
|
248
224
|
}
|
|
249
225
|
|
|
250
|
-
// Check required permissions - session users need admin role, API key users need specific scope
|
|
251
|
-
const hasPermission = authResult.type === 'session' ||
|
|
252
|
-
(authResult.type === 'api-key' && hasRequiredScope(authResult, 'users:delete'));
|
|
253
|
-
|
|
254
|
-
if (!hasPermission) {
|
|
255
|
-
const response = createApiError('Insufficient permissions. Admin access required for user management.', 403);
|
|
256
|
-
return addCorsHeaders(response);
|
|
257
|
-
}
|
|
258
|
-
|
|
259
226
|
const { id } = await params;
|
|
260
227
|
|
|
261
228
|
// Validate that id is not empty
|
|
262
229
|
if (!id || id.trim() === '') {
|
|
263
230
|
const response = createApiError('User ID or email is required', 400, null, 'MISSING_IDENTIFIER');
|
|
264
|
-
return addCorsHeaders(response);
|
|
231
|
+
return addCorsHeaders(response, req);
|
|
265
232
|
}
|
|
266
233
|
|
|
267
234
|
// First, get the user to check if it exists and prevent self-deletion
|
|
@@ -273,13 +240,13 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
273
240
|
|
|
274
241
|
if (!targetUser) {
|
|
275
242
|
const response = createApiError('User not found', 404, null, 'USER_NOT_FOUND');
|
|
276
|
-
return addCorsHeaders(response);
|
|
243
|
+
return addCorsHeaders(response, req);
|
|
277
244
|
}
|
|
278
245
|
|
|
279
246
|
// Prevent self-deletion
|
|
280
247
|
if ((targetUser as Record<string, unknown>).id === authResult.user!.id) {
|
|
281
248
|
const response = createApiError('Cannot delete your own account via API', 403, null, 'SELF_DELETE_FORBIDDEN');
|
|
282
|
-
return addCorsHeaders(response);
|
|
249
|
+
return addCorsHeaders(response, req);
|
|
283
250
|
}
|
|
284
251
|
|
|
285
252
|
const result = await mutateWithRLS(
|
|
@@ -290,14 +257,14 @@ export const DELETE = withRateLimitTier(withApiLogging(async (
|
|
|
290
257
|
|
|
291
258
|
if (result.rows.length === 0) {
|
|
292
259
|
const response = createApiError('User not found', 404, null, 'USER_NOT_FOUND');
|
|
293
|
-
return addCorsHeaders(response);
|
|
260
|
+
return addCorsHeaders(response, req);
|
|
294
261
|
}
|
|
295
262
|
|
|
296
263
|
const response = createApiResponse({ deleted: true, id });
|
|
297
|
-
return addCorsHeaders(response);
|
|
264
|
+
return addCorsHeaders(response, req);
|
|
298
265
|
} catch (error) {
|
|
299
266
|
console.error('Error deleting user:', error);
|
|
300
267
|
const response = createApiError('Internal server error', 500);
|
|
301
|
-
return addCorsHeaders(response);
|
|
268
|
+
return addCorsHeaders(response, req);
|
|
302
269
|
}
|
|
303
270
|
}), 'write');
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
handleEntityMetadataInResponse,
|
|
15
15
|
processEntityMetadata
|
|
16
16
|
} from '@nextsparkjs/core/lib/api/helpers';
|
|
17
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth';
|
|
17
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth';
|
|
18
18
|
import { hasAdminPermission } from '@nextsparkjs/core/lib/api/auth/permissions';
|
|
19
19
|
import { z } from 'zod';
|
|
20
20
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit';
|
|
@@ -34,21 +34,19 @@ const createUserSchema = z.object({
|
|
|
34
34
|
|
|
35
35
|
|
|
36
36
|
// Handle CORS preflight
|
|
37
|
-
export async function OPTIONS() {
|
|
38
|
-
return handleCorsPreflightRequest();
|
|
37
|
+
export async function OPTIONS(request: NextRequest) {
|
|
38
|
+
return handleCorsPreflightRequest(request);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// GET /api/v1/users - List users with dual auth
|
|
42
42
|
export const GET = withRateLimitTier(withApiLogging(async (req: NextRequest): Promise<NextResponse> => {
|
|
43
43
|
try {
|
|
44
|
-
// Authenticate using dual auth
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
45
|
+
// point, which fails closed for keys that lack it (#93).
|
|
46
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:read' });
|
|
47
|
+
|
|
47
48
|
if (!authResult.success) {
|
|
48
|
-
return
|
|
49
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
50
|
-
{ status: 401 }
|
|
51
|
-
);
|
|
49
|
+
return createAuthFailureResponse(authResult);
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
if (authResult.rateLimitResponse) {
|
|
@@ -58,7 +56,7 @@ export const GET = withRateLimitTier(withApiLogging(async (req: NextRequest): Pr
|
|
|
58
56
|
// SECURITY: Only superadmins can list all users
|
|
59
57
|
if (!hasAdminPermission(authResult, 'users:read')) {
|
|
60
58
|
const response = createApiError('Insufficient permissions. Superadmin access required.', 403);
|
|
61
|
-
return addCorsHeaders(response);
|
|
59
|
+
return addCorsHeaders(response, req);
|
|
62
60
|
}
|
|
63
61
|
|
|
64
62
|
const metaParams = parseMetaParams(req);
|
|
@@ -103,25 +101,23 @@ export const GET = withRateLimitTier(withApiLogging(async (req: NextRequest): Pr
|
|
|
103
101
|
const usersWithMeta = await includeEntityMetadata('user', users as { id: string }[], metaParams, authResult.user!.id);
|
|
104
102
|
|
|
105
103
|
const response = createApiResponse(usersWithMeta, paginationMeta);
|
|
106
|
-
return addCorsHeaders(response);
|
|
104
|
+
return addCorsHeaders(response, req);
|
|
107
105
|
} catch (error) {
|
|
108
106
|
console.error('Error fetching users:', error);
|
|
109
107
|
const response = createApiError('Internal server error', 500);
|
|
110
|
-
return addCorsHeaders(response);
|
|
108
|
+
return addCorsHeaders(response, req);
|
|
111
109
|
}
|
|
112
110
|
}), 'read');
|
|
113
111
|
|
|
114
112
|
// POST /api/v1/users - Create user with dual auth
|
|
115
113
|
export const POST = withRateLimitTier(withApiLogging(async (req: NextRequest): Promise<NextResponse> => {
|
|
116
114
|
try {
|
|
117
|
-
// Authenticate using dual auth
|
|
118
|
-
|
|
119
|
-
|
|
115
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
116
|
+
// point, which fails closed for keys that lack it (#93).
|
|
117
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'users:write' });
|
|
118
|
+
|
|
120
119
|
if (!authResult.success) {
|
|
121
|
-
return
|
|
122
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
123
|
-
{ status: 401 }
|
|
124
|
-
);
|
|
120
|
+
return createAuthFailureResponse(authResult);
|
|
125
121
|
}
|
|
126
122
|
|
|
127
123
|
if (authResult.rateLimitResponse) {
|
|
@@ -131,7 +127,7 @@ export const POST = withRateLimitTier(withApiLogging(async (req: NextRequest): P
|
|
|
131
127
|
// SECURITY: Only superadmins can create users
|
|
132
128
|
if (!hasAdminPermission(authResult, 'users:write')) {
|
|
133
129
|
const response = createApiError('Insufficient permissions. Superadmin access required.', 403);
|
|
134
|
-
return addCorsHeaders(response);
|
|
130
|
+
return addCorsHeaders(response, req);
|
|
135
131
|
}
|
|
136
132
|
|
|
137
133
|
const body = await req.json();
|
|
@@ -147,7 +143,7 @@ export const POST = withRateLimitTier(withApiLogging(async (req: NextRequest): P
|
|
|
147
143
|
|
|
148
144
|
if (existingUser.length > 0) {
|
|
149
145
|
const response = createApiError('Email already exists', 409, null, 'EMAIL_EXISTS');
|
|
150
|
-
return addCorsHeaders(response);
|
|
146
|
+
return addCorsHeaders(response, req);
|
|
151
147
|
}
|
|
152
148
|
|
|
153
149
|
const newUserId = globalThis.crypto.randomUUID();
|
|
@@ -183,16 +179,16 @@ export const POST = withRateLimitTier(withApiLogging(async (req: NextRequest): P
|
|
|
183
179
|
const responseData = await handleEntityMetadataInResponse('user', createdUser as { id: string }, metadataWasProvided, authResult.user!.id);
|
|
184
180
|
|
|
185
181
|
const response = createApiResponse(responseData, { created: true }, 201);
|
|
186
|
-
return addCorsHeaders(response);
|
|
182
|
+
return addCorsHeaders(response, req);
|
|
187
183
|
} catch (error) {
|
|
188
184
|
if (error instanceof z.ZodError) {
|
|
189
185
|
const response = createApiError('Validation error', 400, error.issues, 'VALIDATION_ERROR');
|
|
190
|
-
return addCorsHeaders(response);
|
|
186
|
+
return addCorsHeaders(response, req);
|
|
191
187
|
}
|
|
192
188
|
|
|
193
189
|
console.error('Error creating user:', error);
|
|
194
190
|
const response = createApiError('Internal server error', 500);
|
|
195
|
-
return addCorsHeaders(response);
|
|
191
|
+
return addCorsHeaders(response, req);
|
|
196
192
|
}
|
|
197
193
|
}), 'write');
|
|
198
194
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { useAuth } from '@nextsparkjs/core/hooks/useAuth'
|
|
4
4
|
import { useRouter } from 'next/navigation'
|
|
5
5
|
import { useEffect, Suspense } from 'react'
|
|
6
|
-
import {
|
|
6
|
+
import { DashboardAuthSkeleton } from '@nextsparkjs/core/components/dashboard/layouts/DashboardAuthSkeleton'
|
|
7
7
|
import { DashboardProviders } from '@nextsparkjs/core/providers/DashboardProviders'
|
|
8
8
|
import { DashboardTranslationPreloader } from '@nextsparkjs/core/lib/i18n/DashboardTranslationPreloader'
|
|
9
9
|
import { TranslationDebugger } from '@nextsparkjs/core/utils/dev/TranslationDebugger'
|
|
@@ -35,11 +35,7 @@ function DashboardLayoutContent({ children }: { children: React.ReactNode }) {
|
|
|
35
35
|
}, [user, isLoading, router])
|
|
36
36
|
|
|
37
37
|
if (isLoading) {
|
|
38
|
-
return
|
|
39
|
-
<div className="min-h-screen flex items-center justify-center">
|
|
40
|
-
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
|
41
|
-
</div>
|
|
42
|
-
)
|
|
38
|
+
return <DashboardAuthSkeleton />
|
|
43
39
|
}
|
|
44
40
|
|
|
45
41
|
if (!user) {
|