hazo_auth 7.0.1 → 8.0.1

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 (274) hide show
  1. package/README.md +96 -319
  2. package/SETUP_CHECKLIST.md +59 -248
  3. package/cli-src/cli/generate.ts +1 -10
  4. package/cli-src/cli/validate.ts +0 -4
  5. package/cli-src/lib/auth/auth_types.ts +15 -21
  6. package/cli-src/lib/auth/hazo_get_auth.server.ts +19 -0
  7. package/cli-src/lib/auth/hazo_get_tenant_auth.server.ts +24 -25
  8. package/cli-src/lib/auth/index.ts +2 -2
  9. package/cli-src/lib/auth/nextauth_config.ts +27 -67
  10. package/cli-src/lib/auth/with_auth.server.ts +15 -15
  11. package/cli-src/lib/config/default_config.ts +8 -0
  12. package/cli-src/lib/cookies_config.server.ts +1 -1
  13. package/cli-src/lib/email_verification_config.server.ts +34 -0
  14. package/cli-src/lib/forgot_password_config.server.ts +34 -0
  15. package/cli-src/lib/legal/legal_docs_config.server.ts +61 -0
  16. package/cli-src/lib/legal/legal_docs_reader.server.ts +36 -0
  17. package/cli-src/lib/legal/legal_docs_service.ts +196 -0
  18. package/cli-src/lib/legal/legal_docs_types.ts +31 -0
  19. package/cli-src/lib/login_config.server.ts +29 -14
  20. package/cli-src/lib/my_settings_config.server.ts +3 -0
  21. package/cli-src/lib/oauth_config.server.ts +31 -57
  22. package/cli-src/lib/register_config.server.ts +35 -11
  23. package/cli-src/lib/reset_password_config.server.ts +31 -0
  24. package/cli-src/lib/services/email_template_manifest.ts +0 -17
  25. package/cli-src/lib/services/index.ts +2 -8
  26. package/cli-src/lib/services/oauth_service.ts +74 -128
  27. package/cli-src/lib/services/otp_service.ts +7 -2
  28. package/cli-src/lib/services/registration_service.ts +16 -1
  29. package/cli-src/lib/services/session_token_service.ts +0 -2
  30. package/config/hazo_auth_config.example.ini +41 -76
  31. package/dist/cli/generate.d.ts.map +1 -1
  32. package/dist/cli/generate.js +1 -10
  33. package/dist/cli/validate.d.ts.map +1 -1
  34. package/dist/cli/validate.js +0 -4
  35. package/dist/client.d.ts +1 -2
  36. package/dist/client.d.ts.map +1 -1
  37. package/dist/client.js +3 -1
  38. package/dist/components/layouts/create_firm/index.d.ts +8 -4
  39. package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
  40. package/dist/components/layouts/create_firm/index.js +3 -3
  41. package/dist/components/layouts/email_verification/index.d.ts +5 -4
  42. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  43. package/dist/components/layouts/email_verification/index.js +4 -4
  44. package/dist/components/layouts/forgot_password/index.d.ts +5 -4
  45. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  46. package/dist/components/layouts/forgot_password/index.js +2 -2
  47. package/dist/components/layouts/index.d.ts +1 -0
  48. package/dist/components/layouts/index.d.ts.map +1 -1
  49. package/dist/components/layouts/index.js +2 -0
  50. package/dist/components/layouts/legal/index.d.ts +5 -0
  51. package/dist/components/layouts/legal/index.d.ts.map +1 -0
  52. package/dist/components/layouts/legal/index.js +4 -0
  53. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts +7 -0
  54. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts.map +1 -0
  55. package/dist/components/layouts/legal/legal_acceptance_gate.js +84 -0
  56. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts +9 -0
  57. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts.map +1 -0
  58. package/dist/components/layouts/legal/legal_doc_checkbox_list.js +11 -0
  59. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts +9 -0
  60. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts.map +1 -0
  61. package/dist/components/layouts/legal/legal_doc_combined_view.js +11 -0
  62. package/dist/components/layouts/legal/legal_doc_drawer.d.ts +8 -0
  63. package/dist/components/layouts/legal/legal_doc_drawer.d.ts.map +1 -0
  64. package/dist/components/layouts/legal/legal_doc_drawer.js +55 -0
  65. package/dist/components/layouts/login/index.d.ts +13 -19
  66. package/dist/components/layouts/login/index.d.ts.map +1 -1
  67. package/dist/components/layouts/login/index.js +8 -11
  68. package/dist/components/layouts/otp/index.d.ts +5 -1
  69. package/dist/components/layouts/otp/index.d.ts.map +1 -1
  70. package/dist/components/layouts/otp/index.js +2 -2
  71. package/dist/components/layouts/register/hooks/use_register_form.d.ts +5 -1
  72. package/dist/components/layouts/register/hooks/use_register_form.d.ts.map +1 -1
  73. package/dist/components/layouts/register/hooks/use_register_form.js +25 -10
  74. package/dist/components/layouts/register/index.d.ts +11 -11
  75. package/dist/components/layouts/register/index.d.ts.map +1 -1
  76. package/dist/components/layouts/register/index.js +26 -7
  77. package/dist/components/layouts/reset_password/index.d.ts +5 -4
  78. package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
  79. package/dist/components/layouts/reset_password/index.js +5 -5
  80. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +5 -3
  81. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
  82. package/dist/components/layouts/shared/components/already_logged_in_guard.js +2 -2
  83. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +2 -6
  84. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -1
  85. package/dist/components/layouts/shared/components/facebook_sign_in_button.js +11 -13
  86. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  87. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +3 -8
  88. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +6 -3
  89. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
  90. package/dist/components/layouts/shared/components/two_column_auth_layout.js +5 -8
  91. package/dist/components/layouts/shared/index.d.ts +2 -0
  92. package/dist/components/layouts/shared/index.d.ts.map +1 -1
  93. package/dist/components/layouts/shared/index.js +1 -0
  94. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  95. package/dist/components/layouts/user_management/index.js +84 -9
  96. package/dist/components/ui/button.d.ts +1 -1
  97. package/dist/components/ui/input-otp.d.ts +2 -2
  98. package/dist/components/ui/sheet.d.ts +1 -1
  99. package/dist/index.d.ts +2 -1
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/lib/auth/auth_types.d.ts +14 -13
  102. package/dist/lib/auth/auth_types.d.ts.map +1 -1
  103. package/dist/lib/auth/auth_types.js +0 -10
  104. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  105. package/dist/lib/auth/hazo_get_auth.server.js +19 -0
  106. package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts +7 -8
  107. package/dist/lib/auth/hazo_get_tenant_auth.server.d.ts.map +1 -1
  108. package/dist/lib/auth/hazo_get_tenant_auth.server.js +22 -23
  109. package/dist/lib/auth/index.d.ts +2 -2
  110. package/dist/lib/auth/index.d.ts.map +1 -1
  111. package/dist/lib/auth/nextauth_config.d.ts +0 -10
  112. package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
  113. package/dist/lib/auth/nextauth_config.js +23 -52
  114. package/dist/lib/auth/with_auth.server.d.ts +13 -13
  115. package/dist/lib/auth/with_auth.server.d.ts.map +1 -1
  116. package/dist/lib/auth/with_auth.server.js +2 -2
  117. package/dist/lib/config/default_config.d.ts +16 -0
  118. package/dist/lib/config/default_config.d.ts.map +1 -1
  119. package/dist/lib/config/default_config.js +8 -0
  120. package/dist/lib/cookies_config.server.d.ts +1 -1
  121. package/dist/lib/cookies_config.server.js +1 -1
  122. package/dist/lib/email_verification_config.server.d.ts +3 -0
  123. package/dist/lib/email_verification_config.server.d.ts.map +1 -1
  124. package/dist/lib/email_verification_config.server.js +15 -0
  125. package/dist/lib/forgot_password_config.server.d.ts +3 -0
  126. package/dist/lib/forgot_password_config.server.d.ts.map +1 -1
  127. package/dist/lib/forgot_password_config.server.js +15 -0
  128. package/dist/lib/legal/legal_docs_config.server.d.ts +22 -0
  129. package/dist/lib/legal/legal_docs_config.server.d.ts.map +1 -0
  130. package/dist/lib/legal/legal_docs_config.server.js +52 -0
  131. package/dist/lib/legal/legal_docs_reader.server.d.ts +15 -0
  132. package/dist/lib/legal/legal_docs_reader.server.d.ts.map +1 -0
  133. package/dist/lib/legal/legal_docs_reader.server.js +24 -0
  134. package/dist/lib/legal/legal_docs_service.d.ts +49 -0
  135. package/dist/lib/legal/legal_docs_service.d.ts.map +1 -0
  136. package/dist/lib/legal/legal_docs_service.js +140 -0
  137. package/dist/lib/legal/legal_docs_types.d.ts +25 -0
  138. package/dist/lib/legal/legal_docs_types.d.ts.map +1 -0
  139. package/dist/lib/legal/legal_docs_types.js +2 -0
  140. package/dist/lib/login_config.server.d.ts +3 -6
  141. package/dist/lib/login_config.server.d.ts.map +1 -1
  142. package/dist/lib/login_config.server.js +11 -7
  143. package/dist/lib/my_settings_config.server.d.ts +1 -0
  144. package/dist/lib/my_settings_config.server.d.ts.map +1 -1
  145. package/dist/lib/my_settings_config.server.js +2 -0
  146. package/dist/lib/oauth_config.server.d.ts +8 -17
  147. package/dist/lib/oauth_config.server.d.ts.map +1 -1
  148. package/dist/lib/oauth_config.server.js +10 -25
  149. package/dist/lib/register_config.server.d.ts +5 -2
  150. package/dist/lib/register_config.server.d.ts.map +1 -1
  151. package/dist/lib/register_config.server.js +15 -4
  152. package/dist/lib/reset_password_config.server.d.ts +3 -0
  153. package/dist/lib/reset_password_config.server.d.ts.map +1 -1
  154. package/dist/lib/reset_password_config.server.js +13 -0
  155. package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
  156. package/dist/lib/services/email_template_manifest.js +0 -17
  157. package/dist/lib/services/index.d.ts +0 -2
  158. package/dist/lib/services/index.d.ts.map +1 -1
  159. package/dist/lib/services/index.js +0 -1
  160. package/dist/lib/services/oauth_service.d.ts +11 -22
  161. package/dist/lib/services/oauth_service.d.ts.map +1 -1
  162. package/dist/lib/services/oauth_service.js +63 -96
  163. package/dist/lib/services/otp_service.d.ts +1 -1
  164. package/dist/lib/services/otp_service.d.ts.map +1 -1
  165. package/dist/lib/services/otp_service.js +6 -1
  166. package/dist/lib/services/registration_service.d.ts +5 -0
  167. package/dist/lib/services/registration_service.d.ts.map +1 -1
  168. package/dist/lib/services/registration_service.js +6 -0
  169. package/dist/lib/services/session_token_service.d.ts +0 -2
  170. package/dist/lib/services/session_token_service.d.ts.map +1 -1
  171. package/dist/lib/services/session_token_service.js +0 -2
  172. package/dist/page_components/create_firm.d.ts +1 -13
  173. package/dist/page_components/create_firm.d.ts.map +1 -1
  174. package/dist/page_components/create_firm.js +6 -10
  175. package/dist/page_components/forgot_password.d.ts +4 -1
  176. package/dist/page_components/forgot_password.d.ts.map +1 -1
  177. package/dist/page_components/forgot_password.js +6 -2
  178. package/dist/page_components/index.d.ts +0 -5
  179. package/dist/page_components/index.d.ts.map +1 -1
  180. package/dist/page_components/index.js +0 -5
  181. package/dist/page_components/login.d.ts +4 -1
  182. package/dist/page_components/login.d.ts.map +1 -1
  183. package/dist/page_components/login.js +6 -2
  184. package/dist/page_components/register.d.ts +4 -1
  185. package/dist/page_components/register.d.ts.map +1 -1
  186. package/dist/page_components/register.js +6 -2
  187. package/dist/page_components/reset_password.d.ts +4 -1
  188. package/dist/page_components/reset_password.d.ts.map +1 -1
  189. package/dist/page_components/reset_password.js +6 -2
  190. package/dist/page_components/verify_email.d.ts +4 -1
  191. package/dist/page_components/verify_email.d.ts.map +1 -1
  192. package/dist/page_components/verify_email.js +6 -2
  193. package/dist/server/routes/assets.d.ts +8 -0
  194. package/dist/server/routes/assets.d.ts.map +1 -0
  195. package/dist/server/routes/assets.js +38 -0
  196. package/dist/server/routes/consent_me.d.ts +4 -0
  197. package/dist/server/routes/consent_me.d.ts.map +1 -0
  198. package/dist/server/routes/consent_me.js +15 -0
  199. package/dist/server/routes/index.d.ts +9 -4
  200. package/dist/server/routes/index.d.ts.map +1 -1
  201. package/dist/server/routes/index.js +13 -5
  202. package/dist/server/routes/legal_docs_accept.d.ts +3 -0
  203. package/dist/server/routes/legal_docs_accept.d.ts.map +1 -0
  204. package/dist/server/routes/legal_docs_accept.js +43 -0
  205. package/dist/server/routes/legal_docs_get.d.ts +3 -0
  206. package/dist/server/routes/legal_docs_get.d.ts.map +1 -0
  207. package/dist/server/routes/legal_docs_get.js +49 -0
  208. package/dist/server/routes/legal_docs_publish.d.ts +3 -0
  209. package/dist/server/routes/legal_docs_publish.d.ts.map +1 -0
  210. package/dist/server/routes/legal_docs_publish.js +35 -0
  211. package/dist/server/routes/me.d.ts.map +1 -1
  212. package/dist/server/routes/me.js +1 -43
  213. package/dist/server/routes/oauth_facebook_callback.d.ts +1 -1
  214. package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -1
  215. package/dist/server/routes/oauth_facebook_callback.js +8 -1
  216. package/dist/server/routes/oauth_google_callback.js +1 -1
  217. package/dist/server/routes/otp/verify.js +2 -2
  218. package/dist/server/routes/register.d.ts.map +1 -1
  219. package/dist/server/routes/register.js +26 -0
  220. package/dist/server/routes/strings_defaults.d.ts +4 -0
  221. package/dist/server/routes/strings_defaults.d.ts.map +1 -0
  222. package/dist/server/routes/strings_defaults.js +7 -0
  223. package/dist/server/routes/user_management_users.d.ts +11 -0
  224. package/dist/server/routes/user_management_users.d.ts.map +1 -1
  225. package/dist/server/routes/user_management_users.js +94 -0
  226. package/dist/server-lib.d.ts +0 -3
  227. package/dist/server-lib.d.ts.map +1 -1
  228. package/dist/server-lib.js +0 -2
  229. package/dist/server_pages/forgot_password.d.ts +18 -14
  230. package/dist/server_pages/forgot_password.d.ts.map +1 -1
  231. package/dist/server_pages/forgot_password.js +14 -12
  232. package/dist/server_pages/forgot_password_client_wrapper.d.ts +8 -7
  233. package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
  234. package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
  235. package/dist/server_pages/index.d.ts +2 -0
  236. package/dist/server_pages/index.d.ts.map +1 -1
  237. package/dist/server_pages/index.js +1 -0
  238. package/dist/server_pages/login.d.ts +22 -23
  239. package/dist/server_pages/login.d.ts.map +1 -1
  240. package/dist/server_pages/login.js +27 -14
  241. package/dist/server_pages/login_client_wrapper.d.ts +9 -10
  242. package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
  243. package/dist/server_pages/login_client_wrapper.js +2 -2
  244. package/dist/server_pages/my_settings.d.ts +1 -3
  245. package/dist/server_pages/my_settings.d.ts.map +1 -1
  246. package/dist/server_pages/my_settings.js +2 -9
  247. package/dist/server_pages/register.d.ts +17 -20
  248. package/dist/server_pages/register.d.ts.map +1 -1
  249. package/dist/server_pages/register.js +20 -15
  250. package/dist/server_pages/register_client_wrapper.d.ts +8 -10
  251. package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
  252. package/dist/server_pages/register_client_wrapper.js +2 -2
  253. package/dist/server_pages/reset_password.d.ts +16 -11
  254. package/dist/server_pages/reset_password.d.ts.map +1 -1
  255. package/dist/server_pages/reset_password.js +14 -10
  256. package/dist/server_pages/reset_password_client_wrapper.d.ts +8 -7
  257. package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
  258. package/dist/server_pages/reset_password_client_wrapper.js +2 -2
  259. package/dist/server_pages/verify_email.d.ts +18 -12
  260. package/dist/server_pages/verify_email.d.ts.map +1 -1
  261. package/dist/server_pages/verify_email.js +13 -11
  262. package/dist/server_pages/verify_email_client_wrapper.d.ts +8 -7
  263. package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
  264. package/dist/server_pages/verify_email_client_wrapper.js +2 -2
  265. package/dist/strings.d.ts +2 -0
  266. package/dist/strings.d.ts.map +1 -0
  267. package/dist/strings.js +3 -0
  268. package/dist/themes/index.d.ts +0 -1
  269. package/dist/themes/index.d.ts.map +1 -1
  270. package/dist/themes/index.js +1 -1
  271. package/package.json +30 -61
  272. package/dist/themes/preset_indigo_sunset.d.ts +0 -3
  273. package/dist/themes/preset_indigo_sunset.d.ts.map +0 -1
  274. package/dist/themes/preset_indigo_sunset.js +0 -20
