hazo_auth 1.2.0 → 1.4.0

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 (495) hide show
  1. package/README.md +383 -774
  2. package/dist/components/index.d.ts +3 -0
  3. package/dist/components/index.d.ts.map +1 -0
  4. package/dist/components/index.js +5 -0
  5. package/dist/components/layouts/email_verification/config/email_verification_field_config.d.ts +23 -0
  6. package/dist/components/layouts/email_verification/config/email_verification_field_config.d.ts.map +1 -0
  7. package/dist/components/layouts/email_verification/config/email_verification_field_config.js +44 -0
  8. package/dist/components/layouts/email_verification/hooks/use_email_verification.d.ts +31 -0
  9. package/dist/components/layouts/email_verification/hooks/use_email_verification.d.ts.map +1 -0
  10. package/dist/components/layouts/email_verification/hooks/use_email_verification.js +222 -0
  11. package/dist/components/layouts/email_verification/index.d.ts +23 -0
  12. package/dist/components/layouts/email_verification/index.d.ts.map +1 -0
  13. package/dist/components/layouts/email_verification/index.js +61 -0
  14. package/dist/components/layouts/forgot_password/config/forgot_password_field_config.d.ts +10 -0
  15. package/dist/components/layouts/forgot_password/config/forgot_password_field_config.d.ts.map +1 -0
  16. package/dist/components/layouts/forgot_password/config/forgot_password_field_config.js +33 -0
  17. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts +22 -0
  18. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts.map +1 -0
  19. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.js +127 -0
  20. package/dist/components/layouts/forgot_password/index.d.ts +18 -0
  21. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -0
  22. package/dist/components/layouts/forgot_password/index.js +43 -0
  23. package/dist/components/layouts/index.d.ts +16 -0
  24. package/dist/components/layouts/index.d.ts.map +1 -0
  25. package/dist/components/layouts/index.js +11 -0
  26. package/dist/components/layouts/login/config/login_field_config.d.ts +11 -0
  27. package/dist/components/layouts/login/config/login_field_config.d.ts.map +1 -0
  28. package/dist/components/layouts/login/config/login_field_config.js +42 -0
  29. package/dist/components/layouts/login/hooks/use_login_form.d.ts +34 -0
  30. package/dist/components/layouts/login/hooks/use_login_form.d.ts.map +1 -0
  31. package/dist/components/layouts/login/hooks/use_login_form.js +196 -0
  32. package/dist/components/layouts/login/index.d.ts +31 -0
  33. package/dist/components/layouts/login/index.d.ts.map +1 -0
  34. package/dist/components/layouts/login/index.js +58 -0
  35. package/dist/components/layouts/my_settings/components/editable_field.d.ts +19 -0
  36. package/dist/components/layouts/my_settings/components/editable_field.d.ts.map +1 -0
  37. package/dist/components/layouts/my_settings/components/editable_field.js +73 -0
  38. package/dist/components/layouts/my_settings/components/password_change_dialog.d.ts +28 -0
  39. package/dist/components/layouts/my_settings/components/password_change_dialog.d.ts.map +1 -0
  40. package/dist/components/layouts/my_settings/components/password_change_dialog.js +138 -0
  41. package/dist/components/layouts/my_settings/components/profile_picture_dialog.d.ts +42 -0
  42. package/dist/components/layouts/my_settings/components/profile_picture_dialog.d.ts.map +1 -0
  43. package/dist/components/layouts/my_settings/components/profile_picture_dialog.js +198 -0
  44. package/dist/components/layouts/my_settings/components/profile_picture_display.d.ts +16 -0
  45. package/dist/components/layouts/my_settings/components/profile_picture_display.d.ts.map +1 -0
  46. package/dist/components/layouts/my_settings/components/profile_picture_display.js +33 -0
  47. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.d.ts +17 -0
  48. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.d.ts.map +1 -0
  49. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.js +48 -0
  50. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts +21 -0
  51. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.d.ts.map +1 -0
  52. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +144 -0
  53. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.d.ts +23 -0
  54. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.d.ts.map +1 -0
  55. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +169 -0
  56. package/dist/components/layouts/my_settings/config/my_settings_field_config.d.ts +19 -0
  57. package/dist/components/layouts/my_settings/config/my_settings_field_config.d.ts.map +1 -0
  58. package/dist/components/layouts/my_settings/config/my_settings_field_config.js +26 -0
  59. package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts +46 -0
  60. package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts.map +1 -0
  61. package/dist/components/layouts/my_settings/hooks/use_my_settings.js +354 -0
  62. package/dist/components/layouts/my_settings/index.d.ts +64 -0
  63. package/dist/components/layouts/my_settings/index.d.ts.map +1 -0
  64. package/dist/components/layouts/my_settings/index.js +65 -0
  65. package/dist/components/layouts/register/config/register_field_config.d.ts +14 -0
  66. package/dist/components/layouts/register/config/register_field_config.d.ts.map +1 -0
  67. package/dist/components/layouts/register/config/register_field_config.js +69 -0
  68. package/dist/components/layouts/register/hooks/use_register_form.d.ts +30 -0
  69. package/dist/components/layouts/register/hooks/use_register_form.d.ts.map +1 -0
  70. package/dist/components/layouts/register/hooks/use_register_form.js +184 -0
  71. package/dist/components/layouts/register/index.d.ts +23 -0
  72. package/dist/components/layouts/register/index.d.ts.map +1 -0
  73. package/dist/components/layouts/register/index.js +58 -0
  74. package/dist/components/layouts/reset_password/config/reset_password_field_config.d.ts +13 -0
  75. package/dist/components/layouts/reset_password/config/reset_password_field_config.d.ts.map +1 -0
  76. package/dist/components/layouts/reset_password/config/reset_password_field_config.js +53 -0
  77. package/dist/components/layouts/reset_password/hooks/use_reset_password_form.d.ts +28 -0
  78. package/dist/components/layouts/reset_password/hooks/use_reset_password_form.d.ts.map +1 -0
  79. package/dist/components/layouts/reset_password/hooks/use_reset_password_form.js +201 -0
  80. package/dist/components/layouts/reset_password/index.d.ts +23 -0
  81. package/dist/components/layouts/reset_password/index.d.ts.map +1 -0
  82. package/dist/components/layouts/reset_password/index.js +53 -0
  83. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +20 -0
  84. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -0
  85. package/dist/components/layouts/shared/components/already_logged_in_guard.js +32 -0
  86. package/dist/components/layouts/shared/components/auth_page_shell.d.ts +7 -0
  87. package/dist/components/layouts/shared/components/auth_page_shell.d.ts.map +1 -0
  88. package/dist/components/layouts/shared/components/auth_page_shell.js +12 -0
  89. package/dist/components/layouts/shared/components/field_error_message.d.ts +7 -0
  90. package/dist/components/layouts/shared/components/field_error_message.d.ts.map +1 -0
  91. package/dist/components/layouts/shared/components/field_error_message.js +6 -0
  92. package/dist/components/layouts/shared/components/form_action_buttons.d.ts +14 -0
  93. package/dist/components/layouts/shared/components/form_action_buttons.d.ts.map +1 -0
  94. package/dist/components/layouts/shared/components/form_action_buttons.js +15 -0
  95. package/dist/components/layouts/shared/components/form_field_wrapper.d.ts +11 -0
  96. package/dist/components/layouts/shared/components/form_field_wrapper.d.ts.map +1 -0
  97. package/dist/components/layouts/shared/components/form_field_wrapper.js +9 -0
  98. package/dist/components/layouts/shared/components/form_header.d.ts +10 -0
  99. package/dist/components/layouts/shared/components/form_header.d.ts.map +1 -0
  100. package/dist/components/layouts/shared/components/form_header.js +5 -0
  101. package/dist/components/layouts/shared/components/logout_button.d.ts +7 -0
  102. package/dist/components/layouts/shared/components/logout_button.d.ts.map +1 -0
  103. package/dist/components/layouts/shared/components/logout_button.js +44 -0
  104. package/dist/components/layouts/shared/components/password_field.d.ts +13 -0
  105. package/dist/components/layouts/shared/components/password_field.d.ts.map +1 -0
  106. package/dist/components/layouts/shared/components/password_field.js +13 -0
  107. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts +22 -0
  108. package/dist/components/layouts/shared/components/profile_pic_menu.d.ts.map +1 -0
  109. package/dist/components/layouts/shared/components/profile_pic_menu.js +169 -0
  110. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts +12 -0
  111. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.d.ts.map +1 -0
  112. package/dist/components/layouts/shared/components/profile_pic_menu_wrapper.js +16 -0
  113. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts +6 -0
  114. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -0
  115. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +15 -0
  116. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts +11 -0
  117. package/dist/components/layouts/shared/components/standalone_layout_wrapper.d.ts.map +1 -0
  118. package/dist/components/layouts/shared/components/standalone_layout_wrapper.js +10 -0
  119. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +12 -0
  120. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -0
  121. package/dist/components/layouts/shared/components/two_column_auth_layout.js +8 -0
  122. package/dist/components/layouts/shared/components/unauthorized_guard.d.ts +14 -0
  123. package/dist/components/layouts/shared/components/unauthorized_guard.d.ts.map +1 -0
  124. package/dist/components/layouts/shared/components/unauthorized_guard.js +30 -0
  125. package/dist/components/layouts/shared/components/visual_panel.d.ts +9 -0
  126. package/dist/components/layouts/shared/components/visual_panel.d.ts.map +1 -0
  127. package/dist/components/layouts/shared/components/visual_panel.js +10 -0
  128. package/dist/components/layouts/shared/config/layout_customization.d.ts +38 -0
  129. package/dist/components/layouts/shared/config/layout_customization.d.ts.map +1 -0
  130. package/dist/components/layouts/shared/config/layout_customization.js +19 -0
  131. package/dist/components/layouts/shared/data/layout_data_client.d.ts +6 -0
  132. package/dist/components/layouts/shared/data/layout_data_client.d.ts.map +1 -0
  133. package/dist/components/layouts/shared/data/layout_data_client.js +9 -0
  134. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +20 -0
  135. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -0
  136. package/dist/components/layouts/shared/hooks/use_auth_status.js +71 -0
  137. package/dist/components/layouts/shared/hooks/use_hazo_auth.d.ts +48 -0
  138. package/dist/components/layouts/shared/hooks/use_hazo_auth.d.ts.map +1 -0
  139. package/dist/components/layouts/shared/hooks/use_hazo_auth.js +90 -0
  140. package/dist/components/layouts/shared/index.d.ts +24 -0
  141. package/dist/components/layouts/shared/index.d.ts.map +1 -0
  142. package/dist/components/layouts/shared/index.js +27 -0
  143. package/dist/components/layouts/shared/utils/ip_address.d.ts +7 -0
  144. package/dist/components/layouts/shared/utils/ip_address.d.ts.map +1 -0
  145. package/dist/components/layouts/shared/utils/ip_address.js +34 -0
  146. package/dist/components/layouts/shared/utils/validation.d.ts +15 -0
  147. package/dist/components/layouts/shared/utils/validation.d.ts.map +1 -0
  148. package/dist/components/layouts/shared/utils/validation.js +45 -0
  149. package/dist/components/layouts/user_management/components/roles_matrix.d.ts +29 -0
  150. package/dist/components/layouts/user_management/components/roles_matrix.d.ts.map +1 -0
  151. package/dist/components/layouts/user_management/components/roles_matrix.js +287 -0
  152. package/dist/components/layouts/user_management/index.d.ts +13 -0
  153. package/dist/components/layouts/user_management/index.d.ts.map +1 -0
  154. package/dist/components/layouts/user_management/index.js +495 -0
  155. package/dist/components/ui/alert-dialog.d.ts +21 -0
  156. package/dist/components/ui/alert-dialog.d.ts.map +1 -0
  157. package/dist/components/ui/alert-dialog.js +62 -0
  158. package/dist/components/ui/avatar.d.ts +7 -0
  159. package/dist/components/ui/avatar.d.ts.map +1 -0
  160. package/dist/components/ui/avatar.js +32 -0
  161. package/dist/components/ui/button.d.ts +12 -0
  162. package/dist/components/ui/button.d.ts.map +1 -0
  163. package/dist/components/ui/button.js +45 -0
  164. package/dist/components/ui/checkbox.d.ts +5 -0
  165. package/dist/components/ui/checkbox.d.ts.map +1 -0
  166. package/dist/components/ui/checkbox.js +23 -0
  167. package/dist/components/ui/dialog.d.ts +20 -0
  168. package/dist/components/ui/dialog.d.ts.map +1 -0
  169. package/dist/components/ui/dialog.js +52 -0
  170. package/dist/components/ui/dropdown-menu.d.ts +28 -0
  171. package/dist/components/ui/dropdown-menu.d.ts.map +1 -0
  172. package/dist/components/ui/dropdown-menu.js +72 -0
  173. package/dist/components/ui/hazo_ui_tooltip.d.ts +26 -0
  174. package/dist/components/ui/hazo_ui_tooltip.d.ts.map +1 -0
  175. package/dist/components/ui/hazo_ui_tooltip.js +17 -0
  176. package/dist/components/ui/index.d.ts +20 -0
  177. package/dist/components/ui/index.d.ts.map +1 -0
  178. package/dist/components/ui/index.js +21 -0
  179. package/dist/components/ui/input.d.ts +4 -0
  180. package/dist/components/ui/input.d.ts.map +1 -0
  181. package/dist/components/ui/input.js +20 -0
  182. package/dist/components/ui/label.d.ts +6 -0
  183. package/dist/components/ui/label.d.ts.map +1 -0
  184. package/dist/components/ui/label.js +24 -0
  185. package/dist/components/ui/separator.d.ts +5 -0
  186. package/dist/components/ui/separator.d.ts.map +1 -0
  187. package/dist/components/ui/separator.js +22 -0
  188. package/dist/components/ui/sheet.d.ts +23 -0
  189. package/dist/components/ui/sheet.d.ts.map +1 -0
  190. package/dist/components/ui/sheet.js +66 -0
  191. package/dist/components/ui/sidebar.d.ts +66 -0
  192. package/dist/components/ui/sidebar.d.ts.map +1 -0
  193. package/dist/components/ui/sidebar.js +267 -0
  194. package/dist/components/ui/skeleton.d.ts +3 -0
  195. package/dist/components/ui/skeleton.d.ts.map +1 -0
  196. package/dist/components/ui/skeleton.js +18 -0
  197. package/dist/components/ui/sonner.d.ts +5 -0
  198. package/dist/components/ui/sonner.d.ts.map +1 -0
  199. package/dist/components/ui/sonner.js +28 -0
  200. package/dist/components/ui/switch.d.ts +5 -0
  201. package/dist/components/ui/switch.d.ts.map +1 -0
  202. package/dist/components/ui/switch.js +22 -0
  203. package/dist/components/ui/table.d.ts +11 -0
  204. package/dist/components/ui/table.d.ts.map +1 -0
  205. package/dist/components/ui/table.js +55 -0
  206. package/dist/components/ui/tabs.d.ts +8 -0
  207. package/dist/components/ui/tabs.d.ts.map +1 -0
  208. package/dist/components/ui/tabs.js +33 -0
  209. package/dist/components/ui/tooltip.d.ts +8 -0
  210. package/dist/components/ui/tooltip.d.ts.map +1 -0
  211. package/dist/components/ui/tooltip.js +25 -0
  212. package/dist/components/ui/vertical-tabs.d.ts +8 -0
  213. package/dist/components/ui/vertical-tabs.d.ts.map +1 -0
  214. package/dist/components/ui/vertical-tabs.js +37 -0
  215. package/dist/hooks/use-mobile.d.ts +2 -0
  216. package/dist/hooks/use-mobile.d.ts.map +1 -0
  217. package/dist/hooks/use-mobile.js +15 -0
  218. package/dist/index.d.ts +3 -0
  219. package/dist/index.d.ts.map +1 -0
  220. package/dist/index.js +5 -0
  221. package/dist/lib/already_logged_in_config.server.d.ts +14 -0
  222. package/dist/lib/already_logged_in_config.server.d.ts.map +1 -0
  223. package/dist/lib/already_logged_in_config.server.js +29 -0
  224. package/dist/lib/app_logger.d.ts +12 -0
  225. package/dist/lib/app_logger.d.ts.map +1 -0
  226. package/dist/lib/app_logger.js +14 -0
  227. package/dist/lib/auth/auth_cache.d.ts +83 -0
  228. package/dist/lib/auth/auth_cache.d.ts.map +1 -0
  229. package/dist/lib/auth/auth_cache.js +158 -0
  230. package/dist/lib/auth/auth_rate_limiter.d.ts +39 -0
  231. package/dist/lib/auth/auth_rate_limiter.d.ts.map +1 -0
  232. package/dist/lib/auth/auth_rate_limiter.js +95 -0
  233. package/dist/lib/auth/auth_types.d.ts +53 -0
  234. package/dist/lib/auth/auth_types.d.ts.map +1 -0
  235. package/dist/lib/auth/auth_types.js +16 -0
  236. package/dist/lib/auth/auth_utils.server.d.ts +47 -0
  237. package/dist/lib/auth/auth_utils.server.d.ts.map +1 -0
  238. package/dist/lib/auth/auth_utils.server.js +150 -0
  239. package/dist/lib/auth/hazo_get_auth.server.d.ts +12 -0
  240. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -0
  241. package/dist/lib/auth/hazo_get_auth.server.js +256 -0
  242. package/dist/lib/auth/index.d.ts +9 -0
  243. package/dist/lib/auth/index.d.ts.map +1 -0
  244. package/dist/lib/auth/index.js +12 -0
  245. package/dist/lib/auth/server_auth.d.ts +26 -0
  246. package/dist/lib/auth/server_auth.d.ts.map +1 -0
  247. package/dist/lib/auth/server_auth.js +62 -0
  248. package/dist/lib/auth_utility_config.server.d.ts +20 -0
  249. package/dist/lib/auth_utility_config.server.d.ts.map +1 -0
  250. package/dist/lib/auth_utility_config.server.js +64 -0
  251. package/dist/lib/config/config_loader.server.d.ts +44 -0
  252. package/dist/lib/config/config_loader.server.d.ts.map +1 -0
  253. package/dist/lib/config/config_loader.server.js +122 -0
  254. package/dist/lib/email_verification_config.server.d.ts +14 -0
  255. package/dist/lib/email_verification_config.server.d.ts.map +1 -0
  256. package/dist/lib/email_verification_config.server.js +20 -0
  257. package/dist/lib/file_types_config.server.d.ts +11 -0
  258. package/dist/lib/file_types_config.server.d.ts.map +1 -0
  259. package/dist/lib/file_types_config.server.js +16 -0
  260. package/dist/lib/forgot_password_config.server.d.ts +14 -0
  261. package/dist/lib/forgot_password_config.server.d.ts.map +1 -0
  262. package/dist/lib/forgot_password_config.server.js +20 -0
  263. package/dist/lib/hazo_connect_instance.server.d.ts +17 -0
  264. package/dist/lib/hazo_connect_instance.server.d.ts.map +1 -0
  265. package/dist/lib/hazo_connect_instance.server.js +88 -0
  266. package/dist/lib/hazo_connect_setup.d.ts +2 -0
  267. package/dist/lib/hazo_connect_setup.d.ts.map +1 -0
  268. package/dist/lib/hazo_connect_setup.js +49 -0
  269. package/dist/lib/hazo_connect_setup.server.d.ts +20 -0
  270. package/dist/lib/hazo_connect_setup.server.d.ts.map +1 -0
  271. package/dist/lib/hazo_connect_setup.server.js +138 -0
  272. package/dist/lib/index.d.ts +28 -0
  273. package/dist/lib/index.d.ts.map +1 -0
  274. package/dist/lib/index.js +35 -0
  275. package/dist/lib/login_config.server.d.ts +20 -0
  276. package/dist/lib/login_config.server.d.ts.map +1 -0
  277. package/dist/lib/login_config.server.js +37 -0
  278. package/dist/lib/messages_config.server.d.ts +13 -0
  279. package/dist/lib/messages_config.server.d.ts.map +1 -0
  280. package/dist/lib/messages_config.server.js +18 -0
  281. package/dist/lib/migrations/apply_migration.d.ts +22 -0
  282. package/dist/lib/migrations/apply_migration.d.ts.map +1 -0
  283. package/dist/lib/migrations/apply_migration.js +78 -0
  284. package/dist/lib/my_settings_config.server.d.ts +65 -0
  285. package/dist/lib/my_settings_config.server.d.ts.map +1 -0
  286. package/dist/lib/my_settings_config.server.js +67 -0
  287. package/dist/lib/password_requirements_config.server.d.ts +15 -0
  288. package/dist/lib/password_requirements_config.server.d.ts.map +1 -0
  289. package/dist/lib/password_requirements_config.server.js +26 -0
  290. package/dist/lib/profile_pic_menu_config.server.d.ts +26 -0
  291. package/dist/lib/profile_pic_menu_config.server.d.ts.map +1 -0
  292. package/dist/lib/profile_pic_menu_config.server.js +95 -0
  293. package/dist/lib/profile_picture_config.server.d.ts +16 -0
  294. package/dist/lib/profile_picture_config.server.d.ts.map +1 -0
  295. package/dist/lib/profile_picture_config.server.js +40 -0
  296. package/dist/lib/register_config.server.d.ts +24 -0
  297. package/dist/lib/register_config.server.d.ts.map +1 -0
  298. package/dist/lib/register_config.server.js +39 -0
  299. package/dist/lib/reset_password_config.server.d.ts +25 -0
  300. package/dist/lib/reset_password_config.server.d.ts.map +1 -0
  301. package/dist/lib/reset_password_config.server.js +38 -0
  302. package/dist/lib/services/email_service.d.ts +44 -0
  303. package/dist/lib/services/email_service.d.ts.map +1 -0
  304. package/dist/lib/services/email_service.js +480 -0
  305. package/dist/lib/services/email_verification_service.d.ts +35 -0
  306. package/dist/lib/services/email_verification_service.d.ts.map +1 -0
  307. package/dist/lib/services/email_verification_service.js +208 -0
  308. package/dist/lib/services/index.d.ts +13 -0
  309. package/dist/lib/services/index.d.ts.map +1 -0
  310. package/dist/lib/services/index.js +14 -0
  311. package/dist/lib/services/login_service.d.ts +20 -0
  312. package/dist/lib/services/login_service.d.ts.map +1 -0
  313. package/dist/lib/services/login_service.js +94 -0
  314. package/dist/lib/services/password_change_service.d.ts +19 -0
  315. package/dist/lib/services/password_change_service.d.ts.map +1 -0
  316. package/dist/lib/services/password_change_service.js +118 -0
  317. package/dist/lib/services/password_reset_service.d.ts +52 -0
  318. package/dist/lib/services/password_reset_service.d.ts.map +1 -0
  319. package/dist/lib/services/password_reset_service.js +318 -0
  320. package/dist/lib/services/profile_picture_remove_service.d.ts +15 -0
  321. package/dist/lib/services/profile_picture_remove_service.d.ts.map +1 -0
  322. package/dist/lib/services/profile_picture_remove_service.js +94 -0
  323. package/dist/lib/services/profile_picture_service.d.ts +45 -0
  324. package/dist/lib/services/profile_picture_service.d.ts.map +1 -0
  325. package/dist/lib/services/profile_picture_service.js +183 -0
  326. package/dist/lib/services/profile_picture_source_mapper.d.ts +23 -0
  327. package/dist/lib/services/profile_picture_source_mapper.d.ts.map +1 -0
  328. package/dist/lib/services/profile_picture_source_mapper.js +45 -0
  329. package/dist/lib/services/registration_service.d.ts +20 -0
  330. package/dist/lib/services/registration_service.d.ts.map +1 -0
  331. package/dist/lib/services/registration_service.js +147 -0
  332. package/dist/lib/services/token_service.d.ts +20 -0
  333. package/dist/lib/services/token_service.d.ts.map +1 -0
  334. package/dist/lib/services/token_service.js +201 -0
  335. package/dist/lib/services/user_profiles_service.d.ts +31 -0
  336. package/dist/lib/services/user_profiles_service.d.ts.map +1 -0
  337. package/dist/lib/services/user_profiles_service.js +99 -0
  338. package/dist/lib/services/user_update_service.d.ts +23 -0
  339. package/dist/lib/services/user_update_service.d.ts.map +1 -0
  340. package/dist/lib/services/user_update_service.js +103 -0
  341. package/dist/lib/ui_shell_config.server.d.ts +16 -0
  342. package/dist/lib/ui_shell_config.server.d.ts.map +1 -0
  343. package/dist/lib/ui_shell_config.server.js +28 -0
  344. package/dist/lib/ui_sizes_config.server.d.ts +17 -0
  345. package/dist/lib/ui_sizes_config.server.d.ts.map +1 -0
  346. package/dist/lib/ui_sizes_config.server.js +22 -0
  347. package/dist/lib/user_fields_config.server.d.ts +13 -0
  348. package/dist/lib/user_fields_config.server.d.ts.map +1 -0
  349. package/dist/lib/user_fields_config.server.js +21 -0
  350. package/dist/lib/user_management_config.server.d.ts +10 -0
  351. package/dist/lib/user_management_config.server.d.ts.map +1 -0
  352. package/dist/lib/user_management_config.server.js +26 -0
  353. package/dist/lib/utils/api_route_helpers.d.ts +13 -0
  354. package/dist/lib/utils/api_route_helpers.d.ts.map +1 -0
  355. package/dist/lib/utils/api_route_helpers.js +58 -0
  356. package/dist/lib/utils/error_sanitizer.d.ts +16 -0
  357. package/dist/lib/utils/error_sanitizer.d.ts.map +1 -0
  358. package/dist/lib/utils/error_sanitizer.js +39 -0
  359. package/dist/lib/utils.d.ts +4 -0
  360. package/dist/lib/utils.d.ts.map +1 -0
  361. package/dist/lib/utils.js +9 -0
  362. package/dist/server/config/config_loader.d.ts +26 -0
  363. package/dist/server/config/config_loader.d.ts.map +1 -0
  364. package/dist/server/config/config_loader.js +329 -0
  365. package/dist/server/index.d.ts +2 -0
  366. package/dist/server/index.d.ts.map +1 -0
  367. package/dist/server/index.js +32 -0
  368. package/dist/server/logging/logger_service.d.ts +3 -0
  369. package/dist/server/logging/logger_service.d.ts.map +1 -0
  370. package/dist/server/logging/logger_service.js +37 -0
  371. package/dist/server/routes/root_router.d.ts +3 -0
  372. package/dist/server/routes/root_router.d.ts.map +1 -0
  373. package/dist/server/routes/root_router.js +14 -0
  374. package/dist/server/server.d.ts +3 -0
  375. package/dist/server/server.d.ts.map +1 -0
  376. package/dist/server/server.js +25 -0
  377. package/dist/server/types/app_types.d.ts +53 -0
  378. package/dist/server/types/app_types.d.ts.map +1 -0
  379. package/dist/server/types/app_types.js +1 -0
  380. package/migrations/003_add_url_on_logon_to_hazo_users.sql +8 -0
  381. package/next.config.mjs +12 -0
  382. package/package.json +39 -2
  383. package/scripts/init_users.ts +9 -9
  384. package/src/components/index.ts +7 -0
  385. package/src/components/layouts/email_verification/config/email_verification_field_config.ts +2 -2
  386. package/src/components/layouts/email_verification/hooks/use_email_verification.ts +3 -3
  387. package/src/components/layouts/email_verification/index.tsx +11 -11
  388. package/src/components/layouts/forgot_password/config/forgot_password_field_config.ts +2 -2
  389. package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +3 -3
  390. package/src/components/layouts/forgot_password/index.tsx +10 -10
  391. package/src/components/layouts/index.ts +26 -0
  392. package/src/components/layouts/login/config/login_field_config.ts +2 -2
  393. package/src/components/layouts/login/hooks/use_login_form.ts +5 -5
  394. package/src/components/layouts/login/index.tsx +11 -11
  395. package/src/components/layouts/my_settings/components/editable_field.tsx +3 -3
  396. package/src/components/layouts/my_settings/components/password_change_dialog.tsx +5 -5
  397. package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +7 -7
  398. package/src/components/layouts/my_settings/components/profile_picture_display.tsx +2 -2
  399. package/src/components/layouts/my_settings/components/profile_picture_gravatar_tab.tsx +3 -3
  400. package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +5 -5
  401. package/src/components/layouts/my_settings/components/profile_picture_upload_tab.tsx +4 -4
  402. package/src/components/layouts/my_settings/config/my_settings_field_config.ts +2 -2
  403. package/src/components/layouts/my_settings/hooks/use_my_settings.ts +2 -2
  404. package/src/components/layouts/my_settings/index.tsx +10 -10
  405. package/src/components/layouts/register/config/register_field_config.ts +2 -2
  406. package/src/components/layouts/register/hooks/use_register_form.ts +4 -4
  407. package/src/components/layouts/register/index.tsx +11 -11
  408. package/src/components/layouts/reset_password/config/reset_password_field_config.ts +2 -2
  409. package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +4 -4
  410. package/src/components/layouts/reset_password/index.tsx +10 -10
  411. package/src/components/layouts/shared/components/already_logged_in_guard.tsx +4 -4
  412. package/src/components/layouts/shared/components/auth_page_shell.tsx +3 -3
  413. package/src/components/layouts/shared/components/form_action_buttons.tsx +2 -2
  414. package/src/components/layouts/shared/components/form_field_wrapper.tsx +2 -2
  415. package/src/components/layouts/shared/components/logout_button.tsx +2 -2
  416. package/src/components/layouts/shared/components/password_field.tsx +3 -3
  417. package/src/components/layouts/shared/components/profile_pic_menu.tsx +5 -5
  418. package/src/components/layouts/shared/components/profile_pic_menu_wrapper.tsx +2 -2
  419. package/src/components/layouts/shared/components/sidebar_layout_wrapper.tsx +3 -3
  420. package/src/components/layouts/shared/components/standalone_layout_wrapper.tsx +1 -1
  421. package/src/components/layouts/shared/components/two_column_auth_layout.tsx +1 -1
  422. package/src/components/layouts/shared/components/unauthorized_guard.tsx +2 -2
  423. package/src/components/layouts/shared/hooks/use_hazo_auth.ts +1 -1
  424. package/src/components/layouts/shared/index.ts +34 -0
  425. package/src/components/layouts/shared/utils/validation.ts +1 -1
  426. package/src/components/layouts/user_management/components/roles_matrix.tsx +7 -7
  427. package/src/components/layouts/user_management/index.tsx +11 -11
  428. package/src/components/ui/alert-dialog.tsx +2 -2
  429. package/src/components/ui/avatar.tsx +1 -1
  430. package/src/components/ui/button.tsx +1 -1
  431. package/src/components/ui/checkbox.tsx +1 -1
  432. package/src/components/ui/dialog.tsx +1 -1
  433. package/src/components/ui/dropdown-menu.tsx +1 -1
  434. package/src/components/ui/hazo_ui_tooltip.tsx +1 -1
  435. package/src/components/ui/index.ts +22 -0
  436. package/src/components/ui/input.tsx +1 -1
  437. package/src/components/ui/label.tsx +1 -1
  438. package/src/components/ui/separator.tsx +1 -1
  439. package/src/components/ui/sheet.tsx +1 -1
  440. package/src/components/ui/sidebar.tsx +8 -8
  441. package/src/components/ui/skeleton.tsx +1 -1
  442. package/src/components/ui/switch.tsx +1 -1
  443. package/src/components/ui/table.tsx +1 -1
  444. package/src/components/ui/tabs.tsx +1 -1
  445. package/src/components/ui/tooltip.tsx +1 -1
  446. package/src/components/ui/vertical-tabs.tsx +1 -1
  447. package/src/index.ts +7 -0
  448. package/src/lib/already_logged_in_config.server.ts +1 -1
  449. package/src/lib/app_logger.ts +1 -1
  450. package/src/lib/auth/auth_cache.ts +1 -1
  451. package/src/lib/auth/auth_utils.server.ts +2 -2
  452. package/src/lib/auth/hazo_get_auth.server.ts +8 -8
  453. package/src/lib/auth/index.ts +23 -0
  454. package/src/lib/auth/server_auth.ts +2 -2
  455. package/src/lib/auth_utility_config.server.ts +1 -1
  456. package/src/lib/config/config_loader.server.ts +1 -1
  457. package/src/lib/email_verification_config.server.ts +1 -1
  458. package/src/lib/file_types_config.server.ts +1 -1
  459. package/src/lib/forgot_password_config.server.ts +1 -1
  460. package/src/lib/hazo_connect_instance.server.ts +2 -2
  461. package/src/lib/hazo_connect_setup.server.ts +2 -2
  462. package/src/lib/index.ts +44 -0
  463. package/src/lib/login_config.server.ts +2 -2
  464. package/src/lib/messages_config.server.ts +1 -1
  465. package/src/lib/my_settings_config.server.ts +7 -7
  466. package/src/lib/password_requirements_config.server.ts +1 -1
  467. package/src/lib/profile_pic_menu_config.server.ts +1 -1
  468. package/src/lib/profile_picture_config.server.ts +2 -2
  469. package/src/lib/register_config.server.ts +4 -4
  470. package/src/lib/reset_password_config.server.ts +3 -3
  471. package/src/lib/services/email_service.ts +2 -2
  472. package/src/lib/services/email_verification_service.ts +3 -3
  473. package/src/lib/services/index.ts +15 -0
  474. package/src/lib/services/login_service.ts +3 -3
  475. package/src/lib/services/password_change_service.ts +3 -3
  476. package/src/lib/services/password_reset_service.ts +3 -3
  477. package/src/lib/services/profile_picture_remove_service.ts +3 -3
  478. package/src/lib/services/profile_picture_service.ts +5 -5
  479. package/src/lib/services/registration_service.ts +8 -8
  480. package/src/lib/services/token_service.ts +2 -2
  481. package/src/lib/services/user_profiles_service.ts +2 -2
  482. package/src/lib/services/user_update_service.ts +4 -4
  483. package/src/lib/ui_shell_config.server.ts +1 -1
  484. package/src/lib/ui_sizes_config.server.ts +1 -1
  485. package/src/lib/user_fields_config.server.ts +1 -1
  486. package/src/lib/user_management_config.server.ts +1 -2
  487. package/src/lib/utils/error_sanitizer.ts +1 -1
  488. package/src/routes/index.ts +34 -0
  489. package/src/server/config/config_loader.ts +2 -2
  490. package/src/server/index.ts +2 -2
  491. package/src/server/logging/logger_service.ts +1 -1
  492. package/src/server/server.ts +2 -2
  493. package/src/server/types/express.d.ts +1 -1
  494. package/tsconfig.build.json +39 -0
  495. package/tsconfig.json +5 -1
