hazo_auth 7.0.2 → 9.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (145) hide show
  1. package/README.md +34 -0
  2. package/SETUP_CHECKLIST.md +31 -0
  3. package/cli-src/lib/AGENTS.md +26 -0
  4. package/cli-src/lib/app_logger.ts +3 -7
  5. package/cli-src/lib/auth/auth_types.ts +3 -0
  6. package/cli-src/lib/auth/auth_utils.server.ts +2 -1
  7. package/cli-src/lib/auth/ensure_anon_id.server.ts +2 -1
  8. package/cli-src/lib/auth/hazo_get_auth.server.ts +30 -4
  9. package/cli-src/lib/config/hazo_auth_core_config.ts +44 -0
  10. package/cli-src/lib/cookies_config.server.ts +13 -10
  11. package/cli-src/lib/hazo_connect_setup.server.ts +19 -11
  12. package/cli-src/lib/legal/legal_docs_config.server.ts +61 -0
  13. package/cli-src/lib/legal/legal_docs_reader.server.ts +36 -0
  14. package/cli-src/lib/legal/legal_docs_service.ts +197 -0
  15. package/cli-src/lib/legal/legal_docs_types.ts +31 -0
  16. package/cli-src/lib/services/email_service.ts +22 -11
  17. package/cli-src/lib/services/firm_service.ts +2 -1
  18. package/cli-src/lib/services/otp_service.ts +3 -2
  19. package/cli-src/lib/services/profile_picture_service.ts +2 -1
  20. package/cli-src/lib/services/registration_service.ts +16 -1
  21. package/cli-src/lib/services/relationship_service.ts +5 -4
  22. package/cli-src/lib/services/session_token_service.ts +3 -2
  23. package/cli-src/lib/utils/api_route_helpers.ts +4 -59
  24. package/cli-src/lib/utils/get_origin_url.ts +5 -61
  25. package/cli-src/lib/utils.ts +4 -10
  26. package/config/hazo_auth_config.example.ini +6 -0
  27. package/dist/client.d.ts +1 -0
  28. package/dist/client.d.ts.map +1 -1
  29. package/dist/client.js +3 -0
  30. package/dist/components/layouts/index.d.ts +1 -0
  31. package/dist/components/layouts/index.d.ts.map +1 -1
  32. package/dist/components/layouts/index.js +2 -0
  33. package/dist/components/layouts/legal/index.d.ts +5 -0
  34. package/dist/components/layouts/legal/index.d.ts.map +1 -0
  35. package/dist/components/layouts/legal/index.js +4 -0
  36. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts +7 -0
  37. package/dist/components/layouts/legal/legal_acceptance_gate.d.ts.map +1 -0
  38. package/dist/components/layouts/legal/legal_acceptance_gate.js +84 -0
  39. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts +9 -0
  40. package/dist/components/layouts/legal/legal_doc_checkbox_list.d.ts.map +1 -0
  41. package/dist/components/layouts/legal/legal_doc_checkbox_list.js +11 -0
  42. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts +9 -0
  43. package/dist/components/layouts/legal/legal_doc_combined_view.d.ts.map +1 -0
  44. package/dist/components/layouts/legal/legal_doc_combined_view.js +11 -0
  45. package/dist/components/layouts/legal/legal_doc_drawer.d.ts +8 -0
  46. package/dist/components/layouts/legal/legal_doc_drawer.d.ts.map +1 -0
  47. package/dist/components/layouts/legal/legal_doc_drawer.js +55 -0
  48. package/dist/components/layouts/register/hooks/use_register_form.d.ts +5 -1
  49. package/dist/components/layouts/register/hooks/use_register_form.d.ts.map +1 -1
  50. package/dist/components/layouts/register/hooks/use_register_form.js +25 -10
  51. package/dist/components/layouts/register/index.d.ts.map +1 -1
  52. package/dist/components/layouts/register/index.js +21 -1
  53. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  54. package/dist/components/layouts/user_management/index.js +45 -7
  55. package/dist/components/ui/input-otp.d.ts +2 -2
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/lib/app_logger.d.ts +2 -3
  59. package/dist/lib/app_logger.d.ts.map +1 -1
  60. package/dist/lib/app_logger.js +3 -5
  61. package/dist/lib/auth/auth_types.d.ts +2 -0
  62. package/dist/lib/auth/auth_types.d.ts.map +1 -1
  63. package/dist/lib/auth/auth_types.js +0 -2
  64. package/dist/lib/auth/auth_utils.server.d.ts.map +1 -1
  65. package/dist/lib/auth/auth_utils.server.js +2 -1
  66. package/dist/lib/auth/ensure_anon_id.server.d.ts.map +1 -1
  67. package/dist/lib/auth/ensure_anon_id.server.js +2 -1
  68. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  69. package/dist/lib/auth/hazo_get_auth.server.js +30 -4
  70. package/dist/lib/config/hazo_auth_core_config.d.ts +44 -0
  71. package/dist/lib/config/hazo_auth_core_config.d.ts.map +1 -0
  72. package/dist/lib/config/hazo_auth_core_config.js +40 -0
  73. package/dist/lib/cookies_config.server.d.ts.map +1 -1
  74. package/dist/lib/cookies_config.server.js +12 -7
  75. package/dist/lib/hazo_connect_setup.server.d.ts.map +1 -1
  76. package/dist/lib/hazo_connect_setup.server.js +18 -5
  77. package/dist/lib/legal/legal_docs_config.server.d.ts +22 -0
  78. package/dist/lib/legal/legal_docs_config.server.d.ts.map +1 -0
  79. package/dist/lib/legal/legal_docs_config.server.js +52 -0
  80. package/dist/lib/legal/legal_docs_reader.server.d.ts +15 -0
  81. package/dist/lib/legal/legal_docs_reader.server.d.ts.map +1 -0
  82. package/dist/lib/legal/legal_docs_reader.server.js +24 -0
  83. package/dist/lib/legal/legal_docs_service.d.ts +49 -0
  84. package/dist/lib/legal/legal_docs_service.d.ts.map +1 -0
  85. package/dist/lib/legal/legal_docs_service.js +141 -0
  86. package/dist/lib/legal/legal_docs_types.d.ts +25 -0
  87. package/dist/lib/legal/legal_docs_types.d.ts.map +1 -0
  88. package/dist/lib/legal/legal_docs_types.js +2 -0
  89. package/dist/lib/services/email_service.d.ts +1 -1
  90. package/dist/lib/services/email_service.d.ts.map +1 -1
  91. package/dist/lib/services/email_service.js +21 -9
  92. package/dist/lib/services/firm_service.d.ts.map +1 -1
  93. package/dist/lib/services/firm_service.js +2 -1
  94. package/dist/lib/services/otp_service.d.ts.map +1 -1
  95. package/dist/lib/services/otp_service.js +3 -2
  96. package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
  97. package/dist/lib/services/profile_picture_service.js +2 -1
  98. package/dist/lib/services/registration_service.d.ts +5 -0
  99. package/dist/lib/services/registration_service.d.ts.map +1 -1
  100. package/dist/lib/services/registration_service.js +6 -0
  101. package/dist/lib/services/relationship_service.d.ts.map +1 -1
  102. package/dist/lib/services/relationship_service.js +5 -4
  103. package/dist/lib/services/session_token_service.d.ts.map +1 -1
  104. package/dist/lib/services/session_token_service.js +3 -2
  105. package/dist/lib/utils/api_route_helpers.d.ts +1 -12
  106. package/dist/lib/utils/api_route_helpers.d.ts.map +1 -1
  107. package/dist/lib/utils/api_route_helpers.js +4 -57
  108. package/dist/lib/utils/get_origin_url.d.ts +1 -22
  109. package/dist/lib/utils/get_origin_url.d.ts.map +1 -1
  110. package/dist/lib/utils/get_origin_url.js +5 -57
  111. package/dist/lib/utils.d.ts +2 -3
  112. package/dist/lib/utils.d.ts.map +1 -1
  113. package/dist/lib/utils.js +4 -9
  114. package/dist/page_components/index.d.ts +0 -5
  115. package/dist/page_components/index.d.ts.map +1 -1
  116. package/dist/page_components/index.js +0 -5
  117. package/dist/server/config/config_loader.js +2 -2
  118. package/dist/server/index.js +1 -1
  119. package/dist/server/routes/index.d.ts +3 -0
  120. package/dist/server/routes/index.d.ts.map +1 -1
  121. package/dist/server/routes/index.js +4 -0
  122. package/dist/server/routes/legal_docs_accept.d.ts +3 -0
  123. package/dist/server/routes/legal_docs_accept.d.ts.map +1 -0
  124. package/dist/server/routes/legal_docs_accept.js +43 -0
  125. package/dist/server/routes/legal_docs_get.d.ts +3 -0
  126. package/dist/server/routes/legal_docs_get.d.ts.map +1 -0
  127. package/dist/server/routes/legal_docs_get.js +49 -0
  128. package/dist/server/routes/legal_docs_publish.d.ts +3 -0
  129. package/dist/server/routes/legal_docs_publish.d.ts.map +1 -0
  130. package/dist/server/routes/legal_docs_publish.js +35 -0
  131. package/dist/server/routes/register.d.ts.map +1 -1
  132. package/dist/server/routes/register.js +26 -0
  133. package/dist/server/routes/remove_profile_picture.d.ts.map +1 -1
  134. package/dist/server/routes/remove_profile_picture.js +6 -1
  135. package/dist/server/routes/upload_profile_picture.d.ts.map +1 -1
  136. package/dist/server/routes/upload_profile_picture.js +6 -1
  137. package/dist/server/routes/user_management_users.d.ts +2 -2
  138. package/dist/server/routes/user_management_users.d.ts.map +1 -1
  139. package/dist/server/routes/user_management_users.js +46 -2
  140. package/dist/server/server.d.ts.map +1 -1
  141. package/dist/server/server.js +7 -0
  142. package/dist/strings.d.ts +2 -0
  143. package/dist/strings.d.ts.map +1 -0
  144. package/dist/strings.js +3 -0
  145. package/package.json +33 -35
