hazo_auth 4.0.0 → 4.2.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 (93) hide show
  1. package/README.md +312 -8
  2. package/SETUP_CHECKLIST.md +203 -0
  3. package/dist/app/api/hazo_auth/forgot_password/route.d.ts.map +1 -1
  4. package/dist/app/api/hazo_auth/forgot_password/route.js +15 -0
  5. package/dist/app/api/hazo_auth/logout/route.d.ts.map +1 -1
  6. package/dist/app/api/hazo_auth/logout/route.js +31 -0
  7. package/dist/app/api/hazo_auth/me/route.d.ts +3 -0
  8. package/dist/app/api/hazo_auth/me/route.d.ts.map +1 -1
  9. package/dist/app/api/hazo_auth/me/route.js +19 -1
  10. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts +2 -0
  11. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.d.ts.map +1 -1
  12. package/dist/components/layouts/forgot_password/hooks/use_forgot_password_form.js +8 -0
  13. package/dist/components/layouts/forgot_password/index.d.ts +7 -1
  14. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  15. package/dist/components/layouts/forgot_password/index.js +7 -2
  16. package/dist/components/layouts/login/index.d.ts +13 -1
  17. package/dist/components/layouts/login/index.d.ts.map +1 -1
  18. package/dist/components/layouts/login/index.js +11 -2
  19. package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts +17 -0
  20. package/dist/components/layouts/my_settings/components/connected_accounts_section.d.ts.map +1 -0
  21. package/dist/components/layouts/my_settings/components/connected_accounts_section.js +17 -0
  22. package/dist/components/layouts/my_settings/components/set_password_section.d.ts +26 -0
  23. package/dist/components/layouts/my_settings/components/set_password_section.d.ts.map +1 -0
  24. package/dist/components/layouts/my_settings/components/set_password_section.js +127 -0
  25. package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts +3 -0
  26. package/dist/components/layouts/my_settings/hooks/use_my_settings.d.ts.map +1 -1
  27. package/dist/components/layouts/my_settings/hooks/use_my_settings.js +9 -0
  28. package/dist/components/layouts/my_settings/index.d.ts.map +1 -1
  29. package/dist/components/layouts/my_settings/index.js +4 -2
  30. package/dist/components/layouts/profile_stamp_test/index.d.ts +10 -0
  31. package/dist/components/layouts/profile_stamp_test/index.d.ts.map +1 -0
  32. package/dist/components/layouts/profile_stamp_test/index.js +51 -0
  33. package/dist/components/layouts/shared/components/google_icon.d.ts +12 -0
  34. package/dist/components/layouts/shared/components/google_icon.d.ts.map +1 -0
  35. package/dist/components/layouts/shared/components/google_icon.js +9 -0
  36. package/dist/components/layouts/shared/components/google_sign_in_button.d.ts +21 -0
  37. package/dist/components/layouts/shared/components/google_sign_in_button.d.ts.map +1 -0
  38. package/dist/components/layouts/shared/components/google_sign_in_button.js +50 -0
  39. package/dist/components/layouts/shared/components/oauth_divider.d.ts +13 -0
  40. package/dist/components/layouts/shared/components/oauth_divider.d.ts.map +1 -0
  41. package/dist/components/layouts/shared/components/oauth_divider.js +13 -0
  42. package/dist/components/layouts/shared/components/profile_stamp.d.ts +58 -0
  43. package/dist/components/layouts/shared/components/profile_stamp.d.ts.map +1 -0
  44. package/dist/components/layouts/shared/components/profile_stamp.js +72 -0
  45. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.d.ts.map +1 -1
  46. package/dist/components/layouts/shared/components/sidebar_layout_wrapper.js +2 -2
  47. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts +6 -0
  48. package/dist/components/layouts/shared/hooks/use_auth_status.d.ts.map +1 -1
  49. package/dist/components/layouts/shared/hooks/use_auth_status.js +8 -0
  50. package/dist/components/layouts/shared/index.d.ts +7 -0
  51. package/dist/components/layouts/shared/index.d.ts.map +1 -1
  52. package/dist/components/layouts/shared/index.js +4 -0
  53. package/dist/components/ui/button.d.ts +1 -1
  54. package/dist/components/ui/hover-card.d.ts +7 -0
  55. package/dist/components/ui/hover-card.d.ts.map +1 -0
  56. package/dist/components/ui/hover-card.js +29 -0
  57. package/dist/components/ui/index.d.ts +1 -0
  58. package/dist/components/ui/index.d.ts.map +1 -1
  59. package/dist/components/ui/index.js +1 -0
  60. package/dist/lib/auth/nextauth_config.d.ts +34 -0
  61. package/dist/lib/auth/nextauth_config.d.ts.map +1 -0
  62. package/dist/lib/auth/nextauth_config.js +171 -0
  63. package/dist/lib/config/default_config.d.ts +24 -0
  64. package/dist/lib/config/default_config.d.ts.map +1 -1
  65. package/dist/lib/config/default_config.js +14 -0
  66. package/dist/lib/index.d.ts +2 -0
  67. package/dist/lib/index.d.ts.map +1 -1
  68. package/dist/lib/index.js +1 -0
  69. package/dist/lib/login_config.server.d.ts +3 -0
  70. package/dist/lib/login_config.server.d.ts.map +1 -1
  71. package/dist/lib/login_config.server.js +4 -0
  72. package/dist/lib/oauth_config.server.d.ts +29 -0
  73. package/dist/lib/oauth_config.server.d.ts.map +1 -0
  74. package/dist/lib/oauth_config.server.js +40 -0
  75. package/dist/lib/services/login_service.d.ts.map +1 -1
  76. package/dist/lib/services/login_service.js +16 -1
  77. package/dist/lib/services/oauth_service.d.ts +88 -0
  78. package/dist/lib/services/oauth_service.d.ts.map +1 -0
  79. package/dist/lib/services/oauth_service.js +376 -0
  80. package/dist/lib/services/password_reset_service.d.ts +2 -0
  81. package/dist/lib/services/password_reset_service.d.ts.map +1 -1
  82. package/dist/lib/services/password_reset_service.js +10 -0
  83. package/dist/lib/services/registration_service.d.ts.map +1 -1
  84. package/dist/lib/services/registration_service.js +1 -0
  85. package/dist/lib/utils/password_validator.d.ts +13 -0
  86. package/dist/lib/utils/password_validator.d.ts.map +1 -0
  87. package/dist/lib/utils/password_validator.js +36 -0
  88. package/dist/server_pages/login.d.ts.map +1 -1
  89. package/dist/server_pages/login.js +6 -1
  90. package/dist/server_pages/login_client_wrapper.d.ts +5 -2
  91. package/dist/server_pages/login_client_wrapper.d.ts.map +1 -1
  92. package/dist/server_pages/login_client_wrapper.js +2 -2
  93. package/package.json +3 -1
