hazo_auth 4.2.0 → 4.4.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 (136) hide show
  1. package/bin/hazo_auth.mjs +35 -0
  2. package/cli-src/assets/images/forgot_password_default.jpg +0 -0
  3. package/cli-src/assets/images/login_default.jpg +0 -0
  4. package/cli-src/assets/images/register_default.jpg +0 -0
  5. package/cli-src/assets/images/reset_password_default.jpg +0 -0
  6. package/cli-src/assets/images/verify_email_default.jpg +0 -0
  7. package/cli-src/cli/generate.ts +276 -0
  8. package/cli-src/cli/index.ts +207 -0
  9. package/cli-src/cli/init.ts +254 -0
  10. package/cli-src/cli/init_users.ts +376 -0
  11. package/cli-src/cli/validate.ts +581 -0
  12. package/cli-src/lib/already_logged_in_config.server.ts +46 -0
  13. package/cli-src/lib/app_logger.ts +24 -0
  14. package/cli-src/lib/auth/auth_cache.ts +220 -0
  15. package/cli-src/lib/auth/auth_rate_limiter.ts +121 -0
  16. package/cli-src/lib/auth/auth_types.ts +117 -0
  17. package/cli-src/lib/auth/auth_utils.server.ts +196 -0
  18. package/cli-src/lib/auth/dev_lock_validator.edge.ts +171 -0
  19. package/cli-src/lib/auth/hazo_get_auth.server.ts +583 -0
  20. package/cli-src/lib/auth/index.ts +23 -0
  21. package/cli-src/lib/auth/nextauth_config.ts +227 -0
  22. package/cli-src/lib/auth/org_cache.ts +148 -0
  23. package/cli-src/lib/auth/scope_cache.ts +233 -0
  24. package/cli-src/lib/auth/server_auth.ts +88 -0
  25. package/cli-src/lib/auth/session_token_validator.edge.ts +92 -0
  26. package/cli-src/lib/auth_utility_config.server.ts +136 -0
  27. package/cli-src/lib/config/config_loader.server.ts +164 -0
  28. package/cli-src/lib/config/default_config.ts +243 -0
  29. package/cli-src/lib/dev_lock_config.server.ts +148 -0
  30. package/cli-src/lib/email_verification_config.server.ts +63 -0
  31. package/cli-src/lib/file_types_config.server.ts +25 -0
  32. package/cli-src/lib/forgot_password_config.server.ts +63 -0
  33. package/cli-src/lib/hazo_connect_instance.server.ts +101 -0
  34. package/cli-src/lib/hazo_connect_setup.server.ts +194 -0
  35. package/cli-src/lib/hazo_connect_setup.ts +54 -0
  36. package/cli-src/lib/index.ts +46 -0
  37. package/cli-src/lib/login_config.server.ts +106 -0
  38. package/cli-src/lib/messages_config.server.ts +45 -0
  39. package/cli-src/lib/migrations/apply_migration.ts +105 -0
  40. package/cli-src/lib/multi_tenancy_config.server.ts +94 -0
  41. package/cli-src/lib/my_settings_config.server.ts +135 -0
  42. package/cli-src/lib/oauth_config.server.ts +87 -0
  43. package/cli-src/lib/password_requirements_config.server.ts +40 -0
  44. package/cli-src/lib/profile_pic_menu_config.server.ts +138 -0
  45. package/cli-src/lib/profile_picture_config.server.ts +56 -0
  46. package/cli-src/lib/register_config.server.ts +101 -0
  47. package/cli-src/lib/reset_password_config.server.ts +103 -0
  48. package/cli-src/lib/scope_hierarchy_config.server.ts +151 -0
  49. package/cli-src/lib/services/email_service.ts +587 -0
  50. package/cli-src/lib/services/email_verification_service.ts +270 -0
  51. package/cli-src/lib/services/index.ts +16 -0
  52. package/cli-src/lib/services/login_service.ts +150 -0
  53. package/cli-src/lib/services/oauth_service.ts +494 -0
  54. package/cli-src/lib/services/org_service.ts +965 -0
  55. package/cli-src/lib/services/password_change_service.ts +154 -0
  56. package/cli-src/lib/services/password_reset_service.ts +418 -0
  57. package/cli-src/lib/services/profile_picture_remove_service.ts +120 -0
  58. package/cli-src/lib/services/profile_picture_service.ts +451 -0
  59. package/cli-src/lib/services/profile_picture_source_mapper.ts +62 -0
  60. package/cli-src/lib/services/registration_service.ts +185 -0
  61. package/cli-src/lib/services/scope_labels_service.ts +348 -0
  62. package/cli-src/lib/services/scope_service.ts +778 -0
  63. package/cli-src/lib/services/session_token_service.ts +178 -0
  64. package/cli-src/lib/services/token_service.ts +240 -0
  65. package/cli-src/lib/services/user_profiles_cache.ts +189 -0
  66. package/cli-src/lib/services/user_profiles_service.ts +264 -0
  67. package/cli-src/lib/services/user_scope_service.ts +554 -0
  68. package/cli-src/lib/services/user_update_service.ts +141 -0
  69. package/cli-src/lib/ui_shell_config.server.ts +73 -0
  70. package/cli-src/lib/ui_sizes_config.server.ts +37 -0
  71. package/cli-src/lib/user_fields_config.server.ts +31 -0
  72. package/cli-src/lib/user_management_config.server.ts +39 -0
  73. package/cli-src/lib/user_profiles_config.server.ts +55 -0
  74. package/cli-src/lib/utils/api_route_helpers.ts +60 -0
  75. package/cli-src/lib/utils/error_sanitizer.ts +75 -0
  76. package/cli-src/lib/utils/password_validator.ts +65 -0
  77. package/cli-src/lib/utils.ts +11 -0
  78. package/cli-src/server/logging/logger_service.ts +56 -0
  79. package/cli-src/server/types/app_types.ts +74 -0
  80. package/cli-src/server/types/express.d.ts +16 -0
  81. package/dist/cli/index.js +18 -0
  82. package/dist/cli/init_users.d.ts +17 -0
  83. package/dist/cli/init_users.d.ts.map +1 -0
  84. package/dist/cli/init_users.js +307 -0
  85. package/dist/components/layouts/dev_lock/index.d.ts +29 -0
  86. package/dist/components/layouts/dev_lock/index.d.ts.map +1 -0
  87. package/dist/components/layouts/dev_lock/index.js +60 -0
  88. package/dist/components/layouts/index.d.ts +2 -0
  89. package/dist/components/layouts/index.d.ts.map +1 -1
  90. package/dist/components/layouts/index.js +1 -0
  91. package/dist/components/layouts/org_management/index.d.ts +26 -0
  92. package/dist/components/layouts/org_management/index.d.ts.map +1 -0
  93. package/dist/components/layouts/org_management/index.js +75 -0
  94. package/dist/components/layouts/shared/config/layout_customization.d.ts +2 -7
  95. package/dist/components/layouts/shared/config/layout_customization.d.ts.map +1 -1
  96. package/dist/components/layouts/user_management/components/org_hierarchy_tab.d.ts +13 -0
  97. package/dist/components/layouts/user_management/components/org_hierarchy_tab.d.ts.map +1 -0
  98. package/dist/components/layouts/user_management/components/org_hierarchy_tab.js +276 -0
  99. package/dist/components/layouts/user_management/index.d.ts +3 -1
  100. package/dist/components/layouts/user_management/index.d.ts.map +1 -1
  101. package/dist/components/layouts/user_management/index.js +10 -4
  102. package/dist/lib/auth/auth_types.d.ts +6 -0
  103. package/dist/lib/auth/auth_types.d.ts.map +1 -1
  104. package/dist/lib/auth/dev_lock_validator.edge.d.ts +38 -0
  105. package/dist/lib/auth/dev_lock_validator.edge.d.ts.map +1 -0
  106. package/dist/lib/auth/dev_lock_validator.edge.js +122 -0
  107. package/dist/lib/auth/hazo_get_auth.server.d.ts.map +1 -1
  108. package/dist/lib/auth/hazo_get_auth.server.js +61 -1
  109. package/dist/lib/auth/org_cache.d.ts +65 -0
  110. package/dist/lib/auth/org_cache.d.ts.map +1 -0
  111. package/dist/lib/auth/org_cache.js +103 -0
  112. package/dist/lib/config/default_config.d.ts +76 -0
  113. package/dist/lib/config/default_config.d.ts.map +1 -1
  114. package/dist/lib/config/default_config.js +42 -0
  115. package/dist/lib/dev_lock_config.server.d.ts +41 -0
  116. package/dist/lib/dev_lock_config.server.d.ts.map +1 -0
  117. package/dist/lib/dev_lock_config.server.js +50 -0
  118. package/dist/lib/multi_tenancy_config.server.d.ts +30 -0
  119. package/dist/lib/multi_tenancy_config.server.d.ts.map +1 -0
  120. package/dist/lib/multi_tenancy_config.server.js +41 -0
  121. package/dist/lib/services/org_service.d.ts +191 -0
  122. package/dist/lib/services/org_service.d.ts.map +1 -0
  123. package/dist/lib/services/org_service.js +746 -0
  124. package/dist/lib/utils/password_validator.d.ts +7 -1
  125. package/dist/lib/utils/password_validator.d.ts.map +1 -1
  126. package/dist/page_components/dev_lock.d.ts +11 -0
  127. package/dist/page_components/dev_lock.d.ts.map +1 -0
  128. package/dist/page_components/dev_lock.js +17 -0
  129. package/dist/page_components/index.d.ts +1 -0
  130. package/dist/page_components/index.d.ts.map +1 -1
  131. package/dist/page_components/index.js +1 -0
  132. package/dist/page_components/org_management.d.ts +27 -0
  133. package/dist/page_components/org_management.d.ts.map +1 -0
  134. package/dist/page_components/org_management.js +18 -0
  135. package/hazo_auth_config.example.ini +30 -0
  136. package/package.json +27 -3
