hazo_auth 0.1.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.
- package/LICENSE +21 -0
- package/README.md +48 -0
- package/components.json +22 -0
- package/hazo_auth_config.example.ini +414 -0
- package/hazo_notify_config.example.ini +159 -0
- package/instrumentation.ts +32 -0
- package/migrations/001_add_token_type_to_refresh_tokens.sql +14 -0
- package/migrations/002_add_name_to_hazo_users.sql +7 -0
- package/next.config.mjs +55 -0
- package/package.json +114 -0
- package/postcss.config.mjs +8 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/scripts/apply_migration.ts +118 -0
- package/src/app/api/auth/change_password/route.ts +109 -0
- package/src/app/api/auth/forgot_password/route.ts +107 -0
- package/src/app/api/auth/library_photos/route.ts +70 -0
- package/src/app/api/auth/login/route.ts +155 -0
- package/src/app/api/auth/logout/route.ts +62 -0
- package/src/app/api/auth/me/route.ts +47 -0
- package/src/app/api/auth/profile_picture/[filename]/route.ts +67 -0
- package/src/app/api/auth/register/route.ts +106 -0
- package/src/app/api/auth/remove_profile_picture/route.ts +86 -0
- package/src/app/api/auth/resend_verification/route.ts +107 -0
- package/src/app/api/auth/reset_password/route.ts +107 -0
- package/src/app/api/auth/update_user/route.ts +126 -0
- package/src/app/api/auth/upload_profile_picture/route.ts +268 -0
- package/src/app/api/auth/validate_reset_token/route.ts +80 -0
- package/src/app/api/auth/verify_email/route.ts +85 -0
- package/src/app/api/migrations/apply/route.ts +91 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/fonts/GeistMonoVF.woff +0 -0
- package/src/app/fonts/GeistVF.woff +0 -0
- package/src/app/forgot_password/forgot_password_page_client.tsx +60 -0
- package/src/app/forgot_password/page.tsx +24 -0
- package/src/app/globals.css +89 -0
- package/src/app/hazo_connect/api/sqlite/data/route.ts +197 -0
- package/src/app/hazo_connect/api/sqlite/schema/route.ts +35 -0
- package/src/app/hazo_connect/api/sqlite/tables/route.ts +26 -0
- package/src/app/hazo_connect/sqlite_admin/page.tsx +51 -0
- package/src/app/hazo_connect/sqlite_admin/sqlite-admin-client.tsx +947 -0
- package/src/app/layout.tsx +43 -0
- package/src/app/login/login_page_client.tsx +71 -0
- package/src/app/login/page.tsx +26 -0
- package/src/app/my_settings/my_settings_page_client.tsx +120 -0
- package/src/app/my_settings/page.tsx +40 -0
- package/src/app/page.tsx +170 -0
- package/src/app/register/page.tsx +26 -0
- package/src/app/register/register_page_client.tsx +72 -0
- package/src/app/reset_password/page.tsx +29 -0
- package/src/app/reset_password/reset_password_page_client.tsx +81 -0
- package/src/app/verify_email/page.tsx +24 -0
- package/src/app/verify_email/verify_email_page_client.tsx +60 -0
- package/src/components/layouts/email_verification/config/email_verification_field_config.ts +86 -0
- package/src/components/layouts/email_verification/hooks/use_email_verification.ts +291 -0
- package/src/components/layouts/email_verification/index.tsx +297 -0
- package/src/components/layouts/forgot_password/config/forgot_password_field_config.ts +58 -0
- package/src/components/layouts/forgot_password/hooks/use_forgot_password_form.ts +179 -0
- package/src/components/layouts/forgot_password/index.tsx +168 -0
- package/src/components/layouts/login/config/login_field_config.ts +67 -0
- package/src/components/layouts/login/hooks/use_login_form.ts +281 -0
- package/src/components/layouts/login/index.tsx +224 -0
- package/src/components/layouts/my_settings/components/editable_field.tsx +177 -0
- package/src/components/layouts/my_settings/components/password_change_dialog.tsx +301 -0
- package/src/components/layouts/my_settings/components/profile_picture_dialog.tsx +385 -0
- package/src/components/layouts/my_settings/components/profile_picture_display.tsx +66 -0
- package/src/components/layouts/my_settings/components/profile_picture_gravatar_tab.tsx +143 -0
- package/src/components/layouts/my_settings/components/profile_picture_library_tab.tsx +282 -0
- package/src/components/layouts/my_settings/components/profile_picture_upload_tab.tsx +341 -0
- package/src/components/layouts/my_settings/config/my_settings_field_config.ts +61 -0
- package/src/components/layouts/my_settings/hooks/use_my_settings.ts +458 -0
- package/src/components/layouts/my_settings/index.tsx +351 -0
- package/src/components/layouts/register/config/register_field_config.ts +101 -0
- package/src/components/layouts/register/hooks/use_register_form.ts +272 -0
- package/src/components/layouts/register/index.tsx +208 -0
- package/src/components/layouts/reset_password/config/reset_password_field_config.ts +86 -0
- package/src/components/layouts/reset_password/hooks/use_reset_password_form.ts +276 -0
- package/src/components/layouts/reset_password/index.tsx +294 -0
- package/src/components/layouts/shared/components/already_logged_in_guard.tsx +95 -0
- package/src/components/layouts/shared/components/field_error_message.tsx +29 -0
- package/src/components/layouts/shared/components/form_action_buttons.tsx +64 -0
- package/src/components/layouts/shared/components/form_field_wrapper.tsx +44 -0
- package/src/components/layouts/shared/components/form_header.tsx +36 -0
- package/src/components/layouts/shared/components/logout_button.tsx +76 -0
- package/src/components/layouts/shared/components/password_field.tsx +72 -0
- package/src/components/layouts/shared/components/sidebar_layout_wrapper.tsx +264 -0
- package/src/components/layouts/shared/components/two_column_auth_layout.tsx +44 -0
- package/src/components/layouts/shared/components/unauthorized_guard.tsx +78 -0
- package/src/components/layouts/shared/components/visual_panel.tsx +41 -0
- package/src/components/layouts/shared/config/layout_customization.ts +95 -0
- package/src/components/layouts/shared/data/layout_data_client.ts +19 -0
- package/src/components/layouts/shared/hooks/use_auth_status.ts +103 -0
- package/src/components/layouts/shared/utils/ip_address.ts +37 -0
- package/src/components/layouts/shared/utils/validation.ts +66 -0
- package/src/components/ui/avatar.tsx +50 -0
- package/src/components/ui/button.tsx +57 -0
- package/src/components/ui/dialog.tsx +122 -0
- package/src/components/ui/hazo_ui_tooltip.tsx +67 -0
- package/src/components/ui/input.tsx +22 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/separator.tsx +31 -0
- package/src/components/ui/sheet.tsx +139 -0
- package/src/components/ui/sidebar.tsx +773 -0
- package/src/components/ui/skeleton.tsx +15 -0
- package/src/components/ui/sonner.tsx +31 -0
- package/src/components/ui/switch.tsx +29 -0
- package/src/components/ui/tabs.tsx +55 -0
- package/src/components/ui/tooltip.tsx +32 -0
- package/src/components/ui/vertical-tabs.tsx +59 -0
- package/src/hooks/use-mobile.tsx +19 -0
- package/src/lib/already_logged_in_config.server.ts +46 -0
- package/src/lib/app_logger.ts +24 -0
- package/src/lib/auth/auth_utils.server.ts +196 -0
- package/src/lib/auth/server_auth.ts +88 -0
- package/src/lib/config/config_loader.server.ts +149 -0
- package/src/lib/email_verification_config.server.ts +32 -0
- package/src/lib/file_types_config.server.ts +25 -0
- package/src/lib/forgot_password_config.server.ts +32 -0
- package/src/lib/hazo_connect_instance.server.ts +77 -0
- package/src/lib/hazo_connect_setup.server.ts +181 -0
- package/src/lib/hazo_connect_setup.ts +54 -0
- package/src/lib/login_config.server.ts +46 -0
- package/src/lib/messages_config.server.ts +45 -0
- package/src/lib/migrations/apply_migration.ts +105 -0
- package/src/lib/my_settings_config.server.ts +135 -0
- package/src/lib/password_requirements_config.server.ts +39 -0
- package/src/lib/profile_picture_config.server.ts +56 -0
- package/src/lib/register_config.server.ts +57 -0
- package/src/lib/reset_password_config.server.ts +75 -0
- package/src/lib/services/email_service.ts +581 -0
- package/src/lib/services/email_verification_service.ts +264 -0
- package/src/lib/services/login_service.ts +118 -0
- package/src/lib/services/password_change_service.ts +154 -0
- package/src/lib/services/password_reset_service.ts +405 -0
- package/src/lib/services/profile_picture_remove_service.ts +120 -0
- package/src/lib/services/profile_picture_service.ts +215 -0
- package/src/lib/services/profile_picture_source_mapper.ts +62 -0
- package/src/lib/services/registration_service.ts +163 -0
- package/src/lib/services/token_service.ts +240 -0
- package/src/lib/services/user_update_service.ts +128 -0
- package/src/lib/ui_sizes_config.server.ts +37 -0
- package/src/lib/user_fields_config.server.ts +31 -0
- package/src/lib/utils/api_route_helpers.ts +60 -0
- package/src/lib/utils.ts +11 -0
- package/src/middleware.ts +91 -0
- package/src/server/config/config_loader.ts +496 -0
- package/src/server/index.ts +38 -0
- package/src/server/logging/logger_service.ts +56 -0
- package/src/server/routes/root_router.ts +16 -0
- package/src/server/server.ts +28 -0
- package/src/server/types/app_types.ts +74 -0
- package/src/server/types/express.d.ts +15 -0
- package/src/stories/email_verification_layout.stories.tsx +137 -0
- package/src/stories/forgot_password_layout.stories.tsx +85 -0
- package/src/stories/login_layout.stories.tsx +85 -0
- package/src/stories/project_overview.stories.tsx +33 -0
- package/src/stories/register_layout.stories.tsx +107 -0
- package/tailwind.config.ts +77 -0
- package/tsconfig.json +27 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
// file_description: shared utility for reading configuration from hazo_auth_config.ini using hazo_config
|
|
2
|
+
// section: imports
|
|
3
|
+
import { HazoConfig } from "hazo_config/dist/lib";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import fs from "fs";
|
|
6
|
+
import { create_app_logger } from "../app_logger";
|
|
7
|
+
|
|
8
|
+
// section: constants
|
|
9
|
+
const DEFAULT_CONFIG_FILE = "hazo_auth_config.ini";
|
|
10
|
+
|
|
11
|
+
// section: helpers
|
|
12
|
+
/**
|
|
13
|
+
* Gets the default config file path
|
|
14
|
+
* @param custom_path - Optional custom config file path
|
|
15
|
+
* @returns Resolved config file path
|
|
16
|
+
*/
|
|
17
|
+
function get_config_file_path(custom_path?: string): string {
|
|
18
|
+
if (custom_path) {
|
|
19
|
+
return path.isAbsolute(custom_path) ? custom_path : path.resolve(process.cwd(), custom_path);
|
|
20
|
+
}
|
|
21
|
+
return path.resolve(process.cwd(), DEFAULT_CONFIG_FILE);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Reads a section from the config file
|
|
26
|
+
* @param section_name - Name of the section to read (e.g., "hazo_auth__register_layout")
|
|
27
|
+
* @param file_path - Optional custom config file path (defaults to hazo_auth_config.ini)
|
|
28
|
+
* @returns Section data as Record<string, string> or undefined if not found
|
|
29
|
+
*/
|
|
30
|
+
export function read_config_section(
|
|
31
|
+
section_name: string,
|
|
32
|
+
file_path?: string,
|
|
33
|
+
): Record<string, string> | undefined {
|
|
34
|
+
const config_path = get_config_file_path(file_path);
|
|
35
|
+
const logger = create_app_logger();
|
|
36
|
+
|
|
37
|
+
if (!fs.existsSync(config_path)) {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
const hazo_config = new HazoConfig({
|
|
43
|
+
filePath: config_path,
|
|
44
|
+
});
|
|
45
|
+
return hazo_config.getSection(section_name);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
const error_message = error instanceof Error ? error.message : "Unknown error";
|
|
48
|
+
logger.warn("config_loader_read_section_failed", {
|
|
49
|
+
filename: "config_loader.server.ts",
|
|
50
|
+
line_number: 0,
|
|
51
|
+
section_name,
|
|
52
|
+
config_path,
|
|
53
|
+
error: error_message,
|
|
54
|
+
});
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Gets a single config value from a section
|
|
61
|
+
* @param section_name - Name of the section
|
|
62
|
+
* @param key - Key name within the section
|
|
63
|
+
* @param default_value - Default value if key is not found
|
|
64
|
+
* @param file_path - Optional custom config file path
|
|
65
|
+
* @returns Config value as string or default value
|
|
66
|
+
*/
|
|
67
|
+
export function get_config_value(
|
|
68
|
+
section_name: string,
|
|
69
|
+
key: string,
|
|
70
|
+
default_value: string,
|
|
71
|
+
file_path?: string,
|
|
72
|
+
): string {
|
|
73
|
+
const section = read_config_section(section_name, file_path);
|
|
74
|
+
return section?.[key]?.trim() || default_value;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Gets a boolean config value from a section
|
|
79
|
+
* @param section_name - Name of the section
|
|
80
|
+
* @param key - Key name within the section
|
|
81
|
+
* @param default_value - Default boolean value if key is not found
|
|
82
|
+
* @param file_path - Optional custom config file path
|
|
83
|
+
* @returns Config value as boolean
|
|
84
|
+
*/
|
|
85
|
+
export function get_config_boolean(
|
|
86
|
+
section_name: string,
|
|
87
|
+
key: string,
|
|
88
|
+
default_value: boolean,
|
|
89
|
+
file_path?: string,
|
|
90
|
+
): boolean {
|
|
91
|
+
const section = read_config_section(section_name, file_path);
|
|
92
|
+
const value = section?.[key]?.trim().toLowerCase();
|
|
93
|
+
|
|
94
|
+
if (value === undefined) {
|
|
95
|
+
return default_value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return value !== "false" && value !== "0" && value !== "";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Gets a number config value from a section
|
|
103
|
+
* @param section_name - Name of the section
|
|
104
|
+
* @param key - Key name within the section
|
|
105
|
+
* @param default_value - Default number value if key is not found or invalid
|
|
106
|
+
* @param file_path - Optional custom config file path
|
|
107
|
+
* @returns Config value as number
|
|
108
|
+
*/
|
|
109
|
+
export function get_config_number(
|
|
110
|
+
section_name: string,
|
|
111
|
+
key: string,
|
|
112
|
+
default_value: number,
|
|
113
|
+
file_path?: string,
|
|
114
|
+
): number {
|
|
115
|
+
const section = read_config_section(section_name, file_path);
|
|
116
|
+
const value = section?.[key]?.trim();
|
|
117
|
+
|
|
118
|
+
if (!value) {
|
|
119
|
+
return default_value;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const parsed = parseFloat(value);
|
|
123
|
+
return isNaN(parsed) ? default_value : parsed;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Gets a comma-separated list config value from a section
|
|
128
|
+
* @param section_name - Name of the section
|
|
129
|
+
* @param key - Key name within the section
|
|
130
|
+
* @param default_value - Default array value if key is not found
|
|
131
|
+
* @param file_path - Optional custom config file path
|
|
132
|
+
* @returns Config value as array of strings
|
|
133
|
+
*/
|
|
134
|
+
export function get_config_array(
|
|
135
|
+
section_name: string,
|
|
136
|
+
key: string,
|
|
137
|
+
default_value: string[],
|
|
138
|
+
file_path?: string,
|
|
139
|
+
): string[] {
|
|
140
|
+
const section = read_config_section(section_name, file_path);
|
|
141
|
+
const value = section?.[key]?.trim();
|
|
142
|
+
|
|
143
|
+
if (!value) {
|
|
144
|
+
return default_value;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return value.split(",").map((item) => item.trim()).filter((item) => item.length > 0);
|
|
148
|
+
}
|
|
149
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// file_description: server-only helper to read email verification layout configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_already_logged_in_config } from "./already_logged_in_config.server";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type EmailVerificationConfig = {
|
|
7
|
+
alreadyLoggedInMessage: string;
|
|
8
|
+
showLogoutButton: boolean;
|
|
9
|
+
showReturnHomeButton: boolean;
|
|
10
|
+
returnHomeButtonLabel: string;
|
|
11
|
+
returnHomePath: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// section: helpers
|
|
15
|
+
/**
|
|
16
|
+
* Reads email verification layout configuration from hazo_auth_config.ini file
|
|
17
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
18
|
+
* @returns Email verification configuration options
|
|
19
|
+
*/
|
|
20
|
+
export function get_email_verification_config(): EmailVerificationConfig {
|
|
21
|
+
// Get shared already logged in config
|
|
22
|
+
const alreadyLoggedInConfig = get_already_logged_in_config();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
alreadyLoggedInMessage: alreadyLoggedInConfig.message,
|
|
26
|
+
showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
|
|
27
|
+
showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
|
|
28
|
+
returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
|
|
29
|
+
returnHomePath: alreadyLoggedInConfig.returnHomePath,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
// file_description: server-only helper to read file type configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_array } from "./config/config_loader.server";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type FileTypesConfig = {
|
|
7
|
+
allowed_image_extensions: string[];
|
|
8
|
+
allowed_image_mime_types: string[];
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// section: helpers
|
|
12
|
+
/**
|
|
13
|
+
* Reads file type configuration from hazo_auth_config.ini file
|
|
14
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
15
|
+
* @returns File types configuration options
|
|
16
|
+
*/
|
|
17
|
+
export function get_file_types_config(): FileTypesConfig {
|
|
18
|
+
const section = "hazo_auth__file_types";
|
|
19
|
+
|
|
20
|
+
return {
|
|
21
|
+
allowed_image_extensions: get_config_array(section, "allowed_image_extensions", ["jpg", "jpeg", "png"]),
|
|
22
|
+
allowed_image_mime_types: get_config_array(section, "allowed_image_mime_types", ["image/jpeg", "image/jpg", "image/png"]),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// file_description: server-only helper to read forgot password layout configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_already_logged_in_config } from "./already_logged_in_config.server";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type ForgotPasswordConfig = {
|
|
7
|
+
alreadyLoggedInMessage: string;
|
|
8
|
+
showLogoutButton: boolean;
|
|
9
|
+
showReturnHomeButton: boolean;
|
|
10
|
+
returnHomeButtonLabel: string;
|
|
11
|
+
returnHomePath: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
// section: helpers
|
|
15
|
+
/**
|
|
16
|
+
* Reads forgot password layout configuration from hazo_auth_config.ini file
|
|
17
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
18
|
+
* @returns Forgot password configuration options
|
|
19
|
+
*/
|
|
20
|
+
export function get_forgot_password_config(): ForgotPasswordConfig {
|
|
21
|
+
// Get shared already logged in config
|
|
22
|
+
const alreadyLoggedInConfig = get_already_logged_in_config();
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
alreadyLoggedInMessage: alreadyLoggedInConfig.message,
|
|
26
|
+
showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
|
|
27
|
+
showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
|
|
28
|
+
returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
|
|
29
|
+
returnHomePath: alreadyLoggedInConfig.returnHomePath,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// file_description: singleton instance of hazo_connect adapter - initialized once and reused across all routes
|
|
2
|
+
// This ensures all routes/components use the same database connection
|
|
3
|
+
// Uses the new hazo_connect singleton API from hazo_connect/nextjs/setup
|
|
4
|
+
// Reads configuration from hazo_auth_config.ini using hazo_config
|
|
5
|
+
// section: imports
|
|
6
|
+
import type { HazoConnectAdapter } from "hazo_connect";
|
|
7
|
+
import { getHazoConnectSingleton } from "hazo_connect/nextjs/setup";
|
|
8
|
+
import { create_sqlite_hazo_connect_server, get_hazo_connect_config_options } from "./hazo_connect_setup.server";
|
|
9
|
+
import { initializeAdminService, getSqliteAdminService } from "hazo_connect/server";
|
|
10
|
+
import { create_app_logger } from "./app_logger";
|
|
11
|
+
|
|
12
|
+
// section: singleton_state
|
|
13
|
+
let hazoConnectInstance: HazoConnectAdapter | null = null;
|
|
14
|
+
let isInitialized = false;
|
|
15
|
+
|
|
16
|
+
// section: helpers
|
|
17
|
+
/**
|
|
18
|
+
* Gets or creates the singleton hazo_connect adapter instance
|
|
19
|
+
* This ensures all routes/components use the same database connection
|
|
20
|
+
*
|
|
21
|
+
* Uses the new hazo_connect singleton API which:
|
|
22
|
+
* - Automatically reuses the adapter instance
|
|
23
|
+
* - Automatically registers SQLite adapters with the admin service
|
|
24
|
+
* - Is thread-safe for Next.js serverless environments
|
|
25
|
+
* - Reads configuration from hazo_auth_config.ini using hazo_config (falls back to environment variables)
|
|
26
|
+
*
|
|
27
|
+
* Falls back to manual singleton if the new API is not available
|
|
28
|
+
*
|
|
29
|
+
* @returns The singleton HazoConnectAdapter instance
|
|
30
|
+
*/
|
|
31
|
+
export function get_hazo_connect_instance(): HazoConnectAdapter {
|
|
32
|
+
// Use the new singleton API from hazo_connect
|
|
33
|
+
// This automatically handles:
|
|
34
|
+
// - Instance reuse
|
|
35
|
+
// - Admin service registration (via registerSqliteAdapter)
|
|
36
|
+
// - Thread-safety for Next.js serverless
|
|
37
|
+
// - Configuration from hazo_auth_config.ini (via hazo_config) or environment variables
|
|
38
|
+
try {
|
|
39
|
+
// Get configuration from hazo_auth_config.ini (falls back to environment variables)
|
|
40
|
+
const config_options = get_hazo_connect_config_options();
|
|
41
|
+
return getHazoConnectSingleton(config_options);
|
|
42
|
+
} catch (error) {
|
|
43
|
+
// Fallback: Manual singleton implementation if new API fails
|
|
44
|
+
// This should not happen with the updated package, but kept for safety
|
|
45
|
+
if (!hazoConnectInstance) {
|
|
46
|
+
// Initialize admin service first (if not already done)
|
|
47
|
+
if (!isInitialized) {
|
|
48
|
+
initializeAdminService({ enable_admin_ui: true });
|
|
49
|
+
isInitialized = true;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Create the adapter instance (reads from hazo_auth_config.ini)
|
|
53
|
+
hazoConnectInstance = create_sqlite_hazo_connect_server();
|
|
54
|
+
|
|
55
|
+
// Note: Database migrations should be applied manually via SQLite Admin UI
|
|
56
|
+
// or through a separate migration script. The token_service has fallback
|
|
57
|
+
// logic to work without the token_type column if migration hasn't been applied.
|
|
58
|
+
|
|
59
|
+
// Finalize initialization by getting the admin service.
|
|
60
|
+
try {
|
|
61
|
+
getSqliteAdminService();
|
|
62
|
+
} catch (adminError) {
|
|
63
|
+
const logger = create_app_logger();
|
|
64
|
+
const error_message = adminError instanceof Error ? adminError.message : "Unknown error";
|
|
65
|
+
logger.warn("hazo_connect_instance_admin_service_init_failed", {
|
|
66
|
+
filename: "hazo_connect_instance.server.ts",
|
|
67
|
+
line_number: 0,
|
|
68
|
+
error: error_message,
|
|
69
|
+
note: "Could not get SqliteAdminService during initialization, continuing...",
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return hazoConnectInstance;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// file_description: server-only helper to create hazo_connect instance (imports server-side code)
|
|
2
|
+
// This file should only be imported in server contexts (API routes, server components)
|
|
3
|
+
// Reads configuration from hazo_auth_config.ini using hazo_config
|
|
4
|
+
// section: imports
|
|
5
|
+
import { createHazoConnect } from "hazo_connect/server";
|
|
6
|
+
import { HazoConfig } from "hazo_config/dist/lib";
|
|
7
|
+
import path from "path";
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import { create_app_logger } from "./app_logger";
|
|
10
|
+
import { read_config_section } from "./config/config_loader.server";
|
|
11
|
+
|
|
12
|
+
// section: helpers
|
|
13
|
+
/**
|
|
14
|
+
* Reads hazo_connect configuration from hazo_auth_config.ini file
|
|
15
|
+
* Falls back to environment variables if hazo_auth_config.ini is not found or section is missing
|
|
16
|
+
* @returns Configuration options for hazo_connect
|
|
17
|
+
*/
|
|
18
|
+
function get_hazo_connect_config(): {
|
|
19
|
+
type: "sqlite" | "postgrest";
|
|
20
|
+
sqlitePath?: string;
|
|
21
|
+
enableAdminUi: boolean;
|
|
22
|
+
readOnly?: boolean;
|
|
23
|
+
postgrestUrl?: string;
|
|
24
|
+
postgrestApiKey?: string;
|
|
25
|
+
} {
|
|
26
|
+
const default_config_path = path.resolve(process.cwd(), "hazo_auth_config.ini");
|
|
27
|
+
let hazo_connect_section: Record<string, string> | undefined;
|
|
28
|
+
|
|
29
|
+
// Try to read from hazo_auth_config.ini
|
|
30
|
+
const logger = create_app_logger();
|
|
31
|
+
hazo_connect_section = read_config_section("hazo_connect");
|
|
32
|
+
|
|
33
|
+
// Read type (defaults to sqlite)
|
|
34
|
+
const type = (
|
|
35
|
+
hazo_connect_section?.type ||
|
|
36
|
+
process.env.HAZO_CONNECT_TYPE ||
|
|
37
|
+
"sqlite"
|
|
38
|
+
).toLowerCase() as "sqlite" | "postgrest";
|
|
39
|
+
|
|
40
|
+
// Read enable_admin_ui (defaults to true)
|
|
41
|
+
const enable_admin_ui_str =
|
|
42
|
+
hazo_connect_section?.enable_admin_ui ||
|
|
43
|
+
process.env.HAZO_CONNECT_ENABLE_ADMIN_UI ||
|
|
44
|
+
"true";
|
|
45
|
+
const enableAdminUi = enable_admin_ui_str.toLowerCase() === "true";
|
|
46
|
+
|
|
47
|
+
// Read read_only (defaults to false)
|
|
48
|
+
const read_only_str =
|
|
49
|
+
hazo_connect_section?.read_only ||
|
|
50
|
+
process.env.HAZO_CONNECT_SQLITE_READONLY ||
|
|
51
|
+
"false";
|
|
52
|
+
const readOnly = read_only_str.toLowerCase() === "true";
|
|
53
|
+
|
|
54
|
+
// SQLite configuration
|
|
55
|
+
if (type === "sqlite") {
|
|
56
|
+
const sqlite_path_config =
|
|
57
|
+
hazo_connect_section?.sqlite_path || process.env.HAZO_CONNECT_SQLITE_PATH;
|
|
58
|
+
|
|
59
|
+
let sqlite_path: string | undefined;
|
|
60
|
+
|
|
61
|
+
if (sqlite_path_config) {
|
|
62
|
+
// If path is absolute, use as-is; otherwise resolve relative to process.cwd()
|
|
63
|
+
sqlite_path = path.isAbsolute(sqlite_path_config)
|
|
64
|
+
? sqlite_path_config
|
|
65
|
+
: path.resolve(process.cwd(), sqlite_path_config);
|
|
66
|
+
|
|
67
|
+
// Normalize the path to ensure consistency (resolves .., ., etc.)
|
|
68
|
+
sqlite_path = path.normalize(sqlite_path);
|
|
69
|
+
} else {
|
|
70
|
+
// Fallback to test fixture database
|
|
71
|
+
const ui_component_path = path.resolve(
|
|
72
|
+
process.cwd(),
|
|
73
|
+
"ui_component",
|
|
74
|
+
"__tests__",
|
|
75
|
+
"fixtures",
|
|
76
|
+
"hazo_auth.sqlite"
|
|
77
|
+
);
|
|
78
|
+
sqlite_path = path.normalize(ui_component_path);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Log the resolved path for debugging
|
|
82
|
+
logger.debug("hazo_connect_sqlite_path_resolved", {
|
|
83
|
+
filename: "hazo_connect_setup.server.ts",
|
|
84
|
+
line_number: 0,
|
|
85
|
+
sqlite_path,
|
|
86
|
+
process_cwd: process.cwd(),
|
|
87
|
+
config_source: hazo_connect_section ? "hazo_auth_config.ini" : "environment variables",
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
type: "sqlite",
|
|
92
|
+
sqlitePath: sqlite_path,
|
|
93
|
+
enableAdminUi,
|
|
94
|
+
readOnly,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// PostgREST configuration
|
|
99
|
+
if (type === "postgrest") {
|
|
100
|
+
const postgrest_url =
|
|
101
|
+
hazo_connect_section?.postgrest_url ||
|
|
102
|
+
process.env.HAZO_CONNECT_POSTGREST_URL ||
|
|
103
|
+
process.env.POSTGREST_URL;
|
|
104
|
+
const postgrest_api_key =
|
|
105
|
+
hazo_connect_section?.postgrest_api_key ||
|
|
106
|
+
process.env.HAZO_CONNECT_POSTGREST_API_KEY ||
|
|
107
|
+
process.env.POSTGREST_API_KEY;
|
|
108
|
+
|
|
109
|
+
if (!postgrest_url) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
"PostgREST URL is required. Set postgrest_url in [hazo_connect] section of hazo_auth_config.ini or HAZO_CONNECT_POSTGREST_URL environment variable."
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
type: "postgrest",
|
|
117
|
+
postgrestUrl: postgrest_url,
|
|
118
|
+
postgrestApiKey: postgrest_api_key,
|
|
119
|
+
enableAdminUi,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
throw new Error(
|
|
124
|
+
`Unsupported HAZO_CONNECT_TYPE: ${type}. Supported types: sqlite, postgrest`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Server-only function to create hazo_connect adapter
|
|
130
|
+
* Reads configuration from hazo_auth_config.ini using hazo_config, falls back to environment variables
|
|
131
|
+
* This should only be called from server-side code (API routes, server components)
|
|
132
|
+
*/
|
|
133
|
+
export function create_sqlite_hazo_connect_server() {
|
|
134
|
+
const config = get_hazo_connect_config();
|
|
135
|
+
|
|
136
|
+
if (config.type === "sqlite") {
|
|
137
|
+
return createHazoConnect({
|
|
138
|
+
type: "sqlite",
|
|
139
|
+
database: config.sqlitePath!,
|
|
140
|
+
enable_admin_ui: config.enableAdminUi,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (config.type === "postgrest") {
|
|
145
|
+
return createHazoConnect({
|
|
146
|
+
type: "postgrest",
|
|
147
|
+
baseUrl: config.postgrestUrl!,
|
|
148
|
+
apiKey: config.postgrestApiKey,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
throw new Error(`Unsupported database type: ${config.type}`);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Gets hazo_connect configuration options for use with singleton API
|
|
157
|
+
* Reads from hazo_auth_config.ini using hazo_config, falls back to environment variables
|
|
158
|
+
* @returns Configuration options compatible with getHazoConnectSingleton
|
|
159
|
+
*/
|
|
160
|
+
export function get_hazo_connect_config_options(): {
|
|
161
|
+
type?: "sqlite" | "postgrest";
|
|
162
|
+
sqlitePath?: string;
|
|
163
|
+
enableAdminUi?: boolean;
|
|
164
|
+
readOnly?: boolean;
|
|
165
|
+
} {
|
|
166
|
+
const config = get_hazo_connect_config();
|
|
167
|
+
|
|
168
|
+
if (config.type === "sqlite") {
|
|
169
|
+
return {
|
|
170
|
+
type: "sqlite",
|
|
171
|
+
sqlitePath: config.sqlitePath,
|
|
172
|
+
enableAdminUi: config.enableAdminUi,
|
|
173
|
+
readOnly: config.readOnly,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// PostgREST is not supported by the singleton API options yet
|
|
178
|
+
// Return empty object to let it use environment variables
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// file_description: helper function to create hazo_connect instance with configuration from environment variables
|
|
2
|
+
// This file provides a client-safe wrapper that returns a mock on client-side
|
|
3
|
+
// section: imports
|
|
4
|
+
// Note: We don't import server-side code here to avoid client-side bundling issues
|
|
5
|
+
|
|
6
|
+
// section: helpers
|
|
7
|
+
/**
|
|
8
|
+
* Creates a hazo_connect instance configured from environment variables
|
|
9
|
+
*
|
|
10
|
+
* Environment variables:
|
|
11
|
+
* - HAZO_CONNECT_TYPE: Database type ("sqlite" | "postgrest") - defaults to "sqlite"
|
|
12
|
+
* - HAZO_CONNECT_SQLITE_PATH: Path to SQLite database file (relative to process.cwd() or absolute)
|
|
13
|
+
* - HAZO_CONNECT_POSTGREST_URL: PostgREST API URL (for postgrest type)
|
|
14
|
+
* - HAZO_CONNECT_POSTGREST_API_KEY: PostgREST API key (for postgrest type)
|
|
15
|
+
*
|
|
16
|
+
* Falls back to test fixture database if HAZO_CONNECT_SQLITE_PATH is not set
|
|
17
|
+
*
|
|
18
|
+
* Note: For client-side usage (Next.js pages), this returns a mock adapter
|
|
19
|
+
* since SQLite cannot run in browser environments. Use PostgREST for client-side database access.
|
|
20
|
+
*/
|
|
21
|
+
// Lazy loader for server module - prevents webpack from statically analyzing the require
|
|
22
|
+
function loadServerModule() {
|
|
23
|
+
// Use Function constructor to create a dynamic require that webpack can't analyze
|
|
24
|
+
// eslint-disable-next-line no-new-func
|
|
25
|
+
const requireFunc = new Function('modulePath', 'return require(modulePath)');
|
|
26
|
+
return requireFunc('./hazo_connect_setup.server');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function create_sqlite_hazo_connect() {
|
|
30
|
+
// Check if we're in a browser/client environment
|
|
31
|
+
if (typeof window !== "undefined") {
|
|
32
|
+
// Return a mock adapter for client-side usage
|
|
33
|
+
return create_client_mock_hazo_connect();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Server-side: dynamically load server module
|
|
37
|
+
// Using Function constructor prevents webpack from statically analyzing the require
|
|
38
|
+
const serverModule = loadServerModule();
|
|
39
|
+
return serverModule.create_sqlite_hazo_connect_server();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Creates a mock hazo_connect adapter for client-side usage
|
|
44
|
+
* This satisfies the LayoutDataClient interface without requiring SQLite
|
|
45
|
+
*/
|
|
46
|
+
function create_client_mock_hazo_connect() {
|
|
47
|
+
return {
|
|
48
|
+
healthCheck: async () => {
|
|
49
|
+
// Mock health check for client-side - no-op
|
|
50
|
+
return Promise.resolve();
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
// file_description: server-only helper to read login layout configuration from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_value } from "./config/config_loader.server";
|
|
4
|
+
import { get_already_logged_in_config } from "./already_logged_in_config.server";
|
|
5
|
+
|
|
6
|
+
// section: types
|
|
7
|
+
export type LoginConfig = {
|
|
8
|
+
redirectRoute?: string;
|
|
9
|
+
successMessage: string;
|
|
10
|
+
alreadyLoggedInMessage: string;
|
|
11
|
+
showLogoutButton: boolean;
|
|
12
|
+
showReturnHomeButton: boolean;
|
|
13
|
+
returnHomeButtonLabel: string;
|
|
14
|
+
returnHomePath: string;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// section: helpers
|
|
18
|
+
/**
|
|
19
|
+
* Reads login layout configuration from hazo_auth_config.ini file
|
|
20
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
21
|
+
* @returns Login configuration options
|
|
22
|
+
*/
|
|
23
|
+
export function get_login_config(): LoginConfig {
|
|
24
|
+
const section = "hazo_auth__login_layout";
|
|
25
|
+
|
|
26
|
+
// Read redirect route (optional)
|
|
27
|
+
const redirectRouteValue = get_config_value(section, "redirect_route_on_successful_login", "");
|
|
28
|
+
const redirectRoute = redirectRouteValue || undefined;
|
|
29
|
+
|
|
30
|
+
// Read success message (defaults to "Successfully logged in")
|
|
31
|
+
const successMessage = get_config_value(section, "success_message", "Successfully logged in");
|
|
32
|
+
|
|
33
|
+
// Get shared already logged in config
|
|
34
|
+
const alreadyLoggedInConfig = get_already_logged_in_config();
|
|
35
|
+
|
|
36
|
+
return {
|
|
37
|
+
redirectRoute,
|
|
38
|
+
successMessage,
|
|
39
|
+
alreadyLoggedInMessage: alreadyLoggedInConfig.message,
|
|
40
|
+
showLogoutButton: alreadyLoggedInConfig.showLogoutButton,
|
|
41
|
+
showReturnHomeButton: alreadyLoggedInConfig.showReturnHomeButton,
|
|
42
|
+
returnHomeButtonLabel: alreadyLoggedInConfig.returnHomeButtonLabel,
|
|
43
|
+
returnHomePath: alreadyLoggedInConfig.returnHomePath,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// file_description: server-only helper to read user-facing messages from hazo_auth_config.ini
|
|
2
|
+
// section: imports
|
|
3
|
+
import { get_config_value } from "./config/config_loader.server";
|
|
4
|
+
|
|
5
|
+
// section: types
|
|
6
|
+
export type MessagesConfig = {
|
|
7
|
+
photo_upload_disabled_message: string;
|
|
8
|
+
gravatar_setup_message: string;
|
|
9
|
+
gravatar_no_account_message: string;
|
|
10
|
+
library_tooltip_message: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// section: helpers
|
|
14
|
+
/**
|
|
15
|
+
* Reads user-facing messages from hazo_auth_config.ini file
|
|
16
|
+
* Falls back to defaults if hazo_auth_config.ini is not found or section is missing
|
|
17
|
+
* @returns Messages configuration options
|
|
18
|
+
*/
|
|
19
|
+
export function get_messages_config(): MessagesConfig {
|
|
20
|
+
const section = "hazo_auth__messages";
|
|
21
|
+
|
|
22
|
+
return {
|
|
23
|
+
photo_upload_disabled_message: get_config_value(
|
|
24
|
+
section,
|
|
25
|
+
"photo_upload_disabled_message",
|
|
26
|
+
"Photo upload is not enabled. Please contact your administrator."
|
|
27
|
+
),
|
|
28
|
+
gravatar_setup_message: get_config_value(
|
|
29
|
+
section,
|
|
30
|
+
"gravatar_setup_message",
|
|
31
|
+
"To set up your Gravatar:"
|
|
32
|
+
),
|
|
33
|
+
gravatar_no_account_message: get_config_value(
|
|
34
|
+
section,
|
|
35
|
+
"gravatar_no_account_message",
|
|
36
|
+
"You don't have a Gravatar account set up for this email address."
|
|
37
|
+
),
|
|
38
|
+
library_tooltip_message: get_config_value(
|
|
39
|
+
section,
|
|
40
|
+
"library_tooltip_message",
|
|
41
|
+
"Select another tab image style to remove this image"
|
|
42
|
+
),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|