@@ -0,0 +1,171 @@
1
+ import GoogleProvider from "next-auth/providers/google";
2
+ import { get_oauth_config } from "../oauth_config.server";
3
+ import { handle_google_oauth_login } from "../services/oauth_service";
4
+ import { get_hazo_connect_instance } from "../hazo_connect_instance.server";
5
+ import { create_app_logger } from "../app_logger";
6
+ // section: config
7
+ /**
8
+ * Gets NextAuth.js configuration with enabled OAuth providers
9
+ * Providers are dynamically configured based on hazo_auth_config.ini settings
10
+ * @returns NextAuth configuration object
11
+ */
12
+ export function get_nextauth_config() {
13
+ const oauth_config = get_oauth_config();
14
+ const providers = [];
15
+ // Add Google provider if enabled
16
+ if (oauth_config.enable_google) {
17
+ const client_id = process.env.HAZO_AUTH_GOOGLE_CLIENT_ID;
18
+ const client_secret = process.env.HAZO_AUTH_GOOGLE_CLIENT_SECRET;
19
+ if (client_id && client_secret) {
20
+ providers.push(GoogleProvider({
21
+ clientId: client_id,
22
+ clientSecret: client_secret,
23
+ authorization: {
24
+ params: {
25
+ prompt: "consent",
26
+ access_type: "offline",
27
+ response_type: "code",
28
+ },
29
+ },
30
+ }));
31
+ }
32
+ }
33
+ return {
34
+ providers,
35
+ pages: {
36
+ // Use hazo_auth login page for sign-in errors
37
+ signIn: "/hazo_auth/login",
38
+ error: "/hazo_auth/login",
39
+ },
40
+ callbacks: {
41
+ /**
42
+ * Redirect callback - controls where users go after authentication
43
+ * We redirect to our custom callback handler to create hazo_auth session
44
+ */
45
+ async redirect({ url, baseUrl }) {
46
+ // Log for debugging
47
+ console.log("[NextAuth redirect callback]", { url, baseUrl });
48
+ // Always redirect to our custom callback after sign-in to set hazo_auth cookies
49
+ // The callbackUrl from signIn() comes through as `url`
50
+ if (url.includes("/api/hazo_auth/oauth/google/callback")) {
51
+ return url;
52
+ }
53
+ // If URL is relative or same origin, allow it
54
+ if (url.startsWith("/")) {
55
+ return `${baseUrl}${url}`;
56
+ }
57
+ if (url.startsWith(baseUrl)) {
58
+ return url;
59
+ }
60
+ // Default: redirect to our custom OAuth callback to set cookies
61
+ return `${baseUrl}/api/hazo_auth/oauth/google/callback`;
62
+ },
63
+ /**
64
+ * Sign-in callback - handle user creation/linking for Google OAuth
65
+ */
66
+ async signIn({ account, profile, user, }) {
67
+ var _a;
68
+ const logger = create_app_logger();
69
+ if ((account === null || account === void 0 ? void 0 : account.provider) === "google" && profile) {
70
+ try {
71
+ const googleProfile = profile;
72
+ const hazoConnect = get_hazo_connect_instance();
73
+ logger.info("nextauth_google_signin_attempt", {
74
+ email: user.email,
75
+ google_id: googleProfile.sub,
76
+ name: user.name,
77
+ });
78
+ // Handle the Google OAuth login (create user or link account)
79
+ const result = await handle_google_oauth_login(hazoConnect, {
80
+ google_id: googleProfile.sub || account.providerAccountId,
81
+ email: user.email || googleProfile.email || "",
82
+ name: user.name || googleProfile.name || undefined,
83
+ profile_picture_url: user.image || googleProfile.picture || undefined,
84
+ email_verified: (_a = googleProfile.email_verified) !== null && _a !== void 0 ? _a : true,
85
+ });
86
+ if (!result.success) {
87
+ logger.error("nextauth_google_signin_failed", {
88
+ email: user.email,
89
+ error: result.error,
90
+ });
91
+ return false;
92
+ }
93
+ logger.info("nextauth_google_signin_success", {
94
+ user_id: result.user_id,
95
+ email: result.email,
96
+ is_new_user: result.is_new_user,
97
+ was_linked: result.was_linked,
98
+ });
99
+ // Store user_id in account for the JWT callback to pick up
100
+ account.hazo_user_id = result.user_id;
101
+ return true;
102
+ }
103
+ catch (error) {
104
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
105
+ logger.error("nextauth_google_signin_exception", {
106
+ email: user.email,
107
+ error: errorMessage,
108
+ });
109
+ return false;
110
+ }
111
+ }
112
+ return true;
113
+ },
114
+ /**
115
+ * JWT callback - add OAuth provider info to the token
116
+ */
117
+ async jwt({ token, account, profile }) {
118
+ if (account && profile) {
119
+ token.provider = account.provider;
120
+ token.providerAccountId = account.providerAccountId;
121
+ // Store hazo_user_id from signIn callback
122
+ if (account.hazo_user_id) {
123
+ token.hazo_user_id = account.hazo_user_id;
124
+ }
125
+ // For Google, store additional profile data
126
+ if (account.provider === "google") {
127
+ const googleProfile = profile;
128
+ token.google_id = googleProfile.sub;
129
+ token.email_verified = googleProfile.email_verified;
130
+ }
131
+ }
132
+ return token;
133
+ },
134
+ /**
135
+ * Session callback - pass provider info to session
136
+ */
137
+ async session({ session, token }) {
138
+ if (token) {
139
+ const extSession = session;
140
+ const extToken = token;
141
+ extSession.provider = extToken.provider;
142
+ extSession.providerAccountId = extToken.providerAccountId;
143
+ extSession.google_id = extToken.google_id;
144
+ extSession.email_verified = extToken.email_verified;
145
+ }
146
+ return session;
147
+ },
148
+ },
149
+ // Use JWT strategy - we don't need a database adapter since we manage users ourselves
150
+ session: {
151
+ strategy: "jwt",
152
+ maxAge: 60 * 10, // 10 minutes - short lived since we create our own session
153
+ },
154
+ // Disable debug in production
155
+ debug: process.env.NODE_ENV === "development",
156
+ };
157
+ }
158
+ /**
159
+ * Checks if any OAuth providers are configured and enabled
160
+ * @returns true if at least one OAuth provider is available
161
+ */
162
+ export function has_oauth_providers() {
163
+ const oauth_config = get_oauth_config();
164
+ if (oauth_config.enable_google) {
165
+ const has_google_credentials = process.env.HAZO_AUTH_GOOGLE_CLIENT_ID &&
166
+ process.env.HAZO_AUTH_GOOGLE_CLIENT_SECRET;
167
+ if (has_google_credentials)
168
+ return true;
169
+ }
170
+ return false;
171
+ }
@@ -111,6 +111,18 @@ export declare const DEFAULT_PROFILE_PIC_MENU: {
111
111
  export declare const DEFAULT_API_PATHS: {
112
112
  readonly apiBasePath: "/api/hazo_auth";
113
113
  };
114
+ export declare const DEFAULT_OAUTH: {
115
+ /** Enable Google OAuth login (requires HAZO_AUTH_GOOGLE_CLIENT_ID and HAZO_AUTH_GOOGLE_CLIENT_SECRET env vars) */
116
+ readonly enable_google: true;
117
+ /** Enable traditional email/password login */
118
+ readonly enable_email_password: true;
119
+ /** Auto-link Google login to existing unverified email/password accounts and mark as verified */
120
+ readonly auto_link_unverified_accounts: true;
121
+ /** Text displayed on the Google sign-in button */
122
+ readonly google_button_text: "Continue with Google";
123
+ /** Text displayed on the divider between OAuth and email/password form */
124
+ readonly oauth_divider_text: "or continue with email";
125
+ };
114
126
  /**
115
127
  * All default configuration values combined in one object
116
128
  * This makes it easy to see all defaults at a glance and export them as needed
@@ -229,6 +241,18 @@ export declare const HAZO_AUTH_DEFAULTS: {
229
241
  readonly apiPaths: {
230
242
  readonly apiBasePath: "/api/hazo_auth";
231
243
  };
244
+ readonly oauth: {
245
+ /** Enable Google OAuth login (requires HAZO_AUTH_GOOGLE_CLIENT_ID and HAZO_AUTH_GOOGLE_CLIENT_SECRET env vars) */
246
+ readonly enable_google: true;
247
+ /** Enable traditional email/password login */
248
+ readonly enable_email_password: true;
249
+ /** Auto-link Google login to existing unverified email/password accounts and mark as verified */
250
+ readonly auto_link_unverified_accounts: true;
251
+ /** Text displayed on the Google sign-in button */
252
+ readonly google_button_text: "Continue with Google";
253
+ /** Text displayed on the divider between OAuth and email/password form */
254
+ readonly oauth_divider_text: "or continue with email";
255
+ };
232
256
  };
