hazo_auth 6.0.0 → 7.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 (256) hide show
  1. package/README.md +233 -8
  2. package/SETUP_CHECKLIST.md +240 -0
  3. package/cli-src/cli/validate.ts +4 -0
  4. package/cli-src/lib/auth/nextauth_config.ts +101 -1
  5. package/cli-src/lib/cookies_config.server.ts +1 -0
  6. package/cli-src/lib/email_verification_config.server.ts +0 -34
  7. package/cli-src/lib/forgot_password_config.server.ts +0 -34
  8. package/cli-src/lib/login_config.server.ts +14 -31
  9. package/cli-src/lib/my_settings_config.server.ts +0 -3
  10. package/cli-src/lib/oauth_config.server.ts +58 -0
  11. package/cli-src/lib/otp_config.server.ts +91 -0
  12. package/cli-src/lib/register_config.server.ts +11 -31
  13. package/cli-src/lib/reset_password_config.server.ts +0 -31
  14. package/cli-src/lib/services/email_service.ts +3 -1
  15. package/cli-src/lib/services/email_template_manifest.ts +17 -0
  16. package/cli-src/lib/services/email_templates/otp_signin_code.html +13 -0
  17. package/cli-src/lib/services/email_templates/otp_signin_code.txt +5 -0
  18. package/cli-src/lib/services/index.ts +8 -2
  19. package/cli-src/lib/services/oauth_service.ts +197 -0
  20. package/cli-src/lib/services/otp_service.ts +295 -0
  21. package/cli-src/lib/services/session_token_service.ts +4 -1
  22. package/config/hazo_auth_config.example.ini +76 -41
  23. package/dist/cli/validate.d.ts.map +1 -1
  24. package/dist/cli/validate.js +4 -0
  25. package/dist/client.d.ts +2 -0
  26. package/dist/client.d.ts.map +1 -1
  27. package/dist/client.js +1 -0
  28. package/dist/components/layouts/create_firm/index.d.ts +4 -8
  29. package/dist/components/layouts/create_firm/index.d.ts.map +1 -1
  30. package/dist/components/layouts/create_firm/index.js +3 -3
  31. package/dist/components/layouts/email_verification/index.d.ts +4 -5
  32. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  33. package/dist/components/layouts/email_verification/index.js +4 -4
  34. package/dist/components/layouts/forgot_password/index.d.ts +4 -5
  35. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  36. package/dist/components/layouts/forgot_password/index.js +2 -2
  37. package/dist/components/layouts/login/index.d.ts +19 -9
  38. package/dist/components/layouts/login/index.d.ts.map +1 -1
  39. package/dist/components/layouts/login/index.js +12 -6
  40. package/dist/components/layouts/otp/index.d.ts +17 -0
  41. package/dist/components/layouts/otp/index.d.ts.map +1 -0
  42. package/dist/components/layouts/otp/index.js +16 -0
  43. package/dist/components/layouts/register/index.d.ts +11 -7
  44. package/dist/components/layouts/register/index.d.ts.map +1 -1
  45. package/dist/components/layouts/register/index.js +8 -4
  46. package/dist/components/layouts/reset_password/index.d.ts +4 -5
  47. package/dist/components/layouts/reset_password/index.d.ts.map +1 -1
  48. package/dist/components/layouts/reset_password/index.js +5 -5
  49. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts +3 -5
  50. package/dist/components/layouts/shared/components/already_logged_in_guard.d.ts.map +1 -1
  51. package/dist/components/layouts/shared/components/already_logged_in_guard.js +2 -2
  52. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts +25 -0
  53. package/dist/components/layouts/shared/components/facebook_sign_in_button.d.ts.map +1 -0
  54. package/dist/components/layouts/shared/components/facebook_sign_in_button.js +49 -0
  55. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  56. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +8 -3
  57. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts +3 -6
  58. package/dist/components/layouts/shared/components/two_column_auth_layout.d.ts.map +1 -1
  59. package/dist/components/layouts/shared/components/two_column_auth_layout.js +8 -5
  60. package/dist/components/otp/OTPRequestForm.d.ts +11 -0
  61. package/dist/components/otp/OTPRequestForm.d.ts.map +1 -0
  62. package/dist/components/otp/OTPRequestForm.js +42 -0
  63. package/dist/components/otp/OTPVerifyForm.d.ts +16 -0
  64. package/dist/components/otp/OTPVerifyForm.d.ts.map +1 -0
  65. package/dist/components/otp/OTPVerifyForm.js +75 -0
  66. package/dist/components/otp/index.d.ts +5 -0
  67. package/dist/components/otp/index.d.ts.map +1 -0
  68. package/dist/components/otp/index.js +2 -0
  69. package/dist/components/ui/input-otp.d.ts +35 -0
  70. package/dist/components/ui/input-otp.d.ts.map +1 -0
  71. package/dist/components/ui/input-otp.js +44 -0
  72. package/dist/consent/consent_state.d.ts +18 -0
  73. package/dist/consent/consent_state.d.ts.map +1 -0
  74. package/dist/consent/consent_state.js +29 -0
  75. package/dist/consent/cookie_consent_banner.d.ts +11 -0
  76. package/dist/consent/cookie_consent_banner.d.ts.map +1 -0
  77. package/dist/consent/cookie_consent_banner.js +40 -0
  78. package/dist/consent/gtm_mapping.d.ts +13 -0
  79. package/dist/consent/gtm_mapping.d.ts.map +1 -0
  80. package/dist/consent/gtm_mapping.js +30 -0
  81. package/dist/consent/index.d.ts +7 -0
  82. package/dist/consent/index.d.ts.map +1 -0
  83. package/dist/consent/index.js +7 -0
  84. package/dist/consent/manage_modal.d.ts +2 -0
  85. package/dist/consent/manage_modal.d.ts.map +1 -0
  86. package/dist/consent/manage_modal.js +33 -0
  87. package/dist/consent/read_consent.d.ts +15 -0
  88. package/dist/consent/read_consent.d.ts.map +1 -0
  89. package/dist/consent/read_consent.js +23 -0
  90. package/dist/consent/use_consent.d.ts +7 -0
  91. package/dist/consent/use_consent.d.ts.map +1 -0
  92. package/dist/consent/use_consent.js +55 -0
  93. package/dist/lib/auth/nextauth_config.d.ts +10 -0
  94. package/dist/lib/auth/nextauth_config.d.ts.map +1 -1
  95. package/dist/lib/auth/nextauth_config.js +80 -2
  96. package/dist/lib/cookies_config.server.d.ts +1 -0
  97. package/dist/lib/cookies_config.server.d.ts.map +1 -1
  98. package/dist/lib/cookies_config.server.js +1 -0
  99. package/dist/lib/email_verification_config.server.d.ts +0 -3
  100. package/dist/lib/email_verification_config.server.d.ts.map +1 -1
  101. package/dist/lib/email_verification_config.server.js +0 -15
  102. package/dist/lib/forgot_password_config.server.d.ts +0 -3
  103. package/dist/lib/forgot_password_config.server.d.ts.map +1 -1
  104. package/dist/lib/forgot_password_config.server.js +0 -15
  105. package/dist/lib/login_config.server.d.ts +6 -3
  106. package/dist/lib/login_config.server.d.ts.map +1 -1
  107. package/dist/lib/login_config.server.js +7 -13
  108. package/dist/lib/my_settings_config.server.d.ts +0 -1
  109. package/dist/lib/my_settings_config.server.d.ts.map +1 -1
  110. package/dist/lib/my_settings_config.server.js +0 -2
  111. package/dist/lib/oauth_config.server.d.ts +17 -0
  112. package/dist/lib/oauth_config.server.d.ts.map +1 -1
  113. package/dist/lib/oauth_config.server.js +25 -0
  114. package/dist/lib/otp_config.server.d.ts +49 -0
  115. package/dist/lib/otp_config.server.d.ts.map +1 -0
  116. package/dist/lib/otp_config.server.js +48 -0
  117. package/dist/lib/register_config.server.d.ts +2 -3
  118. package/dist/lib/register_config.server.d.ts.map +1 -1
  119. package/dist/lib/register_config.server.js +4 -13
  120. package/dist/lib/reset_password_config.server.d.ts +0 -3
  121. package/dist/lib/reset_password_config.server.d.ts.map +1 -1
  122. package/dist/lib/reset_password_config.server.js +0 -13
  123. package/dist/lib/services/email_service.d.ts +1 -1
  124. package/dist/lib/services/email_service.d.ts.map +1 -1
  125. package/dist/lib/services/email_service.js +2 -0
  126. package/dist/lib/services/email_template_manifest.d.ts.map +1 -1
  127. package/dist/lib/services/email_template_manifest.js +17 -0
  128. package/dist/lib/services/email_templates/otp_signin_code.html +13 -0
  129. package/dist/lib/services/email_templates/otp_signin_code.txt +5 -0
  130. package/dist/lib/services/index.d.ts +2 -0
  131. package/dist/lib/services/index.d.ts.map +1 -1
  132. package/dist/lib/services/index.js +1 -0
  133. package/dist/lib/services/oauth_service.d.ts +24 -0
  134. package/dist/lib/services/oauth_service.d.ts.map +1 -1
  135. package/dist/lib/services/oauth_service.js +155 -0
  136. package/dist/lib/services/otp_service.d.ts +46 -0
  137. package/dist/lib/services/otp_service.d.ts.map +1 -0
  138. package/dist/lib/services/otp_service.js +238 -0
  139. package/dist/lib/services/session_token_service.d.ts +3 -1
  140. package/dist/lib/services/session_token_service.d.ts.map +1 -1
  141. package/dist/lib/services/session_token_service.js +4 -2
  142. package/dist/page_components/create_firm.d.ts +13 -1
  143. package/dist/page_components/create_firm.d.ts.map +1 -1
  144. package/dist/page_components/create_firm.js +10 -6
  145. package/dist/page_components/forgot_password.d.ts +1 -4
  146. package/dist/page_components/forgot_password.d.ts.map +1 -1
  147. package/dist/page_components/forgot_password.js +2 -6
  148. package/dist/page_components/login.d.ts +1 -4
  149. package/dist/page_components/login.d.ts.map +1 -1
  150. package/dist/page_components/login.js +2 -6
  151. package/dist/page_components/otp.d.ts +4 -0
  152. package/dist/page_components/otp.d.ts.map +1 -0
  153. package/dist/page_components/otp.js +5 -0
  154. package/dist/page_components/register.d.ts +1 -4
  155. package/dist/page_components/register.d.ts.map +1 -1
  156. package/dist/page_components/register.js +2 -6
  157. package/dist/page_components/reset_password.d.ts +1 -4
  158. package/dist/page_components/reset_password.d.ts.map +1 -1
  159. package/dist/page_components/reset_password.js +2 -6
  160. package/dist/page_components/verify_email.d.ts +1 -4
  161. package/dist/page_components/verify_email.d.ts.map +1 -1
  162. package/dist/page_components/verify_email.js +2 -6
  163. package/dist/server/routes/index.d.ts +3 -0
  164. package/dist/server/routes/index.d.ts.map +1 -1
  165. package/dist/server/routes/index.js +4 -0
  166. package/dist/server/routes/me.d.ts.map +1 -1
  167. package/dist/server/routes/me.js +43 -1
  168. package/dist/server/routes/oauth_facebook_callback.d.ts +8 -0
  169. package/dist/server/routes/oauth_facebook_callback.d.ts.map +1 -0
  170. package/dist/server/routes/oauth_facebook_callback.js +157 -0
  171. package/dist/server/routes/oauth_google_callback.js +1 -1
  172. package/dist/server/routes/otp/request.d.ts +3 -0
  173. package/dist/server/routes/otp/request.d.ts.map +1 -0
  174. package/dist/server/routes/otp/request.js +33 -0
  175. package/dist/server/routes/otp/verify.d.ts +3 -0
  176. package/dist/server/routes/otp/verify.d.ts.map +1 -0
  177. package/dist/server/routes/otp/verify.js +58 -0
  178. package/dist/server-lib.d.ts +3 -0
  179. package/dist/server-lib.d.ts.map +1 -1
  180. package/dist/server-lib.js +2 -0
  181. package/dist/server_pages/forgot_password.d.ts +13 -17
  182. package/dist/server_pages/forgot_password.d.ts.map +1 -1
  183. package/dist/server_pages/forgot_password.js +12 -8
  184. package/dist/server_pages/forgot_password_client_wrapper.d.ts +7 -6
  185. package/dist/server_pages/forgot_password_client_wrapper.d.ts.map +1 -1
  186. package/dist/server_pages/forgot_password_client_wrapper.js +2 -2
  187. package/dist/server_pages/login.d.ts +22 -21
  188. package/dist/server_pages/login.d.ts.map +1 -1
  189. package/dist/server_pages/login.js +15 -19
  190. package/dist/server_pages/login_client_wrapper.d.ts +10 -6
  191. package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
  192. package/dist/server_pages/login_client_wrapper.js +2 -2
  193. package/dist/server_pages/my_settings.d.ts +2 -0
  194. package/dist/server_pages/my_settings.d.ts.map +1 -1
  195. package/dist/server_pages/my_settings.js +8 -2
  196. package/dist/server_pages/otp.d.ts +56 -0
  197. package/dist/server_pages/otp.d.ts.map +1 -0
  198. package/dist/server_pages/otp.js +45 -0
  199. package/dist/server_pages/register.d.ts +19 -16
  200. package/dist/server_pages/register.d.ts.map +1 -1
  201. package/dist/server_pages/register.js +15 -12
  202. package/dist/server_pages/register_client_wrapper.d.ts +10 -6
  203. package/dist/server_pages/register_client_wrapper.d.ts.map +1 -1
  204. package/dist/server_pages/register_client_wrapper.js +2 -2
  205. package/dist/server_pages/reset_password.d.ts +11 -16
  206. package/dist/server_pages/reset_password.d.ts.map +1 -1
  207. package/dist/server_pages/reset_password.js +11 -9
  208. package/dist/server_pages/reset_password_client_wrapper.d.ts +7 -6
  209. package/dist/server_pages/reset_password_client_wrapper.d.ts.map +1 -1
  210. package/dist/server_pages/reset_password_client_wrapper.js +2 -2
  211. package/dist/server_pages/verify_email.d.ts +11 -17
  212. package/dist/server_pages/verify_email.d.ts.map +1 -1
  213. package/dist/server_pages/verify_email.js +11 -8
  214. package/dist/server_pages/verify_email_client_wrapper.d.ts +7 -6
  215. package/dist/server_pages/verify_email_client_wrapper.d.ts.map +1 -1
  216. package/dist/server_pages/verify_email_client_wrapper.js +2 -2
  217. package/dist/strings/default_strings.d.ts +47 -0
  218. package/dist/strings/default_strings.d.ts.map +1 -0
  219. package/dist/strings/default_strings.js +18 -0
  220. package/dist/strings/index.d.ts +4 -0
  221. package/dist/strings/index.d.ts.map +1 -0
  222. package/dist/strings/index.js +3 -0
  223. package/dist/strings/strings_context.d.ts +12 -0
  224. package/dist/strings/strings_context.d.ts.map +1 -0
  225. package/dist/strings/strings_context.js +23 -0
  226. package/dist/strings/strings_provider.d.ts +26 -0
  227. package/dist/strings/strings_provider.d.ts.map +1 -0
  228. package/dist/strings/strings_provider.js +45 -0
  229. package/dist/theme/create_theme.d.ts +7 -0
  230. package/dist/theme/create_theme.d.ts.map +1 -0
  231. package/dist/theme/create_theme.js +97 -0
  232. package/dist/theme/hex_to_hsl.d.ts +16 -0
  233. package/dist/theme/hex_to_hsl.d.ts.map +1 -0
  234. package/dist/theme/hex_to_hsl.js +110 -0
  235. package/dist/theme/index.d.ts +4 -0
  236. package/dist/theme/index.d.ts.map +1 -0
  237. package/dist/theme/index.js +3 -0
  238. package/dist/theme/luminance.d.ts +11 -0
  239. package/dist/theme/luminance.d.ts.map +1 -0
  240. package/dist/theme/luminance.js +45 -0
  241. package/dist/theme/theme_provider.d.ts +14 -0
  242. package/dist/theme/theme_provider.d.ts.map +1 -0
  243. package/dist/theme/theme_provider.js +23 -0
  244. package/dist/theme/theme_types.d.ts +36 -0
  245. package/dist/theme/theme_types.d.ts.map +1 -0
  246. package/dist/theme/theme_types.js +1 -0
  247. package/dist/themes/index.d.ts +3 -0
  248. package/dist/themes/index.d.ts.map +1 -0
  249. package/dist/themes/index.js +2 -0
  250. package/dist/themes/preset_indigo_sunset.d.ts +3 -0
  251. package/dist/themes/preset_indigo_sunset.d.ts.map +1 -0
  252. package/dist/themes/preset_indigo_sunset.js +20 -0
  253. package/dist/themes/preset_neutral.d.ts +3 -0
  254. package/dist/themes/preset_neutral.d.ts.map +1 -0
  255. package/dist/themes/preset_neutral.js +14 -0
  256. package/package.json +36 -2