@@ -1,23 +1,2 @@
1
- /**
2
- * Gets the public-facing origin URL for redirect construction.
3
- *
4
- * Behind reverse proxies (Cloudflare, nginx, etc.), `request.url` contains the
5
- * internal address (e.g. `http://localhost:3000`), not the public domain.
6
- * This function returns the correct origin from environment variables.
7
- *
8
- * Priority: NEXTAUTH_URL > APP_DOMAIN_NAME > NEXT_PUBLIC_APP_URL > APP_URL > request.url
9
- *
10
- * @param request_url - The request.url to use as fallback
11
- * @returns The origin URL (e.g. "https://gotimer.org")
12
- */
13
- export declare function get_origin_url(request_url: string): string;
14
- /**
15
- * Creates a URL using the public-facing origin instead of request.url.
16
- * Drop-in replacement for `new URL(path, request.url)` in route handlers.
17
- *
18
- * @param path - The path or relative URL (e.g. "/hazo_auth/login")
19
- * @param request_url - The request.url (used as fallback only)
20
- * @returns A URL object with the correct public origin
21
- */
22
- export declare function create_redirect_url(path: string, request_url: string): URL;
1
+ export { get_origin_url, create_redirect_url } from 'hazo_core';
23
2
  //# sourceMappingURL=get_origin_url.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get_origin_url.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/get_origin_url.ts"],"names":[],"mappings":"AAKA;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8B1D;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,GAAG,CAG1E"}
