@nextsparkjs/core 0.1.0-beta.193 → 0.1.0-beta.195

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 (374) hide show
  1. package/README.md +2 -2
  2. package/dist/components/app/guards/DeveloperGuard.d.ts +8 -1
  3. package/dist/components/app/guards/DeveloperGuard.d.ts.map +1 -1
  4. package/dist/components/app/guards/DeveloperGuard.js +2 -1
  5. package/dist/components/app/guards/SuperAdminGuard.d.ts +8 -1
  6. package/dist/components/app/guards/SuperAdminGuard.d.ts.map +1 -1
  7. package/dist/components/app/guards/SuperAdminGuard.js +2 -1
  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/entities/wrappers/EntityDetailWrapper.d.ts.map +1 -1
  22. package/dist/components/entities/wrappers/EntityDetailWrapper.js +5 -2
  23. package/dist/components/entities/wrappers/EntityFormWrapper.d.ts.map +1 -1
  24. package/dist/components/entities/wrappers/EntityFormWrapper.js +5 -2
  25. package/dist/components/entities/wrappers/EntityListWrapper.d.ts.map +1 -1
  26. package/dist/components/entities/wrappers/EntityListWrapper.js +5 -2
  27. package/dist/components/ui/relation-display.d.ts.map +1 -1
  28. package/dist/components/ui/relation-display.js +2 -1
  29. package/dist/components/ui/user-display.d.ts.map +1 -1
  30. package/dist/components/ui/user-display.js +2 -1
  31. package/dist/emails/otp-verification.d.ts.map +1 -1
  32. package/dist/emails/otp-verification.js +5 -3
  33. package/dist/emails/reset-password.d.ts.map +1 -1
  34. package/dist/emails/reset-password.js +5 -3
  35. package/dist/emails/team-invitation.d.ts.map +1 -1
  36. package/dist/emails/team-invitation.js +3 -2
  37. package/dist/emails/verify-email.d.ts.map +1 -1
  38. package/dist/emails/verify-email.js +5 -3
  39. package/dist/hooks/useAuth.d.ts.map +1 -1
  40. package/dist/hooks/useAuth.js +21 -4
  41. package/dist/hooks/usePatternUsages.d.ts.map +1 -1
  42. package/dist/hooks/usePatternUsages.js +3 -2
  43. package/dist/lib/api/auth/permissions.d.ts +10 -0
  44. package/dist/lib/api/auth/permissions.d.ts.map +1 -1
  45. package/dist/lib/api/auth/permissions.js +7 -0
  46. package/dist/lib/api/auth.d.ts +2 -0
  47. package/dist/lib/api/auth.d.ts.map +1 -1
  48. package/dist/lib/api/auth.js +10 -10
  49. package/dist/lib/api/client-headers.d.ts +11 -0
  50. package/dist/lib/api/client-headers.d.ts.map +1 -0
  51. package/dist/lib/api/client-headers.js +12 -0
  52. package/dist/lib/api/client-ip.d.ts +59 -0
  53. package/dist/lib/api/client-ip.d.ts.map +1 -0
  54. package/dist/lib/api/client-ip.js +91 -0
  55. package/dist/lib/api/cors-response.d.ts +54 -0
  56. package/dist/lib/api/cors-response.d.ts.map +1 -0
  57. package/dist/lib/api/cors-response.js +88 -0
  58. package/dist/lib/api/entities.d.ts.map +1 -1
  59. package/dist/lib/api/entities.js +4 -3
  60. package/dist/lib/api/entity/audit-log.d.ts.map +1 -1
  61. package/dist/lib/api/entity/audit-log.js +2 -1
  62. package/dist/lib/api/entity/generic-handler.d.ts.map +1 -1
  63. package/dist/lib/api/entity/generic-handler.js +23 -5
  64. package/dist/lib/api/helpers.d.ts +8 -2
  65. package/dist/lib/api/helpers.d.ts.map +1 -1
  66. package/dist/lib/api/helpers.js +27 -81
  67. package/dist/lib/api/keys.d.ts +6 -0
  68. package/dist/lib/api/keys.d.ts.map +1 -1
  69. package/dist/lib/api/keys.js +7 -1
  70. package/dist/lib/api/rate-limit.d.ts +4 -0
  71. package/dist/lib/api/rate-limit.d.ts.map +1 -1
  72. package/dist/lib/api/rate-limit.js +17 -38
  73. package/dist/lib/api/request-origin.d.ts +35 -0
  74. package/dist/lib/api/request-origin.d.ts.map +1 -0
  75. package/dist/lib/api/request-origin.js +69 -0
  76. package/dist/lib/auth/load-login-page.d.ts +10 -0
  77. package/dist/lib/auth/load-login-page.d.ts.map +1 -0
  78. package/dist/lib/auth/load-login-page.js +7 -0
  79. package/dist/lib/auth/runtime-readiness.d.ts.map +1 -1
  80. package/dist/lib/auth/runtime-readiness.js +2 -0
  81. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts +1 -8
  82. package/dist/lib/auth/security-notifications/device-fingerprint.d.ts.map +1 -1
  83. package/dist/lib/auth/security-notifications/device-fingerprint.js +2 -12
  84. package/dist/lib/auth-email-callbacks.js +3 -3
  85. package/dist/lib/auth.d.ts.map +1 -1
  86. package/dist/lib/auth.js +15 -14
  87. package/dist/lib/config/config-client.d.ts.map +1 -1
  88. package/dist/lib/config/config-client.js +1 -1
  89. package/dist/lib/config/config-sync.d.ts.map +1 -1
  90. package/dist/lib/config/config-sync.js +1 -1
  91. package/dist/lib/config/public-config-client.d.ts +1 -0
  92. package/dist/lib/config/public-config-client.d.ts.map +1 -1
  93. package/dist/lib/config/public-config-client.js +3 -1
  94. package/dist/lib/config/types.d.ts +2 -0
  95. package/dist/lib/config/types.d.ts.map +1 -1
  96. package/dist/lib/constants/reserved-slugs.d.ts +17 -8
  97. package/dist/lib/constants/reserved-slugs.d.ts.map +1 -1
  98. package/dist/lib/constants/reserved-slugs.js +16 -52
  99. package/dist/lib/db.d.ts.map +1 -1
  100. package/dist/lib/db.js +9 -3
  101. package/dist/lib/entities/external-api-generator.d.ts.map +1 -1
  102. package/dist/lib/entities/external-api-generator.js +5 -5
  103. package/dist/lib/entities/public-slug.d.ts +46 -0
  104. package/dist/lib/entities/public-slug.d.ts.map +1 -0
  105. package/dist/lib/entities/public-slug.js +39 -0
  106. package/dist/lib/services/subscription.service.d.ts.map +1 -1
  107. package/dist/lib/services/subscription.service.js +3 -0
  108. package/dist/lib/utils/cors.d.ts +7 -0
  109. package/dist/lib/utils/cors.d.ts.map +1 -1
  110. package/dist/lib/utils/cors.js +8 -0
  111. package/dist/routes/(auth)/signup/page.cc.d.ts +3 -8
  112. package/dist/routes/(auth)/signup/page.cc.d.ts.map +1 -1
  113. package/dist/routes/(auth)/signup/page.cc.js +7 -1
  114. package/dist/routes/(auth)/verify-email/page.d.ts.map +1 -1
  115. package/dist/routes/(auth)/verify-email/page.js +2 -1
  116. package/dist/routes/(public)/page.cc.d.ts +3 -0
  117. package/dist/routes/(public)/page.cc.d.ts.map +1 -0
  118. package/dist/routes/(public)/page.cc.js +3 -0
  119. package/dist/routes/_internal/area-access.cc.d.ts +21 -0
  120. package/dist/routes/_internal/area-access.cc.d.ts.map +1 -0
  121. package/dist/routes/_internal/area-access.cc.js +19 -0
  122. package/dist/routes/_internal/auth-layout.d.ts.map +1 -1
  123. package/dist/routes/_internal/auth-layout.js +3 -2
  124. package/dist/routes/_internal/dashboard-main-shared.d.ts +7 -0
  125. package/dist/routes/_internal/dashboard-main-shared.d.ts.map +1 -0
  126. package/dist/routes/_internal/dashboard-main-shared.js +49 -0
  127. package/dist/routes/_internal/default-auth-layout.d.ts.map +1 -1
  128. package/dist/routes/_internal/default-auth-layout.js +3 -2
  129. package/dist/routes/_internal/devtools-layout.cc.d.ts +3 -2
  130. package/dist/routes/_internal/devtools-layout.cc.d.ts.map +1 -1
  131. package/dist/routes/_internal/devtools-layout.cc.js +1 -1
  132. package/dist/routes/_internal/devtools-layout.d.ts +7 -2
  133. package/dist/routes/_internal/devtools-layout.d.ts.map +1 -1
  134. package/dist/routes/_internal/devtools-layout.js +4 -4
  135. package/dist/routes/_internal/entity-detail-route.cc.d.ts +8 -0
  136. package/dist/routes/_internal/entity-detail-route.cc.d.ts.map +1 -0
  137. package/dist/routes/_internal/entity-detail-route.cc.js +5 -0
  138. package/dist/routes/_internal/entity-edit-route.cc.d.ts +8 -0
  139. package/dist/routes/_internal/entity-edit-route.cc.d.ts.map +1 -0
  140. package/dist/routes/_internal/entity-edit-route.cc.js +5 -0
  141. package/dist/routes/_internal/public-archive-route.d.ts +1 -1
  142. package/dist/routes/_internal/public-archive-route.d.ts.map +1 -1
  143. package/dist/routes/_internal/public-archive-route.js +8 -3
  144. package/dist/routes/_internal/public-item-route.cc.d.ts +5 -1
  145. package/dist/routes/_internal/public-item-route.cc.d.ts.map +1 -1
  146. package/dist/routes/_internal/public-item-route.cc.js +2 -1
  147. package/dist/routes/_internal/public-item-route.d.ts +7 -0
  148. package/dist/routes/_internal/public-item-route.d.ts.map +1 -1
  149. package/dist/routes/_internal/public-item-route.js +6 -1
  150. package/dist/routes/_internal/superadmin-layout.cc.d.ts +2 -1
  151. package/dist/routes/_internal/superadmin-layout.cc.d.ts.map +1 -1
  152. package/dist/routes/_internal/superadmin-layout.cc.js +1 -1
  153. package/dist/routes/_internal/superadmin-layout.d.ts +7 -2
  154. package/dist/routes/_internal/superadmin-layout.d.ts.map +1 -1
  155. package/dist/routes/_internal/superadmin-layout.js +6 -6
  156. package/dist/routes/_internal/suspended-route.d.ts +16 -0
  157. package/dist/routes/_internal/suspended-route.d.ts.map +1 -0
  158. package/dist/routes/_internal/suspended-route.js +7 -0
  159. package/dist/routes/api/auth/[...all]/route.d.ts.map +1 -1
  160. package/dist/routes/api/auth/[...all]/route.js +4 -12
  161. package/dist/routes/api/csp-report/route.d.ts.map +1 -1
  162. package/dist/routes/api/csp-report/route.js +2 -13
  163. package/dist/routes/api/devtools/config/entities/route.d.ts +2 -0
  164. package/dist/routes/api/devtools/config/entities/route.d.ts.map +1 -1
  165. package/dist/routes/api/devtools/config/entities/route.js +2 -0
  166. package/dist/routes/api/devtools/config/theme/route.d.ts +2 -0
  167. package/dist/routes/api/devtools/config/theme/route.d.ts.map +1 -1
  168. package/dist/routes/api/devtools/config/theme/route.js +2 -0
  169. package/dist/routes/api/devtools/tests/[...path]/route.d.ts +2 -0
  170. package/dist/routes/api/devtools/tests/[...path]/route.d.ts.map +1 -1
  171. package/dist/routes/api/devtools/tests/[...path]/route.js +2 -0
  172. package/dist/routes/api/devtools/tests/route.d.ts +2 -0
  173. package/dist/routes/api/devtools/tests/route.d.ts.map +1 -1
  174. package/dist/routes/api/devtools/tests/route.js +2 -0
  175. package/dist/routes/api/health/route.d.ts +2 -0
  176. package/dist/routes/api/health/route.d.ts.map +1 -1
  177. package/dist/routes/api/health/route.js +2 -0
  178. package/dist/routes/api/internal/user-metadata/route.d.ts +2 -0
  179. package/dist/routes/api/internal/user-metadata/route.d.ts.map +1 -1
  180. package/dist/routes/api/internal/user-metadata/route.js +2 -0
  181. package/dist/routes/api/mcp/route.d.ts +2 -0
  182. package/dist/routes/api/mcp/route.d.ts.map +1 -1
  183. package/dist/routes/api/mcp/route.js +2 -0
  184. package/dist/routes/api/superadmin/subscriptions/route.d.ts +2 -0
  185. package/dist/routes/api/superadmin/subscriptions/route.d.ts.map +1 -1
  186. package/dist/routes/api/superadmin/subscriptions/route.js +2 -0
  187. package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts +2 -0
  188. package/dist/routes/api/superadmin/teams/[teamId]/route.d.ts.map +1 -1
  189. package/dist/routes/api/superadmin/teams/[teamId]/route.js +2 -0
  190. package/dist/routes/api/superadmin/teams/route.d.ts +2 -0
  191. package/dist/routes/api/superadmin/teams/route.d.ts.map +1 -1
  192. package/dist/routes/api/superadmin/teams/route.js +2 -0
  193. package/dist/routes/api/superadmin/users/[userId]/route.d.ts +2 -0
  194. package/dist/routes/api/superadmin/users/[userId]/route.d.ts.map +1 -1
  195. package/dist/routes/api/superadmin/users/[userId]/route.js +2 -0
  196. package/dist/routes/api/superadmin/users/route.d.ts +2 -0
  197. package/dist/routes/api/superadmin/users/route.d.ts.map +1 -1
  198. package/dist/routes/api/superadmin/users/route.js +2 -0
  199. package/dist/routes/api/user/delete-account/route.d.ts +2 -0
  200. package/dist/routes/api/user/delete-account/route.d.ts.map +1 -1
  201. package/dist/routes/api/user/delete-account/route.js +2 -0
  202. package/dist/routes/api/user/plan-flags/route.d.ts +2 -0
  203. package/dist/routes/api/user/plan-flags/route.d.ts.map +1 -1
  204. package/dist/routes/api/user/plan-flags/route.js +2 -0
  205. package/dist/routes/api/user/profile/route.d.ts +2 -0
  206. package/dist/routes/api/user/profile/route.d.ts.map +1 -1
  207. package/dist/routes/api/user/profile/route.js +4 -3
  208. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts +2 -0
  209. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.d.ts.map +1 -1
  210. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/[childId]/route.js +2 -0
  211. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts +2 -0
  212. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.d.ts.map +1 -1
  213. package/dist/routes/api/v1/[entity]/[id]/child/[childType]/route.js +2 -0
  214. package/dist/routes/api/v1/billing/cancel/route.d.ts +2 -0
  215. package/dist/routes/api/v1/billing/cancel/route.d.ts.map +1 -1
  216. package/dist/routes/api/v1/billing/cancel/route.js +2 -0
  217. package/dist/routes/api/v1/billing/change-plan/route.d.ts +2 -0
  218. package/dist/routes/api/v1/billing/change-plan/route.d.ts.map +1 -1
  219. package/dist/routes/api/v1/billing/change-plan/route.js +2 -0
  220. package/dist/routes/api/v1/billing/check-action/route.d.ts +2 -0
  221. package/dist/routes/api/v1/billing/check-action/route.d.ts.map +1 -1
  222. package/dist/routes/api/v1/billing/check-action/route.js +2 -0
  223. package/dist/routes/api/v1/billing/checkout/route.d.ts +2 -0
  224. package/dist/routes/api/v1/billing/checkout/route.d.ts.map +1 -1
  225. package/dist/routes/api/v1/billing/checkout/route.js +2 -0
  226. package/dist/routes/api/v1/billing/plans/route.d.ts +2 -0
  227. package/dist/routes/api/v1/billing/plans/route.d.ts.map +1 -1
  228. package/dist/routes/api/v1/billing/plans/route.js +2 -0
  229. package/dist/routes/api/v1/billing/portal/route.d.ts +2 -0
  230. package/dist/routes/api/v1/billing/portal/route.d.ts.map +1 -1
  231. package/dist/routes/api/v1/billing/portal/route.js +2 -0
  232. package/dist/routes/api/v1/blocks/[slug]/route.d.ts +2 -0
  233. package/dist/routes/api/v1/blocks/[slug]/route.d.ts.map +1 -1
  234. package/dist/routes/api/v1/blocks/[slug]/route.js +2 -0
  235. package/dist/routes/api/v1/blocks/route.d.ts +2 -0
  236. package/dist/routes/api/v1/blocks/route.d.ts.map +1 -1
  237. package/dist/routes/api/v1/blocks/route.js +2 -0
  238. package/dist/routes/api/v1/blocks/validate/route.d.ts +2 -0
  239. package/dist/routes/api/v1/blocks/validate/route.d.ts.map +1 -1
  240. package/dist/routes/api/v1/blocks/validate/route.js +2 -0
  241. package/dist/routes/api/v1/devtools/blocks/route.d.ts +2 -1
  242. package/dist/routes/api/v1/devtools/blocks/route.d.ts.map +1 -1
  243. package/dist/routes/api/v1/devtools/blocks/route.js +2 -9
  244. package/dist/routes/api/v1/devtools/docs/route.d.ts +2 -0
  245. package/dist/routes/api/v1/devtools/docs/route.d.ts.map +1 -1
  246. package/dist/routes/api/v1/devtools/docs/route.js +2 -0
  247. package/dist/routes/api/v1/devtools/features/route.d.ts +2 -1
  248. package/dist/routes/api/v1/devtools/features/route.d.ts.map +1 -1
  249. package/dist/routes/api/v1/devtools/features/route.js +2 -9
  250. package/dist/routes/api/v1/devtools/flows/route.d.ts +2 -1
  251. package/dist/routes/api/v1/devtools/flows/route.d.ts.map +1 -1
  252. package/dist/routes/api/v1/devtools/flows/route.js +2 -9
  253. package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts +2 -1
  254. package/dist/routes/api/v1/devtools/scheduled-actions/route.d.ts.map +1 -1
  255. package/dist/routes/api/v1/devtools/scheduled-actions/route.js +2 -9
  256. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts +2 -1
  257. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.d.ts.map +1 -1
  258. package/dist/routes/api/v1/devtools/scheduled-actions/run/route.js +2 -9
  259. package/dist/routes/api/v1/devtools/testing/route.d.ts +2 -1
  260. package/dist/routes/api/v1/devtools/testing/route.d.ts.map +1 -1
  261. package/dist/routes/api/v1/devtools/testing/route.js +2 -9
  262. package/dist/routes/api/v1/media/[id]/route.d.ts +2 -0
  263. package/dist/routes/api/v1/media/[id]/route.d.ts.map +1 -1
  264. package/dist/routes/api/v1/media/[id]/route.js +2 -0
  265. package/dist/routes/api/v1/media/[id]/tags/route.d.ts +2 -0
  266. package/dist/routes/api/v1/media/[id]/tags/route.d.ts.map +1 -1
  267. package/dist/routes/api/v1/media/[id]/tags/route.js +2 -0
  268. package/dist/routes/api/v1/media/check-duplicates/route.d.ts +2 -0
  269. package/dist/routes/api/v1/media/check-duplicates/route.d.ts.map +1 -1
  270. package/dist/routes/api/v1/media/check-duplicates/route.js +2 -0
  271. package/dist/routes/api/v1/media/route.d.ts +2 -0
  272. package/dist/routes/api/v1/media/route.d.ts.map +1 -1
  273. package/dist/routes/api/v1/media/route.js +2 -0
  274. package/dist/routes/api/v1/media/upload/route.d.ts +2 -0
  275. package/dist/routes/api/v1/media/upload/route.d.ts.map +1 -1
  276. package/dist/routes/api/v1/media/upload/route.js +2 -0
  277. package/dist/routes/api/v1/media-tags/route.d.ts +2 -0
  278. package/dist/routes/api/v1/media-tags/route.d.ts.map +1 -1
  279. package/dist/routes/api/v1/media-tags/route.js +2 -0
  280. package/dist/routes/api/v1/post-categories/[id]/route.d.ts +2 -0
  281. package/dist/routes/api/v1/post-categories/[id]/route.d.ts.map +1 -1
  282. package/dist/routes/api/v1/post-categories/[id]/route.js +2 -0
  283. package/dist/routes/api/v1/post-categories/route.d.ts +2 -0
  284. package/dist/routes/api/v1/post-categories/route.d.ts.map +1 -1
  285. package/dist/routes/api/v1/post-categories/route.js +2 -0
  286. package/dist/routes/api/v1/teams/[teamId]/members/route.js +2 -2
  287. package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts +2 -0
  288. package/dist/routes/api/v1/teams/[teamId]/subscription/route.d.ts.map +1 -1
  289. package/dist/routes/api/v1/teams/[teamId]/subscription/route.js +2 -0
  290. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts +2 -0
  291. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.d.ts.map +1 -1
  292. package/dist/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.js +2 -0
  293. package/dist/routes/api/v1/users/[id]/meta/[key]/route.d.ts.map +1 -1
  294. package/dist/routes/api/v1/users/[id]/meta/[key]/route.js +13 -0
  295. package/dist/routes/api/v1/users/[id]/route.d.ts.map +1 -1
  296. package/dist/routes/api/v1/users/[id]/route.js +20 -2
  297. package/dist/routes/api/v1/users/docs.md +34 -19
  298. package/dist/routes/api/v1/users/me/route.d.ts +6 -0
  299. package/dist/routes/api/v1/users/me/route.d.ts.map +1 -0
  300. package/dist/routes/api/v1/users/me/route.js +5 -0
  301. package/dist/routes/api/v1/users/presets.ts +2 -2
  302. package/dist/routes/dashboard/(main)/layout.cc.d.ts +4 -0
  303. package/dist/routes/dashboard/(main)/layout.cc.d.ts.map +1 -0
  304. package/dist/routes/dashboard/(main)/layout.cc.js +10 -0
  305. package/dist/routes/dashboard/(main)/layout.d.ts.map +1 -1
  306. package/dist/routes/dashboard/(main)/layout.js +3 -44
  307. package/dist/routes/dashboard/permission-denied/page.d.ts +1 -1
  308. package/dist/routes/dashboard/permission-denied/page.d.ts.map +1 -1
  309. package/dist/routes/dashboard/permission-denied/page.js +5 -1
  310. package/dist/routes/devtools/layout.cc.d.ts.map +1 -1
  311. package/dist/routes/devtools/layout.cc.js +5 -1
  312. package/dist/routes/manifest.json +10 -0
  313. package/dist/routes/robots.d.ts +10 -0
  314. package/dist/routes/robots.d.ts.map +1 -0
  315. package/dist/routes/robots.js +10 -0
  316. package/dist/routes/superadmin/layout.cc.d.ts.map +1 -1
  317. package/dist/routes/superadmin/layout.cc.js +5 -1
  318. package/dist/routes/variants.json +12 -2
  319. package/dist/templates/next.config.mjs +2 -29
  320. package/dist/templates/projects/blog/api/authors/[username]/route.ts +3 -0
  321. package/dist/templates/projects/blog/api/authors/route.ts +3 -0
  322. package/dist/templates/projects/blog/api/posts/public/route.ts +3 -0
  323. package/dist/templates/projects/blog/package.json +3 -3
  324. package/dist/templates/projects/crm/package.json +3 -3
  325. package/dist/templates/projects/productivity/package.json +3 -3
  326. package/dist/templates/proxy.ts +12 -1
  327. package/dist/templates/public/favicon.ico +0 -0
  328. package/package.json +8 -5
  329. package/scripts/build/auth-readiness.mjs +4 -0
  330. package/scripts/build/registry/__tests__/api-docs-colocated.test.mjs +3 -0
  331. package/scripts/build/registry/__tests__/billing-registry.test.mjs +50 -1
  332. package/scripts/build/registry/__tests__/block-registry.test.mjs +3 -0
  333. package/scripts/build/registry/__tests__/build-output.test.mjs +1 -1
  334. package/scripts/build/registry/__tests__/icons-discovery.test.mjs +3 -0
  335. package/scripts/build/registry/__tests__/project-mode-root-first.test.mjs +6 -6
  336. package/scripts/build/registry/__tests__/quiet-console.mjs +17 -0
  337. package/scripts/build/registry/__tests__/safe-fs.test.mjs +3 -0
  338. package/scripts/build/registry/__tests__/team-roles.test.mjs +3 -0
  339. package/scripts/build/registry/__tests__/write-places.test.mjs +1 -1
  340. package/scripts/build/registry/contracts/__tests__/contracts-wire.test.mjs +1 -1
  341. package/scripts/build/registry/contracts/__tests__/contracts.test.mjs +1 -1
  342. package/scripts/build/registry/contracts/render.mjs +3 -3
  343. package/scripts/build/registry/discovery/permissions.test.mjs +3 -0
  344. package/scripts/build/registry/discovery/plugin-capabilities.mjs +2 -2
  345. package/scripts/build/registry/generators/billing-registry.mjs +7 -3
  346. package/scripts/build/registry/host/README.md +27 -3
  347. package/scripts/build/registry/host/__tests__/facade-emitter.test.mjs +9 -9
  348. package/scripts/build/registry/host/__tests__/host-area-access.test.mjs +32 -0
  349. package/scripts/build/registry/host/__tests__/host-entities.test.mjs +32 -1
  350. package/scripts/build/registry/host/__tests__/host-mode.test.mjs +1 -1
  351. package/scripts/build/registry/host/__tests__/host-plan.test.mjs +12 -2
  352. package/scripts/build/registry/host/__tests__/host-project-composition.test.mjs +1 -1
  353. package/scripts/build/registry/host/__tests__/host-project.test.mjs +2 -2
  354. package/scripts/build/registry/host/__tests__/host-robustness.test.mjs +65 -2
  355. package/scripts/build/registry/host/entity-routes.mjs +9 -3
  356. package/scripts/build/registry/host/facade-emitter.mjs +2 -2
  357. package/scripts/build/registry/host/generation.mjs +54 -0
  358. package/scripts/build/registry/host/next-route-exports.json +2 -2
  359. package/scripts/build/registry/host/prepare.mjs +3 -0
  360. package/scripts/build/registry/host/static-imports.mjs +4 -0
  361. package/scripts/build/routes-manifest.mjs +13 -1
  362. package/scripts/db/migration-time-limit.mjs +216 -34
  363. package/scripts/db/run-migrations.mjs +11 -179
  364. package/scripts/db/ssl-config.mjs +12 -1
  365. package/scripts/db/verify-theme-migrations.mjs +1 -1
  366. package/templates/next.config.mjs +2 -29
  367. package/templates/projects/blog/api/authors/[username]/route.ts +3 -0
  368. package/templates/projects/blog/api/authors/route.ts +3 -0
  369. package/templates/projects/blog/api/posts/public/route.ts +3 -0
  370. package/templates/projects/blog/package.json +3 -3
  371. package/templates/projects/crm/package.json +3 -3
  372. package/templates/projects/productivity/package.json +3 -3
  373. package/templates/proxy.ts +12 -1
  374. package/templates/public/favicon.ico +0 -0
