@nextsparkjs/core 0.1.0-beta.194 → 0.1.0-beta.196

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 (481) hide show
  1. package/dist/components/app/guards/DeveloperGuard.d.ts +8 -1
  2. package/dist/components/app/guards/DeveloperGuard.d.ts.map +1 -1
  3. package/dist/components/app/guards/DeveloperGuard.js +2 -1
  4. package/dist/components/app/guards/SuperAdminGuard.d.ts +8 -1
  5. package/dist/components/app/guards/SuperAdminGuard.d.ts.map +1 -1
  6. package/dist/components/app/guards/SuperAdminGuard.js +2 -1
  7. package/dist/components/billing/InvoicesPagination.js +2 -2
  8. package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
  9. package/dist/components/dashboard/block-editor/block-picker.js +2 -1
  10. package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
  11. package/dist/components/dashboard/block-editor/builder-editor-view.js +39 -23
  12. package/dist/components/dashboard/block-editor/pattern-reference-preview.d.ts.map +1 -1
  13. package/dist/components/dashboard/block-editor/pattern-reference-preview.js +2 -1
  14. package/dist/components/dashboard/layouts/AuthGuard.d.ts.map +1 -1
  15. package/dist/components/dashboard/layouts/AuthGuard.js +3 -4
  16. package/dist/components/dashboard/layouts/AuthenticatedDashboardLayout.d.ts.map +1 -1
  17. package/dist/components/dashboard/layouts/AuthenticatedDashboardLayout.js +9 -10
  18. package/dist/components/dashboard/layouts/DashboardAuthLayout.d.ts.map +1 -1
  19. package/dist/components/dashboard/layouts/DashboardAuthLayout.js +3 -4
  20. package/dist/components/dashboard/layouts/DashboardAuthSkeleton.d.ts +2 -2
  21. package/dist/components/dashboard/navigation/DynamicNavigation.js +2 -2
  22. package/dist/components/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
  23. package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -2
  24. package/dist/components/entities/wrappers/EntityFormWrapper.d.ts.map +1 -1
  25. package/dist/components/entities/wrappers/EntityFormWrapper.js +5 -2
  26. package/dist/components/entities/wrappers/EntityListWrapper.d.ts.map +1 -1
  27. package/dist/components/entities/wrappers/EntityListWrapper.js +5 -2
  28. package/dist/components/settings/layouts/SettingsSidebar.d.ts.map +1 -1
  29. package/dist/components/settings/layouts/SettingsSidebar.js +0 -1
  30. package/dist/components/teams/CreateTeamButton.js +2 -2
  31. package/dist/components/teams/CreateTeamDialog.js +1 -1
  32. package/dist/components/teams/InviteMemberButton.js +3 -3
  33. package/dist/components/teams/InviteMemberDialog.js +1 -1
  34. package/dist/components/teams/TeamPendingInvitations.js +2 -2
  35. package/dist/components/ui/relation-display.d.ts.map +1 -1
  36. package/dist/components/ui/relation-display.js +2 -1
  37. package/dist/components/ui/user-display.d.ts.map +1 -1
  38. package/dist/components/ui/user-display.js +2 -1
  39. package/dist/emails/otp-verification.d.ts.map +1 -1
  40. package/dist/emails/otp-verification.js +5 -3
  41. package/dist/emails/reset-password.d.ts.map +1 -1
  42. package/dist/emails/reset-password.js +5 -3
  43. package/dist/emails/team-invitation.d.ts.map +1 -1
  44. package/dist/emails/team-invitation.js +3 -2
  45. package/dist/emails/verify-email.d.ts.map +1 -1
  46. package/dist/emails/verify-email.js +5 -3
  47. package/dist/hooks/useAuth.d.ts.map +1 -1
  48. package/dist/hooks/useAuth.js +21 -4
  49. package/dist/hooks/usePatternUsages.d.ts.map +1 -1
  50. package/dist/hooks/usePatternUsages.js +3 -2
  51. package/dist/lib/api/api-error.d.ts +2 -0
  52. package/dist/lib/api/api-error.d.ts.map +1 -1
  53. package/dist/lib/api/api-error.js +3 -1
  54. package/dist/lib/api/auth/dual-auth.d.ts +2 -1
  55. package/dist/lib/api/auth/dual-auth.d.ts.map +1 -1
  56. package/dist/lib/api/auth/dual-auth.js +22 -4
  57. package/dist/lib/api/auth/scope-policy.d.ts +6 -3
  58. package/dist/lib/api/auth/scope-policy.d.ts.map +1 -1
  59. package/dist/lib/api/auth.d.ts +2 -0
  60. package/dist/lib/api/auth.d.ts.map +1 -1
  61. package/dist/lib/api/auth.js +10 -10
  62. package/dist/lib/api/client-headers.d.ts +11 -0
  63. package/dist/lib/api/client-headers.d.ts.map +1 -0
  64. package/dist/lib/api/client-headers.js +12 -0
  65. package/dist/lib/api/client-ip.d.ts +59 -0
  66. package/dist/lib/api/client-ip.d.ts.map +1 -0
  67. package/dist/lib/api/client-ip.js +91 -0
  68. package/dist/lib/api/cors-response.d.ts +55 -0
  69. package/dist/lib/api/cors-response.d.ts.map +1 -0
  70. package/dist/lib/api/cors-response.js +90 -0
  71. package/dist/lib/api/entities.d.ts.map +1 -1
  72. package/dist/lib/api/entities.js +4 -3
  73. package/dist/lib/api/entity/audit-log.d.ts.map +1 -1
  74. package/dist/lib/api/entity/audit-log.js +2 -1
  75. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  76. package/dist/lib/api/entity/generic-handler.js +23 -8
  77. package/dist/lib/api/helpers.d.ts +8 -2
  78. package/dist/lib/api/helpers.d.ts.map +1 -1
  79. package/dist/lib/api/helpers.js +32 -103
  80. package/dist/lib/api/keys.d.ts +6 -0
  81. package/dist/lib/api/keys.d.ts.map +1 -1
  82. package/dist/lib/api/keys.js +7 -1
  83. package/dist/lib/api/permission-middleware.d.ts.map +1 -1
  84. package/dist/lib/api/permission-middleware.js +0 -2
  85. package/dist/lib/api/rate-limit.d.ts +12 -0
  86. package/dist/lib/api/rate-limit.d.ts.map +1 -1
  87. package/dist/lib/api/rate-limit.js +50 -43
  88. package/dist/lib/api/request-origin.d.ts +16 -7
  89. package/dist/lib/api/request-origin.d.ts.map +1 -1
  90. package/dist/lib/api/request-origin.js +43 -20
  91. package/dist/lib/auth/load-login-page.d.ts +10 -0
  92. package/dist/lib/auth/load-login-page.d.ts.map +1 -0
  93. package/dist/lib/auth/load-login-page.js +7 -0
  94. package/dist/lib/auth/runtime-readiness.d.ts.map +1 -1
  95. package/dist/lib/auth/runtime-readiness.js +4 -0
  96. package/dist/lib/auth/sample-accounts.d.ts +17 -0
  97. package/dist/lib/auth/sample-accounts.d.ts.map +1 -0
  98. package/dist/lib/auth/sample-accounts.js +22 -0
  99. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts +1 -8
  100. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts.map +1 -1
  101. package/dist/lib/auth/security-notifications/device-fingerprint.js +2 -12
  102. package/dist/lib/auth-email-callbacks.js +3 -3
  103. package/dist/lib/auth.d.ts.map +1 -1
  104. package/dist/lib/auth.js +13 -5
  105. package/dist/lib/cache/public-entity-cache.d.ts +21 -0
  106. package/dist/lib/cache/public-entity-cache.d.ts.map +1 -0
  107. package/dist/lib/cache/public-entity-cache.js +25 -0
  108. package/dist/lib/config/config-client.d.ts.map +1 -1
  109. package/dist/lib/config/config-client.js +1 -1
  110. package/dist/lib/config/config-sync.d.ts.map +1 -1
  111. package/dist/lib/config/config-sync.js +1 -1
  112. package/dist/lib/config/public-config-client.d.ts +1 -0
  113. package/dist/lib/config/public-config-client.d.ts.map +1 -1
  114. package/dist/lib/config/public-config-client.js +3 -1
  115. package/dist/lib/config/types.d.ts +2 -0
  116. package/dist/lib/config/types.d.ts.map +1 -1
  117. package/dist/lib/constants/reserved-slugs.d.ts +17 -8
  118. package/dist/lib/constants/reserved-slugs.d.ts.map +1 -1
  119. package/dist/lib/constants/reserved-slugs.js +16 -52
  120. package/dist/lib/db.d.ts.map +1 -1
  121. package/dist/lib/db.js +9 -3
  122. package/dist/lib/entities/entity-hooks.d.ts.map +1 -1
  123. package/dist/lib/entities/entity-hooks.js +4 -0
  124. package/dist/lib/entities/external-api-generator.d.ts.map +1 -1
  125. package/dist/lib/entities/external-api-generator.js +2 -4
  126. package/dist/lib/entities/public-slug.d.ts +46 -0
  127. package/dist/lib/entities/public-slug.d.ts.map +1 -0
  128. package/dist/lib/entities/public-slug.js +39 -0
  129. package/dist/lib/mcp/errors.d.ts +2 -0
  130. package/dist/lib/mcp/errors.d.ts.map +1 -1
  131. package/dist/lib/mcp/errors.js +3 -1
  132. package/dist/lib/mcp/index.d.ts +1 -1
  133. package/dist/lib/mcp/index.d.ts.map +1 -1
  134. package/dist/lib/mcp/index.js +2 -1
  135. package/dist/lib/services/generic-entity.service.d.ts.map +1 -1
  136. package/dist/lib/services/generic-entity.service.js +2 -0
  137. package/dist/lib/teams/actions.d.ts.map +1 -1
  138. package/dist/lib/teams/actions.js +0 -1
  139. package/dist/messages/de/billing.json +12 -1
  140. package/dist/messages/de/common.json +2 -0
  141. package/dist/messages/de/docs.json +1 -0
  142. package/dist/messages/de/features.json +16 -4
  143. package/dist/messages/de/home.json +5 -0
  144. package/dist/messages/de/index.d.ts +68 -25
  145. package/dist/messages/de/index.d.ts.map +1 -1
  146. package/dist/messages/de/index.js +2 -0
  147. package/dist/messages/de/index.ts +2 -0
  148. package/dist/messages/de/settings.json +1 -0
  149. package/dist/messages/de/teams.json +3 -18
  150. package/dist/messages/en/billing.json +1 -1
  151. package/dist/messages/en/common.json +2 -0
  152. package/dist/messages/en/docs.json +1 -0
  153. package/dist/messages/en/features.json +16 -4
  154. package/dist/messages/en/home.json +5 -0
  155. package/dist/messages/en/index.d.ts +58 -25
  156. package/dist/messages/en/index.d.ts.map +1 -1
  157. package/dist/messages/en/index.js +2 -0
  158. package/dist/messages/en/index.ts +2 -0
  159. package/dist/messages/en/settings.json +1 -0
  160. package/dist/messages/en/teams.json +3 -18
  161. package/dist/messages/es/billing.json +1 -1
  162. package/dist/messages/es/common.json +2 -0
  163. package/dist/messages/es/docs.json +1 -0
  164. package/dist/messages/es/features.json +16 -4
  165. package/dist/messages/es/home.json +5 -0
  166. package/dist/messages/es/index.d.ts +41 -8
  167. package/dist/messages/es/index.d.ts.map +1 -1
  168. package/dist/messages/es/index.js +2 -0
  169. package/dist/messages/es/index.ts +2 -0
  170. package/dist/messages/es/settings.json +1 -0
  171. package/dist/messages/es/teams.json +3 -0
  172. package/dist/messages/fr/billing.json +12 -1
  173. package/dist/messages/fr/common.json +2 -0
  174. package/dist/messages/fr/docs.json +1 -0
  175. package/dist/messages/fr/features.json +16 -4
  176. package/dist/messages/fr/home.json +5 -0
  177. package/dist/messages/fr/index.d.ts +68 -25
  178. package/dist/messages/fr/index.d.ts.map +1 -1
  179. package/dist/messages/fr/index.js +2 -0
  180. package/dist/messages/fr/index.ts +2 -0
  181. package/dist/messages/fr/settings.json +1 -0
  182. package/dist/messages/fr/teams.json +3 -18
  183. package/dist/messages/it/billing.json +12 -1
  184. package/dist/messages/it/common.json +2 -0
  185. package/dist/messages/it/docs.json +1 -0
  186. package/dist/messages/it/features.json +16 -4
  187. package/dist/messages/it/home.json +5 -0
  188. package/dist/messages/it/index.d.ts +68 -25
  189. package/dist/messages/it/index.d.ts.map +1 -1
  190. package/dist/messages/it/index.js +2 -0
  191. package/dist/messages/it/index.ts +2 -0
  192. package/dist/messages/it/settings.json +1 -0
  193. package/dist/messages/it/teams.json +3 -18
  194. package/dist/messages/pt/billing.json +12 -1
  195. package/dist/messages/pt/common.json +2 -0
  196. package/dist/messages/pt/docs.json +1 -0
  197. package/dist/messages/pt/features.json +16 -4
  198. package/dist/messages/pt/home.json +5 -0
  199. package/dist/messages/pt/index.d.ts +68 -25
  200. package/dist/messages/pt/index.d.ts.map +1 -1
  201. package/dist/messages/pt/index.js +2 -0
  202. package/dist/messages/pt/index.ts +2 -0
  203. package/dist/messages/pt/settings.json +1 -0
  204. package/dist/messages/pt/teams.json +3 -18
  205. package/dist/migrations/029_sample_accounts_outside_development.sql +55 -0
  206. package/dist/migrations/090_sample_data.sql +10 -0
  207. package/dist/routes/(auth)/signup/page.cc.d.ts +3 -8
  208. package/dist/routes/(auth)/signup/page.cc.d.ts.map +1 -1
  209. package/dist/routes/(auth)/signup/page.cc.js +7 -1
  210. package/dist/routes/(auth)/verify-email/page.d.ts.map +1 -1
  211. package/dist/routes/(auth)/verify-email/page.js +2 -1
  212. package/dist/routes/(public)/page.cc.d.ts +3 -0
  213. package/dist/routes/(public)/page.cc.d.ts.map +1 -0
  214. package/dist/routes/(public)/page.cc.js +3 -0
  215. package/dist/routes/_internal/area-access.cc.d.ts +21 -0
  216. package/dist/routes/_internal/area-access.cc.d.ts.map +1 -0
  217. package/dist/routes/_internal/area-access.cc.js +19 -0
  218. package/dist/routes/_internal/auth-layout.d.ts.map +1 -1
  219. package/dist/routes/_internal/auth-layout.js +3 -2
  220. package/dist/routes/_internal/dashboard-main-shared.d.ts +7 -0
  221. package/dist/routes/_internal/dashboard-main-shared.d.ts.map +1 -0
  222. package/dist/routes/_internal/dashboard-main-shared.js +49 -0
  223. package/dist/routes/_internal/default-auth-layout.d.ts.map +1 -1
  224. package/dist/routes/_internal/default-auth-layout.js +3 -2
  225. package/dist/routes/_internal/devtools-layout.cc.d.ts +3 -2
  226. package/dist/routes/_internal/devtools-layout.cc.d.ts.map +1 -1
  227. package/dist/routes/_internal/devtools-layout.cc.js +1 -1
  228. package/dist/routes/_internal/devtools-layout.d.ts +7 -2
  229. package/dist/routes/_internal/devtools-layout.d.ts.map +1 -1
  230. package/dist/routes/_internal/devtools-layout.js +4 -4
  231. package/dist/routes/_internal/entity-detail-route.cc.d.ts +8 -0
  232. package/dist/routes/_internal/entity-detail-route.cc.d.ts.map +1 -0
  233. package/dist/routes/_internal/entity-detail-route.cc.js +5 -0
  234. package/dist/routes/_internal/entity-edit-route.cc.d.ts +8 -0
  235. package/dist/routes/_internal/entity-edit-route.cc.d.ts.map +1 -0
  236. package/dist/routes/_internal/entity-edit-route.cc.js +5 -0
  237. package/dist/routes/_internal/entity-permission-layout.d.ts.map +1 -1
  238. package/dist/routes/_internal/entity-permission-layout.js +0 -7
  239. package/dist/routes/_internal/public-archive-route.d.ts +1 -1
  240. package/dist/routes/_internal/public-archive-route.d.ts.map +1 -1
  241. package/dist/routes/_internal/public-archive-route.js +8 -3
  242. package/dist/routes/_internal/public-item-route.cc.d.ts +5 -1
  243. package/dist/routes/_internal/public-item-route.cc.d.ts.map +1 -1
  244. package/dist/routes/_internal/public-item-route.cc.js +2 -1
  245. package/dist/routes/_internal/public-item-route.d.ts +7 -0
  246. package/dist/routes/_internal/public-item-route.d.ts.map +1 -1
  247. package/dist/routes/_internal/public-item-route.js +6 -1
  248. package/dist/routes/_internal/superadmin-layout.cc.d.ts +2 -1
  249. package/dist/routes/_internal/superadmin-layout.cc.d.ts.map +1 -1
  250. package/dist/routes/_internal/superadmin-layout.cc.js +1 -1
  251. package/dist/routes/_internal/superadmin-layout.d.ts +7 -2
  252. package/dist/routes/_internal/superadmin-layout.d.ts.map +1 -1
  253. package/dist/routes/_internal/superadmin-layout.js +6 -6
  254. package/dist/routes/_internal/suspended-route.d.ts +16 -0
  255. package/dist/routes/_internal/suspended-route.d.ts.map +1 -0
  256. package/dist/routes/_internal/suspended-route.js +7 -0
  257. package/dist/routes/api/auth/[...all]/route.d.ts.map +1 -1
  258. package/dist/routes/api/auth/[...all]/route.js +4 -12
  259. package/dist/routes/api/csp-report/route.d.ts.map +1 -1
  260. package/dist/routes/api/csp-report/route.js +2 -13
  261. package/dist/routes/api/devtools/config/entities/route.d.ts +2 -0
  262. package/dist/routes/api/devtools/config/entities/route.d.ts.map +1 -1
  263. package/dist/routes/api/devtools/config/entities/route.js +2 -0
  264. package/dist/routes/api/devtools/config/theme/route.d.ts +2 -0
  265. package/dist/routes/api/devtools/config/theme/route.d.ts.map +1 -1
  266. package/dist/routes/api/devtools/config/theme/route.js +2 -0
  267. package/dist/routes/api/devtools/tests/[...path]/route.d.ts +2 -0
  268. package/dist/routes/api/devtools/tests/[...path]/route.d.ts.map +1 -1
  269. package/dist/routes/api/devtools/tests/[...path]/route.js +2 -0
  270. package/dist/routes/api/devtools/tests/route.d.ts +2 -0
  271. package/dist/routes/api/devtools/tests/route.d.ts.map +1 -1
  272. package/dist/routes/api/devtools/tests/route.js +2 -0
  273. package/dist/routes/api/health/route.d.ts +2 -0
  274. package/dist/routes/api/health/route.d.ts.map +1 -1
  275. package/dist/routes/api/health/route.js +2 -0
  276. package/dist/routes/api/internal/user-metadata/route.d.ts +2 -0
  277. package/dist/routes/api/internal/user-metadata/route.d.ts.map +1 -1
  278. package/dist/routes/api/internal/user-metadata/route.js +2 -0
  279. package/dist/routes/api/mcp/route.d.ts +2 -0
  280. package/dist/routes/api/mcp/route.d.ts.map +1 -1
  281. package/dist/routes/api/mcp/route.js +9 -1
  282. package/dist/routes/api/superadmin/subscriptions/route.d.ts +2 -0
  283. package/dist/routes/api/superadmin/subscriptions/route.d.ts.map +1 -1
  284. package/dist/routes/api/superadmin/subscriptions/route.js +2 -0
  285. package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts +2 -0
  286. package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts.map +1 -1
  287. package/dist/routes/api/superadmin/teams/[teamId]/route.js +2 -0
  288. package/dist/routes/api/superadmin/teams/route.d.ts +2 -0
  289. package/dist/routes/api/superadmin/teams/route.d.ts.map +1 -1
  290. package/dist/routes/api/superadmin/teams/route.js +2 -0
  291. package/dist/routes/api/superadmin/users/[userId]/route.d.ts +2 -0
  292. package/dist/routes/api/superadmin/users/[userId]/route.d.ts.map +1 -1
  293. package/dist/routes/api/superadmin/users/[userId]/route.js +2 -0
  294. package/dist/routes/api/superadmin/users/route.d.ts +2 -0
  295. package/dist/routes/api/superadmin/users/route.d.ts.map +1 -1
  296. package/dist/routes/api/superadmin/users/route.js +2 -0
  297. package/dist/routes/api/user/delete-account/route.d.ts +2 -0
  298. package/dist/routes/api/user/delete-account/route.d.ts.map +1 -1
  299. package/dist/routes/api/user/delete-account/route.js +2 -0
  300. package/dist/routes/api/user/plan-flags/route.d.ts +2 -0
  301. package/dist/routes/api/user/plan-flags/route.d.ts.map +1 -1
  302. package/dist/routes/api/user/plan-flags/route.js +2 -0
  303. package/dist/routes/api/user/profile/route.d.ts +2 -0
  304. package/dist/routes/api/user/profile/route.d.ts.map +1 -1
  305. package/dist/routes/api/user/profile/route.js +4 -3
  306. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts +2 -0
  307. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts.map +1 -1
  308. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.js +2 -0
  309. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts +2 -0
  310. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts.map +1 -1
  311. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.js +2 -0
  312. package/dist/routes/api/v1/billing/cancel/route.d.ts +2 -0
  313. package/dist/routes/api/v1/billing/cancel/route.d.ts.map +1 -1
  314. package/dist/routes/api/v1/billing/cancel/route.js +2 -0
  315. package/dist/routes/api/v1/billing/change-plan/route.d.ts +2 -0
  316. package/dist/routes/api/v1/billing/change-plan/route.d.ts.map +1 -1
  317. package/dist/routes/api/v1/billing/change-plan/route.js +2 -0
  318. package/dist/routes/api/v1/billing/check-action/route.d.ts +2 -0
  319. package/dist/routes/api/v1/billing/check-action/route.d.ts.map +1 -1
  320. package/dist/routes/api/v1/billing/check-action/route.js +2 -0
  321. package/dist/routes/api/v1/billing/checkout/route.d.ts +2 -0
  322. package/dist/routes/api/v1/billing/checkout/route.d.ts.map +1 -1
  323. package/dist/routes/api/v1/billing/checkout/route.js +2 -0
  324. package/dist/routes/api/v1/billing/plans/route.d.ts +2 -0
  325. package/dist/routes/api/v1/billing/plans/route.d.ts.map +1 -1
  326. package/dist/routes/api/v1/billing/plans/route.js +2 -0
  327. package/dist/routes/api/v1/billing/portal/route.d.ts +2 -0
  328. package/dist/routes/api/v1/billing/portal/route.d.ts.map +1 -1
  329. package/dist/routes/api/v1/billing/portal/route.js +2 -0
  330. package/dist/routes/api/v1/blocks/[slug]/route.d.ts +2 -0
  331. package/dist/routes/api/v1/blocks/[slug]/route.d.ts.map +1 -1
  332. package/dist/routes/api/v1/blocks/[slug]/route.js +2 -0
  333. package/dist/routes/api/v1/blocks/route.d.ts +2 -0
  334. package/dist/routes/api/v1/blocks/route.d.ts.map +1 -1
  335. package/dist/routes/api/v1/blocks/route.js +2 -0
  336. package/dist/routes/api/v1/blocks/validate/route.d.ts +2 -0
  337. package/dist/routes/api/v1/blocks/validate/route.d.ts.map +1 -1
  338. package/dist/routes/api/v1/blocks/validate/route.js +2 -0
  339. package/dist/routes/api/v1/devtools/blocks/route.d.ts +2 -1
  340. package/dist/routes/api/v1/devtools/blocks/route.d.ts.map +1 -1
  341. package/dist/routes/api/v1/devtools/blocks/route.js +2 -9
  342. package/dist/routes/api/v1/devtools/docs/route.d.ts +2 -0
  343. package/dist/routes/api/v1/devtools/docs/route.d.ts.map +1 -1
  344. package/dist/routes/api/v1/devtools/docs/route.js +2 -0
  345. package/dist/routes/api/v1/devtools/features/route.d.ts +2 -1
  346. package/dist/routes/api/v1/devtools/features/route.d.ts.map +1 -1
  347. package/dist/routes/api/v1/devtools/features/route.js +2 -9
  348. package/dist/routes/api/v1/devtools/flows/route.d.ts +2 -1
  349. package/dist/routes/api/v1/devtools/flows/route.d.ts.map +1 -1
  350. package/dist/routes/api/v1/devtools/flows/route.js +2 -9
  351. package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts +2 -1
  352. package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts.map +1 -1
  353. package/dist/routes/api/v1/devtools/scheduled-actions/route.js +2 -9
  354. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts +2 -1
  355. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts.map +1 -1
  356. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.js +2 -9
  357. package/dist/routes/api/v1/devtools/testing/route.d.ts +2 -1
  358. package/dist/routes/api/v1/devtools/testing/route.d.ts.map +1 -1
  359. package/dist/routes/api/v1/devtools/testing/route.js +2 -9
  360. package/dist/routes/api/v1/media/[id]/route.d.ts +2 -0
  361. package/dist/routes/api/v1/media/[id]/route.d.ts.map +1 -1
  362. package/dist/routes/api/v1/media/[id]/route.js +2 -0
  363. package/dist/routes/api/v1/media/[id]/tags/route.d.ts +2 -0
  364. package/dist/routes/api/v1/media/[id]/tags/route.d.ts.map +1 -1
  365. package/dist/routes/api/v1/media/[id]/tags/route.js +2 -0
  366. package/dist/routes/api/v1/media/check-duplicates/route.d.ts +2 -0
  367. package/dist/routes/api/v1/media/check-duplicates/route.d.ts.map +1 -1
  368. package/dist/routes/api/v1/media/check-duplicates/route.js +2 -0
  369. package/dist/routes/api/v1/media/route.d.ts +2 -0
  370. package/dist/routes/api/v1/media/route.d.ts.map +1 -1
  371. package/dist/routes/api/v1/media/route.js +2 -0
  372. package/dist/routes/api/v1/media/upload/route.d.ts +4 -1
  373. package/dist/routes/api/v1/media/upload/route.d.ts.map +1 -1
  374. package/dist/routes/api/v1/media/upload/route.js +12 -2
  375. package/dist/routes/api/v1/media-tags/route.d.ts +2 -0
  376. package/dist/routes/api/v1/media-tags/route.d.ts.map +1 -1
  377. package/dist/routes/api/v1/media-tags/route.js +2 -0
  378. package/dist/routes/api/v1/post-categories/[id]/route.d.ts +2 -0
  379. package/dist/routes/api/v1/post-categories/[id]/route.d.ts.map +1 -1
  380. package/dist/routes/api/v1/post-categories/[id]/route.js +2 -0
  381. package/dist/routes/api/v1/post-categories/route.d.ts +2 -0
  382. package/dist/routes/api/v1/post-categories/route.d.ts.map +1 -1
  383. package/dist/routes/api/v1/post-categories/route.js +2 -0
  384. package/dist/routes/api/v1/teams/[teamId]/members/route.d.ts.map +1 -1
  385. package/dist/routes/api/v1/teams/[teamId]/members/route.js +14 -12
  386. package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts +2 -0
  387. package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts.map +1 -1
  388. package/dist/routes/api/v1/teams/[teamId]/subscription/route.js +2 -0
  389. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts +2 -0
  390. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts.map +1 -1
  391. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.js +2 -0
  392. package/dist/routes/api/v1/teams/switch/route.d.ts.map +1 -1
  393. package/dist/routes/api/v1/teams/switch/route.js +4 -1
  394. package/dist/routes/api/v1/users/[id]/route.d.ts.map +1 -1
  395. package/dist/routes/api/v1/users/[id]/route.js +3 -2
  396. package/dist/routes/api/v1/users/docs.md +34 -19
  397. package/dist/routes/api/v1/users/me/route.d.ts +6 -0
  398. package/dist/routes/api/v1/users/me/route.d.ts.map +1 -0
  399. package/dist/routes/api/v1/users/me/route.js +5 -0
  400. package/dist/routes/api/v1/users/presets.ts +2 -2
  401. package/dist/routes/dashboard/(main)/layout.cc.d.ts +4 -0
  402. package/dist/routes/dashboard/(main)/layout.cc.d.ts.map +1 -0
  403. package/dist/routes/dashboard/(main)/layout.cc.js +10 -0
  404. package/dist/routes/dashboard/(main)/layout.d.ts.map +1 -1
  405. package/dist/routes/dashboard/(main)/layout.js +3 -44
  406. package/dist/routes/dashboard/permission-denied/page.d.ts +1 -1
  407. package/dist/routes/dashboard/permission-denied/page.d.ts.map +1 -1
  408. package/dist/routes/dashboard/permission-denied/page.js +5 -1
  409. package/dist/routes/dashboard/settings/password/page.d.ts.map +1 -1
  410. package/dist/routes/dashboard/settings/password/page.js +10 -12
  411. package/dist/routes/devtools/config/page.js +1 -1
  412. package/dist/routes/devtools/layout.cc.d.ts.map +1 -1
  413. package/dist/routes/devtools/layout.cc.js +5 -1
  414. package/dist/routes/devtools/page.js +1 -1
  415. package/dist/routes/devtools/scheduled-actions/page.js +1 -1
  416. package/dist/routes/devtools/tests/[[...path]]/page.js +1 -1
  417. package/dist/routes/manifest.json +10 -0
  418. package/dist/routes/robots.d.ts +10 -0
  419. package/dist/routes/robots.d.ts.map +1 -0
  420. package/dist/routes/robots.js +10 -0
  421. package/dist/routes/superadmin/layout.cc.d.ts.map +1 -1
  422. package/dist/routes/superadmin/layout.cc.js +5 -1
  423. package/dist/routes/variants.json +12 -2
  424. package/dist/templates/ci-workflows/github/cypress-regression.yml +1 -1
  425. package/dist/templates/ci-workflows/github/cypress-smoke.yml +2 -1
  426. package/dist/templates/next.config.mjs +2 -29
  427. package/dist/templates/projects/blog/api/authors/[username]/route.ts +3 -0
  428. package/dist/templates/projects/blog/api/authors/route.ts +3 -0
  429. package/dist/templates/projects/blog/api/posts/public/route.ts +3 -0
  430. package/dist/templates/projects/starter/README.md +2 -0
  431. package/dist/templates/projects/starter/docs/public/01-overview/01-introduction.md +2 -0
  432. package/dist/templates/projects/starter/templates/dashboard/analytics/layout.tsx +14 -0
  433. package/dist/templates/proxy.ts +27 -9
  434. package/dist/templates/public/favicon.ico +0 -0
  435. package/dist/templates/public/uploads/README.md +5 -94
  436. package/migrations/029_sample_accounts_outside_development.sql +55 -0
  437. package/migrations/090_sample_data.sql +10 -0
  438. package/package.json +2 -2
  439. package/scripts/build/registry/__tests__/api-docs-colocated.test.mjs +3 -0
  440. package/scripts/build/registry/__tests__/billing-registry.test.mjs +50 -1
  441. package/scripts/build/registry/__tests__/block-registry.test.mjs +3 -0
  442. package/scripts/build/registry/__tests__/icons-discovery.test.mjs +3 -0
  443. package/scripts/build/registry/__tests__/quiet-console.mjs +17 -0
  444. package/scripts/build/registry/__tests__/safe-fs.test.mjs +3 -0
  445. package/scripts/build/registry/__tests__/team-roles.test.mjs +3 -0
  446. package/scripts/build/registry/discovery/permissions.test.mjs +3 -0
  447. package/scripts/build/registry/discovery/plugin-capabilities.mjs +2 -2
  448. package/scripts/build/registry/generators/billing-registry.mjs +7 -3
  449. package/scripts/build/registry/host/README.md +25 -1
  450. package/scripts/build/registry/host/__tests__/host-area-access.test.mjs +32 -0
  451. package/scripts/build/registry/host/__tests__/host-entities.test.mjs +32 -1
  452. package/scripts/build/registry/host/__tests__/host-plan.test.mjs +12 -2
  453. package/scripts/build/registry/host/__tests__/host-proxy-areas.test.mjs +72 -1
  454. package/scripts/build/registry/host/entity-routes.mjs +9 -3
  455. package/scripts/build/registry/host/proxy-areas.mjs +65 -2
  456. package/scripts/build/registry/host/static-imports.mjs +4 -0
  457. package/scripts/build/routes-manifest.mjs +13 -1
  458. package/scripts/db/run-migrations.mjs +30 -10
  459. package/scripts/db/sample-data.mjs +44 -0
  460. package/scripts/db/ssl-config.mjs +12 -1
  461. package/scripts/db/verify-theme-migrations.mjs +6 -0
  462. package/templates/ci-workflows/github/cypress-regression.yml +1 -1
  463. package/templates/ci-workflows/github/cypress-smoke.yml +2 -1
  464. package/templates/next.config.mjs +2 -29
  465. package/templates/projects/blog/api/authors/[username]/route.ts +3 -0
  466. package/templates/projects/blog/api/authors/route.ts +3 -0
  467. package/templates/projects/blog/api/posts/public/route.ts +3 -0
  468. package/templates/projects/starter/README.md +2 -0
  469. package/templates/projects/starter/docs/public/01-overview/01-introduction.md +2 -0
  470. package/templates/projects/starter/templates/dashboard/analytics/layout.tsx +14 -0
  471. package/templates/proxy.ts +27 -9
  472. package/templates/public/favicon.ico +0 -0
  473. package/templates/public/uploads/README.md +5 -94
  474. package/tests/jest/__mocks__/@nextsparkjs/registries/api-presets-registry.ts +2 -0
  475. package/tests/jest/__mocks__/@nextsparkjs/registries/mcp-registry.ts +2 -0
  476. package/dist/templates/projects/starter/public/brand/.gitkeep +0 -0
  477. package/dist/templates/public/uploads/.gitignore +0 -6
  478. package/dist/templates/public/uploads/temp/.gitkeep +0 -1
  479. package/templates/projects/starter/public/brand/.gitkeep +0 -0
  480. package/templates/public/uploads/.gitignore +0 -6
  481. package/templates/public/uploads/temp/.gitkeep +0 -1