233
257
  /**
234
258
  * Type representing the complete default configuration structure
@@ -1 +1 @@
1
- {"version":3,"file":"default_config.d.ts","sourceRoot":"","sources":["../../../src/lib/config/default_config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,6BAA6B;;;;;;CAMhC,CAAC;AAGX,eAAO,MAAM,mBAAmB;;;;CAItB,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;;;;CAO1B,CAAC;AAGX,eAAO,MAAM,gBAAgB;;;;;;;;;CASnB,CAAC;AAGX,eAAO,MAAM,kBAAkB;;;CAGrB,CAAC;AAGX,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAGX,eAAO,MAAM,yBAAyB;;;;;;CAM5B,CAAC;AAGX,eAAO,MAAM,aAAa;4BACI,MAAM,GAAG,SAAS;;;;;;CAMtC,CAAC;AAGX,eAAO,MAAM,gBAAgB;4BACC,MAAM,GAAG,SAAS;;;;;CAKtC,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAGX,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAC;AAGX,eAAO,MAAM,0BAA0B;;;;;CAK7B,CAAC;AAGX,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAGX,eAAO,MAAM,oBAAoB;;;;CAIvB,CAAC;AAGX,eAAO,MAAM,gBAAgB;0BACE,YAAY,GAAG,cAAc;;;;;CAKlD,CAAC;AAGX,eAAO,MAAM,wBAAwB;;;;;;;;CAQ3B,CAAC;AAGX,eAAO,MAAM,iBAAiB;;CAEpB,CAAC;AAGX;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCA3FD,MAAM,GAAG,SAAS;;;;;;;;gCAUlB,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAqDjB,YAAY,GAAG,cAAc;;;;;;;;;;;;;;;;;;CA+ClD,CAAC;AAGX;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,kBAAkB,CAAC"}
1
+ {"version":3,"file":"default_config.d.ts","sourceRoot":"","sources":["../../../src/lib/config/default_config.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,6BAA6B;;;;;;CAMhC,CAAC;AAGX,eAAO,MAAM,mBAAmB;;;;CAItB,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;;;;CAO1B,CAAC;AAGX,eAAO,MAAM,gBAAgB;;;;;;;;;CASnB,CAAC;AAGX,eAAO,MAAM,kBAAkB;;;CAGrB,CAAC;AAGX,eAAO,MAAM,gBAAgB;;;;;CAKnB,CAAC;AAGX,eAAO,MAAM,yBAAyB;;;;;;CAM5B,CAAC;AAGX,eAAO,MAAM,aAAa;4BACI,MAAM,GAAG,SAAS;;;;;;CAMtC,CAAC;AAGX,eAAO,MAAM,gBAAgB;4BACC,MAAM,GAAG,SAAS;;;;;CAKtC,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAGX,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAC;AAGX,eAAO,MAAM,0BAA0B;;;;;CAK7B,CAAC;AAGX,eAAO,MAAM,mBAAmB;;;;;CAKtB,CAAC;AAGX,eAAO,MAAM,uBAAuB;;;;CAI1B,CAAC;AAGX,eAAO,MAAM,oBAAoB;;;;CAIvB,CAAC;AAGX,eAAO,MAAM,gBAAgB;0BACE,YAAY,GAAG,cAAc;;;;;CAKlD,CAAC;AAGX,eAAO,MAAM,wBAAwB;;;;;;;;CAQ3B,CAAC;AAGX,eAAO,MAAM,iBAAiB;;CAEpB,CAAC;AAGX,eAAO,MAAM,aAAa;IACxB,kHAAkH;;IAElH,8CAA8C;;IAE9C,iGAAiG;;IAEjG,kDAAkD;;IAElD,0EAA0E;;CAElE,CAAC;AAGX;;;GAGG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gCAzGD,MAAM,GAAG,SAAS;;;;;;;;gCAUlB,MAAM,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8BAqDjB,YAAY,GAAG,cAAc;;;;;;;;;;;;;;;;;;;QAyB1D,kHAAkH;;QAElH,8CAA8C;;QAE9C,iGAAiG;;QAEjG,kDAAkD;;QAElD,0EAA0E;;;CA6BlE,CAAC;AAGX;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG,OAAO,kBAAkB,CAAC"}
@@ -132,6 +132,19 @@ export const DEFAULT_PROFILE_PIC_MENU = {
132
132
  export const DEFAULT_API_PATHS = {
133
133
  apiBasePath: "/api/hazo_auth",
134
134
  };
135
+ // section: oauth
136
+ export const DEFAULT_OAUTH = {
137
+ /** Enable Google OAuth login (requires HAZO_AUTH_GOOGLE_CLIENT_ID and HAZO_AUTH_GOOGLE_CLIENT_SECRET env vars) */
138
+ enable_google: true,
139
+ /** Enable traditional email/password login */
140
+ enable_email_password: true,
141
+ /** Auto-link Google login to existing unverified email/password accounts and mark as verified */
142
+ auto_link_unverified_accounts: true,
143
+ /** Text displayed on the Google sign-in button */
144
+ google_button_text: "Continue with Google",
145
+ /** Text displayed on the divider between OAuth and email/password form */
146
+ oauth_divider_text: "or continue with email",
147
+ };
135
148
  // section: combined_defaults
