@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.
Files changed (518) hide show
  1. package/dist/components/app/guards/DeveloperGuard.d.ts.map +1 -1
  2. package/dist/components/app/guards/DeveloperGuard.js +8 -4
  3. package/dist/components/app/guards/SuperAdminGuard.d.ts.map +1 -1
  4. package/dist/components/app/guards/SuperAdminGuard.js +8 -4
  5. package/dist/components/app/layouts/PublicFooter.d.ts.map +1 -1
  6. package/dist/components/app/layouts/PublicFooter.js +2 -2
  7. package/dist/components/app/layouts/PublicNavbar.d.ts.map +1 -1
  8. package/dist/components/app/layouts/PublicNavbar.js +2 -2
  9. package/dist/components/app/misc/ThemeToggle.d.ts.map +1 -1
  10. package/dist/components/app/misc/ThemeToggle.js +4 -1
  11. package/dist/components/auth/DevKeyring.d.ts.map +1 -1
  12. package/dist/components/auth/DevKeyring.js +10 -2
  13. package/dist/components/auth/SessionCookieRefresher.d.ts +21 -0
  14. package/dist/components/auth/SessionCookieRefresher.d.ts.map +1 -0
  15. package/dist/components/auth/SessionCookieRefresher.js +11 -0
  16. package/dist/components/auth/forms/LoginForm.d.ts.map +1 -1
  17. package/dist/components/auth/forms/LoginForm.js +300 -6
  18. package/dist/components/auth/index.d.ts +1 -0
  19. package/dist/components/auth/index.d.ts.map +1 -1
  20. package/dist/components/auth/index.js +2 -0
  21. package/dist/components/billing/InvoicesTable.d.ts.map +1 -1
  22. package/dist/components/billing/InvoicesTable.js +4 -3
  23. package/dist/components/dashboard/block-editor/dynamic-form.d.ts.map +1 -1
  24. package/dist/components/dashboard/layouts/AuthGuard.d.ts.map +1 -1
  25. package/dist/components/dashboard/layouts/AuthGuard.js +2 -2
  26. package/dist/components/dashboard/layouts/DashboardAuthLayout.d.ts.map +1 -1
  27. package/dist/components/dashboard/layouts/DashboardAuthLayout.js +2 -2
  28. package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts +17 -0
  29. package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts.map +1 -0
  30. package/dist/components/dashboard/layouts/DashboardAuthSkeleton.js +52 -0
  31. package/dist/components/dashboard/layouts/Sidebar.d.ts.map +1 -1
  32. package/dist/components/dashboard/layouts/Sidebar.js +2 -3
  33. package/dist/components/dashboard/layouts/TopNavbar.js +2 -2
  34. package/dist/components/dashboard/layouts/index.d.ts +1 -0
  35. package/dist/components/dashboard/layouts/index.d.ts.map +1 -1
  36. package/dist/components/dashboard/layouts/index.js +2 -0
  37. package/dist/components/devtools/api-explorer/ApiExplorer.js +4 -4
  38. package/dist/components/entities/EntityFieldRenderer.d.ts.map +1 -1
  39. package/dist/components/entities/EntityFieldRenderer.js +3 -0
  40. package/dist/components/entities/EntityTable.d.ts.map +1 -1
  41. package/dist/components/entities/EntityTable.js +2 -1
  42. package/dist/components/entities/wrappers/EntityFormWrapper.d.ts.map +1 -1
  43. package/dist/components/entities/wrappers/EntityFormWrapper.js +7 -2
  44. package/dist/components/patterns/pages/PatternEditPage.d.ts +5 -1
  45. package/dist/components/patterns/pages/PatternEditPage.d.ts.map +1 -1
  46. package/dist/components/patterns/pages/PatternEditPage.js +16 -5
  47. package/dist/components/patterns/pages/PatternsCreatePage.d.ts +2 -1
  48. package/dist/components/patterns/pages/PatternsCreatePage.d.ts.map +1 -1
  49. package/dist/components/patterns/pages/PatternsCreatePage.js +17 -5
  50. package/dist/components/ui/combobox.d.ts +8 -1
  51. package/dist/components/ui/combobox.d.ts.map +1 -1
  52. package/dist/components/ui/combobox.js +37 -44
  53. package/dist/components/ui/country-select.d.ts +3 -1
  54. package/dist/components/ui/country-select.d.ts.map +1 -1
  55. package/dist/components/ui/country-select.js +3 -1
  56. package/dist/components/ui/currency-select.d.ts +3 -1
  57. package/dist/components/ui/currency-select.d.ts.map +1 -1
  58. package/dist/components/ui/currency-select.js +3 -1
  59. package/dist/components/ui/sheet.d.ts +5 -0
  60. package/dist/components/ui/sheet.d.ts.map +1 -1
  61. package/dist/components/ui/sheet.js +46 -26
  62. package/dist/components/ui/timezone-select.d.ts +3 -1
  63. package/dist/components/ui/timezone-select.d.ts.map +1 -1
  64. package/dist/components/ui/timezone-select.js +3 -1
  65. package/dist/contexts/TeamContext.d.ts +6 -0
  66. package/dist/contexts/TeamContext.d.ts.map +1 -1
  67. package/dist/contexts/TeamContext.js +8 -1
  68. package/dist/emails/otp-verification.d.ts.map +1 -1
  69. package/dist/emails/reset-password.d.ts.map +1 -1
  70. package/dist/emails/team-invitation.d.ts.map +1 -1
  71. package/dist/emails/team-invitation.js +3 -2
  72. package/dist/emails/verify-email.d.ts.map +1 -1
  73. package/dist/hooks/index.d.ts +1 -0
  74. package/dist/hooks/index.d.ts.map +1 -1
  75. package/dist/hooks/index.js +1 -0
  76. package/dist/hooks/useAuth.d.ts +29 -0
  77. package/dist/hooks/useAuth.d.ts.map +1 -1
  78. package/dist/hooks/useAuth.js +24 -0
  79. package/dist/hooks/useEnsureUserMetadata.d.ts +22 -0
  80. package/dist/hooks/useEnsureUserMetadata.d.ts.map +1 -1
  81. package/dist/hooks/useEnsureUserMetadata.js +18 -5
  82. package/dist/hooks/useSessionCookieRefresh.d.ts +35 -0
  83. package/dist/hooks/useSessionCookieRefresh.d.ts.map +1 -0
  84. package/dist/hooks/useSessionCookieRefresh.js +49 -0
  85. package/dist/lib/api/api-error.d.ts +3 -1
  86. package/dist/lib/api/api-error.d.ts.map +1 -1
  87. package/dist/lib/api/api-error.js +4 -2
  88. package/dist/lib/api/auth/dual-auth.d.ts +38 -3
  89. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  90. package/dist/lib/api/auth/dual-auth.js +42 -7
  91. package/dist/lib/api/auth/permissions.d.ts +7 -2
  92. package/dist/lib/api/auth/permissions.d.ts.map +1 -1
  93. package/dist/lib/api/auth/permissions.js +2 -2
  94. package/dist/lib/api/auth/scope-policy.d.ts +71 -0
  95. package/dist/lib/api/auth/scope-policy.d.ts.map +1 -0
  96. package/dist/lib/api/auth/scope-policy.js +53 -0
  97. package/dist/lib/api/auth.d.ts +15 -0
  98. package/dist/lib/api/auth.d.ts.map +1 -1
  99. package/dist/lib/api/auth.js +17 -4
  100. package/dist/lib/api/entities.js +2 -1
  101. package/dist/lib/api/entity/audit-log.d.ts +35 -0
  102. package/dist/lib/api/entity/audit-log.d.ts.map +1 -0
  103. package/dist/lib/api/entity/audit-log.js +35 -0
  104. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  105. package/dist/lib/api/entity/generic-handler.js +333 -138
  106. package/dist/lib/api/entity-handler.js +2 -2
  107. package/dist/lib/api/helpers.d.ts +29 -4
  108. package/dist/lib/api/helpers.d.ts.map +1 -1
  109. package/dist/lib/api/helpers.js +30 -6
  110. package/dist/lib/api/keys.d.ts +16 -0
  111. package/dist/lib/api/keys.d.ts.map +1 -1
  112. package/dist/lib/api/keys.js +19 -1
  113. package/dist/lib/api/routes/patterns-usages.d.ts.map +1 -1
  114. package/dist/lib/api/routes/patterns-usages.js +3 -11
  115. package/dist/lib/auth/auth-methods.d.ts +52 -0
  116. package/dist/lib/auth/auth-methods.d.ts.map +1 -0
  117. package/dist/lib/auth/auth-methods.js +63 -0
  118. package/dist/lib/auth/registration-guard-plugin.d.ts.map +1 -1
  119. package/dist/lib/auth/registration-helpers.d.ts +9 -0
  120. package/dist/lib/auth/registration-helpers.d.ts.map +1 -1
  121. package/dist/lib/auth/registration-helpers.js +8 -2
  122. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts +52 -0
  123. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts.map +1 -0
  124. package/dist/lib/auth/security-notifications/device-fingerprint.js +42 -0
  125. package/dist/lib/auth/security-notifications/dispatcher.d.ts +37 -0
  126. package/dist/lib/auth/security-notifications/dispatcher.d.ts.map +1 -0
  127. package/dist/lib/auth/security-notifications/dispatcher.js +157 -0
  128. package/dist/lib/auth/security-notifications/index.d.ts +20 -0
  129. package/dist/lib/auth/security-notifications/index.d.ts.map +1 -0
  130. package/dist/lib/auth/security-notifications/index.js +22 -0
  131. package/dist/lib/auth/security-notifications/registry.d.ts +36 -0
  132. package/dist/lib/auth/security-notifications/registry.d.ts.map +1 -0
  133. package/dist/lib/auth/security-notifications/registry.js +26 -0
  134. package/dist/lib/auth/security-notifications/templates/email-changed.d.ts +12 -0
  135. package/dist/lib/auth/security-notifications/templates/email-changed.d.ts.map +1 -0
  136. package/dist/lib/auth/security-notifications/templates/email-changed.js +43 -0
  137. package/dist/lib/auth/security-notifications/templates/new-device-login.d.ts +7 -0
  138. package/dist/lib/auth/security-notifications/templates/new-device-login.d.ts.map +1 -0
  139. package/dist/lib/auth/security-notifications/templates/new-device-login.js +46 -0
  140. package/dist/lib/auth/security-notifications/templates/password-changed.d.ts +7 -0
  141. package/dist/lib/auth/security-notifications/templates/password-changed.d.ts.map +1 -0
  142. package/dist/lib/auth/security-notifications/templates/password-changed.js +35 -0
  143. package/dist/lib/auth/security-notifications/templates/shared.d.ts +36 -0
  144. package/dist/lib/auth/security-notifications/templates/shared.d.ts.map +1 -0
  145. package/dist/lib/auth/security-notifications/templates/shared.js +68 -0
  146. package/dist/lib/auth/security-notifications/types.d.ts +74 -0
  147. package/dist/lib/auth/security-notifications/types.d.ts.map +1 -0
  148. package/dist/lib/auth/session-config.d.ts +37 -0
  149. package/dist/lib/auth/session-config.d.ts.map +1 -0
  150. package/dist/lib/auth/session-config.js +59 -0
  151. package/dist/lib/auth/session-refresh.d.ts +46 -0
  152. package/dist/lib/auth/session-refresh.d.ts.map +1 -0
  153. package/dist/lib/auth/session-refresh.js +11 -0
  154. package/dist/lib/auth-client.d.ts +1639 -0
  155. package/dist/lib/auth-client.d.ts.map +1 -0
  156. package/dist/lib/auth-client.js +13 -1
  157. package/dist/lib/auth.d.ts.map +1 -1
  158. package/dist/lib/auth.js +45 -11
  159. package/dist/lib/billing/gateways/factory.d.ts +8 -3
  160. package/dist/lib/billing/gateways/factory.d.ts.map +1 -1
  161. package/dist/lib/billing/gateways/factory.js +37 -23
  162. package/dist/lib/billing/stripe-webhook.d.ts.map +1 -1
  163. package/dist/lib/billing/stripe-webhook.js +2 -1
  164. package/dist/lib/config/app.config.d.ts.map +1 -1
  165. package/dist/lib/config/app.config.js +71 -0
  166. package/dist/lib/config/config-sync.d.ts +1 -4
  167. package/dist/lib/config/config-sync.d.ts.map +1 -1
  168. package/dist/lib/config/config-sync.js +6 -2
  169. package/dist/lib/config/types.d.ts +130 -0
  170. package/dist/lib/config/types.d.ts.map +1 -1
  171. package/dist/lib/email/templates.d.ts +3 -3
  172. package/dist/lib/email/templates.d.ts.map +1 -1
  173. package/dist/lib/entities/api-generator.js +5 -5
  174. package/dist/lib/entities/entity-hooks.d.ts +9 -1
  175. package/dist/lib/entities/entity-hooks.d.ts.map +1 -1
  176. package/dist/lib/entities/entity-hooks.js +77 -4
  177. package/dist/lib/entities/schema-generator.d.ts.map +1 -1
  178. package/dist/lib/entities/schema-generator.js +20 -4
  179. package/dist/lib/entities/serialization.d.ts +2 -2
  180. package/dist/lib/entities/serialization.d.ts.map +1 -1
  181. package/dist/lib/entities/serialization.js +3 -2
  182. package/dist/lib/entities/types.d.ts +20 -0
  183. package/dist/lib/entities/types.d.ts.map +1 -1
  184. package/dist/lib/locale.d.ts.map +1 -1
  185. package/dist/lib/locale.js +4 -1
  186. package/dist/lib/mcp/audit.d.ts +8 -4
  187. package/dist/lib/mcp/audit.d.ts.map +1 -1
  188. package/dist/lib/plugins/hook-system.d.ts +13 -0
  189. package/dist/lib/plugins/hook-system.d.ts.map +1 -1
  190. package/dist/lib/plugins/hook-system.js +32 -2
  191. package/dist/lib/scheduled-actions/handlers/index.d.ts +1 -0
  192. package/dist/lib/scheduled-actions/handlers/index.d.ts.map +1 -1
  193. package/dist/lib/scheduled-actions/handlers/index.js +3 -1
  194. package/dist/lib/scheduled-actions/handlers/security-notification.d.ts +26 -0
  195. package/dist/lib/scheduled-actions/handlers/security-notification.d.ts.map +1 -0
  196. package/dist/lib/scheduled-actions/handlers/security-notification.js +54 -0
  197. package/dist/lib/selectors/core-selectors.d.ts +12 -0
  198. package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
  199. package/dist/lib/selectors/domains/auth.selectors.d.ts +12 -0
  200. package/dist/lib/selectors/domains/auth.selectors.d.ts.map +1 -1
  201. package/dist/lib/selectors/domains/auth.selectors.js +14 -1
  202. package/dist/lib/selectors/selectors.d.ts +24 -0
  203. package/dist/lib/selectors/selectors.d.ts.map +1 -1
  204. package/dist/lib/services/api-docs.service.d.ts +5 -1
  205. package/dist/lib/services/api-docs.service.d.ts.map +1 -1
  206. package/dist/lib/services/api-presets.service.d.ts +6 -1
  207. package/dist/lib/services/api-presets.service.d.ts.map +1 -1
  208. package/dist/lib/services/feature.service.d.ts +58 -4
  209. package/dist/lib/services/feature.service.d.ts.map +1 -1
  210. package/dist/lib/services/generic-entity.service.d.ts.map +1 -1
  211. package/dist/lib/services/generic-entity.service.js +16 -32
  212. package/dist/lib/services/membership.service.d.ts +10 -2
  213. package/dist/lib/services/membership.service.d.ts.map +1 -1
  214. package/dist/lib/services/membership.service.js +37 -16
  215. package/dist/lib/services/permission.service.d.ts +10 -4
  216. package/dist/lib/services/permission.service.d.ts.map +1 -1
  217. package/dist/lib/services/plugin.service.d.ts +1 -1
  218. package/dist/lib/services/plugin.service.d.ts.map +1 -1
  219. package/dist/lib/services/subscription.service.d.ts.map +1 -1
  220. package/dist/lib/services/subscription.service.js +2 -1
  221. package/dist/lib/services/team-member.service.d.ts +15 -3
  222. package/dist/lib/services/team-member.service.d.ts.map +1 -1
  223. package/dist/lib/services/team-member.service.js +27 -6
  224. package/dist/lib/services/team.service.d.ts.map +1 -1
  225. package/dist/lib/teams/permissions.d.ts +3 -1
  226. package/dist/lib/teams/permissions.d.ts.map +1 -1
  227. package/dist/lib/teams/permissions.js +6 -0
  228. package/dist/lib/teams/schema.d.ts.map +1 -1
  229. package/dist/lib/teams/schema.js +3 -0
  230. package/dist/lib/template-resolver.d.ts +3 -3
  231. package/dist/lib/theme/forced-theme.d.ts +34 -0
  232. package/dist/lib/theme/forced-theme.d.ts.map +1 -0
  233. package/dist/lib/theme/forced-theme.js +27 -0
  234. package/dist/lib/theme/get-default-theme-mode.d.ts +3 -0
  235. package/dist/lib/theme/get-default-theme-mode.d.ts.map +1 -1
  236. package/dist/lib/theme/get-default-theme-mode.js +5 -3
  237. package/dist/lib/utils/cors.d.ts +13 -0
  238. package/dist/lib/utils/cors.d.ts.map +1 -1
  239. package/dist/lib/utils/cors.js +20 -0
  240. package/dist/messages/de/auth.json +25 -2
  241. package/dist/messages/de/index.d.ts +83 -0
  242. package/dist/messages/de/index.d.ts.map +1 -1
  243. package/dist/messages/de/index.js +2 -0
  244. package/dist/messages/de/index.ts +2 -0
  245. package/dist/messages/de/navigation.json +3 -1
  246. package/dist/messages/en/auth.json +25 -2
  247. package/dist/messages/en/index.d.ts +83 -0
  248. package/dist/messages/en/index.d.ts.map +1 -1
  249. package/dist/messages/en/index.js +2 -0
  250. package/dist/messages/en/index.ts +2 -0
  251. package/dist/messages/en/navigation.json +3 -1
  252. package/dist/messages/es/auth.json +25 -2
  253. package/dist/messages/es/index.d.ts +83 -0
  254. package/dist/messages/es/index.d.ts.map +1 -1
  255. package/dist/messages/es/index.js +2 -0
  256. package/dist/messages/es/index.ts +2 -0
  257. package/dist/messages/es/navigation.json +3 -1
  258. package/dist/messages/fr/auth.json +25 -2
  259. package/dist/messages/fr/index.d.ts +83 -0
  260. package/dist/messages/fr/index.d.ts.map +1 -1
  261. package/dist/messages/fr/index.js +2 -0
  262. package/dist/messages/fr/index.ts +2 -0
  263. package/dist/messages/fr/navigation.json +3 -1
  264. package/dist/messages/it/auth.json +25 -2
  265. package/dist/messages/it/index.d.ts +83 -0
  266. package/dist/messages/it/index.d.ts.map +1 -1
  267. package/dist/messages/it/index.js +2 -0
  268. package/dist/messages/it/index.ts +2 -0
  269. package/dist/messages/it/navigation.json +3 -1
  270. package/dist/messages/pt/auth.json +25 -2
  271. package/dist/messages/pt/index.d.ts +83 -0
  272. package/dist/messages/pt/index.d.ts.map +1 -1
  273. package/dist/messages/pt/index.js +2 -0
  274. package/dist/messages/pt/index.ts +2 -0
  275. package/dist/messages/pt/navigation.json +3 -1
  276. package/dist/migrations/005_api_audit_log.sql +2 -1
  277. package/dist/migrations/025_api_audit_log_nullable_api_key.sql +12 -0
  278. package/dist/migrations/026_login_events.sql +91 -0
  279. package/dist/migrations/027_rls_bypass_developer_and_system_admin_team.sql +197 -0
  280. package/dist/nextspark-registries.d.ts +580 -236
  281. package/dist/providers/DashboardProviders.d.ts +12 -3
  282. package/dist/providers/DashboardProviders.d.ts.map +1 -1
  283. package/dist/providers/DashboardProviders.js +6 -2
  284. package/dist/providers/theme-provider.d.ts +19 -2
  285. package/dist/providers/theme-provider.d.ts.map +1 -1
  286. package/dist/providers/theme-provider.js +6 -2
  287. package/dist/templates/app/(auth)/signup/page.tsx +8 -0
  288. package/dist/templates/app/(public)/[...slug]/page.tsx +9 -14
  289. package/dist/templates/app/api/auth/[...all]/route.ts +23 -1
  290. package/dist/templates/app/api/health/route.ts +4 -2
  291. package/dist/templates/app/api/internal/user-metadata/route.ts +5 -3
  292. package/dist/templates/app/api/mcp/route.ts +4 -1
  293. package/dist/templates/app/api/superadmin/subscriptions/route.ts +2 -1
  294. package/dist/templates/app/api/superadmin/teams/[teamId]/route.ts +4 -3
  295. package/dist/templates/app/api/superadmin/users/[userId]/route.ts +10 -3
  296. package/dist/templates/app/api/v1/api-keys/[id]/route.ts +50 -71
  297. package/dist/templates/app/api/v1/api-keys/route.ts +21 -43
  298. package/dist/templates/app/api/v1/auth/signup-with-invite/route.ts +14 -14
  299. package/dist/templates/app/api/v1/billing/cancel/route.ts +7 -6
  300. package/dist/templates/app/api/v1/billing/change-plan/route.ts +5 -4
  301. package/dist/templates/app/api/v1/billing/check-action/route.ts +6 -4
  302. package/dist/templates/app/api/v1/billing/checkout/route.ts +7 -5
  303. package/dist/templates/app/api/v1/billing/plans/route.ts +8 -12
  304. package/dist/templates/app/api/v1/billing/portal/route.ts +7 -5
  305. package/dist/templates/app/api/v1/billing/webhooks/polar/route.ts +1 -1
  306. package/dist/templates/app/api/v1/devtools/blocks/route.ts +5 -4
  307. package/dist/templates/app/api/v1/devtools/features/route.ts +5 -4
  308. package/dist/templates/app/api/v1/devtools/flows/route.ts +5 -4
  309. package/dist/templates/app/api/v1/devtools/scheduled-actions/route.ts +9 -7
  310. package/dist/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +5 -4
  311. package/dist/templates/app/api/v1/devtools/testing/route.ts +5 -4
  312. package/dist/templates/app/api/v1/media/[id]/route.ts +13 -25
  313. package/dist/templates/app/api/v1/media/[id]/tags/route.ts +17 -25
  314. package/dist/templates/app/api/v1/media/check-duplicates/route.ts +5 -7
  315. package/dist/templates/app/api/v1/media/route.ts +5 -9
  316. package/dist/templates/app/api/v1/media/upload/route.ts +9 -21
  317. package/dist/templates/app/api/v1/media-tags/route.ts +9 -13
  318. package/dist/templates/app/api/v1/patterns/[id]/usages/route.ts +11 -19
  319. package/dist/templates/app/api/v1/post-categories/[id]/route.ts +9 -7
  320. package/dist/templates/app/api/v1/post-categories/route.ts +5 -4
  321. package/dist/templates/app/api/v1/team-invitations/[token]/accept/route.ts +16 -18
  322. package/dist/templates/app/api/v1/team-invitations/[token]/decline/route.ts +15 -17
  323. package/dist/templates/app/api/v1/team-invitations/[token]/route.ts +8 -8
  324. package/dist/templates/app/api/v1/team-invitations/route.ts +9 -11
  325. package/dist/templates/app/api/v1/teams/[teamId]/invitations/route.ts +41 -32
  326. package/dist/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +15 -16
  327. package/dist/templates/app/api/v1/teams/[teamId]/invoices/route.ts +14 -15
  328. package/dist/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +32 -36
  329. package/dist/templates/app/api/v1/teams/[teamId]/members/route.ts +33 -33
  330. package/dist/templates/app/api/v1/teams/[teamId]/route.ts +35 -41
  331. package/dist/templates/app/api/v1/teams/[teamId]/subscription/route.ts +5 -3
  332. package/dist/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +10 -6
  333. package/dist/templates/app/api/v1/teams/route.ts +33 -27
  334. package/dist/templates/app/api/v1/teams/switch/route.ts +11 -13
  335. package/dist/templates/app/api/v1/theme/[...path]/route.ts +23 -2
  336. package/dist/templates/app/api/v1/users/[id]/meta/[key]/route.ts +32 -77
  337. package/dist/templates/app/api/v1/users/[id]/route.ts +35 -68
  338. package/dist/templates/app/api/v1/users/route.ts +21 -25
  339. package/dist/templates/app/dashboard/layout.tsx +2 -6
  340. package/dist/templates/app/layout.ppr.tsx +15 -15
  341. package/dist/templates/app/layout.tsx +46 -20
  342. package/dist/templates/contents/themes/starter/config/app.config.ts +19 -0
  343. package/dist/templates/contents/themes/starter/config/theme.config.ts +6 -0
  344. package/dist/templates/contents/themes/starter/styles/globals.css +6 -2
  345. package/dist/templates/proxy.ts +46 -10
  346. package/dist/templates/tsconfig.json +4 -0
  347. package/dist/types/theme.d.ts +9 -0
  348. package/dist/types/theme.d.ts.map +1 -1
  349. package/migrations/005_api_audit_log.sql +2 -1
  350. package/migrations/025_api_audit_log_nullable_api_key.sql +12 -0
  351. package/migrations/026_login_events.sql +91 -0
  352. package/migrations/027_rls_bypass_developer_and_system_admin_team.sql +197 -0
  353. package/package.json +14 -11
  354. package/scripts/build/registry/__tests__/scope-registry.test.mjs +18 -0
  355. package/scripts/build/registry/generators/scope-registry.mjs +9 -2
  356. package/templates/app/(auth)/signup/page.tsx +8 -0
  357. package/templates/app/(public)/[...slug]/page.tsx +9 -14
  358. package/templates/app/api/auth/[...all]/route.ts +23 -1
  359. package/templates/app/api/health/route.ts +4 -2
  360. package/templates/app/api/internal/user-metadata/route.ts +5 -3
  361. package/templates/app/api/mcp/route.ts +4 -1
  362. package/templates/app/api/superadmin/subscriptions/route.ts +2 -1
  363. package/templates/app/api/superadmin/teams/[teamId]/route.ts +4 -3
  364. package/templates/app/api/superadmin/users/[userId]/route.ts +10 -3
  365. package/templates/app/api/v1/api-keys/[id]/route.ts +50 -71
  366. package/templates/app/api/v1/api-keys/route.ts +21 -43
  367. package/templates/app/api/v1/auth/signup-with-invite/route.ts +14 -14
  368. package/templates/app/api/v1/billing/cancel/route.ts +7 -6
  369. package/templates/app/api/v1/billing/change-plan/route.ts +5 -4
  370. package/templates/app/api/v1/billing/check-action/route.ts +6 -4
  371. package/templates/app/api/v1/billing/checkout/route.ts +7 -5
  372. package/templates/app/api/v1/billing/plans/route.ts +8 -12
  373. package/templates/app/api/v1/billing/portal/route.ts +7 -5
  374. package/templates/app/api/v1/billing/webhooks/polar/route.ts +1 -1
  375. package/templates/app/api/v1/devtools/blocks/route.ts +5 -4
  376. package/templates/app/api/v1/devtools/features/route.ts +5 -4
  377. package/templates/app/api/v1/devtools/flows/route.ts +5 -4
  378. package/templates/app/api/v1/devtools/scheduled-actions/route.ts +9 -7
  379. package/templates/app/api/v1/devtools/scheduled-actions/run/route.ts +5 -4
  380. package/templates/app/api/v1/devtools/testing/route.ts +5 -4
  381. package/templates/app/api/v1/media/[id]/route.ts +13 -25
  382. package/templates/app/api/v1/media/[id]/tags/route.ts +17 -25
  383. package/templates/app/api/v1/media/check-duplicates/route.ts +5 -7
  384. package/templates/app/api/v1/media/route.ts +5 -9
  385. package/templates/app/api/v1/media/upload/route.ts +9 -21
  386. package/templates/app/api/v1/media-tags/route.ts +9 -13
  387. package/templates/app/api/v1/patterns/[id]/usages/route.ts +11 -19
  388. package/templates/app/api/v1/post-categories/[id]/route.ts +9 -7
  389. package/templates/app/api/v1/post-categories/route.ts +5 -4
  390. package/templates/app/api/v1/team-invitations/[token]/accept/route.ts +16 -18
  391. package/templates/app/api/v1/team-invitations/[token]/decline/route.ts +15 -17
  392. package/templates/app/api/v1/team-invitations/[token]/route.ts +8 -8
  393. package/templates/app/api/v1/team-invitations/route.ts +9 -11
  394. package/templates/app/api/v1/teams/[teamId]/invitations/route.ts +41 -32
  395. package/templates/app/api/v1/teams/[teamId]/invoices/[invoiceNumber]/route.ts +15 -16
  396. package/templates/app/api/v1/teams/[teamId]/invoices/route.ts +14 -15
  397. package/templates/app/api/v1/teams/[teamId]/members/[memberId]/route.ts +32 -36
  398. package/templates/app/api/v1/teams/[teamId]/members/route.ts +33 -33
  399. package/templates/app/api/v1/teams/[teamId]/route.ts +35 -41
  400. package/templates/app/api/v1/teams/[teamId]/subscription/route.ts +5 -3
  401. package/templates/app/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts +10 -6
  402. package/templates/app/api/v1/teams/route.ts +33 -27
  403. package/templates/app/api/v1/teams/switch/route.ts +11 -13
  404. package/templates/app/api/v1/theme/[...path]/route.ts +23 -2
  405. package/templates/app/api/v1/users/[id]/meta/[key]/route.ts +32 -77
  406. package/templates/app/api/v1/users/[id]/route.ts +35 -68
  407. package/templates/app/api/v1/users/route.ts +21 -25
  408. package/templates/app/dashboard/layout.tsx +2 -6
  409. package/templates/app/layout.ppr.tsx +15 -15
  410. package/templates/app/layout.tsx +46 -20
  411. package/templates/contents/themes/starter/config/app.config.ts +19 -0
  412. package/templates/contents/themes/starter/config/theme.config.ts +6 -0
  413. package/templates/contents/themes/starter/styles/globals.css +6 -2
  414. package/templates/proxy.ts +46 -10
  415. package/templates/tsconfig.json +4 -0
  416. package/tests/jest/__mocks__/@nextsparkjs/registries/permissions-registry.ts +23 -0
  417. package/tests/jest/__mocks__/next-server.js +24 -0
  418. package/dist/components/teams/TeamSwitchModal.d.js +0 -0
  419. package/dist/components/ui/accordion.d.js +0 -0
  420. package/dist/components/ui/avatar.d.js +0 -0
  421. package/dist/components/ui/badge.d.js +0 -0
  422. package/dist/components/ui/button.d.js +0 -0
  423. package/dist/components/ui/card.d.js +0 -0
  424. package/dist/components/ui/dialog.d.js +0 -0
  425. package/dist/components/ui/dropdown-menu.d.js +0 -0
  426. package/dist/components/ui/input.d.js +0 -0
  427. package/dist/components/ui/progress.d.js +0 -0
  428. package/dist/components/ui/scroll-area.d.js +0 -0
  429. package/dist/components/ui/select.d.js +0 -0
  430. package/dist/components/ui/separator.d.js +0 -0
  431. package/dist/components/ui/table.d.js +0 -0
  432. package/dist/components/ui/textarea.d.js +0 -0
  433. package/dist/contexts/TeamContext.d.js +0 -0
  434. package/dist/hooks/useAuth.d.js +0 -0
  435. package/dist/hooks/useLastAuthMethod.d.js +0 -0
  436. package/dist/hooks/useOrigin.d.js +0 -0
  437. package/dist/lib/api/auth/dual-auth.d.js +0 -0
  438. package/dist/lib/api/auth.d.js +0 -0
  439. package/dist/lib/api/cache.d.js +0 -0
  440. package/dist/lib/api/keys.d.js +0 -0
  441. package/dist/lib/auth-client.d.js +0 -0
  442. package/dist/lib/auth-context.d.js +0 -0
  443. package/dist/lib/auth.d.js +0 -0
  444. package/dist/lib/billing/config-types.d.js +0 -0
  445. package/dist/lib/billing/enforcement.d.js +0 -0
  446. package/dist/lib/billing/helpers.d.js +0 -0
  447. package/dist/lib/billing/jobs.d.js +0 -0
  448. package/dist/lib/billing/types.d.js +0 -0
  449. package/dist/lib/blocks/loader.d.js +0 -0
  450. package/dist/lib/config/app.config.d.js +0 -0
  451. package/dist/lib/config/config-loader.d.js +0 -0
  452. package/dist/lib/config/config-sync.d.js +0 -0
  453. package/dist/lib/config/config-types.d.js +0 -0
  454. package/dist/lib/config/config-utils.d.js +0 -0
  455. package/dist/lib/config/dashboard-types.d.js +0 -0
  456. package/dist/lib/config/dashboard.config.d.js +0 -0
  457. package/dist/lib/config/icon-map.d.js +0 -0
  458. package/dist/lib/config/index.d.js +0 -7
  459. package/dist/lib/config/nextspark-types.d.js +0 -0
  460. package/dist/lib/config/roles-merge.d.js +0 -0
  461. package/dist/lib/config/types.d.js +0 -0
  462. package/dist/lib/db.d.js +0 -0
  463. package/dist/lib/email/factory.d.js +0 -0
  464. package/dist/lib/email/index.d.js +0 -3
  465. package/dist/lib/email/providers/console.d.js +0 -0
  466. package/dist/lib/email/providers/resend.d.js +0 -0
  467. package/dist/lib/email/templates.d.js +0 -0
  468. package/dist/lib/email/types.d.js +0 -0
  469. package/dist/lib/entities/types.d.js +0 -0
  470. package/dist/lib/permissions/system.d.js +0 -0
  471. package/dist/lib/permissions/types.d.js +0 -0
  472. package/dist/lib/plugins/hook-system.d.js +0 -0
  473. package/dist/lib/scheduled-actions/cleanup.d.js +0 -0
  474. package/dist/lib/scheduled-actions/index.d.js +0 -19
  475. package/dist/lib/scheduled-actions/initializer.d.js +0 -1
  476. package/dist/lib/scheduled-actions/processor.d.js +0 -0
  477. package/dist/lib/scheduled-actions/registry.d.js +0 -0
  478. package/dist/lib/scheduled-actions/scheduler.d.js +0 -0
  479. package/dist/lib/scheduled-actions/types.d.js +0 -0
  480. package/dist/lib/services/api-routes.service.d.js +0 -0
  481. package/dist/lib/services/entity-type.service.d.js +0 -0
  482. package/dist/lib/services/index.d.js +0 -40
  483. package/dist/lib/services/invoice.service.d.js +0 -0
  484. package/dist/lib/services/membership.service.d.js +0 -0
  485. package/dist/lib/services/meta.service.d.js +0 -0
  486. package/dist/lib/services/middleware.service.d.js +0 -0
  487. package/dist/lib/services/namespace.service.d.js +0 -0
  488. package/dist/lib/services/permission.service.d.js +0 -0
  489. package/dist/lib/services/plan.service.d.js +0 -0
  490. package/dist/lib/services/plugin.service.d.js +0 -0
  491. package/dist/lib/services/route-handler.service.d.js +0 -0
  492. package/dist/lib/services/scope.service.d.js +0 -0
  493. package/dist/lib/services/subscription.service.d.js +0 -0
  494. package/dist/lib/services/team-member.service.d.js +0 -0
  495. package/dist/lib/services/team.service.d.js +0 -0
  496. package/dist/lib/services/theme.service.d.js +0 -0
  497. package/dist/lib/services/usage.service.d.js +0 -0
  498. package/dist/lib/services/user-flags.service.d.js +0 -0
  499. package/dist/lib/services/user.service.d.js +0 -0
  500. package/dist/lib/teams/helpers.d.js +0 -0
  501. package/dist/lib/teams/permissions.d.js +0 -0
  502. package/dist/lib/teams/types.d.js +0 -0
  503. package/dist/lib/utils/config-merge.d.js +0 -0
  504. package/dist/lib/utils/file-logger.d.js +0 -0
  505. package/dist/lib/utils.d.js +0 -0
  506. package/dist/styles/classes.json +0 -1093
  507. package/dist/styles/ui.css +0 -2
  508. package/dist/types/auth.d.js +0 -0
  509. package/dist/types/blocks.d.js +0 -0
  510. package/dist/types/meta.types.d.js +0 -0
  511. package/dist/types/plugin.d.js +0 -0
  512. package/dist/types/testing.types.d.js +0 -0
  513. package/dist/types/theme.d.js +0 -0
  514. package/dist/types/user.types.d.js +0 -0
  515. package/scripts/build/build-ui-css.mjs +0 -351
  516. /package/dist/{components/app/layouts/PublicFooter.d.js → lib/auth/security-notifications/types.js} +0 -0
  517. /package/dist/{components/app/layouts/PublicNavbar.d.js → nextspark-registries.d.js} +0 -0
  518. /package/dist/{components/app/misc/ThemeToggle.d.js → types/use-intl-react-shim.d.js} +0 -0