@@ -1,13 +1,15 @@
1
1
  import { NextResponse } from "next/server";
2
- import { validateApiKey } from "./auth.js";
2
+ import { getValidatedApiKey, validateApiKey } from "./auth.js";
3
3
  import { mutateWithRLS, queryWithRLS } from "../db.js";
4
- import { checkRateLimit, addRateLimitHeaders } from "./rate-limit.js";
4
+ import { apiKeyRateLimitResponse } from "./rate-limit.js";
5
+ import { getRecordedClientIp } from "./client-ip.js";
5
6
  import { getApplicationConfig } from "../config/index.js";
6
7
  import { auth } from "../auth.js";
7
8
  import { MetaService } from "../services/meta.service.js";
8
9
  import { ScopeService } from "../services/scope.service.js";
9
10
  import { getChildEntities } from "../entities/queries.js";
10
- import { getCorsOrigins, normalizeOrigin, isOriginAllowed } from "../utils/cors.js";
11
+ import { getCorsOrigins } from "../utils/cors.js";
12
+ import { corsGrant, requestPathname, setCorsHeaders, varyOnOrigin } from "./cors-response.js";
11
13
  import { isValidUUID } from "../utils/uuid.js";
12
14
  import {
13
15
  describeRoute,
@@ -34,7 +36,6 @@ async function validateAndAuthenticateRequest(request, options = {}) {
34
36
  flags: userFlags,
35
37
  isSession: true
36
38
  };
37
- console.log(`[Auth] Session authentication successful for user ${session.user.id} with role ${userRole}`);
38
39
  return { auth: sessionAuth };
39
40
  }