1
+ {"version":3,"file":"get_origin_url.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/get_origin_url.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC"}
@@ -1,57 +1,5 @@
1
- // file_description: Resolves the public-facing origin URL for constructing redirects
2
- // When running behind a reverse proxy (Cloudflare, nginx), request.url resolves to
3
- // the internal address (e.g. http://localhost:3000). This utility returns the correct
4
- // public origin using NEXTAUTH_URL, falling back to request.url.
5
- /**
6
- * Gets the public-facing origin URL for redirect construction.
7
- *
8
- * Behind reverse proxies (Cloudflare, nginx, etc.), `request.url` contains the
9
- * internal address (e.g. `http://localhost:3000`), not the public domain.
10
- * This function returns the correct origin from environment variables.
11
- *
12
- * Priority: NEXTAUTH_URL > APP_DOMAIN_NAME > NEXT_PUBLIC_APP_URL > APP_URL > request.url
13
- *
14
- * @param request_url - The request.url to use as fallback
15
- * @returns The origin URL (e.g. "https://gotimer.org")
16
- */
17
- export function get_origin_url(request_url) {
18
- // NEXTAUTH_URL is the standard for NextAuth.js apps
19
- const nextauth_url = process.env.NEXTAUTH_URL;
20
- if (nextauth_url) {
21
- return nextauth_url.replace(/\/$/, "");
22
- }
23
- // APP_DOMAIN_NAME (with protocol handling)
24
- const app_domain = process.env.APP_DOMAIN_NAME;
25
- if (app_domain) {
26
- const domain = app_domain.trim();
27
- if (domain.startsWith("http://") || domain.startsWith("https://")) {
28
- return domain.replace(/\/$/, "");
29
- }
30
- return `https://${domain}`;
31
- }
32
- // Other common env vars
33
- const env_url = process.env.NEXT_PUBLIC_APP_URL || process.env.APP_URL;
34
- if (env_url) {
35
- return env_url.replace(/\/$/, "");
36
- }
37
- // Fallback to request.url (works in development without a proxy)
38
- try {
39
- const url = new URL(request_url);
40
- return url.origin;
41
- }
42
- catch (_a) {
43
- return request_url;
44
- }
45
- }
46
- /**
47
- * Creates a URL using the public-facing origin instead of request.url.
48
- * Drop-in replacement for `new URL(path, request.url)` in route handlers.
49
- *
50
- * @param path - The path or relative URL (e.g. "/hazo_auth/login")
51
- * @param request_url - The request.url (used as fallback only)
52
- * @returns A URL object with the correct public origin
53
- */
54
- export function create_redirect_url(path, request_url) {
55
- const origin = get_origin_url(request_url);
56
- return new URL(path, origin);
57
- }
1
+ // file_description: Re-exports get_origin_url and create_redirect_url from hazo_core.
2
+ // Canonical location moved to hazo_core/http in hazo_core v1.
3
+ // This re-export maintains backward compatibility for hazo_auth consumers.
4
+ // Will be removed in hazo_auth v9 import from 'hazo_core' directly.
5
+ export { get_origin_url, create_redirect_url } from 'hazo_core';
@@ -1,4 +1,3 @@
1
- import { type ClassValue } from "clsx";
2
- export declare function merge_class_names(...inputs: ClassValue[]): string;
3
- export declare const cn: (...inputs: ClassValue[]) => string;
1
+ export { cn } from "hazo_ui";
2
+ export { cn as merge_class_names } from "hazo_ui";
4
3
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,UAAU,EAAE,MAAM,MAAM,CAAC;AAI7C,wBAAgB,iBAAiB,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,UAExD;AAGD,eAAO,MAAM,EAAE,GAAI,GAAG,QAAQ,UAAU,EAAE,WAAiC,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/lib/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAG7B,OAAO,EAAE,EAAE,IAAI,iBAAiB,EAAE,MAAM,SAAS,CAAC"}
package/dist/lib/utils.js CHANGED
@@ -1,9 +1,4 @@
1
- // file_description: provide shared utility helpers for the hazo_auth project
2
- import { clsx } from "clsx";
3
- import { twMerge } from "tailwind-merge";
4
- // section: tailwind_merge_helper
5
- export function merge_class_names(...inputs) {
6
- return twMerge(clsx(inputs));
7
- }
8
- // section: shadcn_compatibility_helper
9
- export const cn = (...inputs) => merge_class_names(...inputs);
1
+ // file_description: re-exports cn and merge_class_names from hazo_ui (canonical source)
2
+ export { cn } from "hazo_ui";
3
+ // merge_class_names alias kept for backward compatibility
4
+ export { cn as merge_class_names } from "hazo_ui";
@@ -1,8 +1,3 @@
1
- export { LoginPage, type LoginPageProps } from "./login.js";
2
- export { RegisterPage, type RegisterPageProps } from "./register.js";
3
- export { ForgotPasswordPage, type ForgotPasswordPageProps } from "./forgot_password.js";
4
- export { ResetPasswordPage, type ResetPasswordPageProps } from "./reset_password.js";
5
- export { VerifyEmailPage, type VerifyEmailPageProps } from "./verify_email.js";
6
1
  export { MySettingsPage, type MySettingsPageProps } from "./my_settings.js";
