@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
@@ -1,5 +1,5 @@
1
1
  import { NextRequest } from 'next/server'
2
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
4
4
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -20,15 +20,11 @@ export const GET = withRateLimitTier(async (
20
20
  { params }: { params: Promise<{ id: string }> }
21
21
  ) => {
22
22
  try {
23
- // 1. Authenticate
24
- const authResult = await authenticateRequest(request)
23
+ // 1. Authenticate; the API-key scope is declared at the entry point,
24
+ // which fails closed for keys that lack it (#93).
25
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
25
26
  if (!authResult.success) {
26
- return createApiError('Unauthorized', 401)
27
- }
28
-
29
- // 2. Check permissions
30
- if (!hasRequiredScope(authResult, 'media:read')) {
31
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
27
+ return createAuthFailureResponse(authResult)
32
28
  }
33
29
 
34
30
  // 3. Resolve and validate team context
@@ -76,15 +72,11 @@ export const PATCH = withRateLimitTier(async (
76
72
  { params }: { params: Promise<{ id: string }> }
77
73
  ) => {
78
74
  try {
79
- // 1. Authenticate
80
- const authResult = await authenticateRequest(request)
75
+ // 1. Authenticate; the API-key scope is declared at the entry point,
76
+ // which fails closed for keys that lack it (#93).
77
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
81
78
  if (!authResult.success) {
82
- return createApiError('Unauthorized', 401)
83
- }
84
-
85
- // 2. Check permissions
86
- if (!hasRequiredScope(authResult, 'media:write')) {
87
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
79
+ return createAuthFailureResponse(authResult)
88
80
  }
89
81
 
90
82
  // 3. Resolve and validate team context
@@ -141,15 +133,11 @@ export const DELETE = withRateLimitTier(async (
141
133
  { params }: { params: Promise<{ id: string }> }
142
134
  ) => {
143
135
  try {
144
- // 1. Authenticate
145
- const authResult = await authenticateRequest(request)
136
+ // 1. Authenticate; the API-key scope is declared at the entry point,
137
+ // which fails closed for keys that lack it (#93).
138
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:delete' })
146
139
  if (!authResult.success) {
147
- return createApiError('Unauthorized', 401)
148
- }
149
-
150
- // 2. Check permissions
151
- if (!hasRequiredScope(authResult, 'media:delete')) {
152
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
140
+ return createAuthFailureResponse(authResult)
153
141
  }
154
142
 
155
143
  // 3. Resolve and validate team context
@@ -1,5 +1,5 @@
1
1
  import { NextRequest } from 'next/server'
2
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
4
4
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -25,13 +25,11 @@ export const GET = withRateLimitTier(async (
25
25
  { params }: { params: Promise<{ id: string }> }
26
26
  ) => {
27
27
  try {
28
- const authResult = await authenticateRequest(request)
28
+ // Authenticate; the API-key scope is declared at the entry point, which
29
+ // fails closed for keys that lack it (#93).
30
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
29
31
  if (!authResult.success) {
30
- return createApiError('Unauthorized', 401)
31
- }
32
-
33
- if (!hasRequiredScope(authResult, 'media:read')) {
34
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
32
+ return createAuthFailureResponse(authResult)
35
33
  }
36
34
 
37
35
  const teamResult = await resolveTeamContext(request, authResult)
@@ -70,13 +68,11 @@ export const POST = withRateLimitTier(async (
70
68
  { params }: { params: Promise<{ id: string }> }
71
69
  ) => {
72
70
  try {
73
- const authResult = await authenticateRequest(request)
71
+ // Authenticate; the API-key scope is declared at the entry point, which
72
+ // fails closed for keys that lack it (#93).
73
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
74
74
  if (!authResult.success) {
75
- return createApiError('Unauthorized', 401)
76
- }
77
-
78
- if (!hasRequiredScope(authResult, 'media:write')) {
79
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
75
+ return createAuthFailureResponse(authResult)
80
76
  }
81
77
 
82
78
  const teamResult = await resolveTeamContext(request, authResult)
@@ -124,13 +120,11 @@ export const PUT = withRateLimitTier(async (
124
120
  { params }: { params: Promise<{ id: string }> }
125
121
  ) => {
126
122
  try {
127
- const authResult = await authenticateRequest(request)
123
+ // Authenticate; the API-key scope is declared at the entry point, which
124
+ // fails closed for keys that lack it (#93).
125
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
128
126
  if (!authResult.success) {
129
- return createApiError('Unauthorized', 401)
130
- }
131
-
132
- if (!hasRequiredScope(authResult, 'media:write')) {
133
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
127
+ return createAuthFailureResponse(authResult)
134
128
  }
135
129
 
136
130
  const teamResult = await resolveTeamContext(request, authResult)
@@ -178,13 +172,11 @@ export const DELETE = withRateLimitTier(async (
178
172
  { params }: { params: Promise<{ id: string }> }
179
173
  ) => {
180
174
  try {
181
- const authResult = await authenticateRequest(request)
175
+ // Authenticate; the API-key scope is declared at the entry point, which
176
+ // fails closed for keys that lack it (#93).
177
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
182
178
  if (!authResult.success) {
183
- return createApiError('Unauthorized', 401)
184
- }
185
-
186
- if (!hasRequiredScope(authResult, 'media:write')) {
187
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
179
+ return createAuthFailureResponse(authResult)
188
180
  }
189
181
 
190
182
  const teamResult = await resolveTeamContext(request, authResult)
@@ -1,5 +1,5 @@
1
1
  import { NextRequest } from 'next/server'
2
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
4
4
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -17,13 +17,11 @@ import { MediaService } from '@nextsparkjs/core/lib/services/media.service'
17
17
  */
18
18
  export const POST = withRateLimitTier(async (request: NextRequest) => {
19
19
  try {
20
- const authResult = await authenticateRequest(request)
20
+ // Authenticate; the API-key scope is declared at the entry point, which
21
+ // fails closed for keys that lack it (#93).
22
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
21
23
  if (!authResult.success) {
22
- return createApiError('Unauthorized', 401)
23
- }
24
-
25
- if (!hasRequiredScope(authResult, 'media:read')) {
26
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
24
+ return createAuthFailureResponse(authResult)
27
25
  }
28
26
 
29
27
  const teamResult = await resolveTeamContext(request, authResult)
@@ -1,5 +1,5 @@
1
1
  import { NextRequest } from 'next/server'
2
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
4
4
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -26,15 +26,11 @@ import { mediaListQuerySchema } from '@nextsparkjs/core/lib/media/schemas'
26
26
  */
27
27
  export const GET = withRateLimitTier(async (request: NextRequest) => {
28
28
  try {
29
- // 1. Authenticate
30
- const authResult = await authenticateRequest(request)
29
+ // 1. Authenticate; the API-key scope is declared at the entry point,
30
+ // which fails closed for keys that lack it (#93).
31
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
31
32
  if (!authResult.success) {
32
- return createApiError('Unauthorized', 401)
33
- }
34
-
35
- // 2. Check permissions
36
- if (!hasRequiredScope(authResult, 'media:read')) {
37
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
33
+ return createAuthFailureResponse(authResult)
38
34
  }
39
35
 
40
36
  // 3. Resolve and validate team context
@@ -1,6 +1,6 @@
1
1
  import { NextRequest } from 'next/server'
2
2
  import { put } from '@vercel/blob'
3
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
4
4
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
5
5
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
6
6
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -55,18 +55,12 @@ async function uploadToLocalStorageBuffer(buffer: Buffer, fileName: string): Pro
55
55
  */
56
56
  export const POST = withRateLimitTier(async (request: NextRequest) => {
57
57
  try {
58
- // 1. Dual Authentication (API Key OR Session)
59
- const authResult = await authenticateRequest(request)
58
+ // 1. Dual Authentication (API Key OR Session); the API-key scope is
59
+ // declared at the entry point, which fails closed for keys that lack it (#93).
60
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
60
61
 
61
62
  if (!authResult.success) {
62
- return createApiError('Unauthorized', 401)
63
- }
64
-
65
- // 2. Check permissions for media upload
66
- const hasPermission = hasRequiredScope(authResult, 'media:write')
67
-
68
- if (!hasPermission) {
69
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
63
+ return createAuthFailureResponse(authResult)
70
64
  }
71
65
 
72
66
  // 3. Resolve and validate team context
@@ -237,18 +231,12 @@ export const POST = withRateLimitTier(async (request: NextRequest) => {
237
231
  */
238
232
  export const GET = withRateLimitTier(async (request: NextRequest) => {
239
233
  try {
240
- // 1. Dual Authentication (API Key OR Session)
241
- const authResult = await authenticateRequest(request)
234
+ // 1. Dual Authentication (API Key OR Session); the API-key scope is
235
+ // declared at the entry point, which fails closed for keys that lack it (#93).
236
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
242
237
 
243
238
  if (!authResult.success) {
244
- return createApiError('Unauthorized', 401)
245
- }
246
-
247
- // 2. Check permissions for media read
248
- const hasPermission = hasRequiredScope(authResult, 'media:read')
249
-
250
- if (!hasPermission) {
251
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
239
+ return createAuthFailureResponse(authResult)
252
240
  }
253
241
 
254
242
  // 3. Resolve and validate team context
@@ -1,5 +1,5 @@
1
1
  import { NextRequest } from 'next/server'
2
- import { authenticateRequest, hasRequiredScope, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse, resolveTeamContext } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { createApiResponse, createApiError } from '@nextsparkjs/core/lib/api/helpers'
4
4
  import { API_ERROR_CODES } from '@nextsparkjs/core/lib/api/api-error'
5
5
  import { checkPermission } from '@nextsparkjs/core/lib/permissions/check'
@@ -15,13 +15,11 @@ import { MediaService } from '@nextsparkjs/core/lib/services/media.service'
15
15
  */
16
16
  export const GET = withRateLimitTier(async (request: NextRequest) => {
17
17
  try {
18
- const authResult = await authenticateRequest(request)
18
+ // Authenticate; the API-key scope is declared at the entry point, which
19
+ // fails closed for keys that lack it (#93).
20
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:read' })
19
21
  if (!authResult.success) {
20
- return createApiError('Unauthorized', 401)
21
- }
22
-
23
- if (!hasRequiredScope(authResult, 'media:read')) {
24
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
22
+ return createAuthFailureResponse(authResult)
25
23
  }
26
24
 
27
25
  const teamResult = await resolveTeamContext(request, authResult)
@@ -51,13 +49,11 @@ export const GET = withRateLimitTier(async (request: NextRequest) => {
51
49
  */
52
50
  export const POST = withRateLimitTier(async (request: NextRequest) => {
53
51
  try {
54
- const authResult = await authenticateRequest(request)
52
+ // Authenticate; the API-key scope is declared at the entry point, which
53
+ // fails closed for keys that lack it (#93).
54
+ const authResult = await authenticateRequest(request, { requiredScope: 'media:write' })
55
55
  if (!authResult.success) {
56
- return createApiError('Unauthorized', 401)
57
- }
58
-
59
- if (!hasRequiredScope(authResult, 'media:write')) {
60
- return createApiError('Insufficient permissions', 403, undefined, API_ERROR_CODES.INSUFFICIENT_SCOPE)
56
+ return createAuthFailureResponse(authResult)
61
57
  }
62
58
 
63
59
  const teamResult = await resolveTeamContext(request, authResult)
@@ -23,46 +23,38 @@ import {
23
23
  handleCorsPreflightRequest,
24
24
  addCorsHeaders,
25
25
  } from '@nextsparkjs/core/lib/api/helpers'
26
- import { authenticateRequest, hasRequiredScope } from '@nextsparkjs/core/lib/api/auth/dual-auth'
26
+ import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
27
27
  import { PatternUsageService } from '@nextsparkjs/core/lib/services'
28
28
  import { queryOneWithRLS } from '@nextsparkjs/core/lib/db'
29
29
 
30
30
  // Handle CORS preflight
31
- export async function OPTIONS() {
32
- return handleCorsPreflightRequest()
31
+ export async function OPTIONS(request: NextRequest) {
32
+ return handleCorsPreflightRequest(request)
33
33
  }
34
34
 
35
35
  // GET /api/v1/patterns/:id/usages - Get pattern usages
36
36
  export const GET = withApiLogging(
37
37
  async (req: NextRequest, { params }: { params: Promise<{ id: string }> }): Promise<NextResponse> => {
38
38
  try {
39
- // Authenticate using dual auth
40
- const authResult = await authenticateRequest(req)
39
+ // Authenticate using dual auth; the required API-key scope is declared
40
+ // at the entry point (fail closed, #93).
41
+ const authResult = await authenticateRequest(req, { requiredScope: 'patterns:read' })
41
42
 
42
43
  if (!authResult.success) {
43
- return NextResponse.json(
44
- { success: false, error: 'Authentication required', code: 'AUTHENTICATION_FAILED' },
45
- { status: 401 }
46
- )
44
+ return createAuthFailureResponse(authResult)
47
45
  }
48
46
 
49
47
  if (authResult.rateLimitResponse) {
50
48
  return authResult.rateLimitResponse as NextResponse
51
49
  }
52
50
 
53
- // Check required permissions
54
- if (!hasRequiredScope(authResult, 'patterns:read')) {
55
- const response = createApiError('Insufficient permissions', 403)
56
- return addCorsHeaders(response)
57
- }
58
-
59
51
  const { id: patternId } = await params
60
52
  const userId = authResult.user!.id
61
53
 
62
54
  // Validate that patternId is not empty
63
55
  if (!patternId || patternId.trim() === '') {
64
56
  const response = createApiError('Pattern ID is required', 400, null, 'MISSING_PATTERN_ID')
65
- return addCorsHeaders(response)
57
+ return addCorsHeaders(response, req)
66
58
  }
67
59
 
68
60
  // Verify pattern exists and user has access
@@ -74,7 +66,7 @@ export const GET = withApiLogging(
74
66
 
75
67
  if (!pattern) {
76
68
  const response = createApiError('Pattern not found', 404, null, 'PATTERN_NOT_FOUND')
77
- return addCorsHeaders(response)
69
+ return addCorsHeaders(response, req)
78
70
  }
79
71
 
80
72
  // Parse query parameters
@@ -106,11 +98,11 @@ export const GET = withApiLogging(
106
98
  entityType: entityType || 'all',
107
99
  })
108
100
 
109
- return addCorsHeaders(response)
101
+ return addCorsHeaders(response, req)
110
102
  } catch (error) {
111
103
  console.error('Error fetching pattern usages:', error)
112
104
  const response = createApiError('Internal server error', 500)
113
- return addCorsHeaders(response)
105
+ return addCorsHeaders(response, req)
114
106
  }
115
107
  }
116
108
  )
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
- import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { query as dbQuery } from '@nextsparkjs/core/lib/db'
4
4
  import { z } from 'zod'
5
5
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
@@ -52,10 +52,11 @@ export const PUT = withRateLimitTier(async (
52
52
  { params }: { params: Promise<{ id: string }> }
53
53
  ): Promise<NextResponse> => {
54
54
  try {
55
- // Dual authentication: API key or session
56
- const authResult = await authenticateRequest(request)
55
+ // Dual authentication: API key or session; the API-key scope is declared
56
+ // at the entry point, which fails closed for keys that lack it (#93).
57
+ const authResult = await authenticateRequest(request, { requiredScope: 'posts:write' })
57
58
  if (!authResult.success || !authResult.user) {
58
- return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
59
+ return createAuthFailureResponse(authResult)
59
60
  }
60
61
 
61
62
  const body = await request.json()
@@ -192,10 +193,11 @@ export const DELETE = withRateLimitTier(async (
192
193
  { params }: { params: Promise<{ id: string }> }
193
194
  ): Promise<NextResponse> => {
194
195
  try {
195
- // Dual authentication: API key or session
196
- const authResult = await authenticateRequest(request)
196
+ // Dual authentication: API key or session; the API-key scope is declared
197
+ // at the entry point, which fails closed for keys that lack it (#93).
198
+ const authResult = await authenticateRequest(request, { requiredScope: 'posts:delete' })
197
199
  if (!authResult.success || !authResult.user) {
198
- return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
200
+ return createAuthFailureResponse(authResult)
199
201
  }
200
202
 
201
203
  const { id } = await params
@@ -1,5 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server'
2
- import { authenticateRequest } from '@nextsparkjs/core/lib/api/auth/dual-auth'
2
+ import { authenticateRequest, createAuthFailureResponse } from '@nextsparkjs/core/lib/api/auth/dual-auth'
3
3
  import { query as dbQuery } from '@nextsparkjs/core/lib/db'
4
4
  import { z } from 'zod'
5
5
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
@@ -50,10 +50,11 @@ export const GET = withRateLimitTier(async () => {
50
50
  // POST /api/v1/post-categories - Create category
51
51
  export const POST = withRateLimitTier(async (request: NextRequest) => {
52
52
  try {
53
- // Dual authentication: API key or session
54
- const authResult = await authenticateRequest(request)
53
+ // Dual authentication: API key or session; the API-key scope is declared
54
+ // at the entry point, which fails closed for keys that lack it (#93).
55
+ const authResult = await authenticateRequest(request, { requiredScope: 'posts:write' })
55
56
  if (!authResult.success || !authResult.user) {
56
- return NextResponse.json({ success: false, error: 'Unauthorized' }, { status: 401 })
57
+ return createAuthFailureResponse(authResult)
57
58
  }
58
59
 
59
60
  const body = await request.json()
@@ -7,28 +7,26 @@ 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 { checkRateLimit, withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
12
12
  import { RATE_LIMITS } from '@nextsparkjs/core/lib/api/keys'
13
13
  import type { TeamInvitation, TeamMember } from '@nextsparkjs/core/lib/teams/types'
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
  // POST /api/v1/team-invitations/:token/accept - Accept invitation and become member
21
21
  export const POST = withRateLimitTier(withApiLogging(
22
22
  async (req: NextRequest, { params }: { params: Promise<{ token: string }> }): Promise<NextResponse> => {
23
23
  try {
24
- // Authenticate using dual auth
25
- const authResult = await authenticateRequest(req)
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:write' })
26
27
 
27
28
  if (!authResult.success) {
28
- return NextResponse.json(
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) {
@@ -47,7 +45,7 @@ export const POST = withRateLimitTier(withApiLogging(
47
45
  { retryAfter: Math.ceil((rateLimit.resetTime - Date.now()) / 1000) },
48
46
  'RATE_LIMIT_EXCEEDED'
49
47
  )
50
- return addCorsHeaders(response)
48
+ return addCorsHeaders(response, req)
51
49
  }
52
50
 
53
51
  const { token } = await params
@@ -55,7 +53,7 @@ export const POST = withRateLimitTier(withApiLogging(
55
53
  // Validate that token is not empty
56
54
  if (!token || token.trim() === '') {
57
55
  const response = createApiError('Invitation token is required', 400, null, 'MISSING_TOKEN')
58
- return addCorsHeaders(response)
56
+ return addCorsHeaders(response, req)
59
57
  }
60
58
 
61
59
  // Get invitation by token
@@ -67,7 +65,7 @@ export const POST = withRateLimitTier(withApiLogging(
67
65
 
68
66
  if (!invitation) {
69
67
  const response = createApiError('Invitation not found', 404, null, 'INVITATION_NOT_FOUND')
70
- return addCorsHeaders(response)
68
+ return addCorsHeaders(response, req)
71
69
  }
72
70
 
73
71
  // Verify invitation is for the current user's email
@@ -78,7 +76,7 @@ export const POST = withRateLimitTier(withApiLogging(
78
76
  null,
79
77
  'EMAIL_MISMATCH'
80
78
  )
81
- return addCorsHeaders(response)
79
+ return addCorsHeaders(response, req)
82
80
  }
83
81
 
84
82
  // Check if invitation is pending
@@ -89,7 +87,7 @@ export const POST = withRateLimitTier(withApiLogging(
89
87
  null,
90
88
  'INVITATION_NOT_PENDING'
91
89
  )
92
- return addCorsHeaders(response)
90
+ return addCorsHeaders(response, req)
93
91
  }
94
92
 
95
93
  // Check if invitation has expired
@@ -103,7 +101,7 @@ export const POST = withRateLimitTier(withApiLogging(
103
101
  )
104
102
 
105
103
  const response = createApiError('Invitation has expired', 410, null, 'INVITATION_EXPIRED')
106
- return addCorsHeaders(response)
104
+ return addCorsHeaders(response, req)
107
105
  }
108
106
 
109
107
  // Check if user is already a member
@@ -115,7 +113,7 @@ export const POST = withRateLimitTier(withApiLogging(
115
113
 
116
114
  if (existingMember) {
117
115
  const response = createApiError('You are already a member of this team', 409, null, 'ALREADY_MEMBER')
118
- return addCorsHeaders(response)
116
+ return addCorsHeaders(response, req)
119
117
  }
120
118
 
121
119
  // Use transaction to ensure atomicity
@@ -165,7 +163,7 @@ export const POST = withRateLimitTier(withApiLogging(
165
163
  )
166
164
 
167
165
  const response = createApiResponse(memberWithUser, { created: true }, 201)
168
- return addCorsHeaders(response)
166
+ return addCorsHeaders(response, req)
169
167
  } catch (error) {
170
168
  await tx.rollback()
171
169
  throw error
@@ -173,7 +171,7 @@ export const POST = withRateLimitTier(withApiLogging(
173
171
  } catch (error) {
174
172
  console.error('Error accepting invitation:', error)
175
173
  const response = createApiError('Internal server error', 500)
176
- return addCorsHeaders(response)
174
+ return addCorsHeaders(response, req)
177
175
  }
178
176
  }
179
177
  ), 'write');
@@ -7,28 +7,26 @@ 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 { checkRateLimit, withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
12
12
  import { RATE_LIMITS } from '@nextsparkjs/core/lib/api/keys'
13
13
  import type { TeamInvitation } from '@nextsparkjs/core/lib/teams/types'
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
  // POST /api/v1/team-invitations/:token/decline - Decline invitation
21
21
  export const POST = withRateLimitTier(withApiLogging(
22
22
  async (req: NextRequest, { params }: { params: Promise<{ token: string }> }): Promise<NextResponse> => {
23
23
  try {
24
- // Authenticate using dual auth
25
- const authResult = await authenticateRequest(req)
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:write' })
26
27
 
27
28
  if (!authResult.success) {
28
- return NextResponse.json(
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) {
@@ -47,7 +45,7 @@ export const POST = withRateLimitTier(withApiLogging(
47
45
  { retryAfter: Math.ceil((rateLimit.resetTime - Date.now()) / 1000) },
48
46
  'RATE_LIMIT_EXCEEDED'
49
47
  )
50
- return addCorsHeaders(response)
48
+ return addCorsHeaders(response, req)
51
49
  }
52
50
 
53
51
  const { token } = await params
@@ -55,7 +53,7 @@ export const POST = withRateLimitTier(withApiLogging(
55
53
  // Validate that token is not empty
56
54
  if (!token || token.trim() === '') {
57
55
  const response = createApiError('Invitation token is required', 400, null, 'MISSING_TOKEN')
58
- return addCorsHeaders(response)
56
+ return addCorsHeaders(response, req)
59
57
  }
60
58
 
61
59
  // Get invitation by token
@@ -67,7 +65,7 @@ export const POST = withRateLimitTier(withApiLogging(
67
65
 
68
66
  if (!invitation) {
69
67
  const response = createApiError('Invitation not found', 404, null, 'INVITATION_NOT_FOUND')
70
- return addCorsHeaders(response)
68
+ return addCorsHeaders(response, req)
71
69
  }
72
70
 
73
71
  // Verify invitation is for the current user's email
@@ -78,7 +76,7 @@ export const POST = withRateLimitTier(withApiLogging(
78
76
  null,
79
77
  'EMAIL_MISMATCH'
80
78
  )
81
- return addCorsHeaders(response)
79
+ return addCorsHeaders(response, req)
82
80
  }
83
81
 
84
82
  // Check if invitation is pending
@@ -89,7 +87,7 @@ export const POST = withRateLimitTier(withApiLogging(
89
87
  null,
90
88
  'INVITATION_NOT_PENDING'
91
89
  )
92
- return addCorsHeaders(response)
90
+ return addCorsHeaders(response, req)
93
91
  }
94
92
 
95
93
  // Update invitation status to declined
@@ -104,17 +102,17 @@ export const POST = withRateLimitTier(withApiLogging(
104
102
 
105
103
  if (result.rows.length === 0) {
106
104
  const response = createApiError('Invitation not found', 404, null, 'INVITATION_NOT_FOUND')
107
- return addCorsHeaders(response)
105
+ return addCorsHeaders(response, req)
108
106
  }
109
107
 
110
108
  const declinedInvitation = result.rows[0]
111
109
 
112
110
  const response = createApiResponse(declinedInvitation)
113
- return addCorsHeaders(response)
111
+ return addCorsHeaders(response, req)
114
112
  } catch (error) {
115
113
  console.error('Error declining invitation:', error)
116
114
  const response = createApiError('Internal server error', 500)
117
- return addCorsHeaders(response)
115
+ return addCorsHeaders(response, req)
118
116
  }
119
117
  }
120
118
  ), 'write');