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
@@ -0,0 +1,43 @@
1
+ // file_description: POST /api/hazo_auth/legal_docs/accept — records a user's acceptance of one or more legal docs
2
+ import { NextResponse } from 'next/server';
3
+ import { hazo_get_auth } from '../../lib/auth/hazo_get_auth.server.js';
4
+ import { get_client_ip } from '../../lib/auth/hazo_get_auth.server.js';
5
+ import { get_legal_docs_config } from '../../lib/legal/legal_docs_config.server.js';
6
+ import { read_legal_doc } from '../../lib/legal/legal_docs_reader.server.js';
7
+ import { write_legal_acceptance } from '../../lib/legal/legal_docs_service.js';
8
+ import { get_hazo_connect_instance } from '../../lib/hazo_connect_instance.server.js';
9
+ import { create_app_logger } from '../../lib/app_logger.js';
10
+ export async function legalDocsAcceptPOST(request) {
11
+ const logger = create_app_logger();
12
+ try {
13
+ const auth = await hazo_get_auth(request);
14
+ if (!auth.user) {
15
+ return NextResponse.json({ ok: false, error: 'Authentication required' }, { status: 401 });
16
+ }
17
+ const body = await request.json().catch(() => null);
18
+ const accepted = body === null || body === void 0 ? void 0 : body.accepted;
19
+ if (!accepted || typeof accepted !== 'object' || Object.keys(accepted).length === 0) {
20
+ return NextResponse.json({ ok: false, error: 'accepted is required' }, { status: 400 });
21
+ }
22
+ const config = get_legal_docs_config();
23
+ for (const [doc_key, { hash }] of Object.entries(accepted)) {
24
+ const doc_config = config.docs.find(d => d.key === doc_key);
25
+ if (!doc_config) {
26
+ return NextResponse.json({ ok: false, error: `Unknown doc key: ${doc_key}` }, { status: 400 });
27
+ }
28
+ const { hash: current_hash } = read_legal_doc(doc_config.path);
29
+ if (hash !== current_hash) {
30
+ return NextResponse.json({ ok: false, error: `Hash mismatch for "${doc_key}" — user may have seen a stale version` }, { status: 400 });
31
+ }
32
+ }
33
+ const ip = get_client_ip(request);
34
+ const user_agent = request.headers.get('user-agent');
35
+ const adapter = get_hazo_connect_instance();
36
+ await write_legal_acceptance(adapter, auth.user.id, accepted, ip, user_agent);
37
+ return NextResponse.json({ ok: true });
38
+ }
39
+ catch (err) {
40
+ logger.error('legal_docs_accept: internal server error', { err });
41
+ return NextResponse.json({ ok: false, error: 'Internal server error' }, { status: 500 });
42
+ }
43
+ }
@@ -0,0 +1,3 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function legalDocsGET(_request: NextRequest): Promise<NextResponse>;
3
+ //# sourceMappingURL=legal_docs_get.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legal_docs_get.d.ts","sourceRoot":"","sources":["../../../src/server/routes/legal_docs_get.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,YAAY,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA8C/E"}
@@ -0,0 +1,49 @@
1
+ // file_description: GET /api/hazo_auth/legal_docs — returns configured legal docs with content and required version info
2
+ import { NextResponse } from 'next/server';
3
+ import { get_legal_docs_config } from '../../lib/legal/legal_docs_config.server.js';
4
+ import { read_legal_doc } from '../../lib/legal/legal_docs_reader.server.js';
5
+ import { get_required_versions } from '../../lib/legal/legal_docs_service.js';
6
+ import { get_hazo_connect_instance } from '../../lib/hazo_connect_instance.server.js';
7
+ import { create_app_logger } from '../../lib/app_logger.js';
8
+ export async function legalDocsGET(_request) {
9
+ const logger = create_app_logger();
10
+ try {
11
+ const config = get_legal_docs_config();
12
+ if (config.docs.length === 0) {
13
+ return NextResponse.json({ ok: true, data: { display_mode: config.display_mode, docs: [] } });
14
+ }
15
+ const doc_results = config.docs.map((doc_config) => {
16
+ try {
17
+ const { content, hash } = read_legal_doc(doc_config.path);
18
+ return { ok: true, key: doc_config.key, title: doc_config.title, content, hash };
19
+ }
20
+ catch (err) {
21
+ logger.error('legal_docs_get: failed to read legal doc file', { err, key: doc_config.key, path: doc_config.path });
22
+ return { ok: false, key: doc_config.key, error: `File not found: ${doc_config.path}` };
23
+ }
24
+ });
25
+ const failed = doc_results.find(d => !d.ok);
26
+ if (failed) {
27
+ return NextResponse.json({ ok: false, error: `Legal doc "${failed.key}" could not be read. Check hazo_auth_config.ini path.` }, { status: 500 });
28
+ }
29
+ const adapter = get_hazo_connect_instance();
30
+ const keys = config.docs.map(d => d.key);
31
+ const required_versions = await get_required_versions(adapter, keys);
32
+ const docs = doc_results.map((d) => {
33
+ var _a, _b, _c, _d;
34
+ return ({
35
+ key: d.key,
36
+ title: d.title,
37
+ content: d.content,
38
+ hash: d.hash,
39
+ required_hash: (_b = (_a = required_versions[d.key]) === null || _a === void 0 ? void 0 : _a.required_hash) !== null && _b !== void 0 ? _b : null,
40
+ required_published_at: (_d = (_c = required_versions[d.key]) === null || _c === void 0 ? void 0 : _c.published_at) !== null && _d !== void 0 ? _d : null,
41
+ });
42
+ });
43
+ return NextResponse.json({ ok: true, data: { display_mode: config.display_mode, docs } });
44
+ }
45
+ catch (err) {
46
+ logger.error('legal_docs_get: internal server error', { err });
47
+ return NextResponse.json({ ok: false, error: 'Internal server error' }, { status: 500 });
48
+ }
49
+ }
@@ -0,0 +1,3 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function legalDocsPublishPOST(request: NextRequest): Promise<NextResponse>;
3
+ //# sourceMappingURL=legal_docs_publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legal_docs_publish.d.ts","sourceRoot":"","sources":["../../../src/server/routes/legal_docs_publish.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,wBAAsB,oBAAoB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA+BtF"}
@@ -0,0 +1,35 @@
1
+ // file_description: POST /api/hazo_auth/legal_docs/publish — admin endpoint to publish a new required version of a legal doc
2
+ import { NextResponse } from 'next/server';
3
+ import { hazo_get_auth } from '../../lib/auth/hazo_get_auth.server.js';
4
+ import { get_legal_docs_config } from '../../lib/legal/legal_docs_config.server.js';
5
+ import { read_legal_doc } from '../../lib/legal/legal_docs_reader.server.js';
6
+ import { publish_doc_version } from '../../lib/legal/legal_docs_service.js';
7
+ import { get_hazo_connect_instance } from '../../lib/hazo_connect_instance.server.js';
8
+ import { create_app_logger } from '../../lib/app_logger.js';
9
+ export async function legalDocsPublishPOST(request) {
10
+ const logger = create_app_logger();
11
+ try {
12
+ const auth = await hazo_get_auth(request, { required_permissions: ['admin_user_management'] });
13
+ if (!auth.permission_ok) {
14
+ return NextResponse.json({ ok: false, error: 'Forbidden' }, { status: 403 });
15
+ }
16
+ const body = await request.json().catch(() => null);
17
+ const doc_key = body === null || body === void 0 ? void 0 : body.doc_key;
18
+ if (!doc_key || typeof doc_key !== 'string') {
19
+ return NextResponse.json({ ok: false, error: 'doc_key is required' }, { status: 400 });
20
+ }
21
+ const config = get_legal_docs_config();
22
+ const doc_config = config.docs.find(d => d.key === doc_key);
23
+ if (!doc_config) {
24
+ return NextResponse.json({ ok: false, error: `Unknown doc key: ${doc_key}` }, { status: 400 });
25
+ }
26
+ const { hash } = read_legal_doc(doc_config.path);
27
+ const adapter = get_hazo_connect_instance();
28
+ const { published_at } = await publish_doc_version(adapter, doc_key, hash, auth.user.id);
29
+ return NextResponse.json({ ok: true, data: { doc_key, required_hash: hash, published_at } });
30
+ }
31
+ catch (err) {
32
+ logger.error('legal_docs_publish: internal server error', { err });
33
+ return NextResponse.json({ ok: false, error: 'Internal server error' }, { status: 500 });
34
+ }
35
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../../src/server/routes/me.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AA+BxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IAqJ7C"}
1
+ {"version":3,"file":"me.d.ts","sourceRoot":"","sources":["../../../src/server/routes/me.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAoBxD;;;;;GAKG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;IA+G7C"}
@@ -1,7 +1,6 @@
1
1
  // file_description: API route handler to get current authenticated user information with permissions
2
2
  // section: imports
3
3
  import { NextResponse } from "next/server";
4
- import { jwtVerify } from "jose";
5
4
  import { hazo_get_auth } from "../../lib/auth/hazo_get_auth.server.js";
6
5
  import { get_hazo_connect_instance } from "../../lib/hazo_connect_instance.server.js";
7
6
  import { createCrudService } from "hazo_connect/server";
@@ -9,9 +8,6 @@ import { map_db_source_to_ui } from "../../lib/services/profile_picture_source_m
9
8
  import { create_app_logger } from "../../lib/app_logger.js";
10
9
  import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
11
10
  import { is_user_types_enabled, get_user_type_by_key, } from "../../lib/user_types_config.server.js";
12
- import { get_cookie_name, get_cookie_options, BASE_COOKIE_NAMES, } from "../../lib/cookies_config.server.js";
13
- import { create_session_token } from "../../lib/services/session_token_service.js";
14
- import { get_otp_config, hazo_auth_otp_session_ttl_seconds, } from "../../lib/otp_config.server.js";
15
11
  // section: helpers
16
12
  function strip_sentinel_email(email) {
17
13
  if (!email)
@@ -28,7 +24,6 @@ function strip_sentinel_email(email) {
28
24
  * Always returns the same format to prevent downstream variations.
29
25
  */
30
26
  export async function GET(request) {
31
- var _a, _b, _c, _d, _e, _f;
32
27
  const logger = create_app_logger();
33
28
  try {
34
29
  // Use hazo_get_auth to get user with permissions
@@ -75,7 +70,7 @@ export async function GET(request) {
75
70
  }
76
71
  // Return unified format with all fields
77
72
  const profile_pic = auth_result.user.profile_picture_url;
78
- const response = NextResponse.json({
73
+ return NextResponse.json({
79
74
  authenticated: true,
80
75
  // Top-level fields for backward compatibility
81
76
  user_id: auth_result.user.id,
@@ -105,43 +100,6 @@ export async function GET(request) {
105
100
  permission_ok: auth_result.permission_ok,
106
101
  missing_permissions: auth_result.missing_permissions,
107
102
  }, { status: 200 });
108
- // --- OTP sliding-session hook ---
109
- const session_kind = (_a = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.SESSION_KIND))) === null || _a === void 0 ? void 0 : _a.value;
110
- if (session_kind === "otp") {
111
- try {
112
- const session_cookie = (_b = request.cookies.get(get_cookie_name(BASE_COOKIE_NAMES.SESSION))) === null || _b === void 0 ? void 0 : _b.value;
113
- if (session_cookie) {
114
- const secret = new TextEncoder().encode((_c = process.env.JWT_SECRET) !== null && _c !== void 0 ? _c : "");
115
- const { payload } = await jwtVerify(session_cookie, secret);
116
- const exp = Number((_d = payload.exp) !== null && _d !== void 0 ? _d : 0);
117
- const now_seconds = Math.floor(Date.now() / 1000);
118
- const otp_cfg = get_otp_config();
119
- const seconds_until_exp = exp - now_seconds;
120
- if (seconds_until_exp > 0 && seconds_until_exp < otp_cfg.slide_when_within_seconds) {
121
- const ttl_seconds = hazo_auth_otp_session_ttl_seconds();
122
- const user_id = String((_e = payload.user_id) !== null && _e !== void 0 ? _e : "");
123
- const user_email = String((_f = payload.email) !== null && _f !== void 0 ? _f : "");
124
- const new_token = await create_session_token(user_id, user_email, undefined, ttl_seconds);
125
- const cookie_options = get_cookie_options({
126
- httpOnly: true,
127
- secure: process.env.NODE_ENV === "production",
128
- sameSite: "lax",
129
- path: "/",
130
- maxAge: ttl_seconds,
131
- });
132
- response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION), new_token, cookie_options);
133
- response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_ID), user_id, cookie_options);
134
- response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.USER_EMAIL), user_email, cookie_options);
135
- response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION_KIND), "otp", cookie_options);
136
- }
137
- }
138
- }
139
- catch (slide_err) {
140
- // Slide is best-effort — never break /me for this
141
- }
142
- }
143
- // --- end OTP sliding-session hook ---
144
- return response;
145
103
  }