@@ -22,6 +22,15 @@ export type GoogleOAuthData = {
22
22
  email_verified: boolean;
23
23
  };
24
24
 
25
+ export type FacebookOAuthData = {
26
+ facebook_id: string;
27
+ email: string;
28
+ name?: string;
29
+ profile_picture_url?: string;
30
+ /** Facebook does not always verify emails — only link when hazo user is verified */
31
+ email_verified: boolean;
32
+ };
33
+
25
34
  export type OAuthLoginResult = {
26
35
  success: boolean;
27
36
  user_id?: string;
@@ -36,18 +45,6 @@ export type OAuthLoginResult = {
36
45
  error?: string;
37
46
  };
38
47
 
39
- export type FacebookOAuthData = {
40
- /** Facebook's unique user ID */
41
- facebook_id: string;
42
- /** User's email address from Facebook (may be null if user denied email permission) */
43
- email: string | null;
44
- /** User's full name from Facebook profile */
45
- name?: string;
46
- /** User's profile picture URL from Facebook */
47
- profile_picture_url?: string;
48
- // NOTE: no email_verified — we never trust Facebook's email_verified claim
49
- };
50
-
51
48
  export type LinkGoogleResult = {
52
49
  success: boolean;
53
50
  error?: string;
@@ -254,47 +251,31 @@ export async function handle_google_oauth_login(
254
251
  }
255
252
 
256
253
  /**
257
- * Handles Facebook OAuth login/registration flow
258
- * 1. Check if user exists with facebook_id -> login
259
- * 2. Check if user exists with email -> link Facebook account (respects auto_link_unverified)
260
- * 3. Create new user with Facebook data (email_verified always false — never trust Facebook)
261
- *
262
- * @param adapter - The hazo_connect adapter instance
263
- * @param data - Facebook OAuth user data
264
- * @param opts - Options (auto_link_unverified: whether to link unverified accounts)
265
- * @returns OAuth login result with user_id and status flags
254
+ * Handles Facebook OAuth login: find-by-facebook_id → find-by-email+link → create new.
255
+ * Mirrors handle_google_oauth_login exactly. Uses auto_link_unverified_accounts gate.
266
256
  */
267
257
  export async function handle_facebook_oauth_login(
268
258
  adapter: HazoConnectAdapter,
269
- data: FacebookOAuthData,
270
- opts?: { auto_link_unverified?: boolean }
259
+ data: FacebookOAuthData
271
260
  ): Promise<OAuthLoginResult> {
272
261
  const logger = create_app_logger();
273
262
 
274
263
  try {
275
- const { facebook_id, email, name, profile_picture_url } = data;
276
-
264
+ const { facebook_id, email, name, profile_picture_url, email_verified } = data;
265
+ const oauth_config = get_oauth_config();
277
266
  const users_service = createCrudService(adapter, "hazo_users");
278
267
  const now = new Date().toISOString();
279
268
 
280
- // Step 1: Check if user exists with this facebook_id
281
- const users_by_facebook_id = await users_service.findBy({ facebook_id });
282
-
283
- if (Array.isArray(users_by_facebook_id) && users_by_facebook_id.length > 0) {
284
- const user = users_by_facebook_id[0];
285
-
286
- await users_service.updateById(user.id, {
287
- last_logon: now,
288
- changed_at: now,
289
- });
290
-
291
- logger.info("oauth_service_facebook_login_existing_facebook_user", {
269
+ // Step 1: existing user with this facebook_id
270
+ const users_by_fb_id = await users_service.findBy({ facebook_id });
271
+ if (Array.isArray(users_by_fb_id) && users_by_fb_id.length > 0) {
272
+ const user = users_by_fb_id[0];
273
+ await users_service.updateById(user.id, { last_logon: now, changed_at: now });
274
+ logger.info("oauth_service_facebook_login_existing_fb_user", {
292
275
  filename: "oauth_service.ts",
293
- line_number: get_line_number(),
294
276
  user_id: user.id,
295
277
  email: user.email_address,
296
278
  });
297
-
298
279
  return {
299
280
  success: true,
300
281
  user_id: user.id as string,
@@ -305,117 +286,91 @@ export async function handle_facebook_oauth_login(
305
286
  };
306
287
  }
307
288
 
308
- // Step 2: Check if user exists with this email
309
- if (email) {
310
- const users_by_email = await users_service.findBy({ email_address: email });
311
-
312
- if (Array.isArray(users_by_email) && users_by_email.length > 0) {
313
- const user = users_by_email[0];
314
- const user_email_verified = user.email_verified as boolean;
315
-
316
- if (!user_email_verified) {
317
- if (!opts?.auto_link_unverified) {
318
- return {
319
- success: false,
320
- error: "link_blocked_unverified",
321
- };
322
- }
323
- // auto_link_unverified=true: link but do NOT change email_verified status
324
- }
325
-
326
- // Link Facebook account to existing user
327
- const current_auth_providers = (user.auth_providers as string) || "email";
328
- const new_auth_providers = current_auth_providers.includes("facebook")
329
- ? current_auth_providers
330
- : `${current_auth_providers},facebook`;
331
-
332
- const update_data: Record<string, unknown> = {
333
- facebook_id,
334
- auth_providers: new_auth_providers,
335
- last_logon: now,
336
- changed_at: now,
337
- };
338
-
339
- // Update name if not set and Facebook provides one
340
- if (!user.name && name) {
341
- update_data.name = name;
342
- }
289
+ // Step 2: existing user with matching email
290
+ const users_by_email = await users_service.findBy({ email_address: email });
291
+ if (Array.isArray(users_by_email) && users_by_email.length > 0) {
292
+ const user = users_by_email[0];
293
+ const user_email_verified = user.email_verified as boolean;
343
294
 
344
- // Update profile picture if not set and Facebook provides one
345
- if (!user.profile_picture_url && profile_picture_url) {
346
- update_data.profile_picture_url = profile_picture_url;
347
- update_data.profile_source = "custom";
348
- }
295
+ if (!user_email_verified && !oauth_config.auto_link_unverified_accounts) {
296
+ return {
297
+ success: false,
298
+ error: "An account with this email exists but is not verified. Please verify your email first.",
299
+ };
300
+ }
349
301
 
350
- await users_service.updateById(user.id, update_data);
302
+ const current_auth_providers = (user.auth_providers as string) || "email";
303
+ const new_auth_providers = current_auth_providers.includes("facebook")
304
+ ? current_auth_providers
305
+ : `${current_auth_providers},facebook`;
351
306
 
352
- logger.info("oauth_service_facebook_linked_to_existing", {
353
- filename: "oauth_service.ts",
354
- line_number: get_line_number(),
355
- user_id: user.id,
356
- email,
357
- was_unverified: !user_email_verified,
358
- });
307
+ const update_data: Record<string, unknown> = {
308
+ facebook_id,
309
+ auth_providers: new_auth_providers,
310
+ last_logon: now,
311
+ changed_at: now,
312
+ };
359
313
 
360
- return {
361
- success: true,
362
- user_id: user.id as string,
363
- is_new_user: false,
364
- was_linked: true,
365
- email: user.email_address as string,
366
- name: (update_data.name as string) || (user.name as string | undefined),
367
- };
314
+ if (!user_email_verified && email_verified) {
315
+ update_data.email_verified = true;
316
+ }
317
+ if (!user.name && name) update_data.name = name;
318
+ if (!user.profile_picture_url && profile_picture_url) {
319
+ update_data.profile_picture_url = profile_picture_url;
320
+ update_data.profile_source = "custom";
368
321
  }
322
+
323
+ await users_service.updateById(user.id, update_data);
324
+ logger.info("oauth_service_facebook_linked_to_existing", {
325
+ filename: "oauth_service.ts",
326
+ user_id: user.id,
327
+ email,
328
+ was_unverified: !user_email_verified,
329
+ });
330
+ return {
331
+ success: true,
332
+ user_id: user.id as string,
333
+ is_new_user: false,
334
+ was_linked: true,
335
+ email: user.email_address as string,
336
+ name: user.name as string | undefined,
337
+ };
369
338
  }
370
339
 
371
- // Step 3: Create new user with Facebook data
340
+ // Step 3: create new user
372
341
  const user_id = randomUUID();
373
-
374
342
  const insert_data: Record<string, unknown> = {
375
343
  id: user_id,
376
344
  email_address: email,
377
- password_hash: "", // Empty string for Facebook-only users
378
- email_verified: false, // Never trust Facebook's email_verified claim
379
- status: "ACTIVE",
380
- login_attempts: 0,
381
345
  facebook_id,
382
346
  auth_providers: "facebook",
347
+ email_verified: email_verified,
348
+ last_logon: now,
383
349
  created_at: now,
384
350
  changed_at: now,
385
- last_logon: now,
386
351
  };
387
-
388
- if (name) {
389
- insert_data.name = name;
390
- }
391
-
352
+ if (name) insert_data.name = name;
392
353
  if (profile_picture_url) {
393
354
  insert_data.profile_picture_url = profile_picture_url;
394
355
  insert_data.profile_source = "custom";
395
356
  }
396
357
 
397
- const inserted_users = await users_service.insert(insert_data);
398
-
399
- if (!Array.isArray(inserted_users) || inserted_users.length === 0) {
400
- return {
401
- success: false,
402
- error: "Failed to create user account",
403
- };
358
+ const inserted = await users_service.insert(insert_data);
359
+ if (!Array.isArray(inserted) || inserted.length === 0) {
360
+ return { success: false, error: "Failed to create user account" };
404
361
  }
405
362
 
406
363
  logger.info("oauth_service_facebook_new_user_created", {
407
364
  filename: "oauth_service.ts",
408
- line_number: get_line_number(),
409
365
  user_id,
410
366
  email,
411
367
  });
412
-
413
368
  return {
414
369
  success: true,
415
370
  user_id,
416
371
  is_new_user: true,
417
372
  was_linked: false,
418
- email: email ?? undefined,
373
+ email,
419
374
  name,
420
375
  };
421
376
  } catch (error) {
@@ -423,18 +378,9 @@ export async function handle_facebook_oauth_login(
423
378
  logToConsole: true,
424
379
  logToLogger: true,
425
380
  logger,
426
- context: {
427
- filename: "oauth_service.ts",
428
- line_number: get_line_number(),
429
- email: data.email,
430
- operation: "handle_facebook_oauth_login",
431
- },
381
+ context: { filename: "oauth_service.ts", email: data.email, operation: "handle_facebook_oauth_login" },
432
382
  });
433
-
434
- return {
435
- success: false,
436
- error: user_friendly_error,
437
- };
383
+ return { success: false, error: user_friendly_error };
438
384
  }
439
385
  }
440
386
 
@@ -143,6 +143,11 @@ export async function request_email_otp(args: {
143
143
  expires_at,
144
144
  attempt_count: 0,
145
145
  requester_ip: ip,
146
+ // Explicitly pass created_at in JS ISO format ("2024-01-01T00:00:00.000Z") rather
147
+ // than relying on SQLite's DEFAULT (datetime('now') = "2024-01-01 00:00:00").
148
+ // The space-separated SQLite format compares as less-than the T-separated JS ISO
149
+ // threshold used in rate-limit WHERE clauses, causing the counter to always read 0.
150
+ created_at: new Date().toISOString(),
146
151
  });
147
152
 
148
153
  // 7. Dispatch email — fire-and-forget; errors are logged but do not surface to caller
@@ -168,7 +173,7 @@ export async function request_email_otp(args: {
168
173
 
169
174
  export type VerifyEmailOTPResult =
170
175
  | { ok: true; user_id: string; email: string; session_token: string }
171
- | { ok: false; error: "invalid_or_expired" };
176
+ | { ok: false; error: "invalid_or_expired" | "expired" };
172
177
 
173
178
  export async function verify_email_otp(args: {
174
179
  email: string;
@@ -205,7 +210,7 @@ export async function verify_email_otp(args: {
205
210
  // 2. Check expiry
206
211
  const expires_at_ms = Date.parse(String(row.expires_at));
207
212
  if (Number.isNaN(expires_at_ms) || expires_at_ms < Date.now()) {
208
- return { ok: false, error: "invalid_or_expired" };
213
+ return { ok: false, error: "expired" };
209
214
  }
210
215
 
211
216
  // 3. argon2 verify
@@ -16,6 +16,7 @@ import {
16
16
  is_user_types_enabled,
17
17
  get_default_user_type,
18
18
  } from "../user_types_config.server.js";
19
+ import { write_legal_acceptance } from "../legal/legal_docs_service.js";
19
20
 
20
21
  // section: types
21
22
  export type RegistrationData = {
@@ -23,6 +24,9 @@ export type RegistrationData = {
23
24
  password: string;
24
25
  name?: string;
25
26
  url_on_logon?: string;
27
+ legal_accepted?: Record<string, { hash: string }>;
28
+ ip?: string | null;
29
+ user_agent?: string | null;
26
30
  };
27
31
 
28
32
  export type RegistrationResult = {
@@ -156,7 +160,7 @@ export async function register_user(
156
160
  user_email: email,
157
161
  user_name: name,
158
162
  });
159
-
163
+
160
164
  if (!email_result.success) {
161
165
  const logger = create_app_logger();
162
166
  logger.error("registration_service_email_send_failed", {
@@ -170,6 +174,17 @@ export async function register_user(
170
174
  }
171
175
  }
172
176
 
177
+ // Write legal acceptance records if provided
178
+ if (data.legal_accepted && Object.keys(data.legal_accepted).length > 0) {
179
+ await write_legal_acceptance(
180
+ adapter,
181
+ user_id,
182
+ data.legal_accepted,
183
+ data.ip ?? null,
184
+ data.user_agent ?? null,
185
+ );
186
+ }
187
+
173
188
  return {
174
189
  success: true,
175
190
  user_id,
@@ -63,8 +63,6 @@ function get_session_token_expiry_seconds(): number {
63
63
  * Token includes user_id, email, issued at time, and expiration
64
64
  * @param user_id - User ID
65
65
  * @param email - User email address
66
- * @param managed_by_user_id - Optional: ID of the managing user (for impersonation)
67
- * @param ttl_seconds - Optional: token lifetime in seconds (default: 30 days). Use 604800 for 7-day OTP sessions.
68
66
  * @returns JWT token string
69
67
  */
70
68
  export async function create_session_token(
@@ -74,9 +74,11 @@ enable_admin_ui = true
74
74
  # image_alt = Illustration of a globe representing secure authentication workflows
75
75
  # image_background_color = #e2e8f0
76
76
 
77
- ; Page text is no longer configured via INI.
78
- ; Use HazoAuthStringsProvider or per-page props instead.
79
- ; See MIGRATION.md for details.
77
+ # Labels
78
+ # heading = Create your hazo account
79
+ # sub_heading = Secure your access with editable fields powered by shadcn components.
80
+ # submit_button = Register
81
+ # cancel_button = Cancel
80
82
 
81
83
  # Field labels (defaults shown, uncomment to override)
82
84
  # name_label = Full name
@@ -127,9 +129,11 @@ enable_admin_ui = true
127
129
  # image_alt = Illustration of a globe representing secure authentication workflows
128
130
  # image_background_color = #e2e8f0
129
131
 
130
- ; Page text is no longer configured via INI.
131
- ; Use HazoAuthStringsProvider or per-page props instead.
132
- ; See MIGRATION.md for details.
132
+ # Labels
133
+ # heading = Sign in to your account
134
+ # sub_heading = Enter your credentials to access your secure workspace.
135
+ # submit_button = Login
136
+ # cancel_button = Cancel
133
137
 
134
138
  # Field labels (defaults shown, uncomment to override)
135
139
  # email_label = Email address
@@ -155,20 +159,17 @@ enable_admin_ui = true
155
159
  # Success message (shown when no redirect route is provided)
156
160
  # success_message = Successfully logged in
157
161
 
158
- ; OTP sign-in link in the login layout.
159
- otp_signin_enabled = false
160
- otp_signin_label = Sign in with email code
161
- otp_signin_href = /hazo_auth/otp
162
-
163
162
  [hazo_auth__forgot_password_layout]
164
163
  # Image configuration
165
164
  # image_src = /globe.svg
166
165
  # image_alt = Illustration of a globe representing secure authentication workflows
167
166
  # image_background_color = #e2e8f0
168
167
 
169
- ; Page text is no longer configured via INI.
170
- ; Use HazoAuthStringsProvider or per-page props instead.
171
- ; See MIGRATION.md for details.
168
+ # Labels
169
+ # heading = Forgot your password?
170
+ # sub_heading = Enter your email address and we'll send you a link to reset your password.
171
+ # submit_button = Send reset link
172
+ # cancel_button = Cancel
172
173
 
173
174
  [hazo_auth__reset_password_layout]
174
175
  # Image configuration
@@ -176,9 +177,11 @@ otp_signin_href = /hazo_auth/otp
176
177
  # image_alt = Illustration of a globe representing secure authentication workflows
177
178
  # image_background_color = #e2e8f0
178
179
 
179
- ; Page text is no longer configured via INI.
180
- ; Use HazoAuthStringsProvider or per-page props instead.
181
- ; See MIGRATION.md for details.
180
+ # Labels
181
+ # heading = Reset your password
182
+ # sub_heading = Enter your new password below.
183
+ # submit_button = Reset password
184
+ # cancel_button = Cancel
182
185
 
183
186
  # Field labels (defaults shown, uncomment to override)
184
187
  # password_label = New password
@@ -210,9 +213,22 @@ otp_signin_href = /hazo_auth/otp
210
213
  # image_alt = Illustration of a globe representing secure authentication workflows
211
214
  # image_background_color = #e2e8f0
212
215
 
213
- ; Page text is no longer configured via INI.
214
- ; Use HazoAuthStringsProvider or per-page props instead.
215
- ; See MIGRATION.md for details.
216
+ # Labels (verifying state)
217
+ # heading = Email verification
218
+ # sub_heading = Verifying your email address...
219
+ # submit_button = Resend verification email
220
+ # cancel_button = Cancel
221
+
222
+ # Success labels
223
+ # success_heading = Email verified successfully
224
+ # success_message = Your email address has been verified. You can now log in to your account.
225
+ # success_redirect_message = Redirecting to login page in
226
+ # success_go_to_login_button = Go to login
227
+
228
+ # Error labels
229
+ # error_heading = Verification failed
230
+ # error_message = The verification link is invalid or has expired.
231
+ # error_resend_form_heading = Resend verification email
216
232
 
217
233
  # Field labels (defaults shown, uncomment to override)
218
234
  # email_label = Email address
@@ -254,9 +270,11 @@ otp_signin_href = /hazo_auth/otp
254
270
  # - [hazo_auth__password_requirements] for password validation rules
255
271
  # - [hazo_auth__profile_picture] for profile picture settings and prioritization
256
272
 
257
- ; Page heading text is no longer configured via INI.
258
- ; Use HazoAuthStringsProvider or the title prop on MySettingsPage instead.
259
- ; See MIGRATION.md for details.
273
+ # Heading
274
+ # heading = Account Settings
275
+
276
+ # Sub heading
277
+ # sub_heading = Manage your profile, password, and email preferences.
260
278
 
261
279
  # Profile Photo section
262
280
  # profile_photo_label = Profile Photo
@@ -579,26 +597,6 @@ application_permission_list_defaults = admin_user_management,admin_role_manageme
579
597
  # Redirect when skip_invitation_check=true and user has no scope
580
598
  # no_scope_redirect = /
581
599
 
582
- [hazo_auth__create_firm]
583
- ; heading, sub_heading, and submit_button_label are no longer configured via INI in v7.0.0.
584
- ; Use HazoAuthStringsProvider or the title/subtitle/ctaText props on CreateFirmPage instead.
585
- ; See MIGRATION.md for details.
586
-
587
- ; Firm name field label
588
- # firm_name_label = Firm Name
589
-
590
- ; Organisation structure field label
591
- # org_structure_label = Organisation Structure
592
-
593
- ; Default organisation structure value
594
- # org_structure_default = Headquarters
595
-
596
- ; Success message shown after firm creation
597
- # success_message = Your firm has been created successfully!
598
-
599
- ; Route to redirect to after firm creation
600
- # redirect_route = /
601
-
602
600
  [hazo_auth__multi_tenancy]
603
601
  # Multi-tenancy configuration for organization hierarchy
604
602
  # Enables hierarchical organization structures for company-wide access control
@@ -731,36 +729,3 @@ company_name = My Company
731
729
  # [hazo_auth__login_layout]
732
730
  # image_src = /your-custom-image.jpg
733
731
 
734
- [hazo_auth__otp]
735
- ; Email-OTP sign-in configuration (v6.1.0+).
736
- ;
737
- ; Whether /otp/verify may create new hazo_users rows for unknown emails.
738
- ; false (default): /otp/request silently no-ops for unknown emails.
739
- ; true: /otp/verify creates a user row on first successful code match.
740
- otp_auto_register = false
741
-
742
- ; OTP code lifetime in seconds (default 600 = 10 minutes).
743
- otp_code_ttl_seconds = 600
744
-
745
- ; OTP session lifetime in seconds (default 604800 = 7 days).
746
- otp_session_ttl_seconds = 604800
747
-
748
- ; Sliding-session threshold: if a /me call lands and the JWT exp is within
749
- ; this many seconds, re-issue the session for another otp_session_ttl_seconds.
750
- otp_slide_when_within_seconds = 86400
751
-
752
- ; Per-email rate limit for /otp/request.
753
- otp_email_rate_limit_max = 3
754
- otp_email_rate_limit_window_seconds = 900
755
-
756
- ; Per-IP rate limit for /otp/request.
757
- otp_ip_rate_limit_max = 20
758
- otp_ip_rate_limit_window_seconds = 3600
759
-
760
- ; Wrong-guess limit per code; row is poisoned after this many failures.
761
- otp_max_verify_attempts = 5
762
-
763
- ; Scope binding for newly auto-registered users (only used when otp_auto_register=true).
764
- otp_auto_assign_scope_id = 00000000-0000-0000-0000-000000000001
765
- otp_auto_assign_role_name = member
766
-
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AA0MF,wBAAgB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,IAAI,CA8DnE"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAiMF,wBAAgB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,IAAI,CA8DnE"}
@@ -93,20 +93,11 @@ ${exports}
93
93
  `;
94
94
  }
95
95
  function generate_page_content(page) {
96
- // Next 16 requires page default exports to satisfy `PageProps` (i.e. accept
97
- // `{ params?, searchParams? }` and nothing else). Re-exporting the named
98
- // component directly fails that check because the component carries custom
99
- // props (image_src, layout, …). The wrapper below is a parameter-less
100
- // function that returns the component — Next sees a `() => JSX` signature
101
- // which trivially satisfies PageProps. Direct JSX consumers still use the
102
- // named export from `hazo_auth/pages` and get the full custom-prop API.
103
96
  return `// Generated by hazo_auth - do not edit manually
104
97
  // Page: /${page.path}
105
98
  import { ${page.component_name} } from "hazo_auth/pages";
106
99
 
107
- export default function Page() {
108
- return <${page.component_name} />;
109
- }
100
+ export default ${page.component_name};
110
101
  `;
111
102
  }
112
103
  // section: api_route_generation
@@ -1 +1 @@
1
- {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AA+rBF,wBAAgB,cAAc,IAAI,iBAAiB,CA2ElD"}
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/cli/validate.ts"],"names":[],"mappings":"AAOA,KAAK,WAAW,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAE5C,KAAK,WAAW,GAAG;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,WAAW,EAAE,CAAC;CACxB,CAAC;AA2rBF,wBAAgB,cAAc,IAAI,iBAAiB,CA2ElD"}
@@ -44,9 +44,6 @@ const REQUIRED_API_ROUTES = [
44
44
  { path: "api/hazo_auth/user_management/users/roles", method: "GET" },
45
45
  { path: "api/hazo_auth/user_management/users/roles", method: "POST" },
46
46
  { path: "api/hazo_auth/user_management/users/roles", method: "PUT" },
47
- // OTP routes
48
- { path: "api/hazo_auth/otp/request", method: "POST" },
49
- { path: "api/hazo_auth/otp/verify", method: "POST" },
50
47
  ];
51
48
  // section: helpers
52
49
  function get_project_root() {
@@ -489,7 +486,6 @@ const REQUIRED_TABLES = [
489
486
  "hazo_role_permissions",
490
487
  "hazo_invitations",
491
488
  "hazo_refresh_tokens",
492
- "hazo_email_otps",
493
489
  ];
494
490
  const TEXT_ID_TABLES = [
495
491
  "hazo_users",
package/dist/client.d.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  export * from "./components/index.js";
2
- export { OTPRequestForm, OTPVerifyForm } from "./components/otp.js";
3
- export type { OTPRequestFormProps, OTPVerifyFormProps } from "./components/otp";
2
+ export { LegalAcceptanceGate, LegalDocDrawer, LegalDocCheckboxList, LegalDocCombinedView } from "./components/layouts/legal/index.js";
4
3
  export { cn, merge_class_names } from "./lib/utils.js";
5
4
  export * from "./lib/auth/auth_types.js";
6
5
  export { use_auth_status, trigger_auth_status_refresh } from "./components/layouts/shared/hooks/use_auth_status.js";
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjE,YAAY,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAIhF,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAC7G,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qDAAqD,CAAC;AACnH,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAGvI,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAI/E,cAAc,8CAA8C,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AAInC,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAInI,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAC7G,OAAO,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,qDAAqD,CAAC;AACnH,YAAY,EAAE,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,qDAAqD,CAAC;AAGvI,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAI/E,cAAc,8CAA8C,CAAC"}
package/dist/client.js CHANGED
@@ -10,7 +10,9 @@
10
10
  // section: component_exports
11
11
  // All UI and layout components are client-safe
12
12
  export * from "./components/index.js";
13
- export { OTPRequestForm, OTPVerifyForm } from "./components/otp.js";
13
+ // section: legal_exports
14
+ // Legal acceptance gate and primitives
15
+ export { LegalAcceptanceGate, LegalDocDrawer, LegalDocCheckboxList, LegalDocCombinedView } from "./components/layouts/legal/index.js";
14
16
  // section: utility_exports
15
17
  // CSS utility functions
16
18
  export { cn, merge_class_names } from "./lib/utils.js";
@@ -1,8 +1,12 @@
1
+ import type { StaticImageData } from "next/image";
1
2
  import { type ButtonPaletteOverrides } from "../shared/config/layout_customization.js";
2
- import type { HazoAuthTheme } from "../../../theme/theme_types";
3
3
  export type CreateFirmLayoutProps = {
4
- /** Theme that controls visual appearance and layout mode. */
5
- theme?: HazoAuthTheme;
4
+ /** Image source for the left panel */
5
+ image_src: string | StaticImageData;
6
+ /** Alt text for the image */
7
+ image_alt?: string;
8
+ /** Background color for the image panel */
9
+ image_background_color?: string;
6
10
  /** Page heading */
7
11
  heading?: string;
8
12
  /** Page sub-heading */
@@ -35,6 +39,6 @@ export type CreateFirmLayoutProps = {
35
39
  error: (message: string, data?: Record<string, unknown>) => void;
36
40
  };
37
41
  };
38
- export default function CreateFirmLayout({ theme, heading, sub_heading, firm_name_label, firm_name_placeholder, org_structure_label, org_structure_placeholder, default_org_structure, submit_button_label, success_message, redirect_route, apiBasePath, onSuccess, button_colors, logger, }: CreateFirmLayoutProps): import("react/jsx-runtime").JSX.Element;
42
+ export default function CreateFirmLayout({ image_src, image_alt, image_background_color, heading, sub_heading, firm_name_label, firm_name_placeholder, org_structure_label, org_structure_placeholder, default_org_structure, submit_button_label, success_message, redirect_route, apiBasePath, onSuccess, button_colors, logger, }: CreateFirmLayoutProps): import("react/jsx-runtime").JSX.Element;
39
43
  export { CreateFirmLayout };
40
44
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"AAYA,OAAO,EACL,KAAK,sBAAsB,EAC5B,MAAM,uCAAuC,CAAC;AAM/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGhE,MAAM,MAAM,qBAAqB,GAAG;IAClC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oCAAoC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,2BAA2B;IAC3B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,KAAK,EACL,OAA4B,EAC5B,WAAuD,EACvD,eAA6B,EAC7B,qBAA8C,EAC9C,mBAA8C,EAC9C,yBAA6D,EAC7D,qBAAsC,EACtC,mBAAmC,EACnC,eAA4D,EAC5D,cAAoB,EACpB,WAAW,EACX,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE,qBAAqB,2CAuJvB;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/layouts/create_firm/index.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAOlD,OAAO,EACL,KAAK,sBAAsB,EAC5B,MAAM,uCAAuC,CAAC;AAQ/C,MAAM,MAAM,qBAAqB,GAAG;IAClC,sCAAsC;IACtC,SAAS,EAAE,MAAM,GAAG,eAAe,CAAC;IACpC,6BAA6B;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,mBAAmB;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,oCAAoC;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,0CAA0C;IAC1C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,sCAAsC;IACtC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8BAA8B;IAC9B,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,gDAAgD;IAChD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,4CAA4C;IAC5C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iDAAiD;IACjD,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,6BAA6B;IAC7B,aAAa,CAAC,EAAE,sBAAsB,CAAC;IACvC,2BAA2B;IAC3B,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QAChE,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;KAClE,CAAC;CACH,CAAC;AAGF,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,SAAS,EACT,SAA8B,EAC9B,sBAAkC,EAClC,OAA4B,EAC5B,WAAuD,EACvD,eAA6B,EAC7B,qBAA8C,EAC9C,mBAA8C,EAC9C,yBAA6D,EAC7D,qBAAsC,EACtC,mBAAmC,EACnC,eAA4D,EAC5D,cAAoB,EACpB,WAAW,EACX,SAAS,EACT,aAAa,EACb,MAAM,GACP,EAAE,qBAAqB,2CA2JvB;AAGD,OAAO,EAAE,gBAAgB,EAAE,CAAC"}