136
149
  /**
137
150
  * All default configuration values combined in one object
@@ -156,4 +169,5 @@ export const HAZO_AUTH_DEFAULTS = {
156
169
  uiShell: DEFAULT_UI_SHELL,
157
170
  profilePicMenu: DEFAULT_PROFILE_PIC_MENU,
158
171
  apiPaths: DEFAULT_API_PATHS,
172
+ oauth: DEFAULT_OAUTH,
159
173
  };
@@ -22,6 +22,8 @@ export { get_password_requirements_config } from "./password_requirements_config
22
22
  export { get_messages_config } from "./messages_config.server";
23
23
  export { get_user_fields_config } from "./user_fields_config.server";
24
24
  export { get_file_types_config } from "./file_types_config.server";
25
+ export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled } from "./oauth_config.server";
26
+ export type { OAuthConfig } from "./oauth_config.server";
25
27
  export { sanitize_error_for_user } from "./utils/error_sanitizer";
26
28
  export type { ErrorSanitizationOptions } from "./utils/error_sanitizer";
27
29
  export * from "./utils/api_route_helpers";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAC;AAG7B,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAG/I,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxE,cAAc,2BAA2B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAEA,cAAc,cAAc,CAAC;AAG7B,cAAc,kBAAkB,CAAC;AAGjC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAG/I,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAG3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,6BAA6B,EAAE,MAAM,oCAAoC,CAAC;AACnF,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAAE,gCAAgC,EAAE,MAAM,uCAAuC,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAC;AACrE,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAC;AAC7G,YAAY,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAClE,YAAY,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AACxE,cAAc,2BAA2B,CAAC"}
package/dist/lib/index.js CHANGED
@@ -30,6 +30,7 @@ export { get_password_requirements_config } from "./password_requirements_config
30
30
  export { get_messages_config } from "./messages_config.server";
31
31
  export { get_user_fields_config } from "./user_fields_config.server";
32
32
  export { get_file_types_config } from "./file_types_config.server";
33
+ export { get_oauth_config, is_google_oauth_enabled, is_email_password_enabled } from "./oauth_config.server";
33
34
  // section: util_exports
34
35
  export { sanitize_error_for_user } from "./utils/error_sanitizer";
35
36
  export * from "./utils/api_route_helpers";
@@ -1,3 +1,4 @@
1
+ import { type OAuthConfig } from "./oauth_config.server";
1
2
  import type { StaticImageData } from "next/image";
2
3
  export type LoginConfig = {
3
4
  redirectRoute?: string;
@@ -14,6 +15,8 @@ export type LoginConfig = {
14
15
  imageSrc: string | StaticImageData;
15
16
  imageAlt: string;
16
17
  imageBackgroundColor: string;
18
+ /** OAuth configuration */
19
+ oauth: OAuthConfig;
17
20
  };