@@ -0,0 +1,73 @@
1
+ // file_description: load ui shell layout settings from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_value } from "./config/config_loader.server.js";
4
+
5
+ // section: types
6
+ export type UiShellLayoutMode = "test_sidebar" | "standalone";
7
+
8
+ export type UiShellConfig = {
9
+ layout_mode: UiShellLayoutMode;
10
+ standalone_heading: string;
11
+ standalone_description: string;
12
+ standalone_wrapper_class: string;
13
+ standalone_content_class: string;
14
+ standalone_show_heading: boolean;
15
+ standalone_show_description: boolean;
16
+ };
17
+
18
+ // section: helpers
19
+ /**
20
+ * Reads ui shell configuration controlling whether pages use the sidebar test shell
21
+ * or a clean standalone wrapper that inherits consumer project styling.
22
+ */
23
+ export function get_ui_shell_config(): UiShellConfig {
24
+ const section = "hazo_auth__ui_shell";
25
+
26
+ const layoutModeValue = get_config_value(section, "layout_mode", "test_sidebar").toLowerCase();
27
+ const layout_mode: UiShellLayoutMode =
28
+ layoutModeValue === "standalone" ? "standalone" : "test_sidebar";
29
+
30
+ const standalone_heading = get_config_value(
31
+ section,
32
+ "standalone_heading",
33
+ "Welcome to hazo auth"
34
+ );
35
+ const standalone_description = get_config_value(
36
+ section,
37
+ "standalone_description",
38
+ "Reuse the packaged authentication flows while inheriting your existing app shell styles."
39
+ );
40
+ const standalone_wrapper_class = get_config_value(
41
+ section,
42
+ "standalone_wrapper_class",
43
+ "cls_standalone_shell flex min-h-screen w-full items-center justify-center bg-background px-4 py-10"
44
+ );
45
+ const standalone_content_class = get_config_value(
46
+ section,
47
+ "standalone_content_class",
48
+ "cls_standalone_shell_content w-full max-w-5xl shadow-xl rounded-2xl border bg-card"
49
+ );
50
+ const standalone_show_heading = get_config_value(
51
+ section,
52
+ "standalone_show_heading",
53
+ "true"
54
+ ).toLowerCase() === "true";
55
+ const standalone_show_description = get_config_value(
56
+ section,
57
+ "standalone_show_description",
58
+ "true"
59
+ ).toLowerCase() === "true";
60
+
61
+ return {
62
+ layout_mode,
63
+ standalone_heading,
64
+ standalone_description,
65
+ standalone_wrapper_class,
66
+ standalone_content_class,
67
+ standalone_show_heading,
68
+ standalone_show_description,
69
+ };
70
+ }
71
+
72
+
73
+
@@ -0,0 +1,37 @@
1
+ // file_description: server-only helper to read UI size configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_number } from "./config/config_loader.server.js";
4
+
5
+ // section: types
6
+ export type UISizesConfig = {
7
+ gravatar_size: number;
8
+ profile_picture_size: number;
9
+ tooltip_icon_size_default: number;
10
+ tooltip_icon_size_small: number;
11
+ library_photo_grid_columns: number;
12
+ library_photo_preview_size: number;
13
+ image_compression_max_dimension: number;
14
+ upload_file_hard_limit_bytes: number;
15
+ };
16
+
17
+ // section: helpers
18
+ /**
19
+ * Reads UI size 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 UI sizes configuration options
22
+ */
23
+ export function get_ui_sizes_config(): UISizesConfig {
24
+ const section = "hazo_auth__ui_sizes";
25
+
26
+ return {
27
+ gravatar_size: get_config_number(section, "gravatar_size", 200),
28
+ profile_picture_size: get_config_number(section, "profile_picture_size", 200),
29
+ tooltip_icon_size_default: get_config_number(section, "tooltip_icon_size_default", 16),
30
+ tooltip_icon_size_small: get_config_number(section, "tooltip_icon_size_small", 14),
31
+ library_photo_grid_columns: get_config_number(section, "library_photo_grid_columns", 4),
32
+ library_photo_preview_size: get_config_number(section, "library_photo_preview_size", 200),
33
+ image_compression_max_dimension: get_config_number(section, "image_compression_max_dimension", 200),
34
+ upload_file_hard_limit_bytes: get_config_number(section, "upload_file_hard_limit_bytes", 10485760), // 10MB
35
+ };
36
+ }
37
+
@@ -0,0 +1,31 @@
1
+ // file_description: server-only helper to read shared user fields configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_boolean } from "./config/config_loader.server.js";
4
+
5
+ // section: types
6
+ export type UserFieldsConfig = {
7
+ show_name_field: boolean;
8
+ show_email_field: boolean;
9
+ show_password_field: boolean;
10
+ };
11
+
12
+ // section: helpers
13
+ /**
14
+ * Reads shared user fields 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
+ * This configuration is used by register and my_settings layouts
17
+ * @returns User fields configuration options
18
+ */
19
+ export function get_user_fields_config(): UserFieldsConfig {
20
+ // Read field visibility with defaults (all true by default)
21
+ const show_name_field = get_config_boolean("hazo_auth__user_fields", "show_name_field", true);
22
+ const show_email_field = get_config_boolean("hazo_auth__user_fields", "show_email_field", true);
23
+ const show_password_field = get_config_boolean("hazo_auth__user_fields", "show_password_field", true);
24
+
25
+ return {
26
+ show_name_field,
27
+ show_email_field,
28
+ show_password_field,
29
+ };
30
+ }
31
+
@@ -0,0 +1,39 @@
1
+ // file_description: server-only helper to read user management configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import { get_config_value, get_config_array, read_config_section } from "./config/config_loader.server.js";
4
+
5
+ // section: types
6
+ export type UserManagementConfig = {
7
+ application_permission_list_defaults: string[];
8
+ };
9
+
10
+ // section: helpers
11
+ /**
12
+ * Reads user management configuration from hazo_auth_config.ini file
13
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
14
+ * @returns User management configuration options
15
+ */
16
+ export function get_user_management_config(): UserManagementConfig {
17
+ // Try to read from hazo_auth__user_management section first
18
+ const user_management_section = read_config_section("hazo_auth__user_management");
19
+ const permissions_section = read_config_section("permissions");
20
+
21
+ // Try application_permission_list_defaults from user_management section
22
+ let permission_list: string[] = [];
23
+
24
+ if (user_management_section?.application_permission_list_defaults) {
25
+ permission_list = get_config_array(
26
+ "hazo_auth__user_management",
27
+ "application_permission_list_defaults",
28
+ []
29
+ );
30
+ } else if (permissions_section?.list) {
31
+ // Fallback to permissions section list key
32
+ permission_list = get_config_array("permissions", "list", []);
33
+ }
34
+
35
+ return {
36
+ application_permission_list_defaults: permission_list,
37
+ };
38
+ }
39
+
@@ -0,0 +1,55 @@
1
+ // file_description: server-only helper to read user profiles cache configuration from hazo_auth_config.ini
2
+ // section: imports
3
+ import {
4
+ get_config_number,
5
+ } from "./config/config_loader.server.js";
6
+
7
+ // section: types
8
+
9
+ /**
10
+ * User profiles cache configuration options
11
+ */
12
+ export type UserProfilesCacheConfig = {
13
+ cache_enabled: boolean;
14
+ cache_max_entries: number;
15
+ cache_ttl_minutes: number;
16
+ };
17
+
18
+ // section: helpers
19
+
20
+ /**
21
+ * Reads user profiles cache configuration from hazo_auth_config.ini file
22
+ * Falls back to defaults if hazo_auth_config.ini is not found or section is missing
23
+ * @returns User profiles cache configuration options
24
+ */
25
+ export function get_user_profiles_cache_config(): UserProfilesCacheConfig {
26
+ const section_name = "hazo_auth__user_profiles";
27
+
28
+ // Cache settings
29
+ // cache_enabled: 0 = disabled, 1 = enabled (default: 1)
30
+ const cache_enabled_num = get_config_number(
31
+ section_name,
32
+ "cache_enabled",
33
+ 1,
34
+ );
35
+ const cache_enabled = cache_enabled_num === 1;
36
+
37
+ const cache_max_entries = get_config_number(
38
+ section_name,
39
+ "cache_max_entries",
40
+ 5000, // Default: 5000 entries
41
+ );
42
+
43
+ const cache_ttl_minutes = get_config_number(
44
+ section_name,
45
+ "cache_ttl_minutes",
46
+ 5, // Default: 5 minutes
47
+ );
48
+
49
+ return {
50
+ cache_enabled,
51
+ cache_max_entries,
52
+ cache_ttl_minutes,
53
+ };
54
+ }
55
+
@@ -0,0 +1,60 @@
1
+ // file_description: shared helper functions for API routes to get filename and line number
2
+ // section: helpers
3
+ /**
4
+ * Gets the filename from the call stack
5
+ * This is a simplified version that extracts the filename from the error stack
6
+ * @returns Filename or "route.ts" as default
7
+ */
8
+ export function get_filename(): string {
9
+ try {
10
+ const stack = new Error().stack;
11
+ if (!stack) {
12
+ return "route.ts";
13
+ }
14
+
15
+ // Parse stack trace to find the caller's file
16
+ const lines = stack.split("\n");
17
+ // Skip Error line and get_filename line, get the actual caller
18
+ for (let i = 2; i < lines.length; i++) {
19
+ const line = lines[i];
20
+ // Match file paths in stack trace (e.g., "at /path/to/file.ts:123:45")
21
+ const match = line.match(/([^/\\]+\.tsx?):(\d+):(\d+)/);
22
+ if (match) {
23
+ return match[1];
24
+ }
25
+ }
26
+ return "route.ts";
27
+ } catch {
28
+ return "route.ts";
29
+ }
30
+ }
31
+
32
+ /**
33
+ * Gets the line number from the call stack
34
+ * This is a simplified version that extracts the line number from the error stack
35
+ * @returns Line number or 0
36
+ */
37
+ export function get_line_number(): number {
38
+ try {
39
+ const stack = new Error().stack;
40
+ if (!stack) {
41
+ return 0;
42
+ }
43
+
44
+ // Parse stack trace to find the caller's line number
45
+ const lines = stack.split("\n");
46
+ // Skip Error line and get_line_number line, get the actual caller
47
+ for (let i = 2; i < lines.length; i++) {
48
+ const line = lines[i];
49
+ // Match line numbers in stack trace (e.g., "at /path/to/file.ts:123:45")
50
+ const match = line.match(/([^/\\]+\.tsx?):(\d+):(\d+)/);
51
+ if (match) {
52
+ return parseInt(match[2], 10) || 0;
53
+ }
54
+ }
55
+ return 0;
56
+ } catch {
57
+ return 0;
58
+ }
59
+ }
60
+
@@ -0,0 +1,75 @@
1
+ // file_description: utility functions for sanitizing error messages for user display
2
+ // section: imports
3
+ import { create_app_logger } from "../app_logger.js";
4
+
5
+ // section: constants
6
+ const USER_FRIENDLY_ERROR_MESSAGE = "We are facing some issues in our system, please try again later.";
7
+
8
+ // section: types
9
+ export type ErrorSanitizationOptions = {
10
+ logToConsole?: boolean;
11
+ logToLogger?: boolean;
12
+ logger?: ReturnType<typeof create_app_logger>;
13
+ context?: Record<string, unknown>;
14
+ };
15
+
16
+ // section: helpers
17
+ /**
18
+ * Sanitizes error messages for user display
19
+ * Replaces technical error messages with user-friendly ones
20
+ * @param error - The error object or message
21
+ * @param options - Options for logging and context
22
+ * @returns User-friendly error message
23
+ */
24
+ export function sanitize_error_for_user(
25
+ error: unknown,
26
+ options: ErrorSanitizationOptions = {}
27
+ ): string {
28
+ const { logToConsole = true, logToLogger = true, logger, context = {} } = options;
29
+
30
+ // Extract detailed error message
31
+ const detailed_error_message =
32
+ error instanceof Error ? error.message : String(error);
33
+ const error_stack = error instanceof Error ? error.stack : undefined;
34
+
35
+ // Log detailed error to console
36
+ if (logToConsole) {
37
+ console.error("Detailed error:", {
38
+ message: detailed_error_message,
39
+ stack: error_stack,
40
+ ...context,
41
+ });
42
+ }
43
+
44
+ // Log detailed error to logger if provided
45
+ if (logToLogger && logger) {
46
+ logger.error("error_occurred", {
47
+ filename: context.filename as string || "unknown",
48
+ line_number: context.line_number as number || 0,
49
+ error_message: detailed_error_message,
50
+ error_stack,
51
+ ...context,
52
+ });
53
+ }
54
+
55
+ // Check if error is a PostgREST or database-related error
56
+ const is_database_error =
57
+ detailed_error_message.includes("PostgREST") ||
58
+ detailed_error_message.includes("403 Forbidden") ||
59
+ detailed_error_message.includes("404 Not Found") ||
60
+ detailed_error_message.includes("500 Internal Server Error") ||
61
+ detailed_error_message.includes("database") ||
62
+ detailed_error_message.includes("connection") ||
63
+ detailed_error_message.includes("timeout");
64
+
65
+ // Return user-friendly message for database/API errors
66
+ if (is_database_error) {
67
+ return USER_FRIENDLY_ERROR_MESSAGE;
68
+ }
69
+
70
+ // For other errors, return the original message (could be user-friendly already)
71
+ // But still log the detailed error
72
+ return detailed_error_message;
73
+ }
74
+
75
+
@@ -0,0 +1,65 @@
1
+ // file_description: server-side password validation utility
2
+ // section: types
3
+ export type PasswordRequirementOptions = {
4
+ minimum_length: number;
5
+ require_uppercase: boolean;
6
+ require_lowercase: boolean;
7
+ require_number: boolean;
8
+ require_special: boolean;
9
+ };
10
+
11
+ export type PasswordValidationResult = {
12
+ valid: boolean;
13
+ errors: string[];
14
+ };
15
+
16
+ // section: helpers
17
+ /**
18
+ * Validates a password against specified requirements (server-side version)
19
+ * @param password - The password to validate
20
+ * @param requirements - Password requirement options
21
+ * @returns Validation result with valid flag and error messages
22
+ */
23
+ export function validate_password(
24
+ password: string,
25
+ requirements: PasswordRequirementOptions
26
+ ): PasswordValidationResult {
27
+ const errors: string[] = [];
28
+
29
+ if (!password || password.trim().length === 0) {
30
+ return {
31
+ valid: false,
32
+ errors: ["Password is required"],
33
+ };
34
+ }
35
+
36
+ if (password.length < requirements.minimum_length) {
37
+ errors.push(
38
+ `Password must be at least ${requirements.minimum_length} characters`
39
+ );
40
+ }
41
+
42
+ if (requirements.require_uppercase && !/[A-Z]/.test(password)) {
43
+ errors.push("Password must include at least one uppercase letter");
44
+ }
45
+
46
+ if (requirements.require_lowercase && !/[a-z]/.test(password)) {
47
+ errors.push("Password must include at least one lowercase letter");
48
+ }
49
+
50
+ if (requirements.require_number && !/\d/.test(password)) {
51
+ errors.push("Password must include at least one number");
52
+ }
53
+
54
+ if (
55
+ requirements.require_special &&
56
+ !/[!@#$%^&*(),.?":{}|<>\-_+=\[\];'/\\]/.test(password)
57
+ ) {
58
+ errors.push("Password must include at least one special character");
59
+ }
60
+
61
+ return {
62
+ valid: errors.length === 0,
63
+ errors,
64
+ };
65
+ }
@@ -0,0 +1,11 @@
1
+ // file_description: provide shared utility helpers for the hazo_auth project
2
+ import { clsx, type ClassValue } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+
5
+ // section: tailwind_merge_helper
6
+ export function merge_class_names(...inputs: ClassValue[]) {
7
+ return twMerge(clsx(inputs));
8
+ }
9
+
10
+ // section: shadcn_compatibility_helper
11
+ export const cn = (...inputs: ClassValue[]) => merge_class_names(...inputs);
@@ -0,0 +1,56 @@
1
+ // file_description: expose the logging facade used across the hazo_auth backend
2
+ // section: imports
3
+ import type { logger_method, logger_service } from "../types/app_types";
4
+
5
+ // section: helper_functions
6
+ const create_console_logger = (namespace: string): logger_service => {
7
+ const write = (level: string, message: string, data?: Record<string, unknown>) => {
8
+ const timestamp = new Date().toISOString();
9
+ // eslint-disable-next-line no-console
10
+ console.log(
11
+ JSON.stringify({
12
+ namespace,
13
+ level,
14
+ message,
15
+ data,
16
+ timestamp,
17
+ })
18
+ );
19
+ };
20
+
21
+ return {
22
+ debug: (message, data) => write("debug", message, data),
23
+ info: (message, data) => write("info", message, data),
24
+ warn: (message, data) => write("warn", message, data),
25
+ error: (message, data) => write("error", message, data),
26
+ };
27
+ };
28
+
29
+ // section: factory
30
+ export const create_logger_service = (
31
+ namespace: string,
32
+ external_logger?: Partial<logger_service>
33
+ ): logger_service => {
34
+ const console_logger = create_console_logger(namespace);
35
+
36
+ const safe_bind = (
37
+ level: keyof logger_service,
38
+ fallback: logger_method
39
+ ): logger_method => {
40
+ const candidate = external_logger?.[level];
41
+ if (typeof candidate === "function") {
42
+ return (message, data) => candidate(message, data);
43
+ }
44
+ return fallback;
45
+ };
46
+
47
+ type logger_method = (message: string, data?: Record<string, unknown>) => void;
48
+
49
+ return {
50
+ debug: safe_bind("debug", console_logger.debug),
51
+ info: safe_bind("info", console_logger.info),
52
+ warn: safe_bind("warn", console_logger.warn),
53
+ error: safe_bind("error", console_logger.error),
54
+ };
55
+ };
56
+
@@ -0,0 +1,74 @@
1
+ // file_description: define shared application level types for the hazo_auth server
2
+ // section: request_context_types
3
+ import type { Request } from "express";
4
+
5
+ // section: logger_interface_definition
6
+ export type logger_method = (
7
+ message: string,
8
+ data?: Record<string, unknown>
9
+ ) => void;
10
+
11
+ export type logger_service = {
12
+ debug: logger_method;
13
+ info: logger_method;
14
+ warn: logger_method;
15
+ error: logger_method;
16
+ };
17
+
18
+ // section: configuration_types
19
+ export type emailer_client = {
20
+ send_message: (
21
+ payload: Record<string, unknown>
22
+ ) => Promise<{ success: boolean }>;
23
+ };
24
+
25
+ export type handlebars_templates = Record<string, string>;
26
+
27
+ export type password_policy = {
28
+ min_length: number;
29
+ requires_uppercase: boolean;
30
+ requires_lowercase: boolean;
31
+ requires_number: boolean;
32
+ requires_symbol: boolean;
33
+ };
34
+
35
+ export type token_settings = {
36
+ access_token_ttl_seconds: number;
37
+ refresh_token_ttl_seconds: number;
38
+ };
39
+
40
+ export type rate_limit_settings = {
41
+ max_attempts: number;
42
+ window_minutes: number;
43
+ };
44
+
45
+ export type captcha_settings =
46
+ | {
47
+ provider: "recaptcha_v2" | "recaptcha_v3" | "hcaptcha";
48
+ secret_key: string;
49
+ }
50
+ | undefined;
51
+
52
+ export type runtime_configuration = {
53
+ permission_names: string[];
54
+ logger: logger_service;
55
+ emailer: emailer_client;
56
+ templates: handlebars_templates;
57
+ labels: Record<string, string>;
58
+ styles: Record<string, string>;
59
+ password_policy: password_policy;
60
+ token_settings: token_settings;
61
+ rate_limit: rate_limit_settings;
62
+ captcha: captcha_settings;
63
+ };
64
+
65
+ export type app_context = {
66
+ config: runtime_configuration;
67
+ };
68
+
69
+ // section: typed_request_wrapper
70
+ export type context_request<T = unknown> = Request & {
71
+ body: T;
72
+ context: app_context;
73
+ };
74
+
@@ -0,0 +1,16 @@
1
+ // file_description: augment express request with hazo_auth context
2
+ import type { app_context } from "./app_types";
3
+
4
+ declare global {
5
+ namespace Express {
6
+ interface Request {
7
+ context: app_context;
8
+ }
9
+ }
10
+ }
11
+
12
+ export {};
13
+
14
+
15
+
16
+
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  import { run_validation } from "./validate.js";
6
6
  import { generate_routes } from "./generate.js";
7
7
  import { handle_init } from "./init.js";
8
+ import { handle_init_users, show_init_users_help } from "./init_users.js";
8
9
  // section: constants
9
10
  const VERSION = "1.6.0";
10
11
  const HELP_TEXT = `
@@ -14,6 +15,7 @@ Usage: hazo_auth <command> [options]
14
15
 
15
16
  Commands:
16
17
  init Initialize hazo_auth in your project (creates directories, copies config)
18
+ init-users Initialize permissions, roles, and super user from config
17
19
  validate Check your hazo_auth setup and configuration
18
20
  generate-routes Generate API route files and pages in your project
19
21
 
@@ -23,6 +25,7 @@ Options:
23
25
 
24
26
  Examples:
25
27
  npx hazo_auth init
28
+ npx hazo_auth init-users
26
29
  npx hazo_auth validate
27
30
  npx hazo_auth generate-routes
28
31
  npx hazo_auth generate-routes --pages
@@ -139,6 +142,21 @@ Actions:
139
142
  }
140
143
  handle_init();
141
144
  break;
145
+ case "init-users": {
146
+ if (help) {
147
+ show_init_users_help();
148
+ return;
149
+ }
150
+ // Parse --email option
151
+ let email;
152
+ for (const arg of args) {
153
+ if (arg.startsWith("--email=")) {
154
+ email = arg.replace("--email=", "");
155
+ }
156
+ }
157
+ await handle_init_users({ email });
158
+ break;
159
+ }
142
160
  case "validate":
143
161
  if (help) {
144
162
  console.log(`
@@ -0,0 +1,17 @@
1
+ export type InitUsersOptions = {
2
+ /** Email address of the user to assign super user role (overrides config) */
3
+ email?: string;
4
+ };
5
+ /**
6
+ * Initializes users, roles, and permissions from configuration
7
+ * This function reads from hazo_auth_config.ini and sets up:
8
+ * 1. Permissions from [hazo_auth__user_management] application_permission_list_defaults
9
+ * 2. A default_super_user_role with all permissions
10
+ * 3. Assigns the role to user from --email parameter or [hazo_auth__initial_setup] default_super_user_email
11
+ */
12
+ export declare function handle_init_users(options?: InitUsersOptions): Promise<void>;
13
+ /**
14
+ * Shows help for the init-users command
15
+ */
16
+ export declare function show_init_users_help(): void;
17
+ //# sourceMappingURL=init_users.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init_users.d.ts","sourceRoot":"","sources":["../../src/cli/init_users.ts"],"names":[],"mappings":"AAqFA,MAAM,MAAM,gBAAgB,GAAG;IAC7B,6EAA6E;IAC7E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAGF;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA+OrF;AAGD;;GAEG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CAgC3C"}