@@ -1,6 +1,7 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { validateAndAuthenticateRequest, createApiResponse, createApiError } from "@nextsparkjs/core/lib/api/helpers";
3
3
  import { withRateLimitTier } from "@nextsparkjs/core/lib/api/rate-limit";
4
+ import { corsPreflight } from "@nextsparkjs/core/lib/api/cors-response";
4
5
  import { SubscriptionService, MembershipService } from "@nextsparkjs/core/lib/services";
5
6
  export const GET = withRateLimitTier(async function GET2(request, props) {
6
7
  const { auth, rateLimitResponse, errorResponse } = await validateAndAuthenticateRequest(request, { requiredScope: "billing:read" });
@@ -28,3 +29,4 @@ export const GET = withRateLimitTier(async function GET2(request, props) {
28
29
  return createApiError("Failed to fetch subscription", 500);
29
30
  }
30
31
  }, "read");
32
+ export const OPTIONS = corsPreflight;
@@ -5,6 +5,7 @@
5
5
  * POST /api/v1/teams/[teamId]/usage/[limitSlug] - Track usage
6
6
  */
7
7
  import { NextRequest, NextResponse } from 'next/server';
8
+ import { corsPreflight } from '@nextsparkjs/core/lib/api/cors-response';
8
9
  interface RouteParams {
9
10
  params: Promise<{
10
11
  teamId: string;
@@ -13,5 +14,6 @@ interface RouteParams {
13
14
  }
14
15
  export declare const GET: (request: NextRequest, props: RouteParams) => Promise<NextResponse>;
15
16
  export declare const POST: (request: NextRequest, props: RouteParams) => Promise<NextResponse>;
17
+ export declare const OPTIONS: typeof corsPreflight;
16
18
  export {};
17
19
  //# sourceMappingURL=route.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAMvD,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACvD;AAED,eAAO,MAAM,GAAG,qEAgCN,CAAA;AAEV,eAAO,MAAM,IAAI,qEA4CN,CAAA"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/routes/api/v1/teams/[teamId]/usage/[limitSlug]/route.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAGvD,OAAO,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAA;AAIvE,UAAU,WAAW;IACnB,MAAM,EAAE,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACvD;AAED,eAAO,MAAM,GAAG,qEAgCN,CAAA;AAEV,eAAO,MAAM,IAAI,qEA4CN,CAAA;AAEX,eAAO,MAAM,OAAO,sBAAgB,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { NextResponse } from "next/server";
2
2
  import { validateAndAuthenticateRequest, createApiResponse, createApiError } from "@nextsparkjs/core/lib/api/helpers";
3
3
  import { withRateLimitTier } from "@nextsparkjs/core/lib/api/rate-limit";
4
+ import { corsPreflight } from "@nextsparkjs/core/lib/api/cors-response";
4
5
  import { SubscriptionService, UsageService, MembershipService } from "@nextsparkjs/core/lib/services";
5
6
  import { trackUsageSchema } from "@nextsparkjs/core/lib/billing/schema";
6
7
  export const GET = withRateLimitTier(async function GET2(request, props) {
@@ -65,3 +66,4 @@ export const POST = withRateLimitTier(async function POST2(request, props) {
65
66
  return createApiError(errorMessage, 500);
66
67
  }
67
68
  }, "write");
69
+ export const OPTIONS = corsPreflight;
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/routes/api/v1/users/[id]/meta/[key]/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAsBvD,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,kCAEjD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BA6DjD,CAAC;AAEZ;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BA8FhD,CAAC;AAEb;;;;GAIG;AACH,eAAO,MAAM,KAAK;YArGM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BAqGpC,CAAA;AAExB;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;YAEK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BAwDhD,CAAC"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/routes/api/v1/users/[id]/meta/[key]/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAuBvD,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,kCAEjD;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BAmEjD,CAAC;AAEZ;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BAoGhD,CAAC;AAEb;;;;GAIG;AACH,eAAO,MAAM,KAAK;YA3GM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BA2GpC,CAAA;AAExB;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;YAEK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;2BA8DhD,CAAC"}
@@ -7,6 +7,7 @@ import {
7
7
  addCorsHeaders
8
8
  } from "@nextsparkjs/core/lib/api/helpers";
9
9
  import { authenticateRequest, createAuthFailureResponse } from "@nextsparkjs/core/lib/api/auth/dual-auth";
10
+ import { canAccessUser } from "@nextsparkjs/core/lib/api/auth/permissions";
10
11
  import * as z from "zod";
11
12
  import { withRateLimitTier } from "@nextsparkjs/core/lib/api/rate-limit";
12
13
  const metadataValueSchema = z.object({
@@ -33,6 +34,10 @@ export const GET = withRateLimitTier(withApiLogging(async (req, { params }) => {
33
34
  const response2 = createApiError("User ID is required", 400, null, "MISSING_USER_ID");
34
35
  return addCorsHeaders(response2, req);
35
36
  }
37
+ if (!canAccessUser(authResult, id, "users:read")) {
38
+ const response2 = createApiError("Insufficient permissions", 403, null, "FORBIDDEN");
39
+ return addCorsHeaders(response2, req);
40
+ }
36
41
  if (!key || key.trim() === "") {
37
42
  const response2 = createApiError("Metadata key is required", 400, null, "MISSING_META_KEY");
38
43
  return addCorsHeaders(response2, req);
@@ -75,6 +80,10 @@ export const PUT = withRateLimitTier(withApiLogging(async (req, { params }) => {
75
80
  const response2 = createApiError("User ID is required", 400, null, "MISSING_USER_ID");
76
81
  return addCorsHeaders(response2, req);
77
82
  }
83
+ if (!canAccessUser(authResult, id, "users:write")) {
84
+ const response2 = createApiError("Insufficient permissions", 403, null, "FORBIDDEN");
85
+ return addCorsHeaders(response2, req);
86
+ }
78
87
  if (!key || key.trim() === "") {
79
88
  const response2 = createApiError("Metadata key is required", 400, null, "MISSING_META_KEY");
80
89
  return addCorsHeaders(response2, req);
@@ -150,6 +159,10 @@ export const DELETE = withRateLimitTier(withApiLogging(async (req, { params }) =
150
159
  const response2 = createApiError("User ID is required", 400, null, "MISSING_USER_ID");
151
160
  return addCorsHeaders(response2, req);
152
161
  }
162
+ if (!canAccessUser(authResult, id, "users:write")) {
163
+ const response2 = createApiError("Insufficient permissions", 403, null, "FORBIDDEN");
164
+ return addCorsHeaders(response2, req);
165
+ }
153
166
  if (!key || key.trim() === "") {
154
167
  const response2 = createApiError("Metadata key is required", 400, null, "MISSING_META_KEY");
155
168
  return addCorsHeaders(response2, req);
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/routes/api/v1/users/[id]/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA0BxD,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,kCAEjD;AAGD,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BA8CpC,CAAC;AAGZ,eAAO,MAAM,KAAK;YAEM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BAyHnC,CAAC;AAGb,eAAO,MAAM,MAAM;YAEK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BA2DnC,CAAC"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/routes/api/v1/users/[id]/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA+BxD,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,kCAEjD;AAGD,eAAO,MAAM,GAAG;YAEQ,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BAoDpC,CAAC;AAGZ,eAAO,MAAM,KAAK;YAEM,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BAqInC,CAAC;AAGb,eAAO,MAAM,MAAM;YAEK,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC;2BAiEnC,CAAC"}
@@ -11,6 +11,7 @@ import {
11
11
  processEntityMetadata
12
12
  } from "@nextsparkjs/core/lib/api/helpers";
13
13
  import { authenticateRequest, createAuthFailureResponse } from "@nextsparkjs/core/lib/api/auth/dual-auth";
14
+ import { canAccessUser, hasAdminPermission } from "@nextsparkjs/core/lib/api/auth/permissions";
14
15
  import * as z from "zod";
15
16
  import { withRateLimitTier } from "@nextsparkjs/core/lib/api/rate-limit";
16
17
  const updateUserSchema = z.object({
@@ -20,6 +21,7 @@ const updateUserSchema = z.object({
20
21
  role: z.enum(["member", "superadmin"]).optional(),
21
22
  metas: z.record(z.string(), z.any()).optional()
22
23
  });
24
+ const resolveUserId = ({ id }, callerId) => id === "me" ? callerId : id;
23
25
  export async function OPTIONS(request) {
24
26
  return handleCorsPreflightRequest(request);
25
27
  }
@@ -32,11 +34,15 @@ export const GET = withRateLimitTier(withApiLogging(async (req, { params }) => {
32
34
  if (authResult.rateLimitResponse) {
33
35
  return authResult.rateLimitResponse;
34
36
  }
35
- const { id } = await params;
37
+ const id = resolveUserId(await params, authResult.user.id);
36
38
  if (!id || id.trim() === "") {
37
39
  const response2 = createApiError("User ID or email is required", 400, null, "MISSING_IDENTIFIER");
38
40
  return addCorsHeaders(response2, req);
39
41
  }
42
+ if (!canAccessUser(authResult, id, "users:read")) {
43
+ const response2 = createApiError("Insufficient permissions", 403, null, "FORBIDDEN");
44
+ return addCorsHeaders(response2, req);
45
+ }
40
46
  const user = await queryOneWithRLS(
41
47
  'SELECT id, email, name, "firstName", "lastName", image, country, timezone, language, role, "emailVerified", "createdAt", "updatedAt" FROM "users" WHERE id = $1 OR email = $1',
42
48
  [id],
@@ -65,14 +71,22 @@ export const PATCH = withRateLimitTier(withApiLogging(async (req, { params }) =>
65
71
  if (authResult.rateLimitResponse) {
66
72
  return authResult.rateLimitResponse;
67
73
  }
68
- const { id } = await params;
74
+ const id = resolveUserId(await params, authResult.user.id);
69
75
  if (!id || id.trim() === "") {
70
76
  const response2 = createApiError("User ID or email is required", 400, null, "MISSING_IDENTIFIER");
71
77
  return addCorsHeaders(response2, req);
72
78
  }
79
+ if (!canAccessUser(authResult, id, "users:write")) {
80
+ const response2 = createApiError("Insufficient permissions", 403, null, "FORBIDDEN");
81
+ return addCorsHeaders(response2, req);
82
+ }
73
83
  const body = await req.json();
74
84
  const { metas, ...userData } = body;
75
85
  const validatedData = updateUserSchema.parse(userData);
86
+ if (validatedData.role !== void 0 && !hasAdminPermission(authResult, "users:write")) {
87
+ const response2 = createApiError("Only a superadmin can change a role", 403, null, "FORBIDDEN");
88
+ return addCorsHeaders(response2, req);
89
+ }
76
90
  const updates = [];
77
91
  const values = [];
78
92
  let paramCount = 1;
@@ -157,6 +171,10 @@ export const DELETE = withRateLimitTier(withApiLogging(async (req, { params }) =
157
171
  const response2 = createApiError("User ID or email is required", 400, null, "MISSING_IDENTIFIER");
158
172
  return addCorsHeaders(response2, req);
159
173
  }
174
+ if (!hasAdminPermission(authResult, "users:delete")) {
175
+ const response2 = createApiError("Insufficient permissions. Superadmin access required.", 403, null, "FORBIDDEN");
176
+ return addCorsHeaders(response2, req);
177
+ }
160
178
  const targetUser = await queryOneWithRLS(
161
179
  'SELECT id, email FROM "users" WHERE id = $1 OR email = $1',
162
180
  [id],
@@ -4,52 +4,67 @@ Manage user profiles and account settings.
4
4
 
5
5
  ## Overview
6
6
 
7
- The Users API allows you to view and update user profile information. Users can update their own profile, while admins can manage other users within their team.
7
+ The Users API allows you to view and update user profile information. Users can read and update their own profile; a superadmin can manage any user.
8
8
 
9
9
  ## Authentication
10
10
 
11
11
  All endpoints require authentication via:
12
12
  - **Session cookie** (for browser-based requests)
13
- - **API Key** header (for server-to-server requests)
13
+ - **API Key** (for server-to-server requests), sent as `x-api-key: <key>` or `Authorization: Bearer <key>`: it needs the `users:read` scope to read and `users:write` to update, and it answers as the key's owner
14
+
15
+ A user can read and update only themselves; a superadmin can manage any user. Anything else answers `403`.
14
16
 
15
17
  ## Endpoints
16
18
 
17
19
  ### Get Current User
18
20
  `GET /api/v1/users/me`
19
21
 
20
- Returns the currently authenticated user's profile.
22
+ Returns the signed-in user, with a session cookie or an API key. It is `GET /api/v1/users/:id` for the caller's own id, so it takes the same `metas` query parameters and answers with the same fields.
23
+
24
+ ```bash
25
+ curl -H "Cookie: <session cookie>" https://yourdomain.com/api/v1/users/me
26
+ curl -H "Authorization: Bearer <api key>" https://yourdomain.com/api/v1/users/me
27
+ curl -H "x-api-key: <api key>" https://yourdomain.com/api/v1/users/me
28
+ ```
21
29
 
22
30
  **Example Response:**
23
31
  ```json
24
32
  {
25
- "id": "user_123",
26
- "name": "John Doe",
27
- "email": "john@example.com",
28
- "image": "/uploads/avatar.png",
29
- "createdAt": "2024-01-15T10:30:00Z",
30
- "teams": [
31
- {
32
- "id": "team_456",
33
- "name": "Acme Corp",
34
- "role": "admin"
35
- }
36
- ]
33
+ "success": true,
34
+ "data": {
35
+ "id": "user_123",
36
+ "email": "john@example.com",
37
+ "name": "John Doe",
38
+ "firstName": "John",
39
+ "lastName": "Doe",
40
+ "image": "/uploads/avatar.png",
41
+ "country": null,
42
+ "timezone": null,
43
+ "language": "en",
44
+ "role": "member",
45
+ "emailVerified": true,
46
+ "createdAt": "2024-01-15T10:30:00Z",
47
+ "updatedAt": "2024-01-15T10:30:00Z"
48
+ }
37
49
  }
38
50
  ```
39
51
 
40
52
  ### Update Current User
41
53
  `PATCH /api/v1/users/me`
42
54
 
43
- Update the current user's profile.
55
+ Update the signed-in user. It is `PATCH /api/v1/users/:id` for the caller's own id, with the same rules: only `firstName`, `lastName`, `language` and `metas` are accepted, and `role` is a superadmin's to change (anyone else gets `403`).
44
56
 
45
57
  **Request Body:**
46
58
  ```json
47
59
  {
48
- "name": "John Smith",
49
- "image": "/uploads/new-avatar.png"
60
+ "firstName": "John",
61
+ "lastName": "Smith",
62
+ "metas": { "preferences": { "theme": "dark" } }
50
63
  }
51
64
  ```
52
65
 
66
+ To store per-user settings (the mobile client's preferences), use the user's metadata: `GET`/`PUT /api/v1/users/:id/meta/:key`.
67
+
53
68
  ### List Team Members
54
69
  `GET /api/v1/users`
55
70
 
@@ -63,7 +78,7 @@ Returns all users in the current team.
63
78
  ### Get User by ID
64
79
  `GET /api/v1/users/[id]`
65
80
 
66
- Returns a specific user's profile (within the same team).
81
+ Returns a specific user's profile. Only that user or a superadmin can read it; `403` otherwise.
67
82
 
68
83
  **Path Parameters:**
69
84
  - `id` (string, required): User ID
@@ -0,0 +1,6 @@
1
+ import type { NextRequest } from 'next/server';
2
+ import { OPTIONS } from '@nextsparkjs/core/routes/api/v1/users/[id]/route';
3
+ export { OPTIONS };
4
+ export declare const GET: (req: NextRequest) => Promise<import("next/server").NextResponse<unknown>>;
5
+ export declare const PATCH: (req: NextRequest) => Promise<import("next/server").NextResponse<unknown>>;
6
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../src/routes/api/v1/users/me/route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,OAAO,EAAsC,MAAM,kDAAkD,CAAA;AAO9G,OAAO,EAAE,OAAO,EAAE,CAAA;AAClB,eAAO,MAAM,GAAG,GAAI,KAAK,WAAW,yDAAqB,CAAA;AACzD,eAAO,MAAM,KAAK,GAAI,KAAK,WAAW,yDAAuB,CAAA"}
@@ -0,0 +1,5 @@
1
+ import { OPTIONS, GET as getUser, PATCH as patchUser } from "@nextsparkjs/core/routes/api/v1/users/[id]/route";
2
+ const me = { params: Promise.resolve({ id: "me" }) };
3
+ export { OPTIONS };
4
+ export const GET = (req) => getUser(req, me);
5
+ export const PATCH = (req) => patchUser(req, me);
@@ -34,13 +34,13 @@ export default defineApiEndpoint({
34
34
  {
35
35
  id: 'update-profile',
36
36
  title: 'Update My Profile',
37
- description: 'Update current user name',
37
+ description: 'Update the current user first name',
38
38
  method: 'PATCH',
39
39
  pathParams: {
40
40
  id: 'me'
41
41
  },
42
42
  payload: {
43
- name: 'Updated Name'
43
+ firstName: 'Updated'
44
44
  },
45
45
  tags: ['write', 'profile']
46
46
  },
@@ -0,0 +1,4 @@
1
+ export default function MainDashboardLayout({ children }: {
2
+ children: React.ReactNode;
3
+ }): import("react/jsx-runtime").JSX.Element;
4
+ //# sourceMappingURL=layout.cc.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout.cc.d.ts","sourceRoot":"","sources":["../../../../src/routes/dashboard/(main)/layout.cc.tsx"],"names":[],"mappings":"AAgBA,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAAE,2CAQtF"}
@@ -0,0 +1,10 @@
1
+ import { Fragment, jsx } from "react/jsx-runtime";
2
+ import { Suspense } from "react";
3
+ import { MainDashboardShell, enforceEntityPermission } from "../../_internal/dashboard-main-shared.js";
4
+ async function EntityPermission({ children }) {
5
+ await enforceEntityPermission();
6
+ return /* @__PURE__ */ jsx(Fragment, { children });
7
+ }
8
+ export default function MainDashboardLayout({ children }) {
9
+ return /* @__PURE__ */ jsx(MainDashboardShell, { children: /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(EntityPermission, { children }) }) });
10
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../src/routes/dashboard/(main)/layout.tsx"],"names":[],"mappings":"AAsDA,iBAAe,0BAA0B,CAAC,EACxC,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,oDAmCA;AAGD,eAAe,0BAA0B,CAAA"}
1
+ {"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../src/routes/dashboard/(main)/layout.tsx"],"names":[],"mappings":"AAcA,iBAAe,0BAA0B,CAAC,EACxC,QAAQ,EACT,EAAE;IACD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B,oDAIA;AAGD,eAAe,0BAA0B,CAAA"}
@@ -1,50 +1,9 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { headers } from "next/headers";
3
- import { redirect } from "next/navigation";
4
- import { DashboardShell } from "@nextsparkjs/core/components/dashboard/layouts/DashboardShell";
5
- import { serializeEntityConfig } from "@nextsparkjs/core/lib/entities/serialization";
6
- import { setEntityRegistry } from "@nextsparkjs/core/lib/entities/queries";
7
- import { checkPermission } from "@nextsparkjs/core/lib/permissions/check";
8
- import { getDashboardPermissionContext } from "@nextsparkjs/core/lib/auth/request-session";
9
- import { isValidPermission } from "@nextsparkjs/core/lib/permissions/init";
10
- import { ENTITY_REGISTRY, ENTITY_METADATA } from "@nextsparkjs/registries/entity-registry";
11
- setEntityRegistry(ENTITY_REGISTRY, ENTITY_METADATA);
12
- function parseEntityFromPathname(pathname) {
13
- const match = pathname.match(/^\/dashboard\/([^/]+)(?:\/(.*))?$/);
14
- if (!match) return null;
15
- const entity = match[1];
16
- const rest = match[2] || "";
17
- if (rest === "" || rest === "/") return { entity, action: "list" };
18
- if (rest === "create") return { entity, action: "create" };
19
- if (rest.match(/^[^/]+\/edit$/)) return { entity, action: "update" };
20
- if (rest.match(/^[^/]+$/)) return { entity, action: "read" };
21
- return { entity, action: "read" };
22
- }
23
- function isEntityConfig(entity) {
24
- return "slug" in entity;
25
- }
2
+ import { MainDashboardShell, enforceEntityPermission } from "../../_internal/dashboard-main-shared.js";
26
3
  async function DefaultMainDashboardLayout({
27
4
  children
28
5
  }) {
29
- const allEntities = Object.values(ENTITY_REGISTRY).map((entry) => entry.config);
30
- const entities = allEntities.filter(isEntityConfig);
31
- const serializedEntities = entities.map(serializeEntityConfig);
32
- const headersList = await headers();
33
- const pathname = headersList.get("x-pathname") || "";
34
- const { userId, teamId } = await getDashboardPermissionContext();
35
- if (userId && teamId && pathname) {
36
- const parsed = parseEntityFromPathname(pathname);
37
- if (parsed) {
38
- const { entity, action } = parsed;
39
- const permission = `${entity}.${action}`;
40
- if (isValidPermission(`${entity}.list`)) {
41
- const hasPermission = await checkPermission(userId, teamId, permission);
42
- if (!hasPermission) {
43
- redirect(`/dashboard/permission-denied?entity=${entity}&action=${action}`);
44
- }
45
- }
46
- }
47
- }
48
- return /* @__PURE__ */ jsx(DashboardShell, { entities: serializedEntities, children });
6
+ await enforceEntityPermission();
7
+ return /* @__PURE__ */ jsx(MainDashboardShell, { children });
49
8
  }
50
9
  export default DefaultMainDashboardLayout;
@@ -4,6 +4,6 @@ interface PermissionDeniedPageProps {
4
4
  action?: string;
5
5
  }>;
6
6
  }
7
- declare function PermissionDeniedPage({ searchParams }: PermissionDeniedPageProps): Promise<import("react/jsx-runtime").JSX.Element>;
7
+ declare function PermissionDeniedPage({ searchParams }: PermissionDeniedPageProps): import("react/jsx-runtime").JSX.Element;
8
8
  export default PermissionDeniedPage;
9
9
  //# sourceMappingURL=page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/routes/dashboard/permission-denied/page.tsx"],"names":[],"mappings":"AAQA,UAAU,yBAAyB;IACjC,YAAY,EAAE,OAAO,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;CACH;AAED,iBAAe,oBAAoB,CAAC,EAClC,YAAY,EACb,EAAE,yBAAyB,oDAW3B;AAED,eAAe,oBAAoB,CAAA"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../src/routes/dashboard/permission-denied/page.tsx"],"names":[],"mappings":"AASA,UAAU,yBAAyB;IACjC,YAAY,EAAE,OAAO,CAAC;QACpB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;KAChB,CAAC,CAAA;CACH;AAkBD,iBAAS,oBAAoB,CAAC,EAAE,YAAY,EAAE,EAAE,yBAAyB,2CAMxE;AAED,eAAe,oBAAoB,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
+ import { Suspense } from "react";
2
3
  import { NoPermission } from "@nextsparkjs/core/components/permissions/NoPermission";
3
- async function PermissionDeniedPage({
4
+ async function DeniedMessage({
4
5
  searchParams
5
6
  }) {
6
7
  const { entity, action } = await searchParams;
@@ -14,4 +15,7 @@ async function PermissionDeniedPage({
14
15
  }
15
16
  );
16
17
  }
18
+ function PermissionDeniedPage({ searchParams }) {
19
+ return /* @__PURE__ */ jsx(Suspense, { fallback: null, children: /* @__PURE__ */ jsx(DeniedMessage, { searchParams }) });
20
+ }
17
21
  export default PermissionDeniedPage;
@@ -1 +1 @@
1
- {"version":3,"file":"layout.cc.d.ts","sourceRoot":"","sources":["../../../src/routes/devtools/layout.cc.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAIpC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;;;;AAEjD,wBAAkD"}
1
+ {"version":3,"file":"layout.cc.d.ts","sourceRoot":"","sources":["../../../src/routes/devtools/layout.cc.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAIpC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;;;;AAUjD,wBAA+D"}
@@ -1,4 +1,8 @@
1
+ import { jsx } from "react/jsx-runtime";
1
2
  import { DevLayout, defaultMetadata } from "../_internal/devtools-layout.js";
2
3
  import { withDevtoolsAreaMessages } from "../_internal/devtools-layout.cc.js";
3
4
  export const metadata = defaultMetadata;
4
- export default withDevtoolsAreaMessages(DevLayout);
5
+ function ServerCheckedDevLayout({ children }) {
6
+ return /* @__PURE__ */ jsx(DevLayout, { serverChecked: true, children });
7
+ }
8
+ export default withDevtoolsAreaMessages(ServerCheckedDevLayout);
@@ -422,6 +422,11 @@
422
422
  "target": "api/v1/users/[id]/route.ts",
423
423
  "specifier": "@nextsparkjs/core/routes/api/v1/users/[id]/route"
424
424
  },
425
+ {
426
+ "kind": "route",
427
+ "target": "api/v1/users/me/route.ts",
428
+ "specifier": "@nextsparkjs/core/routes/api/v1/users/me/route"
429
+ },
425
430
  {
426
431
  "kind": "route",
427
432
  "target": "api/v1/users/route.ts",
@@ -716,6 +721,11 @@
716
721
  "target": "public/page.tsx",
717
722
  "specifier": "@nextsparkjs/core/routes/public/page"
718
723
  },
724
+ {
725
+ "kind": "robots",
726
+ "target": "robots.ts",
727
+ "specifier": "@nextsparkjs/core/routes/robots"
728
+ },
719
729
  {
720
730
  "kind": "page",
721
731
  "target": "superadmin/docs/[section]/[page]/page.tsx",
@@ -0,0 +1,10 @@
1
+ import type { MetadataRoute } from 'next';
2
+ /**
3
+ * /robots.txt (#214): public pages are crawlable, the authenticated areas and the API are not.
4
+ *
5
+ * Answers `text/plain` 200 in Cache Components and legacy ISR alike, so a crawler never gets the public
6
+ * catch-all page's HTML. A project overrides it with its own `robots.ts` (templates/robots.ts), which
7
+ * replaces this route. Core has no sitemap, so none is declared.
8
+ */
9
+ export default function robots(): MetadataRoute.Robots;
10
+ //# sourceMappingURL=robots.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"robots.d.ts","sourceRoot":"","sources":["../../src/routes/robots.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,MAAM,CAAA;AAGzC;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,MAAM,IAAI,aAAa,CAAC,MAAM,CAQrD"}
@@ -0,0 +1,10 @@
1
+ import { withBasePath } from "@nextsparkjs/core/lib/base-path";
2
+ export default function robots() {
3
+ return {
4
+ rules: {
5
+ userAgent: "*",
6
+ allow: withBasePath("/"),
7
+ disallow: ["/dashboard", "/superadmin", "/devtools", "/api"].map(withBasePath)
8
+ }
9
+ };
10
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"layout.cc.d.ts","sourceRoot":"","sources":["../../../src/routes/superadmin/layout.cc.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAIpC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;;;;AAEjD,wBAA2D"}
1
+ {"version":3,"file":"layout.cc.d.ts","sourceRoot":"","sources":["../../../src/routes/superadmin/layout.cc.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAA;AAIpC,eAAO,MAAM,QAAQ,EAAE,QAA0B,CAAA;;;;AAUjD,wBAAwE"}
@@ -1,4 +1,8 @@
1
+ import { jsx } from "react/jsx-runtime";
1
2
  import { SuperadminLayout, defaultMetadata } from "../_internal/superadmin-layout.js";
2
3
  import { withSuperadminAreaMessages } from "../_internal/superadmin-layout.cc.js";
3
4
  export const metadata = defaultMetadata;
4
- export default withSuperadminAreaMessages(SuperadminLayout);
5
+ function ServerCheckedSuperadminLayout({ children }) {
6
+ return /* @__PURE__ */ jsx(SuperadminLayout, { serverChecked: true, children });
7
+ }
8
+ export default withSuperadminAreaMessages(ServerCheckedSuperadminLayout);
@@ -39,7 +39,7 @@
39
39
  "wrapper": "withSuperadminAccess",
40
40
  "metadata": "withSuperadminMetadata",
41
41
  "handler": "withSuperadminRouteAccess",
42
- "specifier": "@nextsparkjs/core/routes/_internal/area-access"
42
+ "specifier": "@nextsparkjs/core/routes/_internal/area-access.cc"
43
43
  }
44
44
  },
45
45
  {
@@ -54,7 +54,7 @@
54
54
  "wrapper": "withDevtoolsAccess",
55
55
  "metadata": "withDevtoolsMetadata",
56
56
  "handler": "withDevtoolsRouteAccess",
57
- "specifier": "@nextsparkjs/core/routes/_internal/area-access"
57
+ "specifier": "@nextsparkjs/core/routes/_internal/area-access.cc"
58
58
  }
59
59
  },
60
60
  {
@@ -62,6 +62,16 @@
62
62
  "target": "dashboard/layout.tsx",
63
63
  "specifier": "@nextsparkjs/core/routes/dashboard/layout.cc"
64
64
  },
65
+ {
66
+ "kind": "layout",
67
+ "target": "dashboard/(main)/layout.tsx",
68
+ "specifier": "@nextsparkjs/core/routes/dashboard/(main)/layout.cc"
69
+ },
70
+ {
71
+ "kind": "page",
72
+ "target": "(public)/page.tsx",
73
+ "specifier": "@nextsparkjs/core/routes/(public)/page.cc"
74
+ },
65
75
  {
66
76
  "kind": "page",
67
77
  "target": "(auth)/login/page.tsx",
@@ -260,35 +260,8 @@ const nextConfig = {
260
260
  source: '/:path*',
261
261
  headers: securityHeaders
262
262
  },
263
- // CORS headers for API routes
264
- // NOTE: In development, CORS is handled dynamically by API routes using addCorsHeaders()
265
- // to support multiple origins (web app, mobile app, etc.)
266
- // In production, we set static CORS headers here
267
- ...(isProduction ? [{
268
- source: '/api/:path*',
269
- headers: [
270
- {
271
- key: 'Access-Control-Allow-Origin',
272
- value: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
273
- },
274
- {
275
- key: 'Access-Control-Allow-Methods',
276
- value: 'GET, POST, PUT, DELETE, OPTIONS, PATCH'
277
- },
278
- {
279
- key: 'Access-Control-Allow-Headers',
280
- value: 'Content-Type, Authorization, x-api-key, x-verify-from-ui, Cookie, Set-Cookie'
281
- },
282
- {
283
- key: 'Access-Control-Allow-Credentials',
284
- value: 'true'
285
- },
286
- {
287
- key: 'Access-Control-Expose-Headers',
288
- value: 'Set-Cookie'
289
- }
290
- ]
291
- }] : [])
263
+ // No CORS headers here: core's API routes answer CORS per request (addCorsHeaders), so the
264
+ // origins in api.cors.allowedOrigins and CORS_ADDITIONAL_ORIGINS get their grant in production too
292
265
  ]
293
266
  },
294
267
  }
@@ -10,6 +10,7 @@
10
10
  import { NextRequest, NextResponse } from 'next/server'
11
11
  import { queryWithRLS } from '@nextsparkjs/core/lib/db'
12
12
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
13
+ import { corsPreflight } from '@nextsparkjs/core/lib/api/cors-response'
13
14
 
14
15
  interface Author {
15
16
  id: string
@@ -151,3 +152,5 @@ const getHandler = async (
151
152
  }
152
153
 
153
154
  export const GET = withRateLimitTier(getHandler, 'read')
155
+
156
+ export const OPTIONS = corsPreflight
@@ -10,6 +10,7 @@
10
10
  import { NextRequest, NextResponse } from 'next/server'
11
11
  import { queryWithRLS } from '@nextsparkjs/core/lib/db'
12
12
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
13
+ import { corsPreflight } from '@nextsparkjs/core/lib/api/cors-response'
13
14
 
14
15
  interface AuthorWithCount {
15
16
  id: string
@@ -64,3 +65,5 @@ const getHandler = async (request: NextRequest) => {
64
65
  }
65
66
 
66
67
  export const GET = withRateLimitTier(getHandler, 'read')
68
+
69
+ export const OPTIONS = corsPreflight
@@ -11,6 +11,7 @@
11
11
  import { NextRequest, NextResponse } from 'next/server'
12
12
  import { queryWithRLS } from '@nextsparkjs/core/lib/db'
13
13
  import { withRateLimitTier } from '@nextsparkjs/core/lib/api/rate-limit'
14
+ import { corsPreflight } from '@nextsparkjs/core/lib/api/cors-response'
14
15
 
15
16
  interface Post {
16
17
  id: string
@@ -152,3 +153,5 @@ const getHandler = async (request: NextRequest) => {
152
153
  }
153
154
 
154
155
  export const GET = withRateLimitTier(getHandler, 'read')
156
+
157
+ export const OPTIONS = corsPreflight