@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,4 +1,4 @@
1
- import { auth } from "../auth.js";
1
+ import { getTypedSession } from "../auth.js";
2
2
  import { entityRegistry, ensureInitialized } from "../entities/registry.js";
3
3
  import {
4
4
  createApiResponse,
@@ -13,7 +13,7 @@ import {
13
13
  import { afterEntityCreate, afterEntityUpdate, afterEntityDelete } from "../entities/entity-hooks.js";
14
14
  async function checkBasicAuth(request, entityName) {
15
15
  try {
16
- const session = await auth.api.getSession({ headers: request.headers });
16
+ const session = await getTypedSession(request.headers);
17
17
  if (!session) {
18
18
  return {
19
19
  allowed: false,
@@ -1,5 +1,6 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
2
  import { ApiKeyAuth } from './auth';
3
+ import { type AuthenticateOptions } from './auth/scope-policy';
3
4
  interface SessionAuth {
4
5
  userId: string;
5
6
  scopes: string[];
@@ -10,14 +11,34 @@ type Auth = ApiKeyAuth | SessionAuth;
10
11
  /**
11
12
  * Validates authentication using session or API key
12
13
  * Prefers session auth if available, falls back to API key
13
- */
14
- export declare function validateAndAuthenticateRequest(request: NextRequest): Promise<{
15
- auth: Auth;
14
+ *
15
+ * Resolves to `{ auth: null }` when the request carries neither a valid
16
+ * session nor a valid API key — it never throws for an unauthenticated
17
+ * request (#112). Routes are expected to branch on `auth` and answer 401
18
+ * themselves; a throw here would be swallowed by the generic try/catch most
19
+ * routes wrap around their body and surface as a 500 instead.
20
+ *
21
+ * API-key scope enforcement fails closed here (#93), with the same rule as
22
+ * `authenticateRequest`: declare `{ requiredScope }` (or, explicitly,
23
+ * `{ allowAnyScope: true }`). A key rejected on scope resolves to
24
+ * `{ auth: null, errorResponse }` where `errorResponse` is the ready-made
25
+ * 403 — return it. Session auth keeps its role-derived scopes and is not
26
+ * gated here; use `checkScope` for explicit per-branch checks.
27
+ */
28
+ export declare function validateAndAuthenticateRequest(request: NextRequest, options?: AuthenticateOptions): Promise<{
29
+ auth: Auth | null;
16
30
  rateLimitResponse?: NextResponse;
31
+ /** Set (403) when a valid API key was rejected by scope enforcement. */
32
+ errorResponse?: NextResponse;
17
33
  }>;
18
34
  /**
19
35
  * Valida la API key y aplica rate limiting
20
36
  * Esta función debe ser llamada al inicio de cada endpoint API v1
37
+ *
38
+ * API-key-only and strict: throws when no valid key is present. Endpoints
39
+ * that also accept sessions (or want to treat anonymous callers as a normal
40
+ * 401 branch) should use `validateAndAuthenticateRequest`, which resolves to
41
+ * a null auth instead.
21
42
  */
22
43
  export declare function validateAndAuthenticateApiRequest(request: NextRequest): Promise<{
23
44
  auth: ApiKeyAuth;
@@ -31,8 +52,12 @@ export declare function getApiAuth(request: NextRequest): ApiKeyAuth;
31
52
  /**
32
53
  * Verifica que la autenticación tenga el scope requerido
33
54
  * Retorna un NextResponse de error si no tiene permisos, null si está autorizado
55
+ *
56
+ * Applies to both session auth (role-derived scopes) and API-key auth, with
57
+ * the same matching rule as `hasRequiredScope`: the wildcard `*` satisfies
58
+ * any scope, and an array is satisfied by any one of its entries.
34
59
  */
35
- export declare function checkScope(auth: Auth, requiredScope: string): NextResponse | null;
60
+ export declare function checkScope(auth: Auth, requiredScope: string | string[]): NextResponse | null;
36
61
  /**
37
62
  * Crea una respuesta exitosa estandarizada para la API
38
63
  */
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/api/helpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/api/helpers.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,13 @@ import { MetaService } from "../services/meta.service.js";
8
8
  import { ScopeService } from "../services/scope.service.js";
9
9
  import { getChildEntities } from "../entities/queries.js";
10
10
  import { getCorsOrigins, normalizeOrigin, isOriginAllowed } from "../utils/cors.js";
11
- async function validateAndAuthenticateRequest(request) {
11
+ import {
12
+ describeRoute,
13
+ normalizeRequiredScopes,
14
+ resolveApiKeyScopeFailure,
15
+ scopesSatisfy
16
+ } from "./auth/scope-policy.js";
17
+ async function validateAndAuthenticateRequest(request, options = {}) {
12
18
  var _a;
13
19
  const cookieHeader = request.headers.get("cookie");
14
20
  if (cookieHeader) {
@@ -35,7 +41,21 @@ async function validateAndAuthenticateRequest(request) {
35
41
  }
36
42
  }
37
43
  console.log(`[Auth] Falling back to API key authentication`);
38
- return validateAndAuthenticateApiRequest(request);
44
+ const apiKeyAuth = await validateApiKey(request);
45
+ if (!apiKeyAuth) {
46
+ return { auth: null };
47
+ }
48
+ const scopeFailure = resolveApiKeyScopeFailure(apiKeyAuth.scopes, options, describeRoute(request));
49
+ if (scopeFailure) {
50
+ return {
51
+ auth: null,
52
+ errorResponse: NextResponse.json(
53
+ { success: false, error: scopeFailure.message, code: scopeFailure.code },
54
+ { status: scopeFailure.status }
55
+ )
56
+ };
57
+ }
58
+ return applyApiKeyRateLimit(apiKeyAuth);
39
59
  }
40
60
  function generateScopesForRole(role, flags = []) {
41
61
  const baseScopes = getBaseScopesFromRegistry();
@@ -80,6 +100,9 @@ async function validateAndAuthenticateApiRequest(request) {
80
100
  if (!auth2) {
81
101
  throw new Error("Invalid API key");
82
102
  }
103
+ return applyApiKeyRateLimit(auth2);
104
+ }
105
+ function applyApiKeyRateLimit(auth2) {
83
106
  const rateLimitResult = checkRateLimit(auth2.keyId);
84
107
  if (!rateLimitResult.allowed) {
85
108
  const response = NextResponse.json(
@@ -120,14 +143,15 @@ function getApiAuth(request) {
120
143
  };
121
144
  }
122
145
  function checkScope(auth2, requiredScope) {
123
- const hasRequiredScope = auth2.scopes.includes(requiredScope);
124
- if (!hasRequiredScope) {
146
+ if (!scopesSatisfy(auth2.scopes, requiredScope)) {
147
+ const required = normalizeRequiredScopes(requiredScope);
148
+ const label = required.join("' or '");
125
149
  return NextResponse.json(
126
150
  {
127
151
  success: false,
128
152
  error: "Insufficient permissions",
129
- message: `This operation requires the '${requiredScope}' scope`,
130
- required_scope: requiredScope,
153
+ message: `This operation requires the '${label}' scope`,
154
+ required_scope: required.length === 1 ? required[0] : required,
131
155
  your_scopes: auth2.scopes,
132
156
  code: "INSUFFICIENT_PERMISSIONS"
133
157
  },
@@ -48,8 +48,14 @@ export declare const API_SCOPES: {
48
48
  readonly 'media:read': "Leer información de archivos y media";
49
49
  readonly 'media:write': "Subir y actualizar archivos";
50
50
  readonly 'media:delete': "Eliminar archivos";
51
+ readonly 'teams:read': "Leer equipos, miembros e invitaciones";
52
+ readonly 'teams:write': "Crear y actualizar equipos, miembros e invitaciones";
53
+ readonly 'teams:delete': "Eliminar equipos";
54
+ readonly 'billing:read': "Leer suscripciones, facturas y uso";
55
+ readonly 'billing:write': "Gestionar suscripciones, checkout, cambios de plan y uso";
51
56
  readonly 'admin:api-keys': "Gestionar API keys";
52
57
  readonly 'admin:users': "Administración completa de usuarios";
58
+ readonly 'admin:devtools': "Acceso a las APIs de DevTools (registries, testing, scheduled actions)";
53
59
  readonly '*': "Acceso completo (solo superadmin)";
54
60
  };
55
61
  export type ApiScope = keyof typeof API_SCOPES;
@@ -82,6 +88,16 @@ export declare const SCOPE_CATEGORIES: {
82
88
  readonly description: "Gestión de tareas y TODOs";
83
89
  readonly scopes: ApiScope[];
84
90
  };
91
+ readonly teams: {
92
+ readonly name: "Teams";
93
+ readonly description: "Equipos, miembros e invitaciones";
94
+ readonly scopes: ApiScope[];
95
+ };
96
+ readonly billing: {
97
+ readonly name: "Billing";
98
+ readonly description: "Suscripciones, facturas, uso y planes";
99
+ readonly scopes: ApiScope[];
100
+ };
85
101
  readonly admin: {
86
102
  readonly name: "Administración";
87
103
  readonly description: "Funciones administrativas";
@@ -1 +1 @@
1
- {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/lib/api/keys.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,aAAa;IACxB;;;OAGG;WACU,cAAc,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAyBrF;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAM9C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAKzC;;OAEG;WACU,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQlD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAA;KAAE;IAUpF;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM;CAchD;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;CAsBb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,UAAU,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGrD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxD;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;yBAIgC,QAAQ,EAAE;;;;;yBAKV,QAAQ,EAAE;;;;;yBAKtB,QAAQ,EAAE;;;;;yBAKtC,QAAQ,EAAE;;CAErB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASd,CAAC;AAEX;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAmB9F"}
1
+ {"version":3,"file":"keys.d.ts","sourceRoot":"","sources":["../../../src/lib/api/keys.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,qBAAa,aAAa;IACxB;;;OAGG;WACU,cAAc,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAyBrF;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAM9C;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAKzC;;OAEG;WACU,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQlD;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,aAAa,EAAE,MAAM,EAAE,CAAA;KAAE;IAUpF;;OAEG;IACH,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM;CAchD;AAED;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;CAgCb,CAAC;AAEX,MAAM,MAAM,QAAQ,GAAG,MAAM,OAAO,UAAU,CAAC;AAE/C;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAGrD;AAED,oFAAoF;AACpF,wBAAgB,eAAe,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAIxD;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB;;;;yBAIgC,QAAQ,EAAE;;;;;yBAKV,QAAQ,EAAE;;;;;yBAKV,QAAQ,EAAE;;;;;yBAKtB,QAAQ,EAAE;;;;;yBAKQ,QAAQ,EAAE;;;;;yBAKxD,QAAQ,EAAE;;CAErB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,cAAc;;;;CAIjB,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CASd,CAAC;AAEX;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAmB9F"}
@@ -81,9 +81,17 @@ const API_SCOPES = {
81
81
  "media:read": "Leer informaci\xF3n de archivos y media",
82
82
  "media:write": "Subir y actualizar archivos",
83
83
  "media:delete": "Eliminar archivos",
84
+ // Teams (equipos, miembros e invitaciones)
85
+ "teams:read": "Leer equipos, miembros e invitaciones",
86
+ "teams:write": "Crear y actualizar equipos, miembros e invitaciones",
87
+ "teams:delete": "Eliminar equipos",
88
+ // Billing (suscripciones, facturas, uso y planes)
89
+ "billing:read": "Leer suscripciones, facturas y uso",
90
+ "billing:write": "Gestionar suscripciones, checkout, cambios de plan y uso",
84
91
  // Administración
85
92
  "admin:api-keys": "Gestionar API keys",
86
93
  "admin:users": "Administraci\xF3n completa de usuarios",
94
+ "admin:devtools": "Acceso a las APIs de DevTools (registries, testing, scheduled actions)",
87
95
  // Comodín (solo para superadmins)
88
96
  "*": "Acceso completo (solo superadmin)"
89
97
  };
@@ -109,10 +117,20 @@ const SCOPE_CATEGORIES = {
109
117
  description: "Gesti\xF3n de tareas y TODOs",
110
118
  scopes: ["tasks:read", "tasks:write", "tasks:delete"]
111
119
  },
120
+ teams: {
121
+ name: "Teams",
122
+ description: "Equipos, miembros e invitaciones",
123
+ scopes: ["teams:read", "teams:write", "teams:delete"]
124
+ },
125
+ billing: {
126
+ name: "Billing",
127
+ description: "Suscripciones, facturas, uso y planes",
128
+ scopes: ["billing:read", "billing:write"]
129
+ },
112
130
  admin: {
113
131
  name: "Administraci\xF3n",
114
132
  description: "Funciones administrativas",
115
- scopes: ["admin:api-keys", "admin:users"]
133
+ scopes: ["admin:api-keys", "admin:users", "admin:devtools"]
116
134
  },
117
135
  system: {
118
136
  name: "Sistema",
@@ -1 +1 @@
1
- {"version":3,"file":"patterns-usages.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/routes/patterns-usages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAavD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B;;gBAQQ,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;;;EAkFzE"}
1
+ {"version":3,"file":"patterns-usages.d.ts","sourceRoot":"","sources":["../../../../src/lib/api/routes/patterns-usages.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAavD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,2BAA2B;;gBAQQ,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAA;SAAE,CAAC;;;EA0EzE"}
@@ -1,4 +1,3 @@
1
- import { NextResponse } from "next/server";
2
1
  import {
3
2
  createApiResponse,
4
3
  createApiError,
@@ -7,7 +6,7 @@ import {
7
6
  handleCorsPreflightRequest,
8
7
  addCorsHeaders
9
8
  } from "../helpers.js";
10
- import { authenticateRequest, hasRequiredScope } from "../auth/dual-auth.js";
9
+ import { authenticateRequest, createAuthFailureResponse } from "../auth/dual-auth.js";
11
10
  import { PatternUsageService } from "../../services/index.js";
12
11
  import { queryOneWithRLS } from "../../db.js";
13
12
  function createPatternUsagesHandlers() {
@@ -17,20 +16,13 @@ function createPatternUsagesHandlers() {
17
16
  const GET = withApiLogging(
18
17
  async (req, { params }) => {
19
18
  try {
20
- const authResult = await authenticateRequest(req);
19
+ const authResult = await authenticateRequest(req, { requiredScope: "patterns:read" });
21
20
  if (!authResult.success) {
22
- return NextResponse.json(
23
- { success: false, error: "Authentication required", code: "AUTHENTICATION_FAILED" },
24
- { status: 401 }
25
- );
21
+ return createAuthFailureResponse(authResult);
26
22
  }
27
23
  if (authResult.rateLimitResponse) {
28
24
  return authResult.rateLimitResponse;
29
25
  }
30
- if (!hasRequiredScope(authResult, "patterns:read")) {
31
- const response2 = createApiError("Insufficient permissions", 403);
32
- return addCorsHeaders(response2);
33
- }
34
26
  const { id: patternId } = await params;
35
27
  const userId = authResult.user.id;
36
28
  if (!patternId || patternId.trim() === "") {
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Login Methods & Presets
3
+ *
4
+ * Pure helpers around `AuthConfig.methods` — the list of login methods an app
5
+ * offers (`'email-otp'`, `'google'`, `'email-password'`), in priority order.
6
+ * Safe to import from server and client code: no side effects, types only.
7
+ *
8
+ * Portfolio policy (#126): the DEFAULT is the passwordless preset — a one-time
9
+ * code by email + Google OAuth, no password field. Themes opt into the classic
10
+ * preset (or any combination) from their app.config.ts.
11
+ */
12
+ import type { AuthConfig, AuthLoginMethod, AuthPreset } from '../config/types';
13
+ /** Every method the core knows how to render/serve. */
14
+ export declare const AUTH_LOGIN_METHODS: readonly AuthLoginMethod[];
15
+ /** Named bundles of login methods. Arrays are in UI priority order. */
16
+ export declare const AUTH_PRESETS: Readonly<Record<AuthPreset, readonly AuthLoginMethod[]>>;
17
+ /** The preset applied when a theme does not set `auth.methods`. */
18
+ export declare const DEFAULT_AUTH_METHODS: readonly AuthLoginMethod[];
19
+ export declare function isAuthLoginMethod(value: unknown): value is AuthLoginMethod;
20
+ /**
21
+ * Resolve the login methods an app offers.
22
+ *
23
+ * - Unknown values are dropped (with a warning), duplicates removed, order kept.
24
+ * - No `methods` configured, or nothing valid left → the default (passwordless)
25
+ * preset.
26
+ */
27
+ export declare function resolveAuthMethods(authConfig?: Pick<AuthConfig, 'methods'> | {
28
+ methods?: readonly string[];
29
+ } | null): AuthLoginMethod[];
30
+ export declare function isAuthMethodEnabled(methods: readonly AuthLoginMethod[], method: AuthLoginMethod): boolean;
31
+ /**
32
+ * True when the login has NO password path: a one-time code is offered and
33
+ * `'email-password'` is not. Google may or may not be present.
34
+ */
35
+ export declare function isPasswordlessPreset(methods: readonly AuthLoginMethod[]): boolean;
36
+ /**
37
+ * The email-based method the login form should open with: the first of
38
+ * `'email-otp'` / `'email-password'` in the configured order, or null when the
39
+ * app is Google-only.
40
+ */
41
+ export declare function getPrimaryEmailMethod(methods: readonly AuthLoginMethod[]): Extract<AuthLoginMethod, 'email-otp' | 'email-password'> | null;
42
+ /**
43
+ * Which named preset the resolved methods correspond to (order-insensitive),
44
+ * or null for a custom combination.
45
+ */
46
+ export declare function matchAuthPreset(methods: readonly AuthLoginMethod[]): AuthPreset | null;
47
+ /**
48
+ * Server-side: should Better Auth's email + password endpoints be enabled?
49
+ * Defaults to true regardless of the UI preset (see `AuthConfig.emailAndPassword`).
50
+ */
51
+ export declare function isPasswordLoginEnabled(authConfig?: Pick<AuthConfig, 'emailAndPassword'> | null): boolean;
52
+ //# sourceMappingURL=auth-methods.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-methods.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/auth-methods.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE9E,uDAAuD;AACvD,eAAO,MAAM,kBAAkB,EAAE,SAAS,eAAe,EAA8C,CAAA;AAEvG,uEAAuE;AACvE,eAAO,MAAM,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,UAAU,EAAE,SAAS,eAAe,EAAE,CAAC,CAKjF,CAAA;AAED,mEAAmE;AACnE,eAAO,MAAM,oBAAoB,EAAE,SAAS,eAAe,EAA8B,CAAA;AAEzF,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,eAAe,CAE1E;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,GAChF,eAAe,EAAE,CAkBnB;AAED,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,OAAO,CAEzG;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,OAAO,CAEjF;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,SAAS,eAAe,EAAE,GAClC,OAAO,CAAC,eAAe,EAAE,WAAW,GAAG,gBAAgB,CAAC,GAAG,IAAI,CAKjE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,eAAe,EAAE,GAAG,UAAU,GAAG,IAAI,CAMtF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,kBAAkB,CAAC,GAAG,IAAI,GACvD,OAAO,CAET"}
@@ -0,0 +1,63 @@
1
+ const AUTH_LOGIN_METHODS = ["email-otp", "google", "email-password"];
2
+ const AUTH_PRESETS = {
3
+ /** One-time code by email + Google. No password anywhere. DEFAULT. */
4
+ passwordless: ["email-otp", "google"],
5
+ /** Email + password (with signup / reset flows) + Google. */
6
+ classic: ["email-password", "google"]
7
+ };
8
+ const DEFAULT_AUTH_METHODS = AUTH_PRESETS.passwordless;
9
+ function isAuthLoginMethod(value) {
10
+ return typeof value === "string" && AUTH_LOGIN_METHODS.includes(value);
11
+ }
12
+ function resolveAuthMethods(authConfig) {
13
+ const configured = authConfig == null ? void 0 : authConfig.methods;
14
+ if (!Array.isArray(configured)) return [...DEFAULT_AUTH_METHODS];
15
+ const valid = [];
16
+ for (const method of configured) {
17
+ if (!isAuthLoginMethod(method)) {
18
+ console.warn(`[Auth] Ignoring unknown auth.methods entry: ${String(method)}`);
19
+ continue;
20
+ }
21
+ if (!valid.includes(method)) valid.push(method);
22
+ }
23
+ if (valid.length === 0) {
24
+ console.warn("[Auth] auth.methods resolved to an empty list; falling back to the passwordless preset");
25
+ return [...DEFAULT_AUTH_METHODS];
26
+ }
27
+ return valid;
28
+ }
29
+ function isAuthMethodEnabled(methods, method) {
30
+ return methods.includes(method);
31
+ }
32
+ function isPasswordlessPreset(methods) {
33
+ return methods.includes("email-otp") && !methods.includes("email-password");
34
+ }
35
+ function getPrimaryEmailMethod(methods) {
36
+ for (const method of methods) {
37
+ if (method === "email-otp" || method === "email-password") return method;
38
+ }
39
+ return null;
40
+ }
41
+ function matchAuthPreset(methods) {
42
+ const sorted = [...methods].sort().join(",");
43
+ for (const [preset, presetMethods] of Object.entries(AUTH_PRESETS)) {
44
+ if ([...presetMethods].sort().join(",") === sorted) return preset;
45
+ }
46
+ return null;
47
+ }
48
+ function isPasswordLoginEnabled(authConfig) {
49
+ var _a;
50
+ return ((_a = authConfig == null ? void 0 : authConfig.emailAndPassword) == null ? void 0 : _a.enabled) !== false;
51
+ }
52
+ export {
53
+ AUTH_LOGIN_METHODS,
54
+ AUTH_PRESETS,
55
+ DEFAULT_AUTH_METHODS,
56
+ getPrimaryEmailMethod,
57
+ isAuthLoginMethod,
58
+ isAuthMethodEnabled,
59
+ isPasswordLoginEnabled,
60
+ isPasswordlessPreset,
61
+ matchAuthPreset,
62
+ resolveAuthMethods
63
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"registration-guard-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/registration-guard-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,uBAAuB,QAAO,gBA2C1C,CAAC"}
1
+ {"version":3,"file":"registration-guard-plugin.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/registration-guard-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,uBAAuB,QAAO,gBA6C1C,CAAC"}
@@ -29,9 +29,18 @@ export declare function isDomainAllowed(email: string, allowedDomains: string[])
29
29
  *
30
30
  * Google is disabled when:
31
31
  * - providers.google.enabled is explicitly false
32
+ * - 'google' is not one of the configured login `methods`
32
33
  * - GOOGLE_CLIENT_ID env var is not set (runtime check, not done here)
33
34
  */
34
35
  export declare function isGoogleAuthEnabled(authConfig: AuthConfig): boolean;
36
+ /**
37
+ * Check if the email+password SIGNUP flow (the /signup page and its form) is
38
+ * available: the registration mode must allow self-signup AND
39
+ * 'email-password' must be one of the configured login methods. Under the
40
+ * passwordless preset the first OTP sign-in creates the account, so there is
41
+ * no separate signup page.
42
+ */
43
+ export declare function isPasswordSignupAvailable(authConfig: AuthConfig): boolean;
35
44
  /**
36
45
  * Check if the signup page should be accessible.
37
46
  *
@@ -1 +1 @@
1
- {"version":3,"file":"registration-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/registration-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAErF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAElE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAShF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAEnE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,OAAO,GACf,OAAO,CAGT;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,CAW5E"}
1
+ {"version":3,"file":"registration-helpers.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/registration-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGrF;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAElE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,OAAO,CAShF;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAKnE;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAKzE;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEpE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,OAAO,GACf,OAAO,CAGT;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAEnE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,UAAU,GAAG,gBAAgB,CAY5E"}
@@ -1,3 +1,4 @@
1
+ import { resolveAuthMethods } from "./auth-methods.js";
1
2
  function isRegistrationOpen(mode) {
2
3
  return mode === "open" || mode === "domain-open";
3
4
  }
@@ -12,7 +13,10 @@ function isDomainAllowed(email, allowedDomains) {
12
13
  }
13
14
  function isGoogleAuthEnabled(authConfig) {
14
15
  var _a, _b;
15
- return ((_b = (_a = authConfig.providers) == null ? void 0 : _a.google) == null ? void 0 : _b.enabled) !== false;
16
+ return ((_b = (_a = authConfig.providers) == null ? void 0 : _a.google) == null ? void 0 : _b.enabled) !== false && resolveAuthMethods(authConfig).includes("google");
17
+ }
18
+ function isPasswordSignupAvailable(authConfig) {
19
+ return isEmailSignupEnabled(authConfig.registration.mode) && resolveAuthMethods(authConfig).includes("email-password");
16
20
  }
17
21
  function isSignupPageVisible(mode) {
18
22
  return mode === "open" || mode === "domain-open";
@@ -36,7 +40,8 @@ function getPublicAuthConfig(authConfig) {
36
40
  google: {
37
41
  enabled: isGoogleAuthEnabled(authConfig)
38
42
  }
39
- }
43
+ },
44
+ methods: resolveAuthMethods(authConfig)
40
45
  };
41
46
  }
42
47
  export {
@@ -45,6 +50,7 @@ export {
45
50
  isEmailLoginVisible,
46
51
  isEmailSignupEnabled,
47
52
  isGoogleAuthEnabled,
53
+ isPasswordSignupAvailable,
48
54
  isRegistrationOpen,
49
55
  isSignupPageVisible,
50
56
  shouldBlockSignup
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Device fingerprinting for new-device login detection.
3
+ *
4
+ * The fingerprint is deliberately COARSE:
5
+ * fingerprint = sha256( normalizedUA + "|" + ip/24 )
6
+ *
7
+ * - UA is normalized so browser auto-updates (patch/build version churn) do NOT
8
+ * look like a brand-new device every week. We keep major.minor of each version
9
+ * token and drop the rest (`Chrome/120.0.6099.109` → `Chrome/120.0`).
10
+ * - IP is truncated to its /24 network so a phone hopping between addresses in
11
+ * the same carrier/NAT block is still "the same place".
12
+ *
13
+ * This is an anti-annoyance heuristic for security emails, NOT an
14
+ * authentication signal — a coarse fingerprint means fewer false "new device"
15
+ * alerts, at the cost of not distinguishing devices that share a /24 and a
16
+ * near-identical UA. That trade-off is intentional.
17
+ */
18
+ /**
19
+ * Normalize a User-Agent string:
20
+ * - lower-cased and whitespace-collapsed
21
+ * - every version token with 3+ dotted numeric components is reduced to its
22
+ * first two (major.minor), stripping patch/build churn
23
+ *
24
+ * A missing UA normalizes to the empty string (all UA-less clients from the
25
+ * same /24 then share a fingerprint, which is the desired conservative bucket).
26
+ */
27
+ export declare function normalizeUserAgent(ua: string | null | undefined): string;
28
+ /**
29
+ * Reduce an IP address to its /24 network key.
30
+ * - IPv4 `a.b.c.d` → `a.b.c.0/24`
31
+ * - IPv6 `x:y:z:...` → first three hextets + `::/48` (coarse, best-effort)
32
+ * - anything else → returned unchanged (e.g. the literal 'unknown')
33
+ */
34
+ export declare function ipToNetworkKey(ip: string | null | undefined): string;
35
+ /**
36
+ * Compute the stable device fingerprint for a login.
37
+ *
38
+ * @param ua - raw User-Agent header (or null)
39
+ * @param ip - client IP (or null); truncated to /24 before hashing
40
+ * @returns hex sha256 of `normalizedUA|ipNetworkKey`
41
+ */
42
+ export declare function computeDeviceFingerprint(ua: string | null, ip: string | null): string;
43
+ /**
44
+ * Extract the best-effort client IP from request headers.
45
+ *
46
+ * Strategy mirrors the rate-limiter (see lib/api/rate-limit.ts):
47
+ * Cloudflare > rightmost x-forwarded-for > x-real-ip > true-client-ip > 'unknown'
48
+ * The rightmost x-forwarded-for entry is the one appended by the last (trusted)
49
+ * proxy, so it is the hardest for a client to spoof.
50
+ */
51
+ export declare function extractClientIp(headers: Headers): string;
52
+ //# sourceMappingURL=device-fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device-fingerprint.d.ts","sourceRoot":"","sources":["../../../../src/lib/auth/security-notifications/device-fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAQxE;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAiBpE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,MAAM,GAAG,IAAI,EACjB,EAAE,EAAE,MAAM,GAAG,IAAI,GAChB,MAAM,CAGR;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAoBxD"}
@@ -0,0 +1,42 @@
1
+ import { createHash } from "crypto";
2
+ function normalizeUserAgent(ua) {
3
+ if (!ua) return "";
4
+ return ua.toLowerCase().trim().replace(/\s+/g, " ").replace(/(\d+)\.(\d+)(?:\.\d+)+/g, "$1.$2");
5
+ }
6
+ function ipToNetworkKey(ip) {
7
+ if (!ip) return "";
8
+ const trimmed = ip.trim();
9
+ const v4 = trimmed.match(/(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
10
+ if (v4) {
11
+ return `${v4[1]}.${v4[2]}.${v4[3]}.0/24`;
12
+ }
13
+ if (trimmed.includes(":")) {
14
+ const hextets = trimmed.split(":").filter(Boolean).slice(0, 3);
15
+ if (hextets.length > 0) return `${hextets.join(":")}::/48`;
16
+ }
17
+ return trimmed;
18
+ }
19
+ function computeDeviceFingerprint(ua, ip) {
20
+ const material = `${normalizeUserAgent(ua)}|${ipToNetworkKey(ip)}`;
21
+ return createHash("sha256").update(material).digest("hex");
22
+ }
23
+ function extractClientIp(headers) {
24
+ const cfIp = headers.get("cf-connecting-ip");
25
+ if (cfIp) return cfIp;
26
+ const forwardedFor = headers.get("x-forwarded-for");
27
+ if (forwardedFor) {
28
+ const ips = forwardedFor.split(",").map((v) => v.trim()).filter(Boolean);
29
+ if (ips.length > 0) return ips[ips.length - 1];
30
+ }
31
+ const realIp = headers.get("x-real-ip");
32
+ if (realIp) return realIp;
33
+ const trueClientIp = headers.get("true-client-ip");
34
+ if (trueClientIp) return trueClientIp;
35
+ return "unknown";
36
+ }
37
+ export {
38
+ computeDeviceFingerprint,
39
+ extractClientIp,
40
+ ipToNetworkKey,
41
+ normalizeUserAgent
42
+ };
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Security-notifications dispatcher.
3
+ *
4
+ * Called from the Better Auth route handler AFTER the auth response has been
5
+ * produced. It inspects the request path + the outgoing response, and — when a
6
+ * security-relevant event succeeded — records login history and queues the
7
+ * appropriate email via the `auth:security-notification` scheduled action.
8
+ *
9
+ * ────────────────────────────────────────────────────────────────────────────
10
+ * ⚠️ CRITICAL FOOTGUN — read the user from the RESPONSE BODY, not the session.
11
+ * ────────────────────────────────────────────────────────────────────────────
12
+ * For a sign-in, the session does NOT exist on the INCOMING request: the session
13
+ * cookie is only now being written, sitting in the OUTGOING `Set-Cookie` header.
14
+ * Calling `auth.api.getSession({ headers: req.headers })` here would read the
15
+ * incoming cookies, find none, and silently return null — so new-device emails
16
+ * would NEVER fire. We therefore read the just-authenticated user from
17
+ * `response.clone().json()` (Better Auth's sign-in/change-password responses
18
+ * carry `{ user, token, ... }`).
19
+ *
20
+ * The ONE exception is `change-email`: that request is made by an ALREADY
21
+ * authenticated user (its incoming cookie is valid) and its response body is
22
+ * only `{ status: true }` — no user. There we DO read the session, to recover
23
+ * the *old* address the notification must go to. That asymmetry is deliberate;
24
+ * do not "simplify" it into a single getSession call.
25
+ *
26
+ * Everything here is best-effort: any failure is swallowed so a security email
27
+ * problem can NEVER turn a successful auth response into a 500.
28
+ */
29
+ import type { NextRequest, NextResponse } from 'next/server';
30
+ /**
31
+ * Entry point. Inspect (req, response) and fire the matching security email.
32
+ *
33
+ * @param req the auth request (a clone is fine; headers + body are read here)
34
+ * @param response the outgoing auth response (cloned before reading its body)
35
+ */
36
+ export declare function dispatchSecurityNotificationsForRequest(req: NextRequest, response: NextResponse | Response): Promise<void>;
37
+ //# sourceMappingURL=dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../../../src/lib/auth/security-notifications/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAwM5D;;;;;GAKG;AACH,wBAAsB,uCAAuC,CAC3D,GAAG,EAAE,WAAW,EAChB,QAAQ,EAAE,YAAY,GAAG,QAAQ,GAChC,OAAO,CAAC,IAAI,CAAC,CAsCf"}