package/README.md CHANGED
@@ -2,36 +2,110 @@
2
2
 
3
3
  A reusable authentication UI component package powered by Next.js, TailwindCSS, and shadcn. It integrates `hazo_config` for configuration management and `hazo_connect` for data access, enabling future components to stay aligned with platform conventions.
4
4
 
5
- ### Installation
5
+ ## Table of Contents
6
+
7
+ - [Installation](#installation)
8
+ - [Quick Start](#quick-start)
9
+ - [Configuration Setup](#configuration-setup)
10
+ - [Database Setup](#database-setup)
11
+ - [Using Components](#using-components)
12
+ - [Authentication Service](#authentication-service)
13
+ - [Profile Picture Menu Widget](#profile-picture-menu-widget)
14
+ - [User Profile Service](#user-profile-service)
15
+ - [Local Development](#local-development)
16
+
17
+ ---
18
+
19
+ ## Installation
6
20
 
7
21
  ```bash
8
22
  npm install hazo_auth
9
23
  ```
10
24
 
11
- ### Configuration Setup
25
+ ---
26
+
27
+ ## Quick Start
28
+
29
+ ### 1. Install the package
30
+
31
+ ```bash
32
+ npm install hazo_auth
33
+ ```
34
+
35
+ ### 2. Copy configuration files
36
+
37
+ ```bash
38
+ cp node_modules/hazo_auth/hazo_auth_config.example.ini ./hazo_auth_config.ini
39
+ cp node_modules/hazo_auth/hazo_notify_config.example.ini ./hazo_notify_config.ini
40
+ ```
41
+
42
+ ### 3. Set up environment variables
43
+
44
+ Create a `.env.local` file:
45
+
46
+ ```env
47
+ ZEPTOMAIL_API_KEY=your_api_key_here
48
+ ```
49
+
50
+ ### 4. Set up the database
51
+
52
+ Run the database setup SQL script (see [Database Setup](#database-setup)).
53
+
54
+ ### 5. Import and use components
55
+
56
+ ```typescript
57
+ // Import layout components
58
+ import { LoginLayout } from "hazo_auth/components/layouts/login";
59
+ import { RegisterLayout } from "hazo_auth/components/layouts/register";
60
+
61
+ // Import UI components
62
+ import { Button } from "hazo_auth/components/ui/button";
63
+ import { Input } from "hazo_auth/components/ui/input";
64
+
65
+ // Import hooks
66
+ import { use_hazo_auth } from "hazo_auth/hooks/use_hazo_auth";
67
+ import { use_auth_status } from "hazo_auth/hooks/use_auth_status";
68
+
69
+ // Import server-side utilities
70
+ import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
71
+ import { get_authenticated_user } from "hazo_auth/lib/auth/auth_utils.server";
72
+ ```
73
+
74
+ ---
75
+
76
+ ## Configuration Setup
12
77
 
13
78
  After installing the package, you need to set up configuration files in your project root:
14
79
 
15
- 1. **Copy the example config files to your project root:**
16
- ```bash
17
- cp node_modules/hazo_auth/hazo_auth_config.example.ini ./hazo_auth_config.ini
18
- cp node_modules/hazo_auth/hazo_notify_config.example.ini ./hazo_notify_config.ini
19
- ```
80
+ ### 1. Copy the example config files to your project root:
20
81
 
21
- 2. **Customize the configuration files:**
22
- - Edit `hazo_auth_config.ini` to configure authentication settings, database connection, UI labels, and more
23
- - Edit `hazo_notify_config.ini` to configure email service settings (Zeptomail, SMTP, etc.)
82
+ ```bash
83
+ cp node_modules/hazo_auth/hazo_auth_config.example.ini ./hazo_auth_config.ini
84
+ cp node_modules/hazo_auth/hazo_notify_config.example.ini ./hazo_notify_config.ini
85
+ ```
86
+
87
+ ### 2. Customize the configuration files:
88
+
89
+ - Edit `hazo_auth_config.ini` to configure authentication settings, database connection, UI labels, and more
90
+ - Edit `hazo_notify_config.ini` to configure email service settings (Zeptomail, SMTP, etc.)
24
91
 
25
- 3. **Set up environment variables (recommended for sensitive data):**
26
- - Create a `.env.local` file in your project root
27
- - Add `ZEPTOMAIL_API_KEY=your_api_key_here` (if using Zeptomail)
28
- - Add other sensitive configuration values as needed
92
+ ### 3. Set up environment variables (recommended for sensitive data):
93
+
94
+ - Create a `.env.local` file in your project root
95
+ - Add `ZEPTOMAIL_API_KEY=your_api_key_here` (if using Zeptomail)
96
+ - Add other sensitive configuration values as needed
29
97
 
30
98
  **Important:** The configuration files must be located in your project root directory (where `process.cwd()` points to), not inside `node_modules`. The package reads configuration from `process.cwd()` at runtime, so storing them elsewhere (including `node_modules/hazo_auth`) will break runtime access.
31
99
 
32
- ### Database Setup
100
+ ---
101
+
102
+ ## Database Setup
103
+
104
+ Before using `hazo_auth`, you need to create the required database tables. The package supports both **PostgreSQL** (for production) and **SQLite** (for local development/testing).
105
+
106
+ ### PostgreSQL Setup
33
107
 
34
- Before using `hazo_auth`, you need to create the required database tables. Run the following SQL scripts in your PostgreSQL database:
108
+ Run the following SQL scripts in your PostgreSQL database:
35
109
 
36
110
  #### 1. Create the Profile Source Enum Type
37
111
 
@@ -65,6 +139,8 @@ CREATE TABLE hazo_users (
65
139
  CREATE INDEX idx_hazo_users_email ON hazo_users(email_address);
66
140
  ```
67
141
 
142
+ **Note:** The `url_on_logon` field is used to store a custom redirect URL for users after successful login. This allows per-user customization of post-login navigation.
143
+
68
144
  #### 3. Create the Refresh Tokens Table
69
145
 
70
146
  ```sql
@@ -88,7 +164,7 @@ CREATE INDEX idx_hazo_refresh_tokens_token_type ON hazo_refresh_tokens(token_typ
88
164
  ```sql
89
165
  -- Permissions table for RBAC
90
166
  CREATE TABLE hazo_permissions (
91
- id SERIAL PRIMARY KEY,
167
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
92
168
  permission_name TEXT NOT NULL UNIQUE,
93
169
  description TEXT,
94
170
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
@@ -101,7 +177,7 @@ CREATE TABLE hazo_permissions (
101
177
  ```sql
102
178
  -- Roles table for RBAC
103
179
  CREATE TABLE hazo_roles (
104
- id SERIAL PRIMARY KEY,
180
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
105
181
  role_name TEXT NOT NULL UNIQUE,
106
182
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
107
183
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
@@ -113,8 +189,8 @@ CREATE TABLE hazo_roles (
113
189
  ```sql
114
190
  -- Junction table linking roles to permissions
115
191
  CREATE TABLE hazo_role_permissions (
116
- role_id INTEGER NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
117
- permission_id INTEGER NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
192
+ role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
193
+ permission_id UUID NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
118
194
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
119
195
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
120
196
  PRIMARY KEY (role_id, permission_id)
@@ -131,7 +207,7 @@ CREATE INDEX idx_hazo_role_permissions_permission_id ON hazo_role_permissions(pe
131
207
  -- Junction table linking users to roles
132
208
  CREATE TABLE hazo_user_roles (
133
209
  user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
134
- role_id INTEGER NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
210
+ role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
135
211
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
136
212
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
137
213
  PRIMARY KEY (user_id, role_id)
@@ -142,13 +218,13 @@ CREATE INDEX idx_hazo_user_roles_user_id ON hazo_user_roles(user_id);
142
218
  CREATE INDEX idx_hazo_user_roles_role_id ON hazo_user_roles(role_id);
143
219
  ```
144
220
 
145
- #### Complete Setup Script
221
+ ### Complete PostgreSQL Setup Script
146
222
 
147
223
  For convenience, here's the complete SQL script to create all tables at once:
148
224
 
149
225
  ```sql
150
226
  -- ============================================
151
- -- hazo_auth Database Setup Script
227
+ -- hazo_auth Database Setup Script (PostgreSQL)
152
228
  -- ============================================
153
229
 
154
230
  -- 1. Create enum type
@@ -187,7 +263,7 @@ CREATE INDEX idx_hazo_refresh_tokens_token_type ON hazo_refresh_tokens(token_typ
187
263
 
188
264
  -- 4. Create permissions table
189
265
  CREATE TABLE hazo_permissions (
190
- id SERIAL PRIMARY KEY,
266
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
191
267
  permission_name TEXT NOT NULL UNIQUE,
192
268
  description TEXT,
193
269
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
@@ -196,7 +272,7 @@ CREATE TABLE hazo_permissions (
196
272
 
197
273
  -- 5. Create roles table
198
274
  CREATE TABLE hazo_roles (
199
- id SERIAL PRIMARY KEY,
275
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
200
276
  role_name TEXT NOT NULL UNIQUE,
201
277
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
202
278
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW()
@@ -204,8 +280,8 @@ CREATE TABLE hazo_roles (
204
280
 
205
281
  -- 6. Create role-permissions junction table
206
282
  CREATE TABLE hazo_role_permissions (
207
- role_id INTEGER NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
208
- permission_id INTEGER NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
283
+ role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
284
+ permission_id UUID NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
209
285
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
210
286
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
211
287
  PRIMARY KEY (role_id, permission_id)
@@ -216,7 +292,7 @@ CREATE INDEX idx_hazo_role_permissions_permission_id ON hazo_role_permissions(pe
216
292
  -- 7. Create user-roles junction table
217
293
  CREATE TABLE hazo_user_roles (
218
294
  user_id UUID NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
219
- role_id INTEGER NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
295
+ role_id UUID NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
220
296
  created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
221
297
  changed_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),
222
298
  PRIMARY KEY (user_id, role_id)
@@ -225,7 +301,80 @@ CREATE INDEX idx_hazo_user_roles_user_id ON hazo_user_roles(user_id);
225
301
  CREATE INDEX idx_hazo_user_roles_role_id ON hazo_user_roles(role_id);
226
302
  ```
227
303
 
228
- #### Initialize Default Permissions and Super User
304
+ ### SQLite Setup (for local development)
305
+
306
+ For local development and testing, you can use SQLite. The SQLite schema is slightly different (no UUID type, TEXT used instead):
307
+
308
+ ```sql
309
+ -- ============================================
310
+ -- hazo_auth Database Setup Script (SQLite)
311
+ -- ============================================
312
+
313
+ -- Users table
314
+ CREATE TABLE IF NOT EXISTS hazo_users (
315
+ id TEXT PRIMARY KEY,
316
+ email_address TEXT NOT NULL UNIQUE,
317
+ password_hash TEXT NOT NULL,
318
+ name TEXT,
319
+ email_verified INTEGER NOT NULL DEFAULT 0,
320
+ is_active INTEGER NOT NULL DEFAULT 1,
321
+ login_attempts INTEGER NOT NULL DEFAULT 0,
322
+ last_logon TEXT,
323
+ profile_picture_url TEXT,
324
+ profile_source TEXT,
325
+ mfa_secret TEXT,
326
+ url_on_logon TEXT,
327
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
328
+ changed_at TEXT NOT NULL DEFAULT (datetime('now'))
329
+ );
330
+
331
+ -- Refresh tokens table
332
+ CREATE TABLE IF NOT EXISTS hazo_refresh_tokens (
333
+ id TEXT PRIMARY KEY,
334
+ user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
335
+ token_hash TEXT NOT NULL,
336
+ token_type TEXT NOT NULL,
337
+ expires_at TEXT NOT NULL,
338
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
339
+ );
340
+
341
+ -- Permissions table
342
+ CREATE TABLE IF NOT EXISTS hazo_permissions (
343
+ id TEXT PRIMARY KEY,
344
+ permission_name TEXT NOT NULL UNIQUE,
345
+ description TEXT,
346
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
347
+ changed_at TEXT NOT NULL DEFAULT (datetime('now'))
348
+ );
349
+
350
+ -- Roles table
351
+ CREATE TABLE IF NOT EXISTS hazo_roles (
352
+ id TEXT PRIMARY KEY,
353
+ role_name TEXT NOT NULL UNIQUE,
354
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
355
+ changed_at TEXT NOT NULL DEFAULT (datetime('now'))
356
+ );
357
+
358
+ -- Role-permissions junction table
359
+ CREATE TABLE IF NOT EXISTS hazo_role_permissions (
360
+ role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
361
+ permission_id TEXT NOT NULL REFERENCES hazo_permissions(id) ON DELETE CASCADE,
362
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
363
+ changed_at TEXT NOT NULL DEFAULT (datetime('now')),
364
+ PRIMARY KEY (role_id, permission_id)
365
+ );
366
+
367
+ -- User-roles junction table
368
+ CREATE TABLE IF NOT EXISTS hazo_user_roles (
369
+ user_id TEXT NOT NULL REFERENCES hazo_users(id) ON DELETE CASCADE,
370
+ role_id TEXT NOT NULL REFERENCES hazo_roles(id) ON DELETE CASCADE,
371
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
372
+ changed_at TEXT NOT NULL DEFAULT (datetime('now')),
373
+ PRIMARY KEY (user_id, role_id)
374
+ );
375
+ ```
376
+
377
+ ### Initialize Default Permissions and Super User
229
378
 
230
379
  After creating the tables, you can use the `init-users` script to set up default permissions and a super user:
231
380
 
@@ -238,67 +387,82 @@ This script reads from `hazo_auth_config.ini` and:
238
387
  2. Creates a `default_super_user_role` role with all permissions
239
388
  3. Assigns the role to the user specified in `default_super_user_email`
240
389
 
241
- ### Expose hazo_auth Routes in the Consumer App
390
+ ### Apply Migrations
242
391
 
243
- Because `src/app/hazo_auth` (pages) and `src/app/api/hazo_auth` (API routes) need to be part of the consuming Next.js app’s routing tree, make sure they exist in your project’s `src/app` directory. Two recommended approaches:
392
+ To apply database migrations (e.g., adding new fields):
244
393
 
245
- 1. **Create symlinks (preferred during development):**
246
- ```bash
247
- mkdir -p src/app/api src/app
248
- ln -s ../../node_modules/hazo_auth/src/app/api/hazo_auth src/app/api/hazo_auth
249
- ln -s ../../node_modules/hazo_auth/src/app/hazo_auth src/app/hazo_auth
250
- ```
251
- Adjust the relative paths if your project structure differs.
394
+ ```bash
395
+ # Apply a specific migration
396
+ npx tsx scripts/apply_migration.ts migrations/003_add_url_on_logon_to_hazo_users.sql
252
397
 
253
- 2. **Copy the directories (useful for deployment or when symlinks cause issues):**
254
- ```bash
255
- cp -R node_modules/hazo_auth/src/app/api/hazo_auth src/app/api/hazo_auth
256
- cp -R node_modules/hazo_auth/src/app/hazo_auth src/app/hazo_auth
257
- ```
258
- Add an npm script (e.g., `postinstall`) to automate copying after installations or updates.
398
+ # Or apply all pending migrations
399
+ npx tsx scripts/apply_migration.ts
400
+ ```
259
401
 
260
- > The package expects these routes to live at `src/app/api/hazo_auth` and `src/app/hazo_auth` inside the consumer project. Without copying or linking them, Next.js won’t mount the auth pages or APIs.
402
+ ---
261
403
 
262
- ### Choose the UI Shell (Test Sidebar vs Standalone)
404
+ ## Using Components
263
405
 
264
- By default, the pages render inside the “test workspace” sidebar so you can quickly preview every flow. When you reuse the routes inside another project you’ll usually want a clean, standalone wrapper instead. Set this in `hazo_auth_config.ini`:
406
+ ### Package Exports
265
407
 
266
- ```ini
267
- [hazo_auth__ui_shell]
268
- # Options: test_sidebar | standalone
269
- layout_mode = standalone
270
- # Optional tweaks for the standalone header wrapper/classes:
271
- # standalone_heading = Welcome back
272
- # standalone_description = Your description here
273
- # standalone_wrapper_class = min-h-screen bg-background py-8
274
- # standalone_content_class = mx-auto w-full max-w-4xl rounded-2xl border bg-card
275
- ```
408
+ The package exports components through these paths:
276
409
 
277
- - `test_sidebar`: keeps the developer sidebar (perfect for the demo workspace or Storybook screenshots).
278
- - `standalone`: renders the page body directly so it inherits your own app shell, layout, and theme tokens.
279
- - The wrapper and content class overrides let you align spacing/borders with your design system without editing package code.
410
+ ```typescript
411
+ // Main entry point - exports all public APIs
412
+ import { ... } from "hazo_auth";
413
+
414
+ // Layout components
415
+ import { LoginLayout } from "hazo_auth/components/layouts/login";
416
+ import { RegisterLayout } from "hazo_auth/components/layouts/register";
417
+ import { ForgotPasswordLayout } from "hazo_auth/components/layouts/forgot_password";
418
+ import { ResetPasswordLayout } from "hazo_auth/components/layouts/reset_password";
419
+ import { EmailVerificationLayout } from "hazo_auth/components/layouts/verify_email";
420
+ import { MySettingsLayout } from "hazo_auth/components/layouts/my_settings";
421
+ import { UserManagementLayout } from "hazo_auth/components/layouts/user_management";
280
422
 
281
- Every route (`/hazo_auth/login`, `/hazo_auth/register`, etc.) automatically looks at this config, so switching modes is instant.
423
+ // UI components
424
+ import { Button } from "hazo_auth/components/ui/button";
425
+ import { Input } from "hazo_auth/components/ui/input";
426
+ import { Avatar } from "hazo_auth/components/ui/avatar";
427
+ // ... and more shadcn-based components
282
428
 
283
- ### Using Just the Layout Components
429
+ // Shared layout components
430
+ import { ProfilePicMenu } from "hazo_auth/components/layouts/shared/components/profile_pic_menu";
431
+ import { ProfilePicMenuWrapper } from "hazo_auth/components/layouts/shared/components/profile_pic_menu_wrapper";
432
+ import { FormActionButtons } from "hazo_auth/components/layouts/shared/components/form_action_buttons";
284
433
 
285
- Prefer to drop the forms into your own routes without copying the provided pages? Import the layouts directly and feed them a `data_client` plus any label/button overrides:
434
+ // Hooks (client-side)
435
+ import { use_hazo_auth } from "hazo_auth/hooks/use_hazo_auth";
436
+ import { use_auth_status } from "hazo_auth/hooks/use_auth_status";
437
+ import { use_login_form } from "hazo_auth/hooks/use_login_form";
438
+
439
+ // Library utilities
440
+ import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
441
+ import { get_authenticated_user } from "hazo_auth/lib/auth/auth_utils.server";
442
+ import { get_server_auth_user } from "hazo_auth/lib/auth/server_auth";
443
+
444
+ // Server utilities
445
+ import { get_hazo_connect_instance } from "hazo_auth/server/hazo_connect_instance.server";
446
+ ```
447
+
448
+ ### Using Layout Components
449
+
450
+ Prefer to drop the forms into your own routes without using the pre-built pages? Import the layouts directly and feed them a `data_client` plus any label/button overrides:
286
451
 
287
452
  ```tsx
288
453
  // app/(auth)/login/page.tsx in your project
289
- import login_layout from "hazo_auth/components/layouts/login";
290
- import { createLayoutDataClient } from "hazo_auth/components/layouts/shared/data/layout_data_client";
291
- import { create_sqlite_hazo_connect } from "hazo_auth/lib/hazo_connect_setup";
454
+ import { LoginLayout, createLayoutDataClient } from "hazo_auth";
455
+ import { create_postgrest_hazo_connect } from "hazo_auth/lib/hazo_connect_setup";
292
456
 
293
457
  export default async function LoginPage() {
294
- const hazoConnect = create_sqlite_hazo_connect();
458
+ const hazoConnect = create_postgrest_hazo_connect();
295
459
  const dataClient = createLayoutDataClient(hazoConnect);
296
- const LoginLayout = login_layout;
297
460
 
298
461
  return (
299
462
  <div className="my-app-shell">
300
463
  <LoginLayout
301
464
  image_src="/marketing/login-hero.svg"
465
+ image_alt="Login hero image"
302
466
  data_client={dataClient}
303
467
  redirectRoute="/dashboard"
304
468
  />
@@ -307,7 +471,40 @@ export default async function LoginPage() {
307
471
  }
308
472
  ```
309
473
 
310
- The same import pattern works for every layout under `components/layouts/*`, so you can mix-and-match pieces (profile picture dialog, password field, etc.) wherever you need them.
474
+ **Available Layout Components:**
475
+ - `LoginLayout` - Login form with email/password
476
+ - `RegisterLayout` - Registration form with password requirements
477
+ - `ForgotPasswordLayout` - Request password reset
478
+ - `ResetPasswordLayout` - Set new password with token
479
+ - `EmailVerificationLayout` - Verify email address
480
+ - `MySettingsLayout` - User profile and settings
481
+ - `UserManagementLayout` - Admin user/role management
482
+
483
+ **Shared Components:**
484
+ - `ProfilePicMenu` / `ProfilePicMenuWrapper` - Navbar profile menu
485
+ - `FormActionButtons`, `FormFieldWrapper`, `PasswordField`
486
+ - And more under `hazo_auth/components/layouts/shared/`
487
+
488
+ ### Choose the UI Shell (Test Sidebar vs Standalone)
489
+
490
+ By default, the pages render inside the "test workspace" sidebar so you can quickly preview every flow. When you reuse the routes inside another project you'll usually want a clean, standalone wrapper instead. Set this in `hazo_auth_config.ini`:
491
+
492
+ ```ini
493
+ [hazo_auth__ui_shell]
494
+ # Options: test_sidebar | standalone
495
+ layout_mode = standalone
496
+ # Optional tweaks for the standalone header wrapper/classes:
497
+ # standalone_heading = Welcome back
498
+ # standalone_description = Your description here
499
+ # standalone_wrapper_class = min-h-screen bg-background py-8
500
+ # standalone_content_class = mx-auto w-full max-w-4xl rounded-2xl border bg-card
501
+ ```
502
+
503
+ - `test_sidebar`: keeps the developer sidebar (perfect for the demo workspace or Storybook screenshots).
504
+ - `standalone`: renders the page body directly so it inherits your own app shell, layout, and theme tokens.
505
+ - The wrapper and content class overrides let you align spacing/borders with your design system without editing package code.
506
+
507
+ ---
311
508
 
312
509
  ## Authentication Service
313
510
 
@@ -347,6 +544,7 @@ type HazoAuthResult =
347
544
  email_address: string;
348
545
  is_active: boolean;
349
546
  profile_picture_url: string | null;
547
+ url_on_logon: string | null;
350
548
  };
351
549
  permissions: string[];
352
550
  permission_ok: boolean;
@@ -391,6 +589,9 @@ export async function GET(request: NextRequest) {
391
589
  }
392
590
 
393
591
  // User is authenticated and has required permissions
592
+ // Access url_on_logon for custom redirect
593
+ const redirectUrl = authResult.user.url_on_logon || "/dashboard";
594
+
394
595
  return NextResponse.json({
395
596
  message: "Access granted",
396
597
  user: authResult.user,
@@ -412,43 +613,13 @@ export async function GET(request: NextRequest) {
412
613
  }
413
614
  ```
414
615
 
415
- **Non-strict mode (returns permission status without throwing):**
416
-
417
- ```typescript
418
- // Check permissions without throwing errors
419
- const authResult = await hazo_get_auth(request, {
420
- required_permissions: ["admin_user_management"],
421
- strict: false, // Returns permission_ok: false if missing
422
- });
423
-
424
- if (authResult.authenticated && authResult.permission_ok) {
425
- // User has required permissions
426
- } else if (authResult.authenticated) {
427
- // User is authenticated but missing permissions
428
- console.log("Missing permissions:", authResult.missing_permissions);
429
- } else {
430
- // User is not authenticated
431
- }
432
- ```
433
-
434
616
  #### `get_authenticated_user`
435
617
 
436
618
  Basic authentication check for API routes. Returns user info if authenticated, or `{ authenticated: false }` if not.
437
619
 
438
620
  **Location:** `src/lib/auth/auth_utils.server.ts`
439
621
 
440
- **Function Signature:**
441
- ```typescript
442
- import { get_authenticated_user } from "hazo_auth/lib/auth/auth_utils.server";
443
- import type { AuthResult } from "hazo_auth/lib/auth/auth_utils.server";
444
-
445
- async function get_authenticated_user(request: NextRequest): Promise<AuthResult>
446
- ```
447
-
448
- **Example Usage:**
449
-
450
622
  ```typescript
451
- import { NextRequest, NextResponse } from "next/server";
452
623
  import { get_authenticated_user } from "hazo_auth/lib/auth/auth_utils.server";
453
624
 
454
625
  export async function GET(request: NextRequest) {
@@ -469,89 +640,12 @@ export async function GET(request: NextRequest) {
469
640
  }
470
641
  ```
471
642
 
472
- #### `require_auth`
473
-
474
- Requires authentication and throws an error if the user is not authenticated. Useful for protected API routes.
475
-
476
- **Location:** `src/lib/auth/auth_utils.server.ts`
477
-
478
- **Function Signature:**
479
- ```typescript
480
- import { require_auth } from "hazo_auth/lib/auth/auth_utils.server";
481
- import type { AuthUser } from "hazo_auth/lib/auth/auth_utils.server";
482
-
483
- async function require_auth(request: NextRequest): Promise<AuthUser>
484
- ```
485
-
486
- **Example Usage:**
487
-
488
- ```typescript
489
- import { NextRequest, NextResponse } from "next/server";
490
- import { require_auth } from "hazo_auth/lib/auth/auth_utils.server";
491
-
492
- export async function GET(request: NextRequest) {
493
- try {
494
- const user = await require_auth(request);
495
- // User is guaranteed to be authenticated here
496
- return NextResponse.json({ user_id: user.user_id, email: user.email });
497
- } catch (error) {
498
- return NextResponse.json(
499
- { error: "Authentication required" },
500
- { status: 401 }
501
- );
502
- }
503
- }
504
- ```
505
-
506
- #### `is_authenticated`
507
-
508
- Simple boolean check for authentication status.
509
-
510
- **Location:** `src/lib/auth/auth_utils.server.ts`
511
-
512
- **Function Signature:**
513
- ```typescript
514
- import { is_authenticated } from "hazo_auth/lib/auth/auth_utils.server";
515
-
516
- async function is_authenticated(request: NextRequest): Promise<boolean>
517
- ```
518
-
519
- **Example Usage:**
520
-
521
- ```typescript
522
- import { NextRequest, NextResponse } from "next/server";
523
- import { is_authenticated } from "hazo_auth/lib/auth/auth_utils.server";
524
-
525
- export async function GET(request: NextRequest) {
526
- const authenticated = await is_authenticated(request);
527
-
528
- if (!authenticated) {
529
- return NextResponse.json(
530
- { error: "Authentication required" },
531
- { status: 401 }
532
- );
533
- }
534
-
535
- // Continue with authenticated logic
536
- }
537
- ```
538
-
539
643
  #### `get_server_auth_user`
540
644
 
541
645
  Gets authenticated user in server components and pages (uses Next.js `cookies()` function).
542
646
 
543
647
  **Location:** `src/lib/auth/server_auth.ts`
544
648
 
545
- **Function Signature:**
546
- ```typescript
547
- import { get_server_auth_user } from "hazo_auth/lib/auth/server_auth";
548
- import type { ServerAuthResult } from "hazo_auth/lib/auth/server_auth";
549
-
550
- async function get_server_auth_user(): Promise<ServerAuthResult>
551
- ```
552
-
553
- **Example Usage:**
554
-
555
649
  ```typescript
556
650
  // In a server component (src/app/dashboard/page.tsx)
557
651
  import { get_server_auth_user } from "hazo_auth/lib/auth/server_auth";
@@ -578,36 +672,12 @@ export default async function DashboardPage() {
578
672
 
579
673
  React hook for fetching authentication status and permissions on the client side.
580
674
 
581
- **Location:** `src/components/layouts/shared/hooks/use_hazo_auth.ts`
582
-
583
- **Function Signature:**
584
- ```typescript
585
- import { use_hazo_auth } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
586
- import type { UseHazoAuthOptions, UseHazoAuthResult } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
587
-
588
- function use_hazo_auth(options?: UseHazoAuthOptions): UseHazoAuthResult
589
- ```
590
-
591
- **Options:**
592
- - `required_permissions?: string[]` - Array of permission names to check
593
- - `strict?: boolean` - If `true`, throws error when permissions are missing (default: `false`)
594
- - `skip?: boolean` - Skip fetch (for conditional use)
595
-
596
- **Return Type:**
597
- ```typescript
598
- type UseHazoAuthResult = HazoAuthResult & {
599
- loading: boolean;
600
- error: Error | null;
601
- refetch: () => Promise<void>;
602
- };
603
- ```
604
-
605
- **Example Usage:**
675
+ **Location:** `src/hooks/use_hazo_auth.ts`
606
676
 
607
677
  ```typescript
608
678
  "use client";
609
679
 
610
- import { use_hazo_auth } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
680
+ import { use_hazo_auth } from "hazo_auth/hooks/use_hazo_auth";
611
681
 
612
682
  export function ProtectedComponent() {
613
683
  const { authenticated, user, permissions, permission_ok, loading, error, refetch } =
@@ -616,21 +686,10 @@ export function ProtectedComponent() {
616
686
  strict: false,
617
687
  });
618
688
 
619
- if (loading) {
620
- return <div>Loading...</div>;
621
- }
622
-
623
- if (error) {
624
- return <div>Error: {error.message}</div>;
625
- }
626
-
627
- if (!authenticated) {
628
- return <div>Please log in to access this page.</div>;
629
- }
630
-
631
- if (!permission_ok) {
632
- return <div>You don't have permission to access this page.</div>;
633
- }
689
+ if (loading) return <div>Loading...</div>;
690
+ if (error) return <div>Error: {error.message}</div>;
691
+ if (!authenticated) return <div>Please log in to access this page.</div>;
692
+ if (!permission_ok) return <div>You don't have permission to access this page.</div>;
634
693
 
635
694
  return (
636
695
  <div>
@@ -642,298 +701,48 @@ export function ProtectedComponent() {
642
701
  }
643
702
  ```
644
703
 
645
- **Conditional Permission Checks:**
646
-
647
- ```typescript
648
- "use client";
704
+ #### `use_auth_status`
649
705
 
650
- import { use_hazo_auth } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
706
+ Simpler hook for basic authentication status checking.
651
707
 
652
- export function ConditionalComponent() {
653
- // Check multiple permissions
654
- const userManagementAuth = use_hazo_auth({
655
- required_permissions: ["admin_user_management"],
656
- });
657
-
658
- const roleManagementAuth = use_hazo_auth({
659
- required_permissions: ["admin_role_management"],
660
- });
661
-
662
- return (
663
- <div>
664
- {userManagementAuth.permission_ok && (
665
- <button>Manage Users</button>
666
- )}
667
- {roleManagementAuth.permission_ok && (
668
- <button>Manage Roles</button>
669
- )}
670
- </div>
671
- );
672
- }
673
- ```
674
-
675
- #### `trigger_hazo_auth_refresh`
676
-
677
- Triggers a refresh of authentication status across all components using `use_hazo_auth`. Useful after login, logout, or permission changes.
678
-
679
- **Location:** `src/components/layouts/shared/hooks/use_hazo_auth.ts`
680
-
681
- **Function Signature:**
682
- ```typescript
683
- import { trigger_hazo_auth_refresh } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
684
-
685
- function trigger_hazo_auth_refresh(): void
686
- ```
687
-
688
- **Example Usage:**
708
+ **Location:** `src/hooks/use_auth_status.ts`
689
709
 
690
710
  ```typescript
691
711
  "use client";
692
712
 
693
- import { trigger_hazo_auth_refresh } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
713
+ import { use_auth_status } from "hazo_auth/hooks/use_auth_status";
714
+
715
+ export function UserGreeting() {
716
+ const { authenticated, name, email, loading } = use_auth_status();
694
717
 
695
- export function LogoutButton() {
696
- const handleLogout = async () => {
697
- await fetch("/api/hazo_auth/logout", { method: "POST" });
698
- trigger_hazo_auth_refresh(); // Notify all components to refresh auth status
699
- window.location.href = "/hazo_auth/login";
700
- };
718
+ if (loading) return <div>Loading...</div>;
719
+ if (!authenticated) return <div>Please log in</div>;
701
720
 
702
- return <button onClick={handleLogout}>Logout</button>;
721
+ return <div>Welcome, {name || email}!</div>;
703
722
  }
704
723
  ```
705
724
 
706
725
  ### Configuration
707
726
 
708
- The authentication utility can be configured in `hazo_auth_config.ini` under the `[hazo_auth__auth_utility]` section:
727
+ Configure the authentication utility in `hazo_auth_config.ini`:
709
728
 
710
729
  ```ini
711
730
  [hazo_auth__auth_utility]
712
731
  # Cache settings
713
- # Maximum number of users to cache (LRU eviction, default: 10000)
714
732
  cache_max_users = 10000
715
-
716
- # Cache TTL in minutes (default: 15)
717
733
  cache_ttl_minutes = 15
718
-
719
- # Force cache refresh if older than this many minutes (default: 30)
720
734
  cache_max_age_minutes = 30
721
735
 
722
- # Rate limiting for /api/hazo_auth/get_auth endpoint
723
- # Per-user rate limit (requests per minute, default: 100)
736
+ # Rate limiting
724
737
  rate_limit_per_user = 100
725
-
726
- # Per-IP rate limit for unauthenticated requests (default: 200)
727
738
  rate_limit_per_ip = 200
728
739
 
729
740
  # Permission check behavior
730
- # Log all permission denials for security audit (default: true)
731
741
  log_permission_denials = true
732
-
733
- # User-friendly error messages
734
- # Enable mapping of technical permissions to user-friendly messages (default: true)
735
742
  enable_friendly_error_messages = true
736
-
737
- # Permission message mappings (optional, comma-separated: permission_name:user_message)
738
- # Example: admin_user_management:You don't have access to user management,admin_role_management:You don't have access to role management
739
- permission_error_messages =
740
- ```
741
-
742
- ### Testing Authentication and RBAC
743
-
744
- #### Testing User Authentication
745
-
746
- To test if a user is authenticated, use the `hazo_get_auth` function or the `use_hazo_auth` hook:
747
-
748
- ```typescript
749
- // Server-side test
750
- const authResult = await hazo_get_auth(request);
751
- if (authResult.authenticated) {
752
- console.log("User is authenticated:", authResult.user.email_address);
753
- console.log("User permissions:", authResult.permissions);
754
- } else {
755
- console.log("User is not authenticated");
756
- }
757
-
758
- // Client-side test
759
- const { authenticated, user, permissions } = use_hazo_auth();
760
- if (authenticated) {
761
- console.log("User is authenticated:", user?.email_address);
762
- console.log("User permissions:", permissions);
763
- }
764
- ```
765
-
766
- #### Testing RBAC Permissions
767
-
768
- To test if a user has specific permissions:
769
-
770
- ```typescript
771
- // Server-side - strict mode (throws error if missing)
772
- try {
773
- const authResult = await hazo_get_auth(request, {
774
- required_permissions: ["admin_user_management", "admin_role_management"],
775
- strict: true,
776
- });
777
- // User has all required permissions
778
- console.log("Access granted");
779
- } catch (error) {
780
- if (error instanceof PermissionError) {
781
- console.log("Missing permissions:", error.missing_permissions);
782
- console.log("User permissions:", error.user_permissions);
783
- console.log("User-friendly message:", error.user_friendly_message);
784
- }
785
- }
786
-
787
- // Server-side - non-strict mode (returns status)
788
- const authResult = await hazo_get_auth(request, {
789
- required_permissions: ["admin_user_management"],
790
- strict: false,
791
- });
792
-
793
- if (authResult.authenticated && authResult.permission_ok) {
794
- console.log("User has required permissions");
795
- } else if (authResult.authenticated) {
796
- console.log("User is missing permissions:", authResult.missing_permissions);
797
- }
798
-
799
- // Client-side test
800
- const { permission_ok, missing_permissions, permissions } = use_hazo_auth({
801
- required_permissions: ["admin_user_management"],
802
- });
803
-
804
- if (permission_ok) {
805
- console.log("User has required permissions");
806
- } else {
807
- console.log("Missing permissions:", missing_permissions);
808
- console.log("User permissions:", permissions);
809
- }
810
743
  ```
811
744
 
812
- #### Getting All User Permissions
813
-
814
- To get all permissions for the current user:
815
-
816
- ```typescript
817
- // Server-side
818
- const authResult = await hazo_get_auth(request);
819
- if (authResult.authenticated) {
820
- console.log("All user permissions:", authResult.permissions);
821
- // Check if user has a specific permission
822
- const hasPermission = authResult.permissions.includes("admin_user_management");
823
- }
824
-
825
- // Client-side
826
- const { permissions } = use_hazo_auth();
827
- console.log("All user permissions:", permissions);
828
- const hasPermission = permissions.includes("admin_user_management");
829
- ```
830
-
831
- #### Testing in API Routes
832
-
833
- Example of a protected API route with permission checking:
834
-
835
- ```typescript
836
- // src/app/api/admin/users/route.ts
837
- import { NextRequest, NextResponse } from "next/server";
838
- import { hazo_get_auth } from "hazo_auth/lib/auth/hazo_get_auth.server";
839
- import { PermissionError } from "hazo_auth/lib/auth/auth_types";
840
-
841
- export async function GET(request: NextRequest) {
842
- try {
843
- // Require authentication and specific permission
844
- const authResult = await hazo_get_auth(request, {
845
- required_permissions: ["admin_user_management"],
846
- strict: true,
847
- });
848
-
849
- // Fetch users (only accessible to admins)
850
- const users = await fetchUsers();
851
-
852
- return NextResponse.json({ users });
853
- } catch (error) {
854
- if (error instanceof PermissionError) {
855
- return NextResponse.json(
856
- {
857
- error: "Permission denied",
858
- missing_permissions: error.missing_permissions,
859
- user_friendly_message: error.user_friendly_message,
860
- },
861
- { status: 403 }
862
- );
863
- }
864
-
865
- return NextResponse.json(
866
- { error: "Authentication required" },
867
- { status: 401 }
868
- );
869
- }
870
- }
871
- ```
872
-
873
- #### Testing in React Components
874
-
875
- Example of a protected component with permission-based UI:
876
-
877
- ```typescript
878
- "use client";
879
-
880
- import { use_hazo_auth } from "hazo_auth/components/layouts/shared/hooks/use_hazo_auth";
881
-
882
- export function AdminDashboard() {
883
- const userManagementAuth = use_hazo_auth({
884
- required_permissions: ["admin_user_management"],
885
- });
886
-
887
- const roleManagementAuth = use_hazo_auth({
888
- required_permissions: ["admin_role_management"],
889
- });
890
-
891
- if (userManagementAuth.loading || roleManagementAuth.loading) {
892
- return <div>Loading...</div>;
893
- }
894
-
895
- if (!userManagementAuth.authenticated) {
896
- return <div>Please log in to access this page.</div>;
897
- }
898
-
899
- return (
900
- <div>
901
- <h1>Admin Dashboard</h1>
902
- {userManagementAuth.permission_ok && (
903
- <section>
904
- <h2>User Management</h2>
905
- {/* User management UI */}
906
- </section>
907
- )}
908
- {roleManagementAuth.permission_ok && (
909
- <section>
910
- <h2>Role Management</h2>
911
- {/* Role management UI */}
912
- </section>
913
- )}
914
- {!userManagementAuth.permission_ok && !roleManagementAuth.permission_ok && (
915
- <div>You don't have permission to access any admin features.</div>
916
- )}
917
- </div>
918
- );
919
- }
920
- ```
921
-
922
- ### Cache Invalidation
923
-
924
- The authentication cache is automatically invalidated in the following scenarios:
925
- - User logout
926
- - Password change
927
- - User deactivation
928
- - Role assignment changes
929
- - Permission changes to roles
930
-
931
- You can also manually invalidate the cache using the API endpoint:
932
-
933
- ```typescript
934
- // POST /api/hazo_auth/invalidate_cache
935
- // Body: { user_id?: string, role_ids?: number[], invalidate_all?: boolean }
936
- ```
745
+ ---
937
746
 
938
747
  ## Profile Picture Menu Widget
939
748
 
@@ -962,357 +771,157 @@ export function Navbar() {
962
771
  }
963
772
  ```
964
773
 
965
- ### Direct Usage (Manual Configuration)
966
-
967
- If you prefer to configure the component directly without using the config file:
968
-
969
- ```typescript
970
- "use client";
971
-
972
- import { ProfilePicMenu } from "hazo_auth/components/layouts/shared/components/profile_pic_menu";
973
-
974
- export function Navbar() {
975
- return (
976
- <nav className="flex items-center justify-between p-4">
977
- <div>Logo</div>
978
- <ProfilePicMenu
979
- show_single_button={false}
980
- sign_up_label="Sign Up"
981
- sign_in_label="Sign In"
982
- register_path="/hazo_auth/register"
983
- login_path="/hazo_auth/login"
984
- settings_path="/hazo_auth/my_settings"
985
- logout_path="/api/hazo_auth/logout"
986
- avatar_size="default"
987
- className="ml-auto"
988
- />
989
- </nav>
990
- );
991
- }
992
- ```
993
-
994
774
  ### Configuration
995
775
 
996
- Configure the Profile Picture Menu in `hazo_auth_config.ini` under the `[hazo_auth__profile_pic_menu]` section:
997
-
998
776
  ```ini
999
777
  [hazo_auth__profile_pic_menu]
1000
- # Button configuration for unauthenticated users
1001
- # Show only "Sign Up" button when true, show both "Sign Up" and "Sign In" buttons when false (default)
1002
778
  show_single_button = false
1003
-
1004
- # Sign up button label
1005
779
  sign_up_label = Sign Up
1006
-
1007
- # Sign in button label
1008
780
  sign_in_label = Sign In
1009
-
1010
- # Register page path
1011
781
  register_path = /hazo_auth/register
1012
-
1013
- # Login page path
1014
782
  login_path = /hazo_auth/login
1015
-
1016
- # Settings page path (shown in dropdown menu when authenticated)
1017
783
  settings_path = /hazo_auth/my_settings
1018
-
1019
- # Logout API endpoint path
1020
784
  logout_path = /api/hazo_auth/logout
1021
-
1022
785
  # Custom menu items (optional)
1023
- # Format: "type:label:value_or_href:order" for info/link, or "separator:order" for separator
1024
- # Examples:
1025
- # - Info item: "info:Phone:+1234567890:3"
1026
- # - Link item: "link:My Account:/account:4"
1027
- # - Separator: "separator:2"
1028
- # Custom items are added to the default menu items (name, email, separator, Settings, Logout)
1029
- # Items are sorted by type (info first, then separators, then links) and then by order within each type
1030
- custom_menu_items =
786
+ custom_menu_items = info:Phone:+1234567890:3,separator:2,link:My Account:/account:4
1031
787
  ```
1032
788
 
1033
- ### Component Props
1034
-
1035
- #### `ProfilePicMenuWrapper` Props
789
+ ---
1036
790
 
1037
- - `className?: string` - Additional CSS classes
1038
- - `avatar_size?: "sm" | "default" | "lg"` - Size of the profile picture avatar (default: "default")
1039
-
1040
- #### `ProfilePicMenu` Props
1041
-
1042
- - `show_single_button?: boolean` - Show only "Sign Up" button when true (default: false)
1043
- - `sign_up_label?: string` - Label for sign up button (default: "Sign Up")
1044
- - `sign_in_label?: string` - Label for sign in button (default: "Sign In")
1045
- - `register_path?: string` - Path to registration page (default: "/hazo_auth/register")
1046
- - `login_path?: string` - Path to login page (default: "/hazo_auth/login")
1047
- - `settings_path?: string` - Path to settings page (default: "/hazo_auth/my_settings")
1048
- - `logout_path?: string` - Path to logout API endpoint (default: "/api/hazo_auth/logout")
1049
- - `custom_menu_items?: ProfilePicMenuMenuItem[]` - Array of custom menu items
1050
- - `className?: string` - Additional CSS classes
1051
- - `avatar_size?: "sm" | "default" | "lg"` - Size of the profile picture avatar (default: "default")
791
+ ## User Profile Service
1052
792
 
1053
- ### Custom Menu Items
793
+ The `hazo_auth` package provides a batch user profile retrieval service for applications that need basic user information, such as chat applications or user lists.
1054
794
 
1055
- You can add custom menu items to the dropdown menu. Items are automatically sorted by type (info → separator → link) and then by order.
795
+ ### `hazo_get_user_profiles`
1056
796
 
1057
- **Menu Item Types:**
797
+ Retrieves basic profile information for multiple users in a single batch call.
1058
798
 
1059
- 1. **Info** - Display-only text (e.g., phone number, department)
1060
- - Format: `"info:label:value:order"`
1061
- - Example: `"info:Phone:+1234567890:3"`
799
+ **Location:** `src/lib/services/user_profiles_service.ts`
1062
800
 
1063
- 2. **Link** - Clickable menu item that navigates to a URL
1064
- - Format: `"link:label:href:order"`
1065
- - Example: `"link:My Account:/account:4"`
801
+ ```typescript
802
+ import { hazo_get_user_profiles } from "hazo_auth/lib/services/user_profiles_service";
803
+ import { get_hazo_connect_instance } from "hazo_auth/server/hazo_connect_instance.server";
1066
804
 
1067
- 3. **Separator** - Visual separator line
1068
- - Format: `"separator:order"`
1069
- - Example: `"separator:2"`
805
+ export async function GET(request: NextRequest) {
806
+ const adapter = get_hazo_connect_instance();
807
+
808
+ const result = await hazo_get_user_profiles(adapter, [
809
+ "user-id-1",
810
+ "user-id-2",
811
+ "user-id-3",
812
+ ]);
1070
813
 
1071
- **Example Configuration:**
814
+ if (!result.success) {
815
+ return NextResponse.json({ error: result.error }, { status: 500 });
816
+ }
1072
817
 
1073
- ```ini
1074
- [hazo_auth__profile_pic_menu]
1075
- # Add custom menu items
1076
- custom_menu_items = info:Phone:+1234567890:3,separator:2,link:My Account:/account:4,link:Help:/help:5
818
+ return NextResponse.json({
819
+ profiles: result.profiles,
820
+ not_found: result.not_found_ids,
821
+ });
822
+ }
1077
823
  ```
1078
824
 
1079
- This will create a menu with:
1080
- 1. Default items (name, email, separator, Settings, Logout)
1081
- 2. Custom info item: "Phone: +1234567890" (order 3)
1082
- 3. Custom separator (order 2)
1083
- 4. Custom link: "My Account" → `/account` (order 4)
1084
- 5. Custom link: "Help" → `/help` (order 5)
825
+ ---
1085
826
 
1086
- Items are sorted by type priority (info < separator < link) and then by order within each type.
827
+ ## Local Development (for package contributors)
1087
828
 
1088
- ### Default Menu Items
829
+ ### Prerequisites
1089
830
 
1090
- When authenticated, the dropdown menu automatically includes:
1091
- - User's name (if available)
1092
- - User's email address
1093
- - Separator
1094
- - Settings link (with Settings icon)
1095
- - Logout link (with LogOut icon, triggers logout action)
831
+ - Node.js 18+
832
+ - npm 9+
1096
833
 
1097
- ### Examples
834
+ ### Setup
1098
835
 
1099
- #### Example 1: Simple Navbar Integration
836
+ ```bash
837
+ # Clone the repository
838
+ git clone <repository-url>
839
+ cd hazo_auth
1100
840
 
1101
- ```typescript
1102
- // app/components/navbar.tsx
1103
- import { ProfilePicMenuWrapper } from "hazo_auth/components/layouts/shared/components/profile_pic_menu_wrapper";
841
+ # Install dependencies
842
+ npm install
1104
843
 
1105
- export function Navbar() {
1106
- return (
1107
- <header className="border-b">
1108
- <nav className="container mx-auto flex items-center justify-between p-4">
1109
- <div className="text-xl font-bold">My App</div>
1110
- <ProfilePicMenuWrapper />
1111
- </nav>
1112
- </header>
1113
- );
1114
- }
844
+ # Copy configuration files
845
+ cp hazo_auth_config.example.ini hazo_auth_config.ini
846
+ cp hazo_notify_config.example.ini hazo_notify_config.ini
1115
847
  ```
1116
848
 
1117
- #### Example 2: Custom Styling and Size
1118
-
1119
- ```typescript
1120
- // app/components/navbar.tsx
1121
- import { ProfilePicMenuWrapper } from "hazo_auth/components/layouts/shared/components/profile_pic_menu_wrapper";
849
+ ### Development Commands
1122
850
 
1123
- export function Navbar() {
1124
- return (
1125
- <header className="bg-slate-900 text-white">
1126
- <nav className="container mx-auto flex items-center justify-between p-4">
1127
- <div className="text-xl font-bold">My App</div>
1128
- <ProfilePicMenuWrapper
1129
- avatar_size="sm"
1130
- className="bg-slate-800 rounded-lg p-2"
1131
- />
1132
- </nav>
1133
- </header>
1134
- );
1135
- }
1136
- ```
851
+ ```bash
852
+ # Start development server
853
+ npm run dev
1137
854
 
1138
- #### Example 3: With Custom Menu Items (Programmatic)
855
+ # Run Storybook
856
+ npm run storybook
1139
857
 
1140
- ```typescript
1141
- "use client";
858
+ # Build the package for distribution
859
+ npm run build:pkg
1142
860
 
1143
- import { ProfilePicMenu } from "hazo_auth/components/layouts/shared/components/profile_pic_menu";
1144
- import type { ProfilePicMenuMenuItem } from "hazo_auth/lib/profile_pic_menu_config.server";
861
+ # Run tests
862
+ npm test
1145
863
 
1146
- export function Navbar() {
1147
- const customItems: ProfilePicMenuMenuItem[] = [
1148
- {
1149
- type: "info",
1150
- label: "Department",
1151
- value: "Engineering",
1152
- order: 3,
1153
- id: "dept_info",
1154
- },
1155
- {
1156
- type: "separator",
1157
- order: 2,
1158
- id: "custom_sep",
1159
- },
1160
- {
1161
- type: "link",
1162
- label: "Documentation",
1163
- href: "/docs",
1164
- order: 4,
1165
- id: "docs_link",
1166
- },
1167
- ];
864
+ # Initialize database users/roles
865
+ npm run init-users
1168
866
 
1169
- return (
1170
- <nav className="flex items-center justify-between p-4">
1171
- <div>Logo</div>
1172
- <ProfilePicMenu
1173
- custom_menu_items={customItems}
1174
- avatar_size="default"
1175
- />
1176
- </nav>
1177
- );
1178
- }
867
+ # Apply database migrations
868
+ npx tsx scripts/apply_migration.ts [migration_file_path]
1179
869
  ```
1180
870
 
1181
- #### Example 4: Single Button Mode
871
+ ### Project Structure
1182
872
 
1183
- ```typescript
1184
- // In hazo_auth_config.ini
1185
- [hazo_auth__profile_pic_menu]
1186
- show_single_button = true
1187
- sign_up_label = Get Started
1188
873
  ```
1189
-
1190
- When `show_single_button` is `true`, only the "Sign Up" button is shown for unauthenticated users (no "Sign In" button).
1191
-
1192
- ### Behavior
1193
-
1194
- - **Loading State**: Shows a pulsing placeholder while checking authentication status
1195
- - **Unauthenticated**: Shows Sign Up/Sign In buttons (or single button if configured)
1196
- - **Authenticated**: Shows profile picture with dropdown menu
1197
- - **Profile Picture Fallback**: If no profile picture is set, shows user's initials
1198
- - **Logout**: Handles logout action, refreshes auth status, and redirects appropriately
1199
- - **Responsive**: Works well in both navbar and sidebar layouts
1200
-
1201
- ### Styling
1202
-
1203
- The component uses TailwindCSS classes and can be customized with:
1204
- - `className` prop for additional styling
1205
- - `avatar_size` prop for different avatar sizes
1206
- - CSS class names prefixed with `cls_profile_pic_menu_*` for targeted styling
1207
-
1208
- Example custom styling:
1209
-
1210
- ```css
1211
- /* Target specific elements */
1212
- .cls_profile_pic_menu_avatar {
1213
- border: 2px solid #3b82f6;
1214
- }
1215
-
1216
- .cls_profile_pic_menu_dropdown {
1217
- min-width: 200px;
1218
- }
874
+ hazo_auth/
875
+ ├── src/
876
+ │ ├── app/ # Next.js app directory (demo pages)
877
+ │ ├── components/ # React components
878
+ │ │ ├── layouts/ # Layout components (login, register, etc.)
879
+ │ │ └── ui/ # Reusable UI components (shadcn-based)
880
+ │ ├── hooks/ # Client-side React hooks
881
+ │ ├── lib/ # Shared utilities and services
882
+ │ │ ├── auth/ # Authentication utilities
883
+ │ │ ├── config/ # Configuration loaders
884
+ │ │ └── services/ # Business logic services
885
+ │ ├── server/ # Server-only utilities
886
+ │ └── index.ts # Main entry point
887
+ ├── dist/ # Compiled package output
888
+ ├── migrations/ # Database migration files
889
+ ├── scripts/ # Utility scripts
890
+ ├── __tests__/ # Test files and fixtures
891
+ └── public/ # Static assets
1219
892
  ```
1220
893
 
1221
- ## User Profile Service
1222
-
1223
- The `hazo_auth` package provides a batch user profile retrieval service for applications that need basic user information, such as chat applications or user lists.
1224
-
1225
- ### `hazo_get_user_profiles`
1226
-
1227
- Retrieves basic profile information for multiple users in a single batch call.
894
+ ### Building the Package
1228
895
 
1229
- **Location:** `src/lib/services/user_profiles_service.ts`
1230
-
1231
- **Function Signature:**
1232
- ```typescript
1233
- import { hazo_get_user_profiles } from "hazo_auth/lib/services/user_profiles_service";
1234
- import type { GetProfilesResult, UserProfileInfo } from "hazo_auth/lib/services/user_profiles_service";
1235
-
1236
- async function hazo_get_user_profiles(
1237
- adapter: HazoConnectAdapter,
1238
- user_ids: string[],
1239
- ): Promise<GetProfilesResult>
1240
- ```
896
+ The package is built using TypeScript with a separate build configuration:
1241
897
 
1242
- **Return Type:**
1243
- ```typescript
1244
- type UserProfileInfo = {
1245
- user_id: string;
1246
- profile_picture_url: string | null;
1247
- email: string;
1248
- name: string | null;
1249
- days_since_created: number;
1250
- };
1251
-
1252
- type GetProfilesResult = {
1253
- success: boolean;
1254
- profiles: UserProfileInfo[];
1255
- not_found_ids: string[];
1256
- error?: string;
1257
- };
898
+ ```bash
899
+ npm run build:pkg
1258
900
  ```
1259
901
 
1260
- **Features:**
1261
- - **Batch Retrieval:** Fetches multiple user profiles in a single database query
1262
- - **Deduplication:** Automatically removes duplicate user IDs from input
1263
- - **Not Found Tracking:** Returns list of user IDs that were not found in the database
1264
- - **Profile Picture:** Returns the resolved profile picture URL (Gravatar, library, or uploaded)
1265
- - **Account Age:** Calculates days since account creation
902
+ This compiles the `src/` directory to `dist/` with:
903
+ - Type declarations (`.d.ts` files)
904
+ - ES modules output
905
+ - Excludes Next.js app directory and Storybook stories
1266
906
 
1267
- **Example Usage:**
907
+ ### Package Exports
1268
908
 
1269
- ```typescript
1270
- // In an API route or server component
1271
- import { hazo_get_user_profiles } from "hazo_auth/lib/services/user_profiles_service";
1272
- import { get_hazo_connect_instance } from "hazo_auth/lib/hazo_connect_instance.server";
909
+ The `package.json` exports field defines the public API:
1273
910
 
1274
- export async function GET(request: NextRequest) {
1275
- const adapter = get_hazo_connect_instance();
1276
-
1277
- // Get profiles for multiple users (e.g., chat participants)
1278
- const result = await hazo_get_user_profiles(adapter, [
1279
- "user-id-1",
1280
- "user-id-2",
1281
- "user-id-3",
1282
- ]);
1283
-
1284
- if (!result.success) {
1285
- return NextResponse.json({ error: result.error }, { status: 500 });
911
+ ```json
912
+ {
913
+ "exports": {
914
+ ".": "./dist/index.js",
915
+ "./components/*": "./dist/components/*.js",
916
+ "./components/ui/*": "./dist/components/ui/*.js",
917
+ "./components/layouts/*": "./dist/components/layouts/*.js",
918
+ "./lib/*": "./dist/lib/*.js",
919
+ "./hooks/*": "./dist/hooks/*.js",
920
+ "./server/*": "./dist/server/*.js"
1286
921
  }
1287
-
1288
- // result.profiles contains found user profiles
1289
- // result.not_found_ids contains IDs that weren't found
1290
- return NextResponse.json({
1291
- profiles: result.profiles,
1292
- not_found: result.not_found_ids,
1293
- });
1294
922
  }
1295
923
  ```
1296
924
 
1297
- **Use Cases:**
1298
- - Chat applications displaying participant information
1299
- - User lists with profile pictures and names
1300
- - Activity feeds showing user details
1301
- - Any feature requiring batch user profile lookups
1302
-
1303
- ### Local Development (for package contributors)
1304
-
1305
- - `npm install` to install dependencies.
1306
- - `npm run dev` launches the Next.js app at `http://localhost:3000`.
1307
- - `npm run storybook` launches Storybook at `http://localhost:6006`.
1308
-
1309
- ### Project Structure
1310
-
1311
- - `src/app` contains the application shell and route composition.
1312
- - `src/lib` is the home for shared utilities and authentication functions.
1313
- - `src/components` contains React components and hooks.
1314
- - `src/stories` holds Storybook stories for documenting components.
1315
-
1316
925
  ### Next Steps
1317
926
 
1318
927
  - Use `npx shadcn@latest add <component>` to scaffold new UI primitives.