18
21
  /**
19
22
  * Reads login layout configuration from hazo_auth_config.ini file
@@ -1 +1 @@
1
- {"version":3,"file":"login_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/login_config.server.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,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,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;CAC9B,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAiE9C"}
1
+ {"version":3,"file":"login_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/login_config.server.ts"],"names":[],"mappings":"AAIA,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAI3E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,MAAM,WAAW,GAAG;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,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,kBAAkB,EAAE,MAAM,CAAC;IAC3B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,eAAe,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,0BAA0B;IAC1B,KAAK,EAAE,WAAW,CAAC;CACpB,CAAC;AAGF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAqE9C"}
@@ -2,6 +2,7 @@
2
2
  // section: imports
3
3
  import { get_config_value } from "./config/config_loader.server";
4
4
  import { get_already_logged_in_config } from "./already_logged_in_config.server";
5
+ import { get_oauth_config } from "./oauth_config.server";
5
6
  import loginDefaultImage from "../assets/images/login_default.jpg";
6
7
  // section: helpers
7
8
  /**
@@ -28,6 +29,8 @@ export function get_login_config() {
28
29
  ) || loginDefaultImage;
29
30
  const imageAlt = get_config_value(section, "image_alt", "Secure login illustration");
30
31
  const imageBackgroundColor = get_config_value(section, "image_background_color", "#f1f5f9");
32
+ // Get OAuth configuration
33
+ const oauth = get_oauth_config();
31
34
  return {
32
35
  redirectRoute,
33
36
  successMessage,
@@ -43,5 +46,6 @@ export function get_login_config() {
43
46
  imageSrc,
44
47
  imageAlt,
45
48
  imageBackgroundColor,
49
+ oauth,
46
50
  };
47
51
  }
@@ -0,0 +1,29 @@
1
+ export type OAuthConfig = {
2
+ /** Enable Google OAuth login */
3
+ enable_google: boolean;
4
+ /** Enable traditional email/password login */
5
+ enable_email_password: boolean;
6
+ /** Auto-link Google login to existing unverified email/password accounts */
7
+ auto_link_unverified_accounts: boolean;
8
+ /** Text displayed on the Google sign-in button */
9
+ google_button_text: string;
10
+ /** Text displayed on the divider between OAuth and email/password form */
11
+ oauth_divider_text: string;
12
+ };
13
+ /**
14
+ * Reads OAuth configuration from hazo_auth_config.ini file
15
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
16
+ * @returns OAuth configuration options
17
+ */
18
+ export declare function get_oauth_config(): OAuthConfig;
19
+ /**
20
+ * Helper to check if Google OAuth is enabled
21
+ * @returns true if Google OAuth is enabled in config
22
+ */
23
+ export declare function is_google_oauth_enabled(): boolean;
24
+ /**
25
+ * Helper to check if email/password login is enabled
26
+ * @returns true if email/password login is enabled in config
27
+ */
28
+ export declare function is_email_password_enabled(): boolean;
29
+ //# sourceMappingURL=oauth_config.server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth_config.server.d.ts","sourceRoot":"","sources":["../../src/lib/oauth_config.server.ts"],"names":[],"mappings":"AAMA,MAAM,MAAM,WAAW,GAAG;IACxB,gCAAgC;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,8CAA8C;IAC9C,qBAAqB,EAAE,OAAO,CAAC;IAC/B,4EAA4E;IAC5E,6BAA6B,EAAE,OAAO,CAAC;IACvC,kDAAkD;IAClD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,0EAA0E;IAC1E,kBAAkB,EAAE,MAAM,CAAC;CAC5B,CAAC;AAMF;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAsC9C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,IAAI,OAAO,CAEjD;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,IAAI,OAAO,CAMnD"}
@@ -0,0 +1,40 @@
1
+ // file_description: server-only helper to read OAuth configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_value, get_config_boolean } from "./config/config_loader.server";
4
+ import { DEFAULT_OAUTH } from "./config/default_config";
5
+ // section: constants
6
+ const SECTION_NAME = "hazo_auth__oauth";
7
+ // section: helpers
8
+ /**
9
+ * Reads OAuth configuration from hazo_auth_config.ini file
10
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
11
+ * @returns OAuth configuration options
12
+ */
13
+ export function get_oauth_config() {
14
+ const enable_google = get_config_boolean(SECTION_NAME, "enable_google", DEFAULT_OAUTH.enable_google);
15
+ const enable_email_password = get_config_boolean(SECTION_NAME, "enable_email_password", DEFAULT_OAUTH.enable_email_password);
16
+ const auto_link_unverified_accounts = get_config_boolean(SECTION_NAME, "auto_link_unverified_accounts", DEFAULT_OAUTH.auto_link_unverified_accounts);
17
+ const google_button_text = get_config_value(SECTION_NAME, "google_button_text", DEFAULT_OAUTH.google_button_text);
18
+ const oauth_divider_text = get_config_value(SECTION_NAME, "oauth_divider_text", DEFAULT_OAUTH.oauth_divider_text);
19
+ return {
20
+ enable_google,
21
+ enable_email_password,
22
+ auto_link_unverified_accounts,
23
+ google_button_text,
24
+ oauth_divider_text,
25
+ };
26
+ }
27
+ /**
28
+ * Helper to check if Google OAuth is enabled
29
+ * @returns true if Google OAuth is enabled in config
30
+ */
31
+ export function is_google_oauth_enabled() {
32
+ return get_config_boolean(SECTION_NAME, "enable_google", DEFAULT_OAUTH.enable_google);
33
+ }
34
+ /**
35
+ * Helper to check if email/password login is enabled
36
+ * @returns true if email/password login is enabled in config
37
+ */
38
+ export function is_email_password_enabled() {
39
+ return get_config_boolean(SECTION_NAME, "enable_email_password", DEFAULT_OAUTH.enable_email_password);
40
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"login_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/login_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAQvD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAGF;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,WAAW,CAAC,CAmGtB"}
1
+ {"version":3,"file":"login_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/login_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAQvD,MAAM,MAAM,SAAS,GAAG;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAGF;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,WAAW,CAAC,CAmHtB"}
@@ -34,8 +34,23 @@ export async function authenticate_user(adapter, data) {
34
34
  error: "Account is inactive. Please contact support.",
35
35
  };