@@ -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
- const authResult = await authenticateRequest(req)
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 NextResponse.json(
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.invoices')
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
- const authResult = await authenticateRequest(req)
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 NextResponse.json(
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
- const authResult = await authenticateRequest(req)
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 NextResponse.json(
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')
@@ -8,7 +8,7 @@ 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 { isSuperAdmin } from '@nextsparkjs/core/lib/api/auth/permissions'
13
13
  import { checkRateLimit, withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
14
14
  import { RATE_LIMITS } from '@nextsparkjs/core/lib/api/keys'
@@ -21,22 +21,20 @@ import { sendTeamInvitationEmail } from '@nextsparkjs/core/lib/email/send'
21
21
  import { I18N_CONFIG } from '@nextsparkjs/core/lib/config'
22
22
 
23
23
  // Handle CORS preflight
24
- export async function OPTIONS() {
25
- return handleCorsPreflightRequest()
24
+ export async function OPTIONS(request: NextRequest) {
25
+ return handleCorsPreflightRequest(request)
26
26
  }
27
27
 
28
28
  // GET /api/v1/teams/:teamId/members - List team members
29
29
  export const GET = withRateLimitTier(withApiLogging(
30
30
  async (req: NextRequest, { params }: { params: Promise<{ teamId: string }> }): Promise<NextResponse> => {
31
31
  try {
32
- // Authenticate using dual auth
33
- const authResult = await authenticateRequest(req)
32
+ // Authenticate using dual auth; the API-key scope is declared at the entry
33
+ // point, which fails closed for keys that lack it (#93).
34
+ const authResult = await authenticateRequest(req, { requiredScope: 'teams:read' })
34
35
 
35
36
  if (!authResult.success) {
36
- return NextResponse.json(
37
- { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
38
- { status: 401 }
39
- )
37
+ return createAuthFailureResponse(authResult)
40
38
  }
41
39
 
42
40
  if (authResult.rateLimitResponse) {
@@ -48,19 +46,23 @@ export const GET = withRateLimitTier(withApiLogging(
48
46
  // Validate that teamId is not empty
49
47
  if (!teamId || teamId.trim() === '') {
50
48
  const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
51
- return addCorsHeaders(response)
49
+ return addCorsHeaders(response, req)
52
50
  }
53
51
 
54
52
  // Superadmins can view members of any team
55
53
  const userIsSuperAdmin = isSuperAdmin(authResult)
56
54
 
57
- // Check if user is a member of the team (unless superadmin)
55
+ // Listing the roster is gated by the 'team.members.view' permission, not
56
+ // bare membership — membership only proves you belong to the team, not
57
+ // that your role is allowed to see who else does (a theme may grant
58
+ // 'team.members.view' to a subset of roles; see GHSA-rw2j-9mxg-rx98).
58
59
  if (!userIsSuperAdmin) {
59
- const isMember = await TeamMemberService.isMember(teamId, authResult.user!.id)
60
+ const membership = await MembershipService.get(authResult.user!.id, teamId)
61
+ const actionResult = membership.canPerformAction('team.members.view')
60
62
 
61
- if (!isMember) {
63
+ if (!actionResult.allowed) {
62
64
  const response = createApiError('Team not found or access denied', 404, null, 'TEAM_NOT_FOUND')
63
- return addCorsHeaders(response)
65
+ return addCorsHeaders(response, req)
64
66
  }
65
67
  }
66
68
 
@@ -141,11 +143,11 @@ export const GET = withRateLimitTier(withApiLogging(
141
143
  const paginationMeta = createPaginationMeta(page, limit, total)
142
144
 
143
145
  const response = createApiResponse(members, paginationMeta)
144
- return addCorsHeaders(response)
146
+ return addCorsHeaders(response, req)
145
147
  } catch (error) {
146
148
  console.error('Error fetching team members:', error)
147
149
  const response = createApiError('Internal server error', 500)
148
- return addCorsHeaders(response)
150
+ return addCorsHeaders(response, req)
149
151
  }
150
152
  }
151
153
  ), 'read')
@@ -154,14 +156,12 @@ export const GET = withRateLimitTier(withApiLogging(
154
156
  export const POST = withRateLimitTier(withApiLogging(
155
157
  async (req: NextRequest, { params }: { params: Promise<{ teamId: string }> }): Promise<NextResponse> => {
156
158
  try {
157
- // Authenticate using dual auth
158
- const authResult = await authenticateRequest(req)
159
+ // Authenticate using dual auth; the API-key scope is declared at the entry
160
+ // point, which fails closed for keys that lack it (#93).
161
+ const authResult = await authenticateRequest(req, { requiredScope: 'teams:write' })
159
162
 
160
163
  if (!authResult.success) {
161
- return NextResponse.json(
162
- { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
163
- { status: 401 }
164
- )
164
+ return createAuthFailureResponse(authResult)
165
165
  }
166
166
 
167
167
  if (authResult.rateLimitResponse) {
@@ -180,7 +180,7 @@ export const POST = withRateLimitTier(withApiLogging(
180
180
  { retryAfter: Math.ceil((rateLimit.resetTime - Date.now()) / 1000) },
181
181
  'RATE_LIMIT_EXCEEDED'
182
182
  )
183
- return addCorsHeaders(response)
183
+ return addCorsHeaders(response, req)
184
184
  }
185
185
 
186
186
  const { teamId } = await params
@@ -188,12 +188,12 @@ export const POST = withRateLimitTier(withApiLogging(
188
188
  // Validate that teamId is not empty
189
189
  if (!teamId || teamId.trim() === '') {
190
190
  const response = createApiError('Team ID is required', 400, null, 'MISSING_TEAM_ID')
191
- return addCorsHeaders(response)
191
+ return addCorsHeaders(response, req)
192
192
  }
193
193
 
194
194
  // Check if user has permission to invite members using MembershipService
195
195
  const membership = await MembershipService.get(authResult.user!.id, teamId)
196
- const actionResult = membership.canPerformAction('members.invite')
196
+ const actionResult = membership.canPerformAction('team.members.invite')
197
197
 
198
198
  if (!actionResult.allowed) {
199
199
  const response = NextResponse.json(
@@ -205,7 +205,7 @@ export const POST = withRateLimitTier(withApiLogging(
205
205
  },
206
206
  { status: 403 }
207
207
  )
208
- return addCorsHeaders(response)
208
+ return addCorsHeaders(response, req)
209
209
  }
210
210
 
211
211
  // Get user's role for role hierarchy validation
@@ -223,7 +223,7 @@ export const POST = withRateLimitTier(withApiLogging(
223
223
  null,
224
224
  'ROLE_HIERARCHY_VIOLATION'
225
225
  )
226
- return addCorsHeaders(response)
226
+ return addCorsHeaders(response, req)
227
227
  }
228
228
 
229
229
  // Check if user already exists and is already a member
@@ -243,7 +243,7 @@ export const POST = withRateLimitTier(withApiLogging(
243
243
 
244
244
  if (existingMember) {
245
245
  const response = createApiError('User is already a member of this team', 409, null, 'ALREADY_MEMBER')
246
- return addCorsHeaders(response)
246
+ return addCorsHeaders(response, req)
247
247
  }
248
248
  }
249
249
 
@@ -262,7 +262,7 @@ export const POST = withRateLimitTier(withApiLogging(
262
262
  null,
263
263
  'INVITATION_EXISTS'
264
264
  )
265
- return addCorsHeaders(response)
265
+ return addCorsHeaders(response, req)
266
266
  }
267
267
 
268
268
  // Get team info for email
@@ -274,7 +274,7 @@ export const POST = withRateLimitTier(withApiLogging(
274
274
 
275
275
  if (!team) {
276
276
  const response = createApiError('Team not found', 404, null, 'TEAM_NOT_FOUND')
277
- return addCorsHeaders(response)
277
+ return addCorsHeaders(response, req)
278
278
  }
279
279
 
280
280
  // Create invitation
@@ -333,17 +333,17 @@ export const POST = withRateLimitTier(withApiLogging(
333
333
  }
334
334
 
335
335
  const response = createApiResponse(invitation, { created: true }, 201)
336
- return addCorsHeaders(response)
336
+ return addCorsHeaders(response, req)
337
337
  } catch (error) {
338
338
  if (error instanceof Error && error.name === 'ZodError') {
339
339
  const zodError = error as { issues?: unknown[] }
340
340
  const response = createApiError('Validation error', 400, zodError.issues, 'VALIDATION_ERROR')
341
- return addCorsHeaders(response)
341
+ return addCorsHeaders(response, req)
342
342
  }
343
343
 
344
344
  console.error('Error creating invitation:', error)
345
345
  const response = createApiError('Internal server error', 500)
346
- return addCorsHeaders(response)
346
+ return addCorsHeaders(response, req)
347
347
  }
348
348
  }
349
349
  ), 'write')