7
2
  export { CreateFirmPage, type CreateFirmPageProps } from "./create_firm.js";
8
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/page_components/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,SAAS,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,KAAK,uBAAuB,EAAE,MAAM,mBAAmB,CAAC;AACrF,OAAO,EAAE,iBAAiB,EAAE,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/page_components/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
@@ -1,10 +1,5 @@
1
1
  // file_description: barrel export for zero-config page components
2
2
  // These components can be used directly by consumers with sensible defaults
3
3
  // section: page_exports
4
- export { LoginPage } from "./login.js";
5
- export { RegisterPage } from "./register.js";
6
- export { ForgotPasswordPage } from "./forgot_password.js";
7
- export { ResetPasswordPage } from "./reset_password.js";
8
- export { VerifyEmailPage } from "./verify_email.js";
9
4
  export { MySettingsPage } from "./my_settings.js";
10
5
  export { CreateFirmPage } from "./create_firm.js";
@@ -4,7 +4,7 @@ import fs from "fs";
4
4
  import path from "path";
5
5
  import axios from "axios";
6
6
  import { HazoConfig } from "hazo_config/server";
7
- import { createLogger } from "hazo_logs";
7
+ import { createLogger } from "hazo_core";
8
8
  const is_string_record = (value) => !!value &&
9
9
  typeof value === "object" &&