36
36
  }
37
- // Verify password using argon2
37
+ // Check if user has a password set (Google-only users have empty password_hash)
38
38
  const password_hash = user.password_hash;
39
+ if (!password_hash || password_hash === "") {
40
+ // Check if user has Google linked
41
+ const auth_providers = user.auth_providers || "";
42
+ if (auth_providers.includes("google")) {
43
+ return {
44
+ success: false,
45
+ error: "This account uses Google Sign-In. Please log in with Google instead.",
46
+ };
47
+ }
48
+ return {
49
+ success: false,
50
+ error: "Invalid email or password",
51
+ };
52
+ }
53
+ // Verify password using argon2
39
54
  const is_password_valid = await argon2.verify(password_hash, password);
40
55
  if (!is_password_valid) {
41
56
  // Increment login attempts on failed password
@@ -0,0 +1,88 @@
1
+ import type { HazoConnectAdapter } from "hazo_connect";
2
+ export type GoogleOAuthData = {
3
+ /** Google's unique user ID (sub claim from JWT) */
4
+ google_id: string;
5
+ /** User's email address from Google */
6
+ email: string;
7
+ /** User's full name from Google profile */
8
+ name?: string;
9
+ /** User's profile picture URL from Google */
10
+ profile_picture_url?: string;
11
+ /** Whether Google has verified this email */
12
+ email_verified: boolean;
13
+ };
14
+ export type OAuthLoginResult = {
15
+ success: boolean;
16
+ user_id?: string;
17
+ /** True if this was a newly created account */
18
+ is_new_user?: boolean;
19
+ /** True if Google was linked to an existing account */
20
+ was_linked?: boolean;
21
+ /** The user's email address */
22
+ email?: string;
23
+ /** The user's name */
24
+ name?: string;
25
+ error?: string;
26
+ };
27
+ export type LinkGoogleResult = {
28
+ success: boolean;
29
+ error?: string;
30
+ };
31
+ export type AuthProvidersResult = {
32
+ success: boolean;
33
+ auth_providers?: string[];
34
+ has_password?: boolean;
35
+ error?: string;
36
+ };
37
+ /**
38
+ * Handles Google OAuth login/registration flow
39
+ * 1. Check if user exists with google_id -> login
40
+ * 2. Check if user exists with email -> link Google account
41
+ * 3. Create new user with Google data
42
+ *
43
+ * @param adapter - The hazo_connect adapter instance
44
+ * @param data - Google OAuth user data
45
+ * @returns OAuth login result with user_id and status flags
46
+ */
47
+ export declare function handle_google_oauth_login(adapter: HazoConnectAdapter, data: GoogleOAuthData): Promise<OAuthLoginResult>;
48
+ /**
49
+ * Links a Google account to an existing user
50
+ * @param adapter - The hazo_connect adapter instance
51
+ * @param user_id - The user's ID
52
+ * @param google_id - Google's unique user ID
53
+ * @returns Result indicating success or failure
54
+ */
55
+ export declare function link_google_account(adapter: HazoConnectAdapter, user_id: string, google_id: string): Promise<LinkGoogleResult>;
56
+ /**
57
+ * Checks if a user has a password set (non-empty password_hash)
58
+ * @param adapter - The hazo_connect adapter instance
59
+ * @param user_id - The user's ID
60
+ * @returns True if user has a password set
61
+ */
62
+ export declare function user_has_password(adapter: HazoConnectAdapter, user_id: string): Promise<boolean>;
63
+ /**
64
+ * Checks if a user has a password set by email
65
+ * @param adapter - The hazo_connect adapter instance
66
+ * @param email - The user's email address
67
+ * @returns True if user has a password set
68
+ */
69
+ export declare function user_has_password_by_email(adapter: HazoConnectAdapter, email: string): Promise<boolean>;
70
+ /**
71
+ * Gets a user's authentication providers and password status
72
+ * @param adapter - The hazo_connect adapter instance
73
+ * @param user_id - The user's ID
74
+ * @returns Auth providers array and has_password flag
75
+ */
76
+ export declare function get_user_auth_providers(adapter: HazoConnectAdapter, user_id: string): Promise<AuthProvidersResult>;
77
+ /**
78
+ * Sets a password for a user who doesn't have one (e.g., Google-only users)
79
+ * @param adapter - The hazo_connect adapter instance
80
+ * @param user_id - The user's ID
81
+ * @param password_hash - The hashed password to set
82
+ * @returns Result indicating success or failure
83
+ */
84
+ export declare function set_user_password(adapter: HazoConnectAdapter, user_id: string, password_hash: string): Promise<{
85
+ success: boolean;
86
+ error?: string;
87
+ }>;
88
+ //# sourceMappingURL=oauth_service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth_service.d.ts","sourceRoot":"","sources":["../../../src/lib/services/oauth_service.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AASvD,MAAM,MAAM,eAAe,GAAG;IAC5B,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6CAA6C;IAC7C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,6CAA6C;IAC7C,cAAc,EAAE,OAAO,CAAC;CACzB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,uDAAuD;IACvD,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+BAA+B;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,gBAAgB,CAAC,CAiL3B;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAgE3B;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;GAKG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,kBAAkB,EAC3B,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAclB;AAED;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,mBAAmB,CAAC,CA2C9B;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0D/C"}