@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
|
@@ -11,8 +11,8 @@ import type { TeamInvitation } from '@nextsparkjs/core/lib/teams/types'
|
|
|
11
11
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
12
12
|
|
|
13
13
|
// Handle CORS preflight
|
|
14
|
-
export async function OPTIONS() {
|
|
15
|
-
return handleCorsPreflightRequest()
|
|
14
|
+
export async function OPTIONS(request: NextRequest) {
|
|
15
|
+
return handleCorsPreflightRequest(request)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// GET /api/v1/team-invitations/:token - Get invitation details (public endpoint for preview)
|
|
@@ -24,7 +24,7 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
24
24
|
// Validate that token is not empty
|
|
25
25
|
if (!token || token.trim() === '') {
|
|
26
26
|
const response = createApiError('Invitation token is required', 400, null, 'MISSING_TOKEN')
|
|
27
|
-
return addCorsHeaders(response)
|
|
27
|
+
return addCorsHeaders(response, req)
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
// Get invitation by token with team and inviter details
|
|
@@ -49,14 +49,14 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
49
49
|
|
|
50
50
|
if (!invitation) {
|
|
51
51
|
const response = createApiError('Invitation not found', 404, null, 'INVITATION_NOT_FOUND')
|
|
52
|
-
return addCorsHeaders(response)
|
|
52
|
+
return addCorsHeaders(response, req)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// Check if invitation has expired
|
|
56
56
|
const expiresAt = new Date(invitation.expiresAt)
|
|
57
57
|
if (expiresAt < new Date()) {
|
|
58
58
|
const response = createApiError('Invitation has expired', 410, null, 'INVITATION_EXPIRED')
|
|
59
|
-
return addCorsHeaders(response)
|
|
59
|
+
return addCorsHeaders(response, req)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// Check if invitation is still pending
|
|
@@ -67,7 +67,7 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
67
67
|
null,
|
|
68
68
|
`INVITATION_${invitation.status.toUpperCase()}`
|
|
69
69
|
)
|
|
70
|
-
return addCorsHeaders(response)
|
|
70
|
+
return addCorsHeaders(response, req)
|
|
71
71
|
}
|
|
72
72
|
|
|
73
73
|
// Return public invitation details (don't expose sensitive data)
|
|
@@ -80,11 +80,11 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
const response = createApiResponse(publicDetails)
|
|
83
|
-
return addCorsHeaders(response)
|
|
83
|
+
return addCorsHeaders(response, req)
|
|
84
84
|
} catch (error) {
|
|
85
85
|
console.error('Error fetching invitation:', error)
|
|
86
86
|
const response = createApiError('Internal server error', 500)
|
|
87
|
-
return addCorsHeaders(response)
|
|
87
|
+
return addCorsHeaders(response, req)
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
), 'read');
|
|
@@ -8,27 +8,25 @@ import {
|
|
|
8
8
|
handleCorsPreflightRequest,
|
|
9
9
|
addCorsHeaders,
|
|
10
10
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
11
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
11
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
12
12
|
import { invitationListQuerySchema } from '@nextsparkjs/core/lib/teams/schema'
|
|
13
13
|
import type { TeamInvitation } from '@nextsparkjs/core/lib/teams/types'
|
|
14
14
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
15
15
|
|
|
16
16
|
// Handle CORS preflight
|
|
17
|
-
export async function OPTIONS() {
|
|
18
|
-
return handleCorsPreflightRequest()
|
|
17
|
+
export async function OPTIONS(request: NextRequest) {
|
|
18
|
+
return handleCorsPreflightRequest(request)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// GET /api/v1/team-invitations - List pending invitations for current user
|
|
22
22
|
export const GET = withRateLimitTier(withApiLogging(async (req: NextRequest): Promise<NextResponse> => {
|
|
23
23
|
try {
|
|
24
|
-
// Authenticate using dual auth
|
|
25
|
-
|
|
24
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
25
|
+
// point, which fails closed for keys that lack it (#93).
|
|
26
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'teams:read' })
|
|
26
27
|
|
|
27
28
|
if (!authResult.success) {
|
|
28
|
-
return
|
|
29
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
30
|
-
{ status: 401 }
|
|
31
|
-
)
|
|
29
|
+
return createAuthFailureResponse(authResult)
|
|
32
30
|
}
|
|
33
31
|
|
|
34
32
|
if (authResult.rateLimitResponse) {
|
|
@@ -106,10 +104,10 @@ export const GET = withRateLimitTier(withApiLogging(async (req: NextRequest): Pr
|
|
|
106
104
|
const paginationMeta = createPaginationMeta(page, limit, total)
|
|
107
105
|
|
|
108
106
|
const response = createApiResponse(invitations, paginationMeta)
|
|
109
|
-
return addCorsHeaders(response)
|
|
107
|
+
return addCorsHeaders(response, req)
|
|
110
108
|
} catch (error) {
|
|
111
109
|
console.error('Error fetching invitations:', error)
|
|
112
110
|
const response = createApiError('Internal server error', 500)
|
|
113
|
-
return addCorsHeaders(response)
|
|
111
|
+
return addCorsHeaders(response, req)
|
|
114
112
|
}
|
|
115
113
|
}), 'read');
|
|
@@ -8,28 +8,26 @@ import {
|
|
|
8
8
|
handleCorsPreflightRequest,
|
|
9
9
|
addCorsHeaders,
|
|
10
10
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
11
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
11
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
12
12
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
13
|
-
import {
|
|
13
|
+
import { MembershipService } from '@nextsparkjs/core/lib/services'
|
|
14
14
|
import type { TeamInvitation } from '@nextsparkjs/core/lib/teams/types'
|
|
15
15
|
|
|
16
16
|
// Handle CORS preflight
|
|
17
|
-
export async function OPTIONS() {
|
|
18
|
-
return handleCorsPreflightRequest()
|
|
17
|
+
export async function OPTIONS(request: NextRequest) {
|
|
18
|
+
return handleCorsPreflightRequest(request)
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// GET /api/v1/teams/:teamId/invitations - List pending invitations for a team
|
|
22
22
|
export const GET = withRateLimitTier(withApiLogging(
|
|
23
23
|
async (req: NextRequest, { params }: { params: Promise<{ teamId: string }> }): Promise<NextResponse> => {
|
|
24
24
|
try {
|
|
25
|
-
// Authenticate using dual auth
|
|
26
|
-
|
|
25
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
26
|
+
// point, which fails closed for keys that lack it (#93).
|
|
27
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'teams:read' })
|
|
27
28
|
|
|
28
29
|
if (!authResult.success) {
|
|
29
|
-
return
|
|
30
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
31
|
-
{ status: 401 }
|
|
32
|
-
)
|
|
30
|
+
return createAuthFailureResponse(authResult)
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
if (authResult.rateLimitResponse) {
|
|
@@ -41,15 +39,22 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
41
39
|
// Validate that teamId is not empty
|
|
42
40
|
if (!teamId || teamId.trim() === '') {
|
|
43
41
|
const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
|
|
44
|
-
return addCorsHeaders(response)
|
|
42
|
+
return addCorsHeaders(response, req)
|
|
45
43
|
}
|
|
46
44
|
|
|
47
|
-
//
|
|
48
|
-
|
|
45
|
+
// Listing invitations — including who invited whom, to what role, and
|
|
46
|
+
// when it expires — is gated by the same 'team.members.invite'
|
|
47
|
+
// permission that already protects creating/cancelling one, not bare
|
|
48
|
+
// membership: an invitation's raw acceptance token grants whoever holds
|
|
49
|
+
// it the invitee's role, so a low-privilege member (member/viewer, who
|
|
50
|
+
// typically lack 'team.members.invite') must not be able to read it
|
|
51
|
+
// (see GHSA-rw2j-9mxg-rx98).
|
|
52
|
+
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
53
|
+
const actionResult = membership.canPerformAction('team.members.invite')
|
|
49
54
|
|
|
50
|
-
if (!
|
|
55
|
+
if (!actionResult.allowed) {
|
|
51
56
|
const response = createApiError('Team not found or access denied', 404, null, 'TEAM_NOT_FOUND')
|
|
52
|
-
return addCorsHeaders(response)
|
|
57
|
+
return addCorsHeaders(response, req)
|
|
53
58
|
}
|
|
54
59
|
|
|
55
60
|
// Parse query parameters
|
|
@@ -59,15 +64,21 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
59
64
|
const status = searchParams.get('status') || 'pending'
|
|
60
65
|
const offset = (page - 1) * limit
|
|
61
66
|
|
|
62
|
-
// Fetch team invitations
|
|
67
|
+
// Fetch team invitations — explicit column list, deliberately excluding
|
|
68
|
+
// "token": it is a bearer credential that grants the invitee's role to
|
|
69
|
+
// whoever holds it, and has no business leaving this endpoint at all
|
|
70
|
+
// (see GHSA-rw2j-9mxg-rx98). The accept flow re-derives it server-side
|
|
71
|
+
// from the URL param it already has; nothing legitimate reads it back
|
|
72
|
+
// from this list response.
|
|
63
73
|
const invitations = await queryWithRLS<
|
|
64
|
-
TeamInvitation & {
|
|
74
|
+
Omit<TeamInvitation, 'token'> & {
|
|
65
75
|
inviterName: string | null
|
|
66
76
|
inviterEmail: string
|
|
67
77
|
}
|
|
68
78
|
>(
|
|
69
79
|
`SELECT
|
|
70
|
-
ti
|
|
80
|
+
ti.id, ti."teamId", ti.email, ti.role, ti.status, ti."invitedBy",
|
|
81
|
+
ti."expiresAt", ti."acceptedAt", ti."declinedAt", ti."createdAt", ti."updatedAt",
|
|
71
82
|
u.name as "inviterName",
|
|
72
83
|
u.email as "inviterEmail"
|
|
73
84
|
FROM "team_invitations" ti
|
|
@@ -92,11 +103,11 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
92
103
|
const paginationMeta = createPaginationMeta(page, limit, total)
|
|
93
104
|
|
|
94
105
|
const response = createApiResponse(invitations, paginationMeta)
|
|
95
|
-
return addCorsHeaders(response)
|
|
106
|
+
return addCorsHeaders(response, req)
|
|
96
107
|
} catch (error) {
|
|
97
108
|
console.error('Error fetching team invitations:', error)
|
|
98
109
|
const response = createApiError('Internal server error', 500)
|
|
99
|
-
return addCorsHeaders(response)
|
|
110
|
+
return addCorsHeaders(response, req)
|
|
100
111
|
}
|
|
101
112
|
}
|
|
102
113
|
), 'read')
|
|
@@ -105,14 +116,12 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
105
116
|
export const DELETE = withRateLimitTier(withApiLogging(
|
|
106
117
|
async (req: NextRequest, { params }: { params: Promise<{ teamId: string }> }): Promise<NextResponse> => {
|
|
107
118
|
try {
|
|
108
|
-
// Authenticate using dual auth
|
|
109
|
-
|
|
119
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
120
|
+
// point, which fails closed for keys that lack it (#93).
|
|
121
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'teams:write' })
|
|
110
122
|
|
|
111
123
|
if (!authResult.success) {
|
|
112
|
-
return
|
|
113
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
114
|
-
{ status: 401 }
|
|
115
|
-
)
|
|
124
|
+
return createAuthFailureResponse(authResult)
|
|
116
125
|
}
|
|
117
126
|
|
|
118
127
|
if (authResult.rateLimitResponse) {
|
|
@@ -127,12 +136,12 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
127
136
|
|
|
128
137
|
if (!invitationId) {
|
|
129
138
|
const response = createApiError('Invitation ID is required', 400, null, 'MISSING_INVITATION_ID')
|
|
130
|
-
return addCorsHeaders(response)
|
|
139
|
+
return addCorsHeaders(response, req)
|
|
131
140
|
}
|
|
132
141
|
|
|
133
142
|
// Check if user has permission to manage invitations using MembershipService
|
|
134
143
|
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
135
|
-
const actionResult = membership.canPerformAction('members.invite')
|
|
144
|
+
const actionResult = membership.canPerformAction('team.members.invite')
|
|
136
145
|
|
|
137
146
|
if (!actionResult.allowed) {
|
|
138
147
|
const response = NextResponse.json(
|
|
@@ -144,7 +153,7 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
144
153
|
},
|
|
145
154
|
{ status: 403 }
|
|
146
155
|
)
|
|
147
|
-
return addCorsHeaders(response)
|
|
156
|
+
return addCorsHeaders(response, req)
|
|
148
157
|
}
|
|
149
158
|
|
|
150
159
|
// Update invitation status to 'cancelled' (or delete it)
|
|
@@ -158,15 +167,15 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
158
167
|
|
|
159
168
|
if (result.rowCount === 0) {
|
|
160
169
|
const response = createApiError('Invitation not found or already processed', 404, null, 'INVITATION_NOT_FOUND')
|
|
161
|
-
return addCorsHeaders(response)
|
|
170
|
+
return addCorsHeaders(response, req)
|
|
162
171
|
}
|
|
163
172
|
|
|
164
173
|
const response = createApiResponse({ deleted: true, id: invitationId })
|
|
165
|
-
return addCorsHeaders(response)
|
|
174
|
+
return addCorsHeaders(response, req)
|
|
166
175
|
} catch (error) {
|
|
167
176
|
console.error('Error cancelling invitation:', error)
|
|
168
177
|
const response = createApiError('Internal server error', 500)
|
|
169
|
-
return addCorsHeaders(response)
|
|
178
|
+
return addCorsHeaders(response, req)
|
|
170
179
|
}
|
|
171
180
|
}
|
|
172
181
|
), 'write')
|
|
@@ -7,14 +7,14 @@ import {
|
|
|
7
7
|
handleCorsPreflightRequest,
|
|
8
8
|
addCorsHeaders,
|
|
9
9
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
10
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
10
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
11
11
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
12
12
|
import { MembershipService } from '@nextsparkjs/core/lib/services'
|
|
13
13
|
import type { InvoiceResponse } from '@nextsparkjs/core/lib/validation/invoices'
|
|
14
14
|
|
|
15
15
|
// Handle CORS preflight
|
|
16
|
-
export async function OPTIONS() {
|
|
17
|
-
return handleCorsPreflightRequest()
|
|
16
|
+
export async function OPTIONS(request: NextRequest) {
|
|
17
|
+
return handleCorsPreflightRequest(request)
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
// GET /api/v1/teams/:teamId/invoices/:invoiceNumber - Get single invoice (owner only)
|
|
@@ -24,14 +24,13 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
24
24
|
{ params }: { params: Promise<{ teamId: string; invoiceNumber: string }> }
|
|
25
25
|
): Promise<NextResponse> => {
|
|
26
26
|
try {
|
|
27
|
-
// Authenticate using dual auth (API key OR session)
|
|
28
|
-
|
|
27
|
+
// Authenticate using dual auth (API key OR session); the API-key scope
|
|
28
|
+
// is declared at the entry point, which fails closed for keys that
|
|
29
|
+
// lack it (#93).
|
|
30
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'billing:read' })
|
|
29
31
|
|
|
30
32
|
if (!authResult.success) {
|
|
31
|
-
return
|
|
32
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
33
|
-
{ status: 401 }
|
|
34
|
-
)
|
|
33
|
+
return createAuthFailureResponse(authResult)
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
if (authResult.rateLimitResponse) {
|
|
@@ -43,18 +42,18 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
43
42
|
// Validate that teamId is not empty
|
|
44
43
|
if (!teamId || teamId.trim() === '') {
|
|
45
44
|
const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
|
|
46
|
-
return addCorsHeaders(response)
|
|
45
|
+
return addCorsHeaders(response, req)
|
|
47
46
|
}
|
|
48
47
|
|
|
49
48
|
// Validate that invoiceNumber is not empty
|
|
50
49
|
if (!invoiceNumber || invoiceNumber.trim() === '') {
|
|
51
50
|
const response = createApiError('Invoice number is required', 400, null, 'MISSING_INVOICE_NUMBER')
|
|
52
|
-
return addCorsHeaders(response)
|
|
51
|
+
return addCorsHeaders(response, req)
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
// Check if user has permission to view invoices using MembershipService
|
|
56
55
|
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
57
|
-
const actionResult = membership.canPerformAction('billing.
|
|
56
|
+
const actionResult = membership.canPerformAction('team.billing.view')
|
|
58
57
|
|
|
59
58
|
if (!actionResult.allowed) {
|
|
60
59
|
const response = NextResponse.json(
|
|
@@ -66,7 +65,7 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
66
65
|
},
|
|
67
66
|
{ status: 403 }
|
|
68
67
|
)
|
|
69
|
-
return addCorsHeaders(response)
|
|
68
|
+
return addCorsHeaders(response, req)
|
|
70
69
|
}
|
|
71
70
|
|
|
72
71
|
// Query single invoice by invoiceNumber
|
|
@@ -92,15 +91,15 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
92
91
|
|
|
93
92
|
if (invoices.length === 0) {
|
|
94
93
|
const response = createApiError('Invoice not found', 404, null, 'INVOICE_NOT_FOUND')
|
|
95
|
-
return addCorsHeaders(response)
|
|
94
|
+
return addCorsHeaders(response, req)
|
|
96
95
|
}
|
|
97
96
|
|
|
98
97
|
const response = createApiResponse(invoices[0])
|
|
99
|
-
return addCorsHeaders(response)
|
|
98
|
+
return addCorsHeaders(response, req)
|
|
100
99
|
} catch (error) {
|
|
101
100
|
console.error('Error fetching invoice:', error)
|
|
102
101
|
const response = createApiError('Internal server error', 500)
|
|
103
|
-
return addCorsHeaders(response)
|
|
102
|
+
return addCorsHeaders(response, req)
|
|
104
103
|
}
|
|
105
104
|
}
|
|
106
105
|
), 'read')
|
|
@@ -8,29 +8,28 @@ import {
|
|
|
8
8
|
handleCorsPreflightRequest,
|
|
9
9
|
addCorsHeaders,
|
|
10
10
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
11
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
11
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
12
12
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
13
13
|
import { MembershipService } from '@nextsparkjs/core/lib/services'
|
|
14
14
|
import { invoiceQuerySchema } from '@nextsparkjs/core/lib/validation/invoices'
|
|
15
15
|
import type { InvoiceResponse } from '@nextsparkjs/core/lib/validation/invoices'
|
|
16
16
|
|
|
17
17
|
// Handle CORS preflight
|
|
18
|
-
export async function OPTIONS() {
|
|
19
|
-
return handleCorsPreflightRequest()
|
|
18
|
+
export async function OPTIONS(request: NextRequest) {
|
|
19
|
+
return handleCorsPreflightRequest(request)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// GET /api/v1/teams/:teamId/invoices - List team invoices (owner only)
|
|
23
23
|
export const GET = withRateLimitTier(withApiLogging(
|
|
24
24
|
async (req: NextRequest, { params }: { params: Promise<{ teamId: string }> }): Promise<NextResponse> => {
|
|
25
25
|
try {
|
|
26
|
-
// Authenticate using dual auth (API key OR session)
|
|
27
|
-
|
|
26
|
+
// Authenticate using dual auth (API key OR session); the API-key scope
|
|
27
|
+
// is declared at the entry point, which fails closed for keys that
|
|
28
|
+
// lack it (#93).
|
|
29
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'billing:read' })
|
|
28
30
|
|
|
29
31
|
if (!authResult.success) {
|
|
30
|
-
return
|
|
31
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
32
|
-
{ status: 401 }
|
|
33
|
-
)
|
|
32
|
+
return createAuthFailureResponse(authResult)
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
if (authResult.rateLimitResponse) {
|
|
@@ -42,12 +41,12 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
42
41
|
// Validate that teamId is not empty
|
|
43
42
|
if (!teamId || teamId.trim() === '') {
|
|
44
43
|
const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
|
|
45
|
-
return addCorsHeaders(response)
|
|
44
|
+
return addCorsHeaders(response, req)
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
// Check if user has permission to view invoices using MembershipService
|
|
49
48
|
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
50
|
-
const actionResult = membership.canPerformAction('billing.
|
|
49
|
+
const actionResult = membership.canPerformAction('team.billing.view')
|
|
51
50
|
|
|
52
51
|
if (!actionResult.allowed) {
|
|
53
52
|
const response = NextResponse.json(
|
|
@@ -59,7 +58,7 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
59
58
|
},
|
|
60
59
|
{ status: 403 }
|
|
61
60
|
)
|
|
62
|
-
return addCorsHeaders(response)
|
|
61
|
+
return addCorsHeaders(response, req)
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
// Parse query parameters for pagination
|
|
@@ -110,17 +109,17 @@ export const GET = withRateLimitTier(withApiLogging(
|
|
|
110
109
|
const paginationMeta = createPaginationMeta(page, limit, total)
|
|
111
110
|
|
|
112
111
|
const response = createApiResponse(invoices, paginationMeta)
|
|
113
|
-
return addCorsHeaders(response)
|
|
112
|
+
return addCorsHeaders(response, req)
|
|
114
113
|
} catch (error) {
|
|
115
114
|
if (error instanceof Error && error.name === 'ZodError') {
|
|
116
115
|
const zodError = error as { issues?: unknown[] }
|
|
117
116
|
const response = createApiError('Validation error', 400, zodError.issues, 'VALIDATION_ERROR')
|
|
118
|
-
return addCorsHeaders(response)
|
|
117
|
+
return addCorsHeaders(response, req)
|
|
119
118
|
}
|
|
120
119
|
|
|
121
120
|
console.error('Error fetching invoices:', error)
|
|
122
121
|
const response = createApiError('Internal server error', 500)
|
|
123
|
-
return addCorsHeaders(response)
|
|
122
|
+
return addCorsHeaders(response, req)
|
|
124
123
|
}
|
|
125
124
|
}
|
|
126
125
|
), 'read')
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
handleCorsPreflightRequest,
|
|
8
8
|
addCorsHeaders,
|
|
9
9
|
} from '@nextsparkjs/core/lib/api/helpers'
|
|
10
|
-
import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
10
|
+
import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
|
|
11
11
|
import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
|
|
12
12
|
import { updateMemberRoleSchema } from '@nextsparkjs/core/lib/teams/schema'
|
|
13
13
|
import { MembershipService } from '@nextsparkjs/core/lib/services'
|
|
@@ -15,8 +15,8 @@ import { validateRoleTransition, canManageRole } from '@nextsparkjs/core/lib/tea
|
|
|
15
15
|
import type { TeamMember, TeamRole } from '@nextsparkjs/core/lib/teams/types'
|
|
16
16
|
|
|
17
17
|
// Handle CORS preflight
|
|
18
|
-
export async function OPTIONS() {
|
|
19
|
-
return handleCorsPreflightRequest()
|
|
18
|
+
export async function OPTIONS(request: NextRequest) {
|
|
19
|
+
return handleCorsPreflightRequest(request)
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
// PATCH /api/v1/teams/:teamId/members/:memberId - Update member role
|
|
@@ -26,14 +26,12 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
26
26
|
{ params }: { params: Promise<{ teamId: string; memberId: string }> }
|
|
27
27
|
): Promise<NextResponse> => {
|
|
28
28
|
try {
|
|
29
|
-
// Authenticate using dual auth
|
|
30
|
-
|
|
29
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
30
|
+
// point, which fails closed for keys that lack it (#93).
|
|
31
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'teams:write' })
|
|
31
32
|
|
|
32
33
|
if (!authResult.success) {
|
|
33
|
-
return
|
|
34
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
35
|
-
{ status: 401 }
|
|
36
|
-
)
|
|
34
|
+
return createAuthFailureResponse(authResult)
|
|
37
35
|
}
|
|
38
36
|
|
|
39
37
|
if (authResult.rateLimitResponse) {
|
|
@@ -45,17 +43,17 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
45
43
|
// Validate parameters
|
|
46
44
|
if (!teamId || teamId.trim() === '') {
|
|
47
45
|
const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
|
|
48
|
-
return addCorsHeaders(response)
|
|
46
|
+
return addCorsHeaders(response, req)
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
if (!memberId || memberId.trim() === '') {
|
|
52
50
|
const response = createApiError('Member ID is required', 400, null, 'MISSING_MEMBER_ID')
|
|
53
|
-
return addCorsHeaders(response)
|
|
51
|
+
return addCorsHeaders(response, req)
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
// Check if user has permission to update member roles using MembershipService
|
|
57
55
|
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
58
|
-
const actionResult = membership.canPerformAction('members.update_role')
|
|
56
|
+
const actionResult = membership.canPerformAction('team.members.update_role')
|
|
59
57
|
|
|
60
58
|
if (!actionResult.allowed) {
|
|
61
59
|
const response = NextResponse.json(
|
|
@@ -67,7 +65,7 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
67
65
|
},
|
|
68
66
|
{ status: 403 }
|
|
69
67
|
)
|
|
70
|
-
return addCorsHeaders(response)
|
|
68
|
+
return addCorsHeaders(response, req)
|
|
71
69
|
}
|
|
72
70
|
|
|
73
71
|
// Get user's role for role hierarchy validation
|
|
@@ -82,7 +80,7 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
82
80
|
|
|
83
81
|
if (!targetMember) {
|
|
84
82
|
const response = createApiError('Member not found', 404, null, 'MEMBER_NOT_FOUND')
|
|
85
|
-
return addCorsHeaders(response)
|
|
83
|
+
return addCorsHeaders(response, req)
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
const body = await req.json()
|
|
@@ -93,7 +91,7 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
93
91
|
|
|
94
92
|
if (!transitionValidation.allowed) {
|
|
95
93
|
const response = createApiError(transitionValidation.reason || 'Invalid role transition', 403, null, 'INVALID_ROLE_TRANSITION')
|
|
96
|
-
return addCorsHeaders(response)
|
|
94
|
+
return addCorsHeaders(response, req)
|
|
97
95
|
}
|
|
98
96
|
|
|
99
97
|
// Check if actor can manage the target role
|
|
@@ -104,7 +102,7 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
104
102
|
null,
|
|
105
103
|
'INSUFFICIENT_PERMISSIONS'
|
|
106
104
|
)
|
|
107
|
-
return addCorsHeaders(response)
|
|
105
|
+
return addCorsHeaders(response, req)
|
|
108
106
|
}
|
|
109
107
|
|
|
110
108
|
// Update member role
|
|
@@ -119,7 +117,7 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
119
117
|
|
|
120
118
|
if (result.rows.length === 0) {
|
|
121
119
|
const response = createApiError('Member not found', 404, null, 'MEMBER_NOT_FOUND')
|
|
122
|
-
return addCorsHeaders(response)
|
|
120
|
+
return addCorsHeaders(response, req)
|
|
123
121
|
}
|
|
124
122
|
|
|
125
123
|
// Fetch member with user details
|
|
@@ -143,17 +141,17 @@ export const PATCH = withRateLimitTier(withApiLogging(
|
|
|
143
141
|
)
|
|
144
142
|
|
|
145
143
|
const response = createApiResponse(memberWithUser)
|
|
146
|
-
return addCorsHeaders(response)
|
|
144
|
+
return addCorsHeaders(response, req)
|
|
147
145
|
} catch (error) {
|
|
148
146
|
if (error instanceof Error && error.name === 'ZodError') {
|
|
149
147
|
const zodError = error as { issues?: unknown[] }
|
|
150
148
|
const response = createApiError('Validation error', 400, zodError.issues, 'VALIDATION_ERROR')
|
|
151
|
-
return addCorsHeaders(response)
|
|
149
|
+
return addCorsHeaders(response, req)
|
|
152
150
|
}
|
|
153
151
|
|
|
154
152
|
console.error('Error updating member role:', error)
|
|
155
153
|
const response = createApiError('Internal server error', 500)
|
|
156
|
-
return addCorsHeaders(response)
|
|
154
|
+
return addCorsHeaders(response, req)
|
|
157
155
|
}
|
|
158
156
|
}
|
|
159
157
|
), 'write')
|
|
@@ -165,14 +163,12 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
165
163
|
{ params }: { params: Promise<{ teamId: string; memberId: string }> }
|
|
166
164
|
): Promise<NextResponse> => {
|
|
167
165
|
try {
|
|
168
|
-
// Authenticate using dual auth
|
|
169
|
-
|
|
166
|
+
// Authenticate using dual auth; the API-key scope is declared at the entry
|
|
167
|
+
// point, which fails closed for keys that lack it (#93).
|
|
168
|
+
const authResult = await authenticateRequest(req, { requiredScope: 'teams:write' })
|
|
170
169
|
|
|
171
170
|
if (!authResult.success) {
|
|
172
|
-
return
|
|
173
|
-
{ success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
|
|
174
|
-
{ status: 401 }
|
|
175
|
-
)
|
|
171
|
+
return createAuthFailureResponse(authResult)
|
|
176
172
|
}
|
|
177
173
|
|
|
178
174
|
if (authResult.rateLimitResponse) {
|
|
@@ -184,17 +180,17 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
184
180
|
// Validate parameters
|
|
185
181
|
if (!teamId || teamId.trim() === '') {
|
|
186
182
|
const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
|
|
187
|
-
return addCorsHeaders(response)
|
|
183
|
+
return addCorsHeaders(response, req)
|
|
188
184
|
}
|
|
189
185
|
|
|
190
186
|
if (!memberId || memberId.trim() === '') {
|
|
191
187
|
const response = createApiError('Member ID is required', 400, null, 'MISSING_MEMBER_ID')
|
|
192
|
-
return addCorsHeaders(response)
|
|
188
|
+
return addCorsHeaders(response, req)
|
|
193
189
|
}
|
|
194
190
|
|
|
195
191
|
// Check if user has permission to remove members using MembershipService
|
|
196
192
|
const membership = await MembershipService.get(authResult.user!.id, teamId)
|
|
197
|
-
const actionResult = membership.canPerformAction('members.remove')
|
|
193
|
+
const actionResult = membership.canPerformAction('team.members.remove')
|
|
198
194
|
|
|
199
195
|
if (!actionResult.allowed) {
|
|
200
196
|
const response = NextResponse.json(
|
|
@@ -206,7 +202,7 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
206
202
|
},
|
|
207
203
|
{ status: 403 }
|
|
208
204
|
)
|
|
209
|
-
return addCorsHeaders(response)
|
|
205
|
+
return addCorsHeaders(response, req)
|
|
210
206
|
}
|
|
211
207
|
|
|
212
208
|
// Get user's role for role hierarchy validation
|
|
@@ -221,13 +217,13 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
221
217
|
|
|
222
218
|
if (!targetMember) {
|
|
223
219
|
const response = createApiError('Member not found', 404, null, 'MEMBER_NOT_FOUND')
|
|
224
|
-
return addCorsHeaders(response)
|
|
220
|
+
return addCorsHeaders(response, req)
|
|
225
221
|
}
|
|
226
222
|
|
|
227
223
|
// Cannot remove the owner
|
|
228
224
|
if (targetMember.role === 'owner') {
|
|
229
225
|
const response = createApiError('Cannot remove the team owner', 403, null, 'CANNOT_REMOVE_OWNER')
|
|
230
|
-
return addCorsHeaders(response)
|
|
226
|
+
return addCorsHeaders(response, req)
|
|
231
227
|
}
|
|
232
228
|
|
|
233
229
|
// Check if actor can manage the target role
|
|
@@ -238,7 +234,7 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
238
234
|
null,
|
|
239
235
|
'INSUFFICIENT_PERMISSIONS'
|
|
240
236
|
)
|
|
241
|
-
return addCorsHeaders(response)
|
|
237
|
+
return addCorsHeaders(response, req)
|
|
242
238
|
}
|
|
243
239
|
|
|
244
240
|
// Remove member
|
|
@@ -250,15 +246,15 @@ export const DELETE = withRateLimitTier(withApiLogging(
|
|
|
250
246
|
|
|
251
247
|
if (result.rows.length === 0) {
|
|
252
248
|
const response = createApiError('Member not found', 404, null, 'MEMBER_NOT_FOUND')
|
|
253
|
-
return addCorsHeaders(response)
|
|
249
|
+
return addCorsHeaders(response, req)
|
|
254
250
|
}
|
|
255
251
|
|
|
256
252
|
const response = createApiResponse({ deleted: true, id: memberId })
|
|
257
|
-
return addCorsHeaders(response)
|
|
253
|
+
return addCorsHeaders(response, req)
|
|
258
254
|
} catch (error) {
|
|
259
255
|
console.error('Error removing member:', error)
|
|
260
256
|
const response = createApiError('Internal server error', 500)
|
|
261
|
-
return addCorsHeaders(response)
|
|
257
|
+
return addCorsHeaders(response, req)
|
|
262
258
|
}
|
|
263
259
|
}
|
|
264
260
|
), 'write')
|