@@ -0,0 +1,44 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
+ import * as React from "react";
15
+ import { OTPInput, OTPInputContext } from "input-otp";
16
+ import { Minus } from "lucide-react";
17
+ import { cn } from "../../lib/utils.js";
18
+ const InputOTP = React.forwardRef((_a, ref) => {
19
+ var { className, containerClassName } = _a, props = __rest(_a, ["className", "containerClassName"]);
20
+ return (_jsx(OTPInput, Object.assign({ ref: ref, containerClassName: cn("flex items-center gap-2 has-[:disabled]:opacity-50", containerClassName), className: cn("disabled:cursor-not-allowed", className) }, props)));
21
+ });
22
+ InputOTP.displayName = "InputOTP";
23
+ const InputOTPGroup = React.forwardRef((_a, ref) => {
24
+ var { className } = _a, props = __rest(_a, ["className"]);
25
+ return (_jsx("div", Object.assign({ ref: ref, className: cn("flex items-center", className) }, props)));
26
+ });
27
+ InputOTPGroup.displayName = "InputOTPGroup";
28
+ const InputOTPSlot = React.forwardRef((_a, ref) => {
29
+ var _b;
30
+ var { index, className } = _a, props = __rest(_a, ["index", "className"]);
31
+ const inputOTPContext = React.useContext(OTPInputContext);
32
+ const slot = (_b = inputOTPContext === null || inputOTPContext === void 0 ? void 0 : inputOTPContext.slots) === null || _b === void 0 ? void 0 : _b[index];
33
+ const char = slot === null || slot === void 0 ? void 0 : slot.char;
34
+ const hasFakeCaret = slot === null || slot === void 0 ? void 0 : slot.hasFakeCaret;
35
+ const isActive = slot === null || slot === void 0 ? void 0 : slot.isActive;
36
+ return (_jsxs("div", Object.assign({ ref: ref, className: cn("relative flex h-10 w-10 items-center justify-center border-y border-r border-input text-sm transition-all first:rounded-l-md first:border-l last:rounded-r-md", isActive && "z-10 ring-2 ring-ring ring-offset-background", className) }, props, { children: [char, hasFakeCaret && (_jsx("div", { className: "pointer-events-none absolute inset-0 flex items-center justify-center", children: _jsx("div", { className: "h-4 w-px animate-caret-blink bg-foreground duration-1000" }) }))] })));
37
+ });
38
+ InputOTPSlot.displayName = "InputOTPSlot";
39
+ const InputOTPSeparator = React.forwardRef((_a, ref) => {
40
+ var props = __rest(_a, []);
41
+ return (_jsx("div", Object.assign({ ref: ref, role: "separator" }, props, { children: _jsx(Minus, {}) })));
42
+ });
43
+ InputOTPSeparator.displayName = "InputOTPSeparator";
44
+ export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };
@@ -0,0 +1,18 @@
1
+ export interface ConsentState {
2
+ necessary: true;
3
+ functional: boolean;
4
+ analytics: boolean;
5
+ marketing: boolean;
6
+ version: 1;
7
+ }
8
+ export declare const HAZO_CONSENT_COOKIE_NAME = "hazo_consent_v1";
9
+ /**
10
+ * Parse a URL-encoded JSON cookie value into a ConsentState.
11
+ * Returns null if the value is invalid or has an unexpected shape.
12
+ */
13
+ export declare function parse_consent(value: string): ConsentState | null;
14
+ /**
15
+ * Serialize a ConsentState to a URL-encoded JSON string suitable for cookie storage.
16
+ */
17
+ export declare function serialize_consent(state: ConsentState): string;
18
+ //# sourceMappingURL=consent_state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent_state.d.ts","sourceRoot":"","sources":["../../src/consent/consent_state.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,IAAI,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,CAAC,CAAC;CACZ;AAED,eAAO,MAAM,wBAAwB,oBAAoB,CAAC;AAE1D;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAgBhE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAE7D"}
@@ -0,0 +1,29 @@
1
+ // file_description: isomorphic consent state types, parser, and serializer — no Node.js or browser-specific imports
2
+ export const HAZO_CONSENT_COOKIE_NAME = "hazo_consent_v1";
3
+ /**
4
+ * Parse a URL-encoded JSON cookie value into a ConsentState.
5
+ * Returns null if the value is invalid or has an unexpected shape.
6
+ */
7
+ export function parse_consent(value) {
8
+ try {
9
+ const decoded = decodeURIComponent(value);
10
+ const parsed = JSON.parse(decoded);
11
+ // Validate shape
12
+ if (parsed.version !== 1 ||
13
+ parsed.necessary !== true ||
14
+ typeof parsed.functional !== "boolean" ||
15
+ typeof parsed.analytics !== "boolean" ||
16
+ typeof parsed.marketing !== "boolean")
17
+ return null;
18
+ return parsed;
19
+ }
20
+ catch (_a) {
21
+ return null;
22
+ }
23
+ }
24
+ /**
25
+ * Serialize a ConsentState to a URL-encoded JSON string suitable for cookie storage.
26
+ */
27
+ export function serialize_consent(state) {
28
+ return encodeURIComponent(JSON.stringify(state));
29
+ }
@@ -0,0 +1,11 @@
1
+ import { type ConsentState } from "./consent_state.js";
2
+ interface CookieConsentBannerProps {
3
+ enableGTM?: boolean;
4
+ gtmContainerId?: string;
5
+ onChange?: (state: ConsentState) => void;
6
+ /** Default: "bottom" */
7
+ position?: "bottom" | "top";
8
+ }
9
+ export declare function CookieConsentBanner({ enableGTM, gtmContainerId, onChange, position, }: CookieConsentBannerProps): import("react/jsx-runtime").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=cookie_consent_banner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cookie_consent_banner.d.ts","sourceRoot":"","sources":["../../src/consent/cookie_consent_banner.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKpD,UAAU,wBAAwB;IAChC,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,wBAAwB;IACxB,QAAQ,CAAC,EAAE,QAAQ,GAAG,KAAK,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,SAAS,EACT,cAAc,EACd,QAAQ,EACR,QAAmB,GACpB,EAAE,wBAAwB,2CA4E1B"}
@@ -0,0 +1,40 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ // file_description: cookie consent banner — shown until the user makes a consent choice; renders manage modal afterward
4
+ import { useEffect, useRef } from "react";
5
+ import { useConsent } from "./use_consent.js";
6
+ import { ConsentManageModal } from "./manage_modal.js";
7
+ import { to_gtm_signals, gtm_default_payload } from "./gtm_mapping.js";
8
+ export function CookieConsentBanner({ enableGTM, gtmContainerId, onChange, position = "bottom", }) {
9
+ const { consent, set_consent, open_manager } = useConsent();
10
+ const gtm_default_pushed = useRef(false);
11
+ // Push consent_default to GTM on first mount (before user has consented)
12
+ useEffect(() => {
13
+ if (!enableGTM || !gtmContainerId)
14
+ return;
15
+ if (gtm_default_pushed.current)
16
+ return;
17
+ gtm_default_pushed.current = true;
18
+ window.dataLayer = window.dataLayer || [];
19
+ window.dataLayer.push(Object.assign({ event: "consent_default" }, gtm_default_payload()));
20
+ // eslint-disable-next-line react-hooks/exhaustive-deps
21
+ }, []); // only on mount
22
+ // Push consent_update to GTM whenever the user's consent changes
23
+ useEffect(() => {
24
+ if (!consent)
25
+ return; // no state yet — don't push
26
+ onChange === null || onChange === void 0 ? void 0 : onChange(consent);
27
+ if (enableGTM && gtmContainerId) {
28
+ window.dataLayer = window.dataLayer || [];
29
+ window.dataLayer.push(Object.assign({ event: "consent_update" }, to_gtm_signals(consent)));
30
+ }
31
+ // onChange is intentionally excluded to avoid infinite loops with unstable prop refs
32
+ // eslint-disable-next-line react-hooks/exhaustive-deps
33
+ }, [consent, enableGTM, gtmContainerId]);
34
+ // Consent already captured — only render the modal so open_manager() still works
35
+ if (consent !== null) {
36
+ return _jsx(ConsentManageModal, {});
37
+ }
38
+ const positionClass = position === "top" ? "top-0" : "bottom-0";
39
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: `fixed ${positionClass} left-0 right-0 z-40 bg-primary text-primary-foreground p-4 flex flex-wrap items-center gap-3 justify-between`, children: [_jsx("p", { className: "text-sm flex-1 min-w-[200px]", children: "We use cookies to improve your experience. By continuing, you agree to our use of cookies." }), _jsxs("div", { className: "flex gap-2 flex-wrap", children: [_jsx("button", { onClick: () => set_consent({ functional: false, analytics: false, marketing: false }), className: "px-3 py-1.5 text-xs bg-primary-foreground/20 hover:bg-primary-foreground/30 rounded text-primary-foreground", children: "Decline all" }), _jsx("button", { onClick: () => open_manager(), className: "px-3 py-1.5 text-xs bg-primary-foreground/20 hover:bg-primary-foreground/30 rounded text-primary-foreground", children: "Manage" }), _jsx("button", { onClick: () => set_consent({ functional: true, analytics: true, marketing: true }), className: "px-3 py-1.5 text-xs bg-primary-foreground rounded text-primary font-medium", children: "Accept all" })] })] }), _jsx(ConsentManageModal, {})] }));
40
+ }
@@ -0,0 +1,13 @@
1
+ import type { ConsentState } from "./consent_state";
2
+ export type GtmSignal = "security_storage" | "functionality_storage" | "personalization_storage" | "analytics_storage" | "ad_storage" | "ad_user_data" | "ad_personalization";
3
+ /**
4
+ * Maps a ConsentState to GTM consent signals.
5
+ * security_storage is always granted; other signals follow the user's category choices.
6
+ */
7
+ export declare function to_gtm_signals(state: ConsentState): Record<GtmSignal, "granted" | "denied">;
8
+ /**
9
+ * Default GTM consent payload before the user has made a choice.
10
+ * security_storage is granted; all others are denied.
11
+ */
12
+ export declare function gtm_default_payload(): Record<GtmSignal, "granted" | "denied">;
13
+ //# sourceMappingURL=gtm_mapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gtm_mapping.d.ts","sourceRoot":"","sources":["../../src/consent/gtm_mapping.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEpD,MAAM,MAAM,SAAS,GACjB,kBAAkB,GAClB,uBAAuB,GACvB,yBAAyB,GACzB,mBAAmB,GACnB,YAAY,GACZ,cAAc,GACd,oBAAoB,CAAC;AAEzB;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,CAAC,CAU3F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAAC,SAAS,EAAE,SAAS,GAAG,QAAQ,CAAC,CAU7E"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Maps a ConsentState to GTM consent signals.
3
+ * security_storage is always granted; other signals follow the user's category choices.
4
+ */
5
+ export function to_gtm_signals(state) {
6
+ return {
7
+ security_storage: "granted", // always granted
8
+ functionality_storage: state.functional ? "granted" : "denied",
9
+ personalization_storage: state.functional ? "granted" : "denied",
10
+ analytics_storage: state.analytics ? "granted" : "denied",
11
+ ad_storage: state.marketing ? "granted" : "denied",
12
+ ad_user_data: state.marketing ? "granted" : "denied",
13
+ ad_personalization: state.marketing ? "granted" : "denied",
14
+ };
15
+ }
16
+ /**
17
+ * Default GTM consent payload before the user has made a choice.
18
+ * security_storage is granted; all others are denied.
19
+ */
20
+ export function gtm_default_payload() {
21
+ return {
22
+ security_storage: "granted",
23
+ functionality_storage: "denied",
24
+ personalization_storage: "denied",
25
+ analytics_storage: "denied",
26
+ ad_storage: "denied",
27
+ ad_user_data: "denied",
28
+ ad_personalization: "denied",
29
+ };
30
+ }
@@ -0,0 +1,7 @@
1
+ export * from "./consent_state.js";
2
+ export * from "./cookie_consent_banner.js";
3
+ export * from "./use_consent.js";
4
+ export * from "./read_consent.js";
5
+ export * from "./gtm_mapping.js";
6
+ export * from "./manage_modal.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/consent/index.ts"],"names":[],"mappings":"AACA,cAAc,iBAAiB,CAAC;AAChC,cAAc,yBAAyB,CAAC;AACxC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,7 @@
1
+ // file_description: barrel export for the hazo_auth consent module
2
+ export * from "./consent_state.js";
3
+ export * from "./cookie_consent_banner.js";
4
+ export * from "./use_consent.js";
5
+ export * from "./read_consent.js";
6
+ export * from "./gtm_mapping.js";
7
+ export * from "./manage_modal.js";
@@ -0,0 +1,2 @@
1
+ export declare function ConsentManageModal(): import("react/jsx-runtime").JSX.Element;
2
+ //# sourceMappingURL=manage_modal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manage_modal.d.ts","sourceRoot":"","sources":["../../src/consent/manage_modal.tsx"],"names":[],"mappings":"AAOA,wBAAgB,kBAAkB,4CA0GjC"}
@@ -0,0 +1,33 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // file_description: modal dialog for managing individual cookie consent categories
4
+ import { useEffect, useState } from "react";
5
+ import * as Dialog from "@radix-ui/react-dialog";
6
+ import { useConsent } from "./use_consent.js";
7
+ export function ConsentManageModal() {
8
+ const { consent, set_consent } = useConsent();
9
+ const [open, setOpen] = useState(false);
10
+ const [local, setLocal] = useState({
11
+ functional: false,
12
+ analytics: false,
13
+ marketing: false,
14
+ });
15
+ // Listen for the open event dispatched by open_manager()
16
+ useEffect(() => {
17
+ const handle = () => {
18
+ setLocal({
19
+ functional: !!(consent === null || consent === void 0 ? void 0 : consent.functional),
20
+ analytics: !!(consent === null || consent === void 0 ? void 0 : consent.analytics),
21
+ marketing: !!(consent === null || consent === void 0 ? void 0 : consent.marketing),
22
+ });
23
+ setOpen(true);
24
+ };
25
+ window.addEventListener("hazo_auth:open_consent_manager", handle);
26
+ return () => window.removeEventListener("hazo_auth:open_consent_manager", handle);
27
+ }, [consent]);
28
+ const save = () => {
29
+ set_consent(Object.assign(Object.assign({}, local), { necessary: true, version: 1 }));
30
+ setOpen(false);
31
+ };
32
+ return (_jsx(Dialog.Root, { open: open, onOpenChange: setOpen, children: _jsxs(Dialog.Portal, { children: [_jsx(Dialog.Overlay, { className: "fixed inset-0 bg-black/50 z-50" }), _jsxs(Dialog.Content, { className: "fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-background rounded-lg p-6 z-50 w-full max-w-md shadow-lg", children: [_jsx(Dialog.Title, { className: "text-lg font-semibold mb-4", children: "Cookie preferences" }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Necessary" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Required for the site to function" })] }), _jsx("input", { type: "checkbox", checked: true, disabled: true, className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Functional" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Remembers your preferences" })] }), _jsx("input", { type: "checkbox", checked: local.functional, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { functional: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3 border-b", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Analytics" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Helps us understand how you use the site" })] }), _jsx("input", { type: "checkbox", checked: local.analytics, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { analytics: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "flex items-center justify-between py-3", children: [_jsxs("div", { children: [_jsx("p", { className: "font-medium", children: "Marketing" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "Used for targeted advertising" })] }), _jsx("input", { type: "checkbox", checked: local.marketing, onChange: (e) => setLocal((p) => (Object.assign(Object.assign({}, p), { marketing: e.target.checked }))), className: "h-4 w-4" })] }), _jsxs("div", { className: "mt-6 flex gap-3 justify-end", children: [_jsx("button", { className: "px-4 py-2 text-sm border rounded-md hover:bg-muted", onClick: () => setOpen(false), children: "Cancel" }), _jsx("button", { className: "px-4 py-2 text-sm bg-primary text-primary-foreground rounded-md hover:opacity-90", onClick: save, children: "Save preferences" })] })] })] }) }));
33
+ }
@@ -0,0 +1,15 @@
1
+ import { type ConsentState } from "./consent_state.js";
2
+ /** Structural type covering both `Headers` and Next.js `ReadonlyHeaders`. */
3
+ type AnyHeaders = {
4
+ get(name: string): string | null;
5
+ };
6
+ /**
7
+ * Reads the consent state from request headers (server-side).
8
+ * Returns null if the consent cookie is absent or contains invalid data.
9
+ *
10
+ * Prefix support (Phase 7): when cookie_prefix config is set, the cookie name
11
+ * is `${prefix}hazo_consent_v1`. Currently uses the base name only.
12
+ */
13
+ export declare function read_consent(headers: AnyHeaders): ConsentState | null;
14
+ export {};
15
+ //# sourceMappingURL=read_consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"read_consent.d.ts","sourceRoot":"","sources":["../../src/consent/read_consent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAA2C,MAAM,iBAAiB,CAAC;AAE7F,6EAA6E;AAC7E,KAAK,UAAU,GAAG;IAAE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC;AAEvD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,UAAU,GAAG,YAAY,GAAG,IAAI,CAcrE"}
@@ -0,0 +1,23 @@
1
+ // file_description: server-side helper that reads consent state from request headers
2
+ import { HAZO_CONSENT_COOKIE_NAME, parse_consent } from "./consent_state.js";
3
+ /**
4
+ * Reads the consent state from request headers (server-side).
5
+ * Returns null if the consent cookie is absent or contains invalid data.
6
+ *
7
+ * Prefix support (Phase 7): when cookie_prefix config is set, the cookie name
8
+ * is `${prefix}hazo_consent_v1`. Currently uses the base name only.
9
+ */
10
+ export function read_consent(headers) {
11
+ const cookie_header = headers.get("cookie");
12
+ if (!cookie_header)
13
+ return null;
14
+ const cookie_name = HAZO_CONSENT_COOKIE_NAME;
15
+ const match = cookie_header
16
+ .split(";")
17
+ .map((c) => c.trim())
18
+ .find((c) => c.startsWith(`${cookie_name}=`));
19
+ if (!match)
20
+ return null;
21
+ const value = match.slice(cookie_name.length + 1);
22
+ return parse_consent(value);
23
+ }
@@ -0,0 +1,7 @@
1
+ import { type ConsentState } from "./consent_state.js";
2
+ export declare function useConsent(): {
3
+ consent: ConsentState | null;
4
+ set_consent: (patch: Partial<ConsentState>) => void;
5
+ open_manager: () => void;
6
+ };
7
+ //# sourceMappingURL=use_consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use_consent.d.ts","sourceRoot":"","sources":["../../src/consent/use_consent.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,YAAY,EAIlB,MAAM,iBAAiB,CAAC;AAmBzB,wBAAgB,UAAU,IAAI;IAC5B,OAAO,EAAE,YAAY,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,KAAK,IAAI,CAAC;IACpD,YAAY,EAAE,MAAM,IAAI,CAAC;CAC1B,CAyCA"}
@@ -0,0 +1,55 @@
1
+ "use client";
2
+ // file_description: client hook to read and update the user's cookie consent state
3
+ import { useState, useEffect, useCallback } from "react";
4
+ import { HAZO_CONSENT_COOKIE_NAME, parse_consent, serialize_consent, } from "./consent_state.js";
5
+ function read_from_cookie() {
6
+ if (typeof document === "undefined")
7
+ return null;
8
+ const match = document.cookie
9
+ .split(";")
10
+ .map((c) => c.trim())
11
+ .find((c) => c.startsWith(`${HAZO_CONSENT_COOKIE_NAME}=`));
12
+ if (!match)
13
+ return null;
14
+ return parse_consent(match.slice(HAZO_CONSENT_COOKIE_NAME.length + 1));
15
+ }
16
+ function write_cookie(state) {
17
+ const value = serialize_consent(state);
18
+ const maxAge = 13 * 30 * 24 * 60 * 60; // ~13 months in seconds
19
+ const secure = location.protocol === "https:" ? "; Secure" : "";
20
+ document.cookie = `${HAZO_CONSENT_COOKIE_NAME}=${value}; Max-Age=${maxAge}; SameSite=Lax; Path=/${secure}`;
21
+ }
22
+ export function useConsent() {
23
+ const [consent, setConsent] = useState(null);
24
+ useEffect(() => {
25
+ // Hydrate from cookie on mount
26
+ setConsent(read_from_cookie());
27
+ // Subscribe to cross-component updates dispatched by other useConsent instances.
28
+ // Read state from event.detail to avoid a redundant cookie parse and prevent
29
+ // a double re-render when the same hook instance dispatches the event itself.
30
+ const handle_update = (e) => {
31
+ const detail = e.detail;
32
+ setConsent(detail);
33
+ };
34
+ window.addEventListener("hazo_auth:consent_update", handle_update);
35
+ return () => window.removeEventListener("hazo_auth:consent_update", handle_update);
36
+ }, []);
37
+ const set_consent = useCallback((patch) => {
38
+ const base = consent !== null && consent !== void 0 ? consent : {
39
+ necessary: true,
40
+ functional: false,
41
+ analytics: false,
42
+ marketing: false,
43
+ version: 1,
44
+ };
45
+ // necessary and version are always forced to their fixed values
46
+ const next = Object.assign(Object.assign(Object.assign({}, base), patch), { necessary: true, version: 1 });
47
+ write_cookie(next);
48
+ setConsent(next);
49
+ window.dispatchEvent(new CustomEvent("hazo_auth:consent_update", { detail: next }));
50
+ }, [consent]);
51
+ const open_manager = useCallback(() => {
52
+ window.dispatchEvent(new CustomEvent("hazo_auth:open_consent_manager"));
53
+ }, []);
54
+ return { consent, set_consent, open_manager };
55
+ }
@@ -20,6 +20,16 @@ export type NextAuthCallbackProfile = {
20
20
  picture?: string;
21
21
  email_verified?: boolean;
22
22
  };
23
+ export type FacebookCallbackProfile = {
24
+ id?: string;
25
+ name?: string;
26
+ email?: string;
27
+ picture?: {
28
+ data?: {
29
+ url: string;
30
+ };
31
+ } | string;
32
+ };
23
33
  /**
24
34
  * Gets NextAuth.js configuration with enabled OAuth providers
25
35
  * Providers are dynamically configured based on hazo_auth_config.ini settings
@@ -1 +1 @@
1
- {"version":3,"file":"nextauth_config.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/nextauth_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAW,MAAM,WAAW,CAAC;AAWtD,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CAwKjD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAW7C"}
1
+ {"version":3,"file":"nextauth_config.d.ts","sourceRoot":"","sources":["../../../src/lib/auth/nextauth_config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAW,MAAM,WAAW,CAAC;AAatD,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE;YAAE,GAAG,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,GAAG,MAAM,CAAC;CAC/C,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,WAAW,CA+PjD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAe7C"}
@@ -1,8 +1,10 @@
1
1
  // ESM/CJS interop: next-auth providers are CommonJS, handle both export scenarios
2
2
  import GoogleProviderImport from "next-auth/providers/google";
3
3
  const GoogleProvider = GoogleProviderImport.default || GoogleProviderImport;
4
+ import FacebookProviderImport from "next-auth/providers/facebook";
5
+ const FacebookProvider = FacebookProviderImport.default || FacebookProviderImport;
4
6
  import { get_oauth_config } from "../oauth_config.server.js";
5
- import { handle_google_oauth_login } from "../services/oauth_service.js";
7
+ import { handle_google_oauth_login, handle_facebook_oauth_login } from "../services/oauth_service.js";
6
8
  import { get_hazo_connect_instance } from "../hazo_connect_instance.server.js";
7
9
  import { create_app_logger } from "../app_logger.js";
8
10
  // section: config
@@ -32,6 +34,18 @@ export function get_nextauth_config() {
32
34
  }));
33
35
  }
34
36
  }
37
+ // Add Facebook provider if enabled and credentials are present
38
+ if (oauth_config.enable_facebook && oauth_config.facebook_client_id && oauth_config.facebook_client_secret) {
39
+ providers.push(FacebookProvider({
40
+ clientId: oauth_config.facebook_client_id,
41
+ clientSecret: oauth_config.facebook_client_secret,
42
+ authorization: {
43
+ params: {
44
+ scope: "email,public_profile",
45
+ },
46
+ },
47
+ }));
48
+ }
35
49
  return {
36
50
  providers,
37
51
  pages: {
@@ -52,6 +66,9 @@ export function get_nextauth_config() {
52
66
  if (url.includes("/api/hazo_auth/oauth/google/callback")) {
53
67
  return url;
54
68
  }
69
+ if (url.includes("/api/hazo_auth/oauth/facebook/callback")) {
70
+ return url;
71
+ }
55
72
  // If URL is relative or same origin, allow it
56
73
  if (url.startsWith("/")) {
57
74
  return `${baseUrl}${url}`;
@@ -66,7 +83,7 @@ export function get_nextauth_config() {
66
83
  * Sign-in callback - handle user creation/linking for Google OAuth
67
84
  */
68
85
  async signIn({ account, profile, user, }) {
69
- var _a;
86
+ var _a, _b, _c, _d, _e, _f;
70
87
  const logger = create_app_logger();
71
88
  if ((account === null || account === void 0 ? void 0 : account.provider) === "google" && profile) {
72
89
  try {
@@ -111,6 +128,64 @@ export function get_nextauth_config() {
111
128
  return false;
112
129
  }
113
130
  }
131
+ if ((account === null || account === void 0 ? void 0 : account.provider) === "facebook" && profile) {
132
+ try {
133
+ const fbProfile = profile;
134
+ const hazoConnect = get_hazo_connect_instance();
135
+ const current_oauth_config = get_oauth_config();
136
+ // Resolve profile picture URL from Facebook's nested structure
137
+ let fb_picture_url;
138
+ if (fbProfile.picture) {
139
+ if (typeof fbProfile.picture === "string") {
140
+ fb_picture_url = fbProfile.picture;
141
+ }
142
+ else if ((_c = (_b = fbProfile.picture) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.url) {
143
+ fb_picture_url = fbProfile.picture.data.url;
144
+ }
145
+ }
146
+ if (!fb_picture_url && user.image) {
147
+ fb_picture_url = (_d = user.image) !== null && _d !== void 0 ? _d : undefined;
148
+ }
149
+ logger.info("nextauth_facebook_signin_attempt", {
150
+ email: user.email,
151
+ facebook_id: fbProfile.id,
152
+ name: user.name,
153
+ });
154
+ const result = await handle_facebook_oauth_login(hazoConnect, {
155
+ facebook_id: fbProfile.id || account.providerAccountId,
156
+ email: (_f = (_e = user.email) !== null && _e !== void 0 ? _e : fbProfile.email) !== null && _f !== void 0 ? _f : null,
157
+ name: user.name || fbProfile.name || undefined,
158
+ profile_picture_url: fb_picture_url,
159
+ }, { auto_link_unverified: current_oauth_config.auto_link_unverified_accounts_facebook });
160
+ if (!result.success) {
161
+ logger.error("nextauth_facebook_signin_failed", {
162
+ email: user.email,
163
+ error: result.error,
164
+ });
165
+ if (result.error === "link_blocked_unverified") {
166
+ return `/hazo_auth/login?error=link_blocked_unverified`;
167
+ }
168
+ return false;
169
+ }
170
+ logger.info("nextauth_facebook_signin_success", {
171
+ user_id: result.user_id,
172
+ email: result.email,
173
+ is_new_user: result.is_new_user,
174
+ was_linked: result.was_linked,
175
+ });
176
+ // Store user_id in account for the JWT callback to pick up
177
+ account.hazo_user_id = result.user_id;
178
+ return true;
179
+ }
180
+ catch (error) {
181
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
182
+ logger.error("nextauth_facebook_signin_exception", {
183
+ email: user.email,
184
+ error: errorMessage,
185
+ });
186
+ return false;
187
+ }
188
+ }
114
189
  return true;
115
190
  },
116
191
  /**
@@ -169,5 +244,8 @@ export function has_oauth_providers() {
169
244
  if (has_google_credentials)
170
245
  return true;
171
246
  }
247
+ if (oauth_config.enable_facebook && oauth_config.facebook_client_id && oauth_config.facebook_client_secret) {
248
+ return true;
249
+ }
172
250
  return false;
173
251
  }
@@ -9,6 +9,7 @@ export declare const BASE_COOKIE_NAMES: {
9
9
  readonly USER_ID: "hazo_auth_user_id";
10
10
  readonly USER_EMAIL: "hazo_auth_user_email";
11
11
  readonly SESSION: "hazo_auth_session";
12
+ readonly SESSION_KIND: "hazo_auth_session_kind";
12
13
  readonly DEV_LOCK: "hazo_auth_dev_lock";
13
14
  readonly SCOPE_ID: "hazo_auth_scope_id";
14
15
  readonly ANON_ID: "hazo_auth_anon_id";
@@ -1 +1 @@
1
- {"version":3,"file":"cookies_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/cookies_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,MAAM,MAAM,aAAa,GAAG;IAC1B,6FAA6F;IAC7F,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAYF,eAAO,MAAM,iBAAiB;;;;;;;CAOpB,CAAC;AAGX;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAoBlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAQzG;AAKD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAKzD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
1
+ {"version":3,"file":"cookies_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/cookies_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,MAAM,MAAM,aAAa,GAAG;IAC1B,6FAA6F;IAC7F,aAAa,EAAE,MAAM,CAAC;IACtB,6EAA6E;IAC7E,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC;AAYF,eAAO,MAAM,iBAAiB;;;;;;;;CAQpB,CAAC;AAGX;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,aAAa,CAoBlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAGzD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAQzG;AAKD;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,aAAa,CAKzD;AAED;;GAEG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD"}
@@ -14,6 +14,7 @@ export const BASE_COOKIE_NAMES = {
14
14
  USER_ID: "hazo_auth_user_id",
15
15
  USER_EMAIL: "hazo_auth_user_email",
16
16
  SESSION: "hazo_auth_session",
17
+ SESSION_KIND: "hazo_auth_session_kind", // v6.1: marks OTP-issued sessions so /me can apply sliding expiry
17
18
  DEV_LOCK: "hazo_auth_dev_lock",
18
19
  SCOPE_ID: "hazo_auth_scope_id", // v5.2: Tenant context cookie for multi-tenancy
19
20
  ANON_ID: "hazo_auth_anon_id", // v5.2: Stable opaque per-visitor ID for anonymous flows (e.g. hazo_feedback)
@@ -5,9 +5,6 @@ export type EmailVerificationConfig = {
5
5
  showReturnHomeButton: boolean;
6
6
  returnHomeButtonLabel: string;
7
7
  returnHomePath: string;
8
- imageSrc: string;
9
- imageAlt: string;
10
- imageBackgroundColor: string;
11
8
  };
12
9
  /**
13
10
  * Reads email verification layout configuration from hazo_auth_config.ini file
@@ -1 +1 @@
1
- {"version":3,"file":"email_verification_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/email_verification_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAYrB,MAAM,MAAM,uBAAuB,GAAG;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,uBAAuB,CAoCvE"}
1
+ {"version":3,"file":"email_verification_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/email_verification_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,MAAM,MAAM,uBAAuB,GAAG;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,uBAAuB,CAWvE"}
@@ -3,11 +3,6 @@
3
3
  import "server-only";
4
4
  // section: imports
5
5
  import { get_already_logged_in_config } from "./already_logged_in_config.server.js";
6
- import { get_config_value } from "./config/config_loader.server.js";
7
- // Default image path - consuming apps should either:
8
- // 1. Configure their own image_src in hazo_auth_config.ini
9
- // 2. Copy the default images from node_modules/hazo_auth/public/hazo_auth/images/ to their public folder
10
- const DEFAULT_VERIFY_EMAIL_IMAGE_PATH = "/hazo_auth/images/verify_email_default.jpg";
11
6
  // section: helpers
12
7
  /**
13
8
  * Reads email verification layout configuration from hazo_auth_config.ini file
@@ -15,23 +10,13 @@ const DEFAULT_VERIFY_EMAIL_IMAGE_PATH = "/hazo_auth/images/verify_email_default.
15
10
  * @returns Email verification configuration options
16
11
  */
17
12
  export function get_email_verification_config() {
18
- const section = "hazo_auth__email_verification_layout";
19
13
  // Get shared already logged in config
20
14
  const alreadyLoggedInConfig = get_already_logged_in_config();
21
- // Read image configuration
22
- // If not set in config, falls back to default path-based image
23
- // Consuming apps should copy images to public/hazo_auth/images/ or configure their own image_src
24
- const imageSrc = get_config_value(section, "image_src", DEFAULT_VERIFY_EMAIL_IMAGE_PATH);
25
- const imageAlt = get_config_value(section, "image_alt", "Email verification illustration");
26
- const imageBackgroundColor = get_config_value(section, "image_background_color", "#f1f5f9");
27
15
  return {
28
16
  alreadyLoggedInMessage: alreadyLoggedInConfig.message,
29
17
  showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
30
18
  showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
31
19
  returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
32
20
  returnHomePath: alreadyLoggedInConfig.returnHomePath,
33
- imageSrc,
34
- imageAlt,
35
- imageBackgroundColor,
36
21
  };
37
22
  }
@@ -5,9 +5,6 @@ export type ForgotPasswordConfig = {
5
5
  showReturnHomeButton: boolean;
6
6
  returnHomeButtonLabel: string;
7
7
  returnHomePath: string;
8
- imageSrc: string;
9
- imageAlt: string;
10
- imageBackgroundColor: string;
11
8
  };
12
9
  /**
13
10
  * Reads forgot password layout configuration from hazo_auth_config.ini file
@@ -1 +1 @@
1
- {"version":3,"file":"forgot_password_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/forgot_password_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAYrB,MAAM,MAAM,oBAAoB,GAAG;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,CAoCjE"}
1
+ {"version":3,"file":"forgot_password_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/forgot_password_config.server.ts"],"names":[],"mappings":"AAEA,OAAO,aAAa,CAAC;AAMrB,MAAM,MAAM,oBAAoB,GAAG;IACjC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,oBAAoB,CAWjE"}