146
104
  catch (error) {
147
105
  const error_message = error instanceof Error ? error.message : "Unknown error";
@@ -4,5 +4,5 @@ import { NextRequest, NextResponse } from "next/server";
4
4
  * The user creation/linking is done in NextAuth signIn callback
5
5
  * This route just sets the hazo_auth session cookies
6
6
  */
7
- export declare function facebookCallbackGET(original_request: NextRequest): Promise<NextResponse<unknown>>;
7
+ export declare function GET(original_request: NextRequest): Promise<NextResponse<unknown>>;
8
8
  //# sourceMappingURL=oauth_facebook_callback.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"oauth_facebook_callback.d.ts","sourceRoot":"","sources":["../../../src/server/routes/oauth_facebook_callback.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuBxD;;;;GAIG;AACH,wBAAsB,mBAAmB,CAAC,gBAAgB,EAAE,WAAW,kCAoKtE"}
1
+ {"version":3,"file":"oauth_facebook_callback.d.ts","sourceRoot":"","sources":["../../../src/server/routes/oauth_facebook_callback.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAuBxD;;;;GAIG;AACH,wBAAsB,GAAG,CAAC,gBAAgB,EAAE,WAAW,kCAiLtD"}
@@ -17,7 +17,7 @@ import { rewrite_request_for_proxy } from "../../lib/utils/proxy_request.js";
17
17
  * The user creation/linking is done in NextAuth signIn callback
18
18
  * This route just sets the hazo_auth session cookies
19
19
  */
20
- export async function facebookCallbackGET(original_request) {
20
+ export async function GET(original_request) {
21
21
  // Rewrite request.url to public origin when behind a reverse proxy.
22
22
  const request = rewrite_request_for_proxy(original_request);
23
23
  const logger = create_app_logger();
@@ -139,6 +139,13 @@ export async function facebookCallbackGET(original_request) {
139
139
  note: "OAuth login succeeded but session token creation failed - using legacy cookies",
140
140
  });
141
141
  }
142
+ // Set session kind cookie so downstream can identify sign-in method
143
+ response.cookies.set(get_cookie_name(BASE_COOKIE_NAMES.SESSION_KIND), "facebook", cookie_options);
144
+ logger.info("facebook_callback_session_created", {
145
+ filename: get_filename(),
146
+ user_id,
147
+ email,
148
+ });
142
149
  return response;
143
150
  }
144
151
  catch (error) {
@@ -172,7 +172,7 @@ export async function GET(original_request) {
172
172
  error_message,
173
173
  error_stack,
174
174
  });
175
- const login_url = new URL(sign_in_page, request.url);
175
+ const login_url = new URL("/hazo_auth/login", request.url);
176
176
  login_url.searchParams.set("error", "oauth_error");
177
177
  return NextResponse.redirect(login_url.toString());
178
178
  }