40
41
  } catch (sessionError) {
@@ -56,7 +57,8 @@ async function validateAndAuthenticateRequest(request, options = {}) {
56
57
  )
57
58
  };
58
59
  }
59
- return applyApiKeyRateLimit(apiKeyAuth);
60
+ const rateLimitResponse = apiKeyRateLimitResponse(request, apiKeyAuth);
61
+ return rateLimitResponse ? { auth: apiKeyAuth, rateLimitResponse } : { auth: apiKeyAuth };
60
62
  }
61
63
  function generateScopesForRole(role, flags = []) {
62
64
  const baseScopes = getBaseScopesFromRegistry();
@@ -101,47 +103,15 @@ async function validateAndAuthenticateApiRequest(request) {
101
103
  if (!auth2) {
102
104
  throw new Error("Invalid API key");
103
105
  }
104
- return applyApiKeyRateLimit(auth2);
105
- }
106
- function applyApiKeyRateLimit(auth2) {
107
- const rateLimitResult = checkRateLimit(auth2.keyId);
108
- if (!rateLimitResult.allowed) {
109
- const response = NextResponse.json(
110
- {
111
- success: false,
112
- error: "Rate limit exceeded",
113
- message: `Too many requests. Limit: ${rateLimitResult.limit} requests per minute`,
114
- code: "RATE_LIMIT_EXCEEDED",
115
- retryAfter: Math.ceil((rateLimitResult.resetTime - Date.now()) / 1e3)
116
- },
117
- { status: 429 }
118
- );
119
- addRateLimitHeaders(response, auth2.keyId, auth2.scopes);
120
- return { auth: auth2, rateLimitResponse: response };
121
- }
122
- return { auth: auth2 };
106
+ const rateLimitResponse = apiKeyRateLimitResponse(request, auth2);
107
+ return rateLimitResponse ? { auth: auth2, rateLimitResponse } : { auth: auth2 };
123
108
  }
124
109
  function getApiAuth(request) {
125
- const userId = request.headers.get("x-api-user-id");
126
- const keyId = request.headers.get("x-api-key-id");
127
- const scopesHeader = request.headers.get("x-api-scopes");
128
- if (!userId || !keyId || !scopesHeader) {
129
- throw new Error("Missing API authentication headers");
130
- }
131
- let scopes = [];
132
- try {
133
- const parsed = JSON.parse(scopesHeader);
134
- if (Array.isArray(parsed)) {
135
- scopes = parsed.filter((s) => typeof s === "string");
136
- }
137
- } catch {
138
- console.warn("[API] Invalid scopes header format");
110
+ const auth2 = getValidatedApiKey(request);
111
+ if (!auth2) {
112
+ throw new Error("No validated API key for this request");
139
113
  }
140
- return {
141
- userId,
142
- keyId,
143
- scopes
144
- };
114
+ return auth2;
145
115
  }
146
116
  function checkScope(auth2, requiredScope) {
147
117
  if (!scopesSatisfy(auth2.scopes, requiredScope)) {
@@ -203,7 +173,7 @@ async function logApiUsage(auth2, request, statusCode, responseTime, requestBody
203
173
  try {
204
174
  const endpoint = request.nextUrl.pathname;
205
175
  const method = request.method;
206
- const ipAddress = request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || "unknown";
176
+ const ipAddress = getRecordedClientIp(request.headers);
207
177
  const userAgent = request.headers.get("user-agent");
208
178
  await mutateWithRLS(
209
179
  `INSERT INTO "api_audit_log"
@@ -229,31 +199,18 @@ async function logApiUsage(auth2, request, statusCode, responseTime, requestBody
229
199
  function withApiLogging(handler) {
230
200
  return async (request, ...args) => {
231
201
  const startTime = Date.now();
232
- let auth2 = null;
233
- let requestBody = null;
234
- try {
235
- try {
236
- auth2 = getApiAuth(request);
237
- } catch {
238
- }
239
- if (["POST", "PUT", "PATCH"].includes(request.method)) {
240
- try {
241
- const clonedRequest = request.clone();
242
- requestBody = await clonedRequest.json();
243
- } catch {
244
- }
245
- }
246
- const response = await handler(request, ...args);
247
- const responseTime = Date.now() - startTime;
202
+ const log = (status) => {
203
+ const auth2 = getValidatedApiKey(request);
248
204
  if (auth2) {
249
- logApiUsage(auth2, request, response.status, responseTime, requestBody).catch(console.error);
205
+ logApiUsage(auth2, request, status, Date.now() - startTime).catch(console.error);
250
206
  }
207
+ };
208
+ try {
209
+ const response = await handler(request, ...args);
210
+ log(response.status);
251
211
  return response;
252
212
  } catch (error) {
253
- const responseTime = Date.now() - startTime;
254
- if (auth2) {
255
- logApiUsage(auth2, request, 500, responseTime, requestBody).catch(console.error);
256
- }
213
+ log(500);
257
214
  throw error;
258
215
  }
259
216
  };
@@ -282,32 +239,15 @@ function getAllowedFiltersFromRegistry() {
282
239
  async function addCorsHeaders(response, request) {
283
240
  const env = process.env.NODE_ENV || "development";
284
241
  const config = await getApplicationConfig();
285
- const corsConfig = config.api.cors;
286
- let allowedOrigin = "null";
242
+ let grant = null;
287
243
  if (request) {
288
244
  const origin = request.headers.get("origin");
289
- if (origin) {
290
- const normalizedOrigin = normalizeOrigin(origin);
291
- if (env === "development" && corsConfig.allowAllOrigins.development) {
292
- allowedOrigin = normalizedOrigin;
293
- } else {
294
- const allowedOrigins = getCorsOrigins(config, env);
295
- const matched = isOriginAllowed(normalizedOrigin, allowedOrigins);
296
- if (matched) {
297
- allowedOrigin = matched;
298
- }
299
- }
300
- }
301
- } else if (env === "development" && corsConfig.allowAllOrigins.development) {
245
+ if (origin) grant = corsGrant(origin, config, env, requestPathname(request));
246
+ } else if (env === "development" && config.api.cors.allowAllOrigins.development) {
302
247
  const allowedOrigins = getCorsOrigins(config, env);
303
- allowedOrigin = allowedOrigins[0] || "http://localhost:3000";
248
+ grant = { origin: allowedOrigins[0] || "http://localhost:3000", credentials: true };
304
249
  }
305
- response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
306
- response.headers.append("Vary", "Origin");
307
- response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS");
308
- response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-API-Key, x-team-id, x-builder-source");
309
- response.headers.set("Access-Control-Allow-Credentials", "true");
310
- response.headers.set("Access-Control-Max-Age", "86400");
250
+ setCorsHeaders(response.headers, grant);
311
251
  return response;
312
252
  }
313
253
  async function handleCorsPreflightRequest(request) {
@@ -321,25 +261,14 @@ async function wrapAuthHandlerWithCors(handler, request) {
321
261
  statusText: response.statusText,
322
262
  headers: new Headers(response.headers)
323
263
  });
324
- const env = process.env.NODE_ENV || "development";
325
- const config = await getApplicationConfig();
326
- const corsConfig = config.api.cors;
327
264
  const origin = request.headers.get("origin");
328
265
  if (origin) {
329
- const normalizedOrigin = normalizeOrigin(origin);
330
- let allowedOrigin = "null";
331
- if (env === "development" && corsConfig.allowAllOrigins.development) {
332
- allowedOrigin = normalizedOrigin;
333
- } else {
334
- const allowedOrigins = getCorsOrigins(config, env);
335
- const matched = isOriginAllowed(normalizedOrigin, allowedOrigins);
336
- if (matched) {
337
- allowedOrigin = matched;
338
- }
266
+ const grant = corsGrant(origin, await getApplicationConfig(), process.env.NODE_ENV || "development", requestPathname(request));
267
+ if (grant) {
268
+ newResponse.headers.set("Access-Control-Allow-Origin", grant.origin);
269
+ if (grant.credentials) newResponse.headers.set("Access-Control-Allow-Credentials", "true");
339
270
  }
340
- newResponse.headers.set("Access-Control-Allow-Origin", allowedOrigin);
341
- newResponse.headers.set("Access-Control-Allow-Credentials", "true");
342
- newResponse.headers.append("Vary", "Origin");
271
+ varyOnOrigin(newResponse.headers);
343
272
  }
344
273
  return newResponse;
345
274
  }
@@ -35,6 +35,12 @@ export declare class ApiKeyManager {
35
35
  */
36
36
  static suggestKeyName(scopes: string[]): string;
37
37
  }
38
+ /**
39
+ * The API key a request presents: the token of `Authorization: Bearer <token>`,
40
+ * else the `x-api-key` header. validateApiKey checks this value, and the
41
+ * cookie-write origin check (lib/api/request-origin) reads it too.
42
+ */
43
+ export declare function presentedApiKey(headers: Headers): string | null;
38
44
  /**
39
45
  * Definición de scopes disponibles para API keys
40
46
  */
@@ -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;;;;;;;;;;;;;;;;;;;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"}
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;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAI/D;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"}
@@ -68,6 +68,11 @@ class ApiKeyManager {
68
68
  return `${categoryNames} Access Key`;
69
69
  }
70
70
  }
71
+ function presentedApiKey(headers) {
72
+ const authorization = headers.get("authorization");
73
+ if (authorization == null ? void 0 : authorization.startsWith("Bearer ")) return authorization.substring(7);
74
+ return headers.get("x-api-key") || null;
75
+ }
71
76
  const API_SCOPES = {
72
77
  // Usuarios
73
78
  "users:read": "Read user information",
@@ -183,5 +188,6 @@ export {
183
188
  SCOPE_CATEGORIES,
184
189
  getApiScopes,
185
190
  getAppApiScopes,
186
- getRateLimitForScopes
191
+ getRateLimitForScopes,
192
+ presentedApiKey
187
193
  };
@@ -1 +1 @@
1
- {"version":3,"file":"permission-middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/api/permission-middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAc1C;;GAEG;AACH,eAAO,MAAM,WAAW,SAAS,CAAA;AAEjC;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAElF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAOjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC,CAkCtE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAK9B"}
1
+ {"version":3,"file":"permission-middleware.d.ts","sourceRoot":"","sources":["../../../src/lib/api/permission-middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAA;AACtD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAc1C;;GAEG;AACH,eAAO,MAAM,WAAW,SAAS,CAAA;AAEjC;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,CAElF;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAOjF;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CAAC,CA8BtE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAK9B"}
@@ -21,9 +21,7 @@ function getActionFromMethod(method, isCollection) {
21
21
  }
22
22
  async function checkEntityPermission(userId, teamId, entitySlug, action) {
23
23
  const permission = getEntityPermission(entitySlug, action);
24
- console.log(`[PermMiddleware] Checking permission: ${permission} for user ${userId} in team ${teamId}`);
25
24
  const hasPermission = await checkPermission(userId, teamId, permission);
26
- console.log(`[PermMiddleware] Result: ${hasPermission}`);
27
25
  if (!hasPermission) {
28
26
  return {
29
27
  allowed: false,
@@ -1,4 +1,5 @@
1
1
  import { NextRequest, NextResponse } from 'next/server';
2
+ import { type ApiKeyAuth } from './auth';
2
3
  import { type RateLimitTier } from '../rate-limit-redis';
3
4
  export interface RateLimitResult {
4
5
  allowed: boolean;
@@ -10,6 +11,13 @@ export interface RateLimitResult {
10
11
  * Verifica el rate limit para un identificador específico
11
12
  */
12
13
  export declare function checkRateLimit(identifier: string, limit?: number, windowMs?: number): RateLimitResult;
14
+ /**
15
+ * The per-key limit (checkRateLimit, by the key's id) for a request authenticated with `auth`: a 429 ready to
16
+ * return when the key is over it, null otherwise. Counted once per request, however many times the request is
17
+ * authenticated (authenticateRequest, validateAndAuthenticate*Request). The per-address limit of the route
18
+ * wrapper (withRateLimitTier) still applies on top. It is a safety cap, so DISABLE_RATE_LIMITING does not turn it off.
19
+ */
20
+ export declare function apiKeyRateLimitResponse(request: Request, auth: ApiKeyAuth): NextResponse | null;
13
21
  /**
14
22
  * Rate limit types for distributed rate limiting
15
23
  * Re-export from rate-limit-redis for convenience
@@ -47,6 +55,10 @@ export declare function applyRateLimit(request: NextRequest, keyId: string, scop
47
55
  export declare function addRateLimitHeaders(response: NextResponse, keyId: string, scopes: string[]): NextResponse;
48
56
  /**
49
57
  * Middleware helper para aplicar rate limiting automáticamente
58
+ *
59
+ * Limits per API key, with the limits of the key's scopes, when the request presents a key that validates.
60
+ * The key id and scopes come from that validation, never from request headers; any other request runs the
61
+ * handler without this limit.
50
62
  */
51
63
  export declare function withRateLimit<T extends unknown[]>(handler: (request: NextRequest, ...args: T) => Promise<NextResponse>): (request: NextRequest, ...args: T) => Promise<NextResponse>;
52
64
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/lib/api/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAIxD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAG7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAa,EACpB,QAAQ,GAAE,MAAc,GACvB,eAAe,CAyCjB;AAED;;;GAGG;AACH,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6CpD;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAwB5G;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,IAAI,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,GAAG,IAAI,CAkCrB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,CASd;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,OAAO,EAAE,EAC/C,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,IAEtD,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CAwCvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,IAAI,CAaP;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CASD;AAED;;GAEG;AACH,wBAAgB,sBAAsB;;;;;EAErC;AAsGD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,EACnD,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,EACpE,IAAI,GAAE,aAAqB,IAEb,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CAsCvE"}
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../../src/lib/api/rate-limit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGxD,OAAO,EAAkB,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGzD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAI7B,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,KAAK,GAAE,MAAa,EACpB,QAAQ,GAAE,MAAc,GACvB,eAAe,CAyCjB;AAKD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,GAAG,YAAY,GAAG,IAAI,CA0B/F;AAED;;;GAGG;AACH,YAAY,EAAE,aAAa,EAAE,CAAC;AAE9B;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,MAAM,EAClB,IAAI,GAAE,aAAqB,GAC1B,OAAO,CAAC,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA6CpD;AAED;;GAEG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,eAAe,GAAG;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,YAAY,CAwB5G;AAED;;;GAGG;AACH,wBAAgB,+BAA+B,IAAI,OAAO,CAEzD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,WAAW,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,GAAG,IAAI,CAkCrB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EACtB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EAAE,GACf,YAAY,CASd;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,OAAO,EAAE,EAC/C,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,IAEtD,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CA2BvE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,OAAO,CAAC;CACtB,GAAG,IAAI,CAaP;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAGlD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC;IAC5C,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CASD;AAED;;GAEG;AACH,wBAAgB,sBAAsB;;;;;EAErC;AA4DD,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,OAAO,EAAE,EACnD,OAAO,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,YAAY,CAAC,EACpE,IAAI,GAAE,aAAqB,IAqCb,SAAS,WAAW,EAAE,GAAG,MAAM,CAAC,KAAG,OAAO,CAAC,YAAY,CAAC,CAIvE"}
@@ -1,12 +1,15 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { unstable_rethrow } from "next/navigation";
3
- import { getRateLimitForScopes } from "./keys.js";
3
+ import { getRateLimitForScopes, presentedApiKey } from "./keys.js";
4
+ import { validateApiKey } from "./auth.js";
4
5
  import { rateLimitCache, getCacheKey } from "./cache.js";
6
+ import { getClientIp } from "./client-ip.js";
5
7
  import {
6
8
  checkRateLimit as checkRedisRateLimit,
7
9
  maybeRedisConfigured
8
10
  } from "../rate-limit-redis.js";
9
11
  import { checkRequestOrigin } from "./request-origin.js";
12
+ import { withCors } from "./cors-response.js";
10
13
  function checkRateLimit(identifier, limit = 1e3, windowMs = 6e4) {
11
14
  const now = Date.now();
12
15
  const cacheKey = getCacheKey("rate_limit", identifier);
@@ -40,6 +43,34 @@ function checkRateLimit(identifier, limit = 1e3, windowMs = 6e4) {
40
43
  limit
41
44
  };
42
45
  }
46
+ const apiKeyChecks = /* @__PURE__ */ new WeakMap();
47
+ function apiKeyRateLimitResponse(request, auth) {
48
+ let result = apiKeyChecks.get(request);
49
+ if (!result) {
50
+ result = checkRateLimit(auth.keyId);
51
+ apiKeyChecks.set(request, result);
52
+ }
53
+ if (result.allowed) return null;
54
+ const retryAfter = Math.ceil((result.resetTime - Date.now()) / 1e3);
55
+ return NextResponse.json(
56
+ {
57
+ success: false,
58
+ error: "Rate limit exceeded",
59
+ message: `Too many requests. Limit: ${result.limit} requests per minute`,
60
+ code: "RATE_LIMIT_EXCEEDED",
61
+ retryAfter
62
+ },
63
+ {
64
+ status: 429,
65
+ headers: {
66
+ "X-RateLimit-Limit": result.limit.toString(),
67
+ "X-RateLimit-Remaining": "0",
68
+ "X-RateLimit-Reset": result.resetTime.toString(),
69
+ "Retry-After": retryAfter.toString()
70
+ }
71
+ }
72
+ );
73
+ }
43
74
  async function checkDistributedRateLimit(identifier, type = "api") {
44
75
  if (isRateLimitingDisabled()) {
45
76
  return { allowed: true, remaining: 999, resetTime: Date.now() + 6e4, limit: 999 };
@@ -152,20 +183,11 @@ function addRateLimitHeaders(response, keyId, scopes) {
152
183
  function withRateLimit(handler) {
153
184
  return async (request, ...args) => {
154
185
  try {
155
- const keyId = request.headers.get("x-api-key-id");
156
- const scopesHeader = request.headers.get("x-api-scopes");
157
- if (!keyId || !scopesHeader) {
186
+ const auth = presentedApiKey(request.headers) ? await validateApiKey(request) : null;
187
+ if (!auth) {
158
188
  return handler(request, ...args);
159
189
  }
160
- let scopes = [];
161
- try {
162
- const parsed = JSON.parse(scopesHeader);
163
- if (Array.isArray(parsed)) {
164
- scopes = parsed.filter((s) => typeof s === "string");
165
- }
166
- } catch {
167
- console.warn("[RateLimit] Invalid scopes header format");
168
- }
190
+ const { keyId, scopes } = auth;
169
191
  const rateLimitResponse = applyRateLimit(request, keyId, scopes);
170
192
  if (rateLimitResponse) {
171
193
  return rateLimitResponse;
@@ -208,27 +230,6 @@ function getAllRateLimitStats() {
208
230
  function getRateLimitCacheStats() {
209
231
  return rateLimitCache.getStats();
210
232
  }
211
- function getClientIp(request) {
212
- const cfIp = request.headers.get("cf-connecting-ip");
213
- if (cfIp) return cfIp;
214
- const forwardedFor = request.headers.get("x-forwarded-for");
215
- if (forwardedFor) {
216
- const ips = forwardedFor.split(",").map((ip) => ip.trim()).filter(Boolean);
217
- if (ips.length > 0) return ips[ips.length - 1];
218
- }
219
- const realIp = request.headers.get("x-real-ip");
220
- if (realIp) return realIp;
221
- const trueClientIp = request.headers.get("true-client-ip");
222
- if (trueClientIp) return trueClientIp;
223
- return "unknown";
224
- }
225
- function getUserIdentifier(request) {
226
- const apiKey = request.headers.get("x-api-key");
227
- if (apiKey) {
228
- return `apikey:${apiKey.substring(0, 16)}`;
229
- }
230
- return null;
231
- }
232
233
  let rateLimitDisabledWarningLogged = false;
233
234
  function isRateLimitingDisabled() {
234
235
  const disabled = process.env.DISABLE_RATE_LIMITING === "true";
@@ -239,28 +240,34 @@ function isRateLimitingDisabled() {
239
240
  return disabled;
240
241
  }
241
242
  function withRateLimitTier(handler, tier = "api") {
242
- return async (request, ...args) => {
243
- const originRefused = checkRequestOrigin(request);
244
- if (originRefused) return originRefused;
243
+ const limited = async (request, ...args) => {
244
+ const checked = checkRequestOrigin(request);
245
+ if (checked instanceof NextResponse) return checked;
246
+ request = checked;
245
247
  if (isRateLimitingDisabled()) {
246
248
  return handler(request, ...args);
247
249
  }
248
- const userIdentifier = getUserIdentifier(request);
249
- const clientIp = getClientIp(request);
250
- const identifier = userIdentifier ? `${tier}:${userIdentifier}` : `${tier}:ip:${clientIp}`;
250
+ const identifier = `${tier}:ip:${getClientIp(request.headers)}`;
251
251
  const rateLimitResult = await checkDistributedRateLimit(identifier, tier);
252
252
  if (!rateLimitResult.allowed) {
253
253
  return createRateLimitErrorResponse(rateLimitResult);
254
254
  }
255
255
  const response = await handler(request, ...args);
256
- response.headers.set("X-RateLimit-Limit", rateLimitResult.limit.toString());
257
- response.headers.set("X-RateLimit-Remaining", Math.max(0, rateLimitResult.remaining).toString());
258
- response.headers.set("X-RateLimit-Reset", rateLimitResult.resetTime.toString());
256
+ if (response.status !== 429) {
257
+ response.headers.set("X-RateLimit-Limit", rateLimitResult.limit.toString());
258
+ response.headers.set("X-RateLimit-Remaining", Math.max(0, rateLimitResult.remaining).toString());
259
+ response.headers.set("X-RateLimit-Reset", rateLimitResult.resetTime.toString());
260
+ }
259
261
  return response;
260
262
  };
263
+ return async (request, ...args) => {
264
+ const response = await limited(request, ...args);
265
+ return tier === "webhook" ? response : withCors(response, request);
266
+ };
261
267
  }
262
268
  export {
263
269
  addRateLimitHeaders,
270
+ apiKeyRateLimitResponse,
264
271
  applyRateLimit,
265
272
  checkDistributedRateLimit,
266
273
  checkRateLimit,
@@ -5,22 +5,31 @@
5
5
  * from an origin the app trusts: its own (NEXT_PUBLIC_APP_URL / BETTER_AUTH_URL)
6
6
  * or one in the list Better Auth already trusts for sign-in (see
7
7
  * getTrustedOrigins). withRateLimitTier runs it before every handler it wraps.
8
+ * Under the admin and developer areas (isAppOnlyCorsPath) only the app's own
9
+ * origin is trusted, plus, outside production, the request's own origin when it
10
+ * is a private-network address (#170); no other listed origin.
8
11
  *
9
12
  * What passes without a trusted origin, and why:
10
13
  * - Reads (GET/HEAD/OPTIONS).
11
14
  * - Requests without the session cookie: there is no session for them to use.
12
- * - Requests with an `Authorization: Bearer` token or an x-api-key header (API
13
- * keys, the mobile client's bearer token). A browser adds those only when the page's script
14
- * sets them, and a script on another origin needs CORS approval first.
15
+ * - Requests that present an API key (`Authorization: Bearer sk_...` or
16
+ * x-api-key, in the API-key format). They are let through without their
17
+ * session cookie, so the handler can authenticate them only by the key: a key
18
+ * that does not validate gets 401, never the cookie's session. Any other
19
+ * Authorization value is not a credential here, and the check applies. Handlers
20
+ * should read the session from the request they are given, not from
21
+ * next/headers.
15
22
  * - Requests with neither Origin nor Referer, unless their body is one an HTML
16
23
  * form can send. Browsers send Origin on every write, so these come from
17
24
  * native or server-side clients; requiring a non-form content type keeps
18
25
  * a body without origin information from ever being read as a form post.
19
26
  */
20
- import { NextResponse } from 'next/server';
27
+ import { NextRequest, NextResponse } from 'next/server';
21
28
  /**
22
- * Returns a 403 response when a cookie-authenticated write does not come from a
23
- * trusted origin, or null when the request may proceed.
29
+ * Checks a write's origin. Returns a 403 response when a cookie-authenticated
30
+ * write does not come from a trusted origin. Otherwise returns the request the
31
+ * handler should get: the same request, or, for a write that would be refused
32
+ * but presents an API key, a copy without its session cookie.
24
33
  */
25
- export declare function checkRequestOrigin(request: Request): NextResponse | null;
34
+ export declare function checkRequestOrigin(request: NextRequest): NextResponse | NextRequest;
26
35
  //# sourceMappingURL=request-origin.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"request-origin.d.ts","sourceRoot":"","sources":["../../../src/lib/api/request-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AA6B1C;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAsBxE"}
1
+ {"version":3,"file":"request-origin.d.ts","sourceRoot":"","sources":["../../../src/lib/api/request-origin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAgEvD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,CAoBnF"}
@@ -1,7 +1,9 @@
1
- import { NextResponse } from "next/server";
1
+ import { NextRequest, NextResponse } from "next/server";
2
2
  import { APP_CONFIG_MERGED } from "../config/index.js";
3
3
  import { hasSessionCookie } from "../auth/session-hint.js";
4
- import { getTrustedOrigins, isOriginAllowed, normalizeOrigin } from "../utils/cors.js";
4
+ import { getTrustedOrigins, isOriginAllowed, isPrivateLanOrigin, normalizeCorsEnvironment, normalizeOrigin } from "../utils/cors.js";
5
+ import { ApiKeyManager, presentedApiKey } from "./keys.js";
6
+ import { appOrigins, isAppOnlyCorsPath, requestPathname } from "./cors-response.js";
5
7
  const WRITE_METHODS = /* @__PURE__ */ new Set(["POST", "PUT", "PATCH", "DELETE"]);
6
8
  const FORM_CONTENT_TYPES = /* @__PURE__ */ new Set(["text/plain", "application/x-www-form-urlencoded", "multipart/form-data"]);
7
9
  function requestOrigin(headers) {
@@ -15,31 +17,52 @@ function requestOrigin(headers) {
15
17
  return "null";
16
18
  }
17
19
  }
18
- function hasHeaderCredential(headers) {
19
- var _a;
20
- if ((_a = headers.get("x-api-key")) == null ? void 0 : _a.trim()) return true;
21
- return /^bearer\s+\S/i.test(headers.get("authorization") ?? "");
20
+ const SESSION_COOKIE_NAME = /^(?:__Secure-)?better-auth[.-]/;
21
+ function withoutSessionCookies(request) {
22
+ const headers = {};
23
+ request.headers.forEach((value, key) => {
24
+ headers[key] = value;
25
+ });
26
+ const kept = (headers.cookie ?? "").split(";").map((part) => part.trim()).filter((part) => part && !SESSION_COOKIE_NAME.test(part));
27
+ if (kept.length) headers.cookie = kept.join("; ");
28
+ else delete headers.cookie;
29
+ return new NextRequest(request.url, {
30
+ method: request.method,
31
+ headers,
32
+ body: request.body,
33
+ signal: request.signal,
34
+ nextConfig: { basePath: request.nextUrl.basePath }
35
+ });
36
+ }
37
+ function isTrustedWriteOrigin(request, origin) {
38
+ const path = requestPathname(request);
39
+ if (path === void 0 || isAppOnlyCorsPath(path)) {
40
+ const lan = normalizeCorsEnvironment(process.env.NODE_ENV || "development") !== "production" && isPrivateLanOrigin(origin);
41
+ return lan || appOrigins().includes(origin);
42
+ }
43
+ return isOriginAllowed(origin, getTrustedOrigins(APP_CONFIG_MERGED, origin)) !== null;
44
+ }
45
+ function refusal(error, code) {
46
+ return NextResponse.json({ success: false, error, code }, { status: 403 });
22
47
  }
23
48
  function checkRequestOrigin(request) {
24
- if (!WRITE_METHODS.has(request.method.toUpperCase())) return null;
49
+ if (!WRITE_METHODS.has(request.method.toUpperCase())) return request;
25
50
  const headers = request.headers;
26
- if (!hasSessionCookie(headers.get("cookie"))) return null;
27
- if (hasHeaderCredential(headers)) return null;
51
+ if (!hasSessionCookie(headers.get("cookie"))) return request;
52
+ let refused;
28
53
  const origin = requestOrigin(headers);
29
54
  if (origin === null) {
30
55
  const contentType = (headers.get("content-type") ?? "").split(";")[0].trim().toLowerCase();
31
- if (!FORM_CONTENT_TYPES.has(contentType)) return null;
32
- return NextResponse.json(
33
- { success: false, error: "This request needs an Origin header", code: "ORIGIN_REQUIRED" },
34
- { status: 403 }
35
- );
56
+ if (!FORM_CONTENT_TYPES.has(contentType)) return request;
57
+ refused = refusal("This request needs an Origin header", "ORIGIN_REQUIRED");
58
+ } else {
59
+ const normalized = normalizeOrigin(origin);
60
+ if (isTrustedWriteOrigin(request, normalized)) return request;
61
+ refused = refusal("Request origin not allowed", "ORIGIN_NOT_ALLOWED");
36
62
  }
37
- const normalized = normalizeOrigin(origin);
38
- if (isOriginAllowed(normalized, getTrustedOrigins(APP_CONFIG_MERGED, normalized))) return null;
39
- return NextResponse.json(
40
- { success: false, error: "Request origin not allowed", code: "ORIGIN_NOT_ALLOWED" },
41
- { status: 403 }
42
- );
63
+ const apiKey = presentedApiKey(headers);
64
+ if (apiKey && ApiKeyManager.validateKeyFormat(apiKey)) return withoutSessionCookies(request);
65
+ return refused;
43
66
  }
44
67
  export {
45
68
  checkRequestOrigin
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Leaves for the login page with a full page load, base path included. Sign-out and the dashboard guards use it.
3
+ *
4
+ * With Cache Components a client navigation out of the dashboard leaves it mounted, hidden, with its last render
5
+ * ("signed out"); shown again after the next sign-in, its effects act on that and send the user back to /login. The
6
+ * login page comes back as the form the last sign-in left. Loading the page drops the React tree, the session store
7
+ * and the query cache together, whichever way the session ended (this tab's sign-out, another tab's, an expiry).
8
+ */
9
+ export declare function loadLoginPage(): void;
10
+ //# sourceMappingURL=load-login-page.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load-login-page.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/load-login-page.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -0,0 +1,7 @@
1
+ import { withBasePath } from "../base-path.js";
2
+ function loadLoginPage() {
3
+ window.location.assign(withBasePath("/login"));
4
+ }
5
+ export {
6
+ loadLoginPage
7
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-readiness.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/runtime-readiness.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAElE,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAA;AAEpB,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAE5D,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,WAAW,GAAG,kBAAkB,CAAC,GAAG,IAAI,CAAA;IAClF,GAAG,CAAC,EAAE,kBAAkB,CAAA;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,wBAAwB,EAAE,OAAO,CAAA;IACjC,mFAAmF;IACnF,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,GAAG,aAAa,CAAA;IAC/B,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,YAAY,EAAE,sBAAsB,CAAA;CACrC;AAaD,qEAAqE;AACrE,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,2BAAgC,GAAG,mBAAmB,CAEtG;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,2BAAgC,GAAG,IAAI,CAazF;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,2BAAgC,GAAG,mBAAmB,CAYrG;AAiBD,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,2BAAgC,GAAG,OAAO,CAE1F;AAED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,2BAAgC,GAAG,OAAO,CAE3F;AAkDD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA4E1B;AAED,sFAAsF;AACtF,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,EAChC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,QAAQ,CAAC,CAGnB"}
1
+ {"version":3,"file":"runtime-readiness.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/runtime-readiness.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,KAAK,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAIlE,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,aAAa,CAAA;AAEpB,KAAK,kBAAkB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;AAE5D,MAAM,WAAW,2BAA2B;IAC1C,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,SAAS,GAAG,WAAW,GAAG,kBAAkB,CAAC,GAAG,IAAI,CAAA;IAClF,GAAG,CAAC,EAAE,kBAAkB,CAAA;CACzB;AAED;;;;;GAKG;AACH,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,wBAAwB,EAAE,OAAO,CAAA;IACjC,mFAAmF;IACnF,gBAAgB,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,GAAG,aAAa,CAAA;IAC/B,gBAAgB,EAAE,eAAe,EAAE,CAAA;IACnC,YAAY,EAAE,sBAAsB,CAAA;CACrC;AAaD,qEAAqE;AACrE,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,2BAAgC,GAAG,mBAAmB,CAEtG;AAED;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,GAAE,2BAAgC,GAAG,IAAI,CAgBzF;AAED,sFAAsF;AACtF,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,2BAAgC,GAAG,mBAAmB,CAYrG;AAiBD,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,2BAAgC,GAAG,OAAO,CAE1F;AAED,wBAAgB,wBAAwB,CAAC,OAAO,GAAE,2BAAgC,GAAG,OAAO,CAE3F;AAkDD;;;;GAIG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA4E1B;AAED,sFAAsF;AACtF,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,EAChC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,QAAQ,CAAC,CAGnB"}
@@ -1,6 +1,8 @@
1
1
  import "server-only";
2
2
  import { AUTH_CONFIG } from "../config/index.js";
3
3
  import { isPasswordLoginEnabled } from "./auth-methods.js";
4
+ import { warnClientIpSourceAtStartup } from "../api/client-ip.js";
5
+ import { warnSampleAccountsAtStartup } from "./sample-accounts.js";
4
6
  import {
5
7
  authReadinessConfigurationFromEnv,
6
8
  evaluateAuthReadiness
@@ -19,6 +21,8 @@ function getRuntimeAuthReadiness(options = {}) {
19
21
  return evaluateAuthReadiness(runtimeInput(options));
20
22
  }
21
23
  function logAuthReadinessAtStartup(options = {}) {
24
+ warnClientIpSourceAtStartup(options.env ?? process.env);
25
+ void warnSampleAccountsAtStartup(options.env ?? process.env);
22
26
  try {
23
27
  const env = options.env ?? process.env;
24
28
  if (env.NODE_ENV !== "production") return;