10
10
  !Array.isArray(value) &&
@@ -268,7 +268,7 @@ export const load_runtime_configuration = (options) => {
268
268
  const fallback_logger = createLogger("hazo_auth_config");
269
269
  const parsed_options = sanitize_configuration_options(options, fallback_logger);
270
270
  const direct_configuration = parsed_options.direct_configuration;
271
- const logger = (_a = direct_configuration === null || direct_configuration === void 0 ? void 0 : direct_configuration.logger) !== null && _a !== void 0 ? _a : fallback_logger;
271
+ const logger = ((_a = direct_configuration === null || direct_configuration === void 0 ? void 0 : direct_configuration.logger) !== null && _a !== void 0 ? _a : fallback_logger);
272
272
  let hazo_config;
273
273
  try {
274
274
  const config_file_path = (_b = parsed_options === null || parsed_options === void 0 ? void 0 : parsed_options.config_file_path) !== null && _b !== void 0 ? _b : default_config_path;
@@ -3,7 +3,7 @@ var _a;
3
3
  // section: imports
4
4
  import http from "http";
5
5
  import { create_server_app } from "./server.js";
6
- import { createLogger } from "hazo_logs";
6
+ import { createLogger } from "hazo_core";
7
7
  // section: constants
8
8
  const default_port = Number((_a = process.env.PORT) !== null && _a !== void 0 ? _a : 4100);
9
9
  // section: bootstrap_runner
@@ -34,6 +34,9 @@ export { POST as relationshipUpgradePOST } from "./relationship_upgrade.js";
34
34
  export { POST as pinLoginPOST } from "./pin_login.js";
35
35
  export { otpRequestPOST } from "./otp/request.js";
36
36
  export { otpVerifyPOST } from "./otp/verify.js";
37
+ export { legalDocsGET } from './legal_docs_get.js';
38
+ export { legalDocsAcceptPOST } from './legal_docs_accept.js';
39
+ export { legalDocsPublishPOST } from './legal_docs_publish.js';
37
40
  export { consentMeGET } from "./consent_me.js";
38
41
  export { stringsDefaultsGET } from "./strings_defaults.js";
39
42
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/routes/index.ts"],"names":[],"mappings":"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"}
@@ -48,6 +48,10 @@ export { POST as pinLoginPOST } from "./pin_login.js";
48
48
  // OTP sign-in routes
49
49
  export { otpRequestPOST } from "./otp/request.js";
50
50
  export { otpVerifyPOST } from "./otp/verify.js";
51
+ // Legal docs routes
52
+ export { legalDocsGET } from './legal_docs_get.js';
53
+ export { legalDocsAcceptPOST } from './legal_docs_accept.js';
54
+ export { legalDocsPublishPOST } from './legal_docs_publish.js';
51
55
  // Consent routes
52
56
  export { consentMeGET } from "./consent_me.js";
53
57
  // Strings routes
@@ -0,0 +1,3 @@
1
+ import { NextRequest, NextResponse } from 'next/server';
2
+ export declare function legalDocsAcceptPOST(request: NextRequest): Promise<NextResponse>;
3
+ //# sourceMappingURL=legal_docs_accept.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"legal_docs_accept.d.ts","sourceRoot":"","sources":["../../../src/server/routes/legal_docs_accept.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CA0CrF"}
@@ -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":"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;
@@ -1 +1 @@
1
- {"version":3,"file":"remove_profile_picture.d.ts","sourceRoot":"","sources":["../../../src/server/routes/remove_profile_picture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAOxD,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;;IAkGhD"}
1
+ {"version":3,"file":"remove_profile_picture.d.ts","sourceRoot":"","sources":["../../../src/server/routes/remove_profile_picture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAQxD,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;;IAsGhD"}
@@ -5,6 +5,7 @@ import { get_hazo_connect_instance } from "../../lib/hazo_connect_instance.serve
5
5
  import { create_app_logger } from "../../lib/app_logger.js";
6
6
  import { remove_user_profile_picture } from "../../lib/services/profile_picture_remove_service.js";
7
7
  import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
8
+ import { optional_import } from "hazo_core";
8
9
  // section: api_handler
9
10
  export async function DELETE(request) {
10
11
  const logger = create_app_logger();
@@ -36,7 +37,11 @@ export async function DELETE(request) {
36
37
  return NextResponse.json({ error: "Relationship accounts not enabled" }, { status: 403 });
37
38
  }
38
39
  const hazoConnect_rel = get_hazo_connect_instance();
39
- const { createCrudService } = await import("hazo_connect/server");
40
+ const hazo_connect_module = await optional_import("hazo_connect/server");
41
+ if (!hazo_connect_module) {
42
+ return NextResponse.json({ error: "hazo_connect not available" }, { status: 503 });
43
+ }
44
+ const { createCrudService } = hazo_connect_module;
40
45
  const rel_service = createCrudService(hazoConnect_rel, "hazo_user_relationships");
41
46
  const rels = await rel_service.findBy({ parent_user_id: user_id, child_user_id: target_user_id });
42
47
  if (!rels || rels.length === 0) {
@@ -1 +1 @@
1
- {"version":3,"file":"upload_profile_picture.d.ts","sourceRoot":"","sources":["../../../src/server/routes/upload_profile_picture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAaxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;IAkR9C"}
1
+ {"version":3,"file":"upload_profile_picture.d.ts","sourceRoot":"","sources":["../../../src/server/routes/upload_profile_picture.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAcxD,wBAAsB,IAAI,CAAC,OAAO,EAAE,WAAW;;;;;;IAsR9C"}
@@ -9,6 +9,7 @@ import { update_user_profile_picture } from "../../lib/services/profile_picture_
9
9
  import { createCrudService } from "hazo_connect/server";
10
10
  import { map_db_source_to_ui } from "../../lib/services/profile_picture_source_mapper.js";
11
11
  import { get_filename, get_line_number } from "../../lib/utils/api_route_helpers.js";
12
+ import { optional_import } from "hazo_core";
12
13
  import fs from "fs";
13
14
  import path from "path";
14
15
  // section: api_handler
@@ -42,7 +43,11 @@ export async function POST(request) {
42
43
  return NextResponse.json({ error: "Relationship accounts not enabled" }, { status: 403 });
43
44
  }
44
45
  const hazoConnect = get_hazo_connect_instance();
45
- const { createCrudService: createRelCrudService } = await import("hazo_connect/server");
46
+ const hazo_connect_module = await optional_import("hazo_connect/server");
47
+ if (!hazo_connect_module) {
48
+ return NextResponse.json({ error: "hazo_connect not available" }, { status: 503 });
49
+ }
50
+ const { createCrudService: createRelCrudService } = hazo_connect_module;
46
51
  const rel_service = createRelCrudService(hazoConnect, "hazo_user_relationships");
47
52
  const rels = await rel_service.findBy({ parent_user_id: user_id, child_user_id: target_user_id });
48
53
  if (!rels || rels.length === 0) {
@@ -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" | "none" | "outdated";
29
30
  }[];
30
31
  }>>;
31
32
  /**
@@ -47,8 +48,7 @@ export declare function POST(request: NextRequest): Promise<NextResponse<{
47
48
  /**
48
49
  * DELETE - Hard-delete a user from hazo_users (cascades to all related rows).
49
50
  * Body: { user_id: string }
50
- * Requires: admin_user_management permission (enforced by UI, not here — same
51
- * pattern as PATCH/POST in this file which also don't re-auth).
51
+ * Requires: admin_user_management permission.
52
52
  */
53
53
  export declare function DELETE(request: NextRequest): Promise<NextResponse<{
54
54
  error: string;
@@ -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;AAED;;;;;GAKG;AACH,wBAAsB,MAAM,CAAC,OAAO,EAAE,WAAW;;;;IAuDhD"}
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 });
@@ -244,14 +279,23 @@ export async function POST(request) {
244
279
  /**
245
280
  * DELETE - Hard-delete a user from hazo_users (cascades to all related rows).
246
281
  * Body: { user_id: string }
247
- * Requires: admin_user_management permission (enforced by UI, not here — same
248
- * pattern as PATCH/POST in this file which also don't re-auth).
282
+ * Requires: admin_user_management permission.
249
283
  */
250
284
  export async function DELETE(request) {
251
285
  const logger = create_app_logger();
252
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
+ }
253
294
  const body = await request.json();
254
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
+ }
255
299
  if (!user_id) {
256
300
  return NextResponse.json({ error: "user_id is required" }, { status: 400 });
257
301
  }
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAK3C,eAAO,MAAM,iBAAiB,QAAO,WAcpC,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/server/server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAM3C,eAAO,MAAM,iBAAiB,QAAO,WAoBpC,CAAC"}
@@ -7,6 +7,7 @@ import cookie_parser from "cookie-parser";
7
7
  import compression from "compression";
8
8
  import { create_root_router } from "./routes/root_router.js";
9
9
  import { create_app_context } from "./config/config_loader.js";
10
+ import { withContext, generateRequestId, REQUEST_ID_HEADER } from "hazo_core";
10
11
  // section: app_factory
11
12
  export const create_server_app = () => {
12
13
  const server_app = express();
@@ -15,6 +16,12 @@ export const create_server_app = () => {
15
16
  server_app.use(express.json({ limit: "1mb" }));
16
17
  server_app.use(express.urlencoded({ extended: true }));
17
18
  server_app.use(cookie_parser());
19
+ server_app.use((request, response, next) => {
20
+ var _a;
21
+ const correlationId = (_a = request.headers[REQUEST_ID_HEADER]) !== null && _a !== void 0 ? _a : generateRequestId();
22
+ response.setHeader(REQUEST_ID_HEADER, correlationId);
23
+ withContext({ correlationId }, () => next());
24
+ });
18
25
  server_app.use(compression());
19
26
  server_app.use((request, _response, next) => {
20
27
  request.context = create_app_context();