@@ -28,7 +28,7 @@ export async function otpVerifyPOST(request) {
28
28
  ip,
29
29
  });
30
30
  if (result.ok === false) {
31
- return NextResponse.json({ ok: false, error: "invalid_or_expired" }, { status: 400 });
31
+ return NextResponse.json({ ok: false, error: result.error }, { status: 401 });
32
32
  }
33
33
  const ttl_seconds = hazo_auth_otp_session_ttl_seconds();
34
34
  const base_cookie_options = {
@@ -53,6 +53,6 @@ export async function otpVerifyPOST(request) {
53
53
  catch (err) {
54
54
  const msg = err instanceof Error ? err.message : String(err);
55
55
  logger.error("otp_verify_route_error", { error: msg });
56
- return NextResponse.json({ ok: false, error: "invalid_or_expired" }, { status: 400 });
56
+ return NextResponse.json({ ok: false, error: "invalid_or_expired" }, { status: 401 });
57
57
  }
58
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/server/routes/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;IAiG9C"}
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/server/routes/register.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAWxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;IAgI9C"}
@@ -6,12 +6,17 @@ import { create_app_logger } from "../../lib/app_logger.js";
6
6
  import { register_user } from "../../lib/services/registration_service.js";
7
7
  import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
8
8
  import { sanitize_error_for_user } from "../../lib/utils/error_sanitizer.js";
9
+ import { get_legal_docs_config } from "../../lib/legal/legal_docs_config.server.js";
10
+ import { read_legal_doc } from "../../lib/legal/legal_docs_reader.server.js";
11
+ import { get_client_ip } from "../../lib/auth/hazo_get_auth.server.js";
9
12
  // section: api_handler
10
13
  export async function POST(request) {
14
+ var _a;
11
15
  const logger = create_app_logger();
12
16
  try {
13
17
  const body = await request.json();
14
18
  const { name, email, password, url_on_logon } = body;
19
+ const legal_accepted = body === null || body === void 0 ? void 0 : body.legal_accepted;
15
20
  // Validate input
16
21
  if (!email || !password) {
17
22
  logger.warn("registration_validation_failed", {
@@ -32,6 +37,24 @@ export async function POST(request) {
32
37
  });
33
38
  return NextResponse.json({ error: "Invalid email address format" }, { status: 400 });
34
39
  }
40
+ // Validate legal acceptance if docs are configured
41
+ const legal_config = get_legal_docs_config();
42
+ if (legal_config.docs.length > 0) {
43
+ const missing_keys = legal_config.docs
44
+ .map(d => d.key)
45
+ .filter(key => !(legal_accepted === null || legal_accepted === void 0 ? void 0 : legal_accepted[key]));
46
+ if (missing_keys.length > 0) {
47
+ return NextResponse.json({ ok: false, error: 'legal_acceptance_required', missing_keys }, { status: 400 });
48
+ }
49
+ // Validate hashes match current file content
50
+ for (const doc_config of legal_config.docs) {
51
+ const submitted_hash = (_a = legal_accepted[doc_config.key]) === null || _a === void 0 ? void 0 : _a.hash;
52
+ const { hash: current_hash } = read_legal_doc(doc_config.path);
53
+ if (submitted_hash !== current_hash) {
54
+ return NextResponse.json({ ok: false, error: `Hash mismatch for "${doc_config.key}"` }, { status: 400 });
55
+ }
56
+ }
57
+ }
35
58
  // Get singleton hazo_connect instance (reuses same connection across all routes)
36
59
  const hazoConnect = get_hazo_connect_instance();
37
60
  // Register user using the registration service
@@ -40,6 +63,9 @@ export async function POST(request) {
40
63
  password,
41
64
  name,
42
65
  url_on_logon,
66
+ legal_accepted,
67
+ ip: get_client_ip(request),
68
+ user_agent: request.headers.get('user-agent'),
43
69
  });
44
70
  if (!result.success) {
45
71
  const status_code = result.error === "Email address already registered" ? 409 : 500;
@@ -0,0 +1,4 @@
1
+ import "server-only";
2
+ import { NextResponse } from "next/server";
3
+ export declare function stringsDefaultsGET(): Promise<NextResponse>;
4
+ //# sourceMappingURL=strings_defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strings_defaults.d.ts","sourceRoot":"","sources":["../../../src/server/routes/strings_defaults.ts"],"names":[],"mappings":"AACA,OAAO,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,YAAY,CAAC,CAEhE"}
@@ -0,0 +1,7 @@
1
+ // file_description: Route handler returning the DEFAULT_STRINGS object for introspection and testing
2
+ import "server-only";
3
+ import { NextResponse } from "next/server";
4
+ import { DEFAULT_STRINGS } from "../../strings/default_strings.js";
5
+ export async function stringsDefaultsGET() {
6
+ return NextResponse.json(DEFAULT_STRINGS, { status: 200 });
7
+ }
@@ -26,6 +26,7 @@ export declare function GET(request: NextRequest): Promise<NextResponse<{
26
26
  profile_source: {} | null;
27
27
  user_type: string | null;
28
28
  app_user_data: Record<string, unknown> | null;
29
+ legal_acceptance_status: "current" | "outdated" | "none";
29
30
  }[];
30
31
  }>>;
31
32
  /**
@@ -44,4 +45,14 @@ export declare function POST(request: NextRequest): Promise<NextResponse<{
44
45
  }> | NextResponse<{
45
46
  success: boolean;
46
47
  }>>;
48
+ /**
49
+ * DELETE - Hard-delete a user from hazo_users (cascades to all related rows).
50
+ * Body: { user_id: string }
51
+ * Requires: admin_user_management permission.
52
+ */
53
+ export declare function DELETE(request: NextRequest): Promise<NextResponse<{
54
+ error: string;
55
+ }> | NextResponse<{
56
+ success: boolean;
57
+ }>>;
47
58
  //# sourceMappingURL=user_management_users.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"user_management_users.d.ts","sourceRoot":"","sources":["../../../src/server/routes/user_management_users.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAexD,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAGvC;;;GAGG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;IAyF7C;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,WAAW;;;;IAgI/C;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IA2E9C"}
1
+ {"version":3,"file":"user_management_users.d.ts","sourceRoot":"","sources":["../../../src/server/routes/user_management_users.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkBxD,eAAO,MAAM,OAAO,kBAAkB,CAAC;AA+BvC;;;GAGG;AACH,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;;;IAsG7C;AAED;;GAEG;AACH,wBAAsB,KAAK,CAAC,OAAO,EAAE,WAAW;;;;IAgI/C;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;IA2E9C;AAED;;;;GAIG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;IAmEhD"}
@@ -9,8 +9,35 @@ import { request_password_reset } from "../../lib/services/password_reset_servic
9
9
  import { get_auth_cache } from "../../lib/auth/auth_cache.js";
10
10
  import { get_auth_utility_config } from "../../lib/auth_utility_config.server.js";
11
11
  import { is_user_types_enabled, get_all_user_types, get_user_types_config, } from "../../lib/user_types_config.server.js";
12
+ import { get_required_versions } from "../../lib/legal/legal_docs_service.js";
13
+ import { get_legal_docs_config } from "../../lib/legal/legal_docs_config.server.js";
14
+ import { hazo_get_auth } from "../../lib/auth/hazo_get_auth.server.js";
12
15
  // section: route_config
13
16
  export const dynamic = 'force-dynamic';
17
+ // section: helpers
18
+ /**
19
+ * Compute a user's legal compliance status given their raw legal_acceptance JSON,
20
+ * the currently-required hashes, and the configured doc keys.
21
+ */
22
+ function compute_legal_status(raw, required, docs) {
23
+ if (docs.length === 0)
24
+ return 'none';
25
+ if (Object.keys(required).length === 0)
26
+ return 'none';
27
+ let map = {};
28
+ try {
29
+ map = typeof raw === 'string' ? JSON.parse(raw) : (raw !== null && raw !== void 0 ? raw : {});
30
+ }
31
+ catch ( /* ignore */_a) { /* ignore */ }
32
+ const all_current = docs.every(doc => {
33
+ var _a;
34
+ const req = required[doc.key];
35
+ if (!req)
36
+ return true;
37
+ return ((_a = map[doc.key]) === null || _a === void 0 ? void 0 : _a.hash) === req.required_hash;
38
+ });
39
+ return all_current ? 'current' : 'outdated';
40
+ }
14
41
  // section: api_handler
15
42
  /**
16
43
  * GET - Fetch all users with details or a specific user by id
@@ -42,6 +69,13 @@ export async function GET(request) {
42
69
  badge_color: t.badge_color,
43
70
  }))
44
71
  : [];
72
+ // Load legal docs required versions for compliance status
73
+ const legal_config = get_legal_docs_config();
74
+ let required_versions = {};
75
+ if (legal_config.docs.length > 0) {
76
+ const adapter = get_hazo_connect_instance();
77
+ required_versions = await get_required_versions(adapter, legal_config.docs.map(d => d.key));
78
+ }
45
79
  return NextResponse.json({
46
80
  success: true,
47
81
  user_types_enabled,
@@ -74,6 +108,7 @@ export async function GET(request) {
74
108
  profile_source: user.profile_source || null,
75
109
  user_type: user.user_type || null,
76
110
  app_user_data,
111
+ legal_acceptance_status: compute_legal_status(user.legal_acceptance, required_versions, legal_config.docs),
77
112
  };
78
113
  }),
79
114
  }, { status: 200 });
@@ -241,3 +276,62 @@ export async function POST(request) {
241
276
  return NextResponse.json({ error: "Failed to send password reset email" }, { status: 500 });
242
277
  }
243
278
  }
279
+ /**
280
+ * DELETE - Hard-delete a user from hazo_users (cascades to all related rows).
281
+ * Body: { user_id: string }
282
+ * Requires: admin_user_management permission.
283
+ */
284
+ export async function DELETE(request) {
285
+ const logger = create_app_logger();
286
+ try {
287
+ const auth = await hazo_get_auth(request, { required_permissions: ['admin_user_management'] });
288
+ if (!auth.user) {
289
+ return NextResponse.json({ error: 'Authentication required' }, { status: 401 });
290
+ }
291
+ if (!auth.permission_ok) {
292
+ return NextResponse.json({ error: 'Forbidden' }, { status: 403 });
293
+ }
294
+ const body = await request.json();
295
+ const { user_id } = body;
296
+ if (auth.user.id === user_id) {
297
+ return NextResponse.json({ error: 'Cannot delete your own account' }, { status: 400 });
298
+ }
299
+ if (!user_id) {
300
+ return NextResponse.json({ error: "user_id is required" }, { status: 400 });
301
+ }
302
+ const hazoConnect = get_hazo_connect_instance();
303
+ const users_service = createCrudService(hazoConnect, "hazo_users");
304
+ // Verify user exists before deleting
305
+ const users = await users_service.findBy({ id: user_id });
306
+ if (!Array.isArray(users) || users.length === 0) {
307
+ return NextResponse.json({ error: "User not found" }, { status: 404 });
308
+ }
309
+ // Invalidate auth cache first
310
+ try {
311
+ const auth_config = get_auth_utility_config();
312
+ const auth_cache = get_auth_cache(auth_config.cache_max_users, auth_config.cache_ttl_minutes, auth_config.cache_max_age_minutes);
313
+ auth_cache.invalidate_user(user_id);
314
+ }
315
+ catch (_a) {
316
+ // Non-fatal
317
+ }
318
+ await users_service.deleteById(user_id);
319
+ logger.info("user_management_user_deleted", {
320
+ filename: get_filename(),
321
+ line_number: get_line_number(),
322
+ user_id,
323
+ });
324
+ return NextResponse.json({ success: true }, { status: 200 });
325
+ }
326
+ catch (error) {
327
+ const error_message = error instanceof Error ? error.message : "Unknown error";
328
+ const error_stack = error instanceof Error ? error.stack : undefined;
329
+ logger.error("user_management_user_delete_error", {
330
+ filename: get_filename(),
331
+ line_number: get_line_number(),
332
+ error_message,
333
+ error_stack,
334
+ });
335
+ return NextResponse.json({ error: "Failed to delete user" }, { status: 500 });
336
+ }
337
+ }
@@ -24,9 +24,6 @@ export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled, }
24
24
  export type { OAuthConfig } from "./lib/oauth_config.server";
25
25
  export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes, } from "./lib/branding_config.server.js";
26
26
  export type { FirmBrandingConfig } from "./lib/branding_config.server";
27
- export { get_otp_config, hazo_auth_otp_session_ttl_seconds, OTP_CONFIG_DEFAULTS } from "./lib/otp_config.server.js";
28
- export type { OtpConfig } from "./lib/otp_config.server";
29
- export { request_email_otp, verify_email_otp } from "./lib/services/otp_service.js";
30
27
  export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
31
28
  export { get_hazo_connect_instance } from "./lib/hazo_connect_instance.server.js";
32
29
  export { create_app_logger } from "./lib/app_logger.js";
@@ -1 +1 @@
1
- {"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"AAYA,OAAO,aAAa,CAAC;AAGrB,cAAc,kBAAkB,CAAC;AAGjC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAGrF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,cAAc,EAAE,iCAAiC,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AACjH,YAAY,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAGjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAG/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,cAAc,+BAA+B,CAAC"}
1
+ {"version":3,"file":"server-lib.d.ts","sourceRoot":"","sources":["../src/server-lib.ts"],"names":[],"mappings":"AAYA,OAAO,aAAa,CAAC;AAGrB,cAAc,kBAAkB,CAAC;AAGjC,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,2BAA2B,EAAE,MAAM,wCAAwC,CAAC;AAGrF,OAAO,EACL,gBAAgB,EAChB,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mCAAmC,CAAC;AAG3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAC/E,OAAO,EAAE,6BAA6B,EAAE,MAAM,wCAAwC,CAAC;AACvF,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,qCAAqC,CAAC;AACjF,OAAO,EAAE,2BAA2B,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,4BAA4B,EAAE,MAAM,uCAAuC,CAAC;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAC3E,OAAO,EAAE,gCAAgC,EAAE,MAAM,2CAA2C,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,2BAA2B,CAAC;AACnC,YAAY,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,8BAA8B,CAAC;AACtC,YAAY,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAGvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAG/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,YAAY,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAC;AAC5E,cAAc,+BAA+B,CAAC"}
@@ -37,8 +37,6 @@ export { get_user_fields_config } from "./lib/user_fields_config.server.js";
37
37
  export { get_file_types_config } from "./lib/file_types_config.server.js";
38
38
  export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled, } from "./lib/oauth_config.server.js";
39
39
  export { get_branding_config, is_branding_enabled, is_allowed_logo_format, get_max_logo_size_bytes, } from "./lib/branding_config.server.js";
40
- export { get_otp_config, hazo_auth_otp_session_ttl_seconds, OTP_CONFIG_DEFAULTS } from "./lib/otp_config.server.js";
41
- export { request_email_otp, verify_email_otp } from "./lib/services/otp_service.js";
42
40
  // section: hazo_connect_exports
43
41
  export { create_sqlite_hazo_connect } from "./lib/hazo_connect_setup.js";
44
42
  export { get_hazo_connect_instance } from "./lib/hazo_connect_instance.server.js";
@@ -1,5 +1,21 @@
1
1
  import "server-only";
2
+ import type { StaticImageData } from "next/image";
2
3
  export type ForgotPasswordPageProps = {
4
+ /**
5
+ * Optional image source for the visual panel
6
+ * Defaults from hazo_auth_config.ini or package default image
7
+ */
8
+ image_src?: string | StaticImageData;
9
+ /**
10
+ * Optional image alt text
11
+ * Defaults to "Password recovery illustration"
12
+ */
13
+ image_alt?: string;
14
+ /**
15
+ * Optional image background color
16
+ * Defaults to "#f1f5f9"
17
+ */
18
+ image_background_color?: string;
3
19
  /**
4
20
  * Optional sign in path
5
21
  * Defaults from DEFAULT_FORGOT_PASSWORD.loginPath
@@ -10,18 +26,6 @@ export type ForgotPasswordPageProps = {
10
26
  * Defaults from DEFAULT_FORGOT_PASSWORD.loginLabel
11
27
  */
12
28
  sign_in_label?: string;
13
- /**
14
- * Optional theme that controls visual appearance and layout mode.
15
- * When `theme.layout` is `"split"`, activates the two-column split layout
16
- * with the brand panel on the left.
17
- */
18
- theme?: import("../theme/theme_types").HazoAuthTheme;
19
- /** Override the page heading. Falls back to HazoAuthStringsProvider → DEFAULT_STRINGS. */
20
- title?: string;
21
- /** Override the page subtitle. Falls back to HazoAuthStringsProvider → DEFAULT_STRINGS. */
22
- subtitle?: string;
23
- /** Override the submit button label. Falls back to HazoAuthStringsProvider → DEFAULT_STRINGS. */
24
- ctaText?: string;
25
29
  };
26
30
  /**
27
31
  * Zero-config ForgotPasswordPage server component
@@ -43,9 +47,9 @@ export type ForgotPasswordPageProps = {
43
47
  *
44
48
  * Zero configuration required - works out of the box!
45
49
  *
46
- * @param props - Optional navigation customization props
50
+ * @param props - Optional visual and navigation customization props
47
51
  * @returns Server-rendered forgot password page
48
52
  */
49
- export default function ForgotPasswordPage(props: ForgotPasswordPageProps): import("react/jsx-runtime").JSX.Element;
53
+ export default function ForgotPasswordPage({ image_src, image_alt, image_background_color, sign_in_path, sign_in_label, }?: ForgotPasswordPageProps): import("react/jsx-runtime").JSX.Element;
50
54
  export { ForgotPasswordPage };
51
55
  //# sourceMappingURL=forgot_password.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"forgot_password.d.ts","sourceRoot":"","sources":["../../src/server_pages/forgot_password.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAUrB,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,sBAAsB,EAAE,aAAa,CAAC;IACrD,0FAA0F;IAC1F,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2FAA2F;IAC3F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iGAAiG;IACjG,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,2CAoCxE;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"forgot_password.d.ts","sourceRoot":"","sources":["../../src/server_pages/forgot_password.tsx"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AASrB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAErC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB;;;OAGG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,SAAS,EACT,SAAS,EACT,sBAAsB,EACtB,YAAgD,EAChD,aAAkD,GACnD,GAAE,uBAA4B,2CAkC9B;AAGD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}