hazo_auth 1.6.0 → 1.6.2

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 (74) hide show
  1. package/README.md +191 -19
  2. package/SETUP_CHECKLIST.md +190 -65
  3. package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.d.ts +9 -0
  4. package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.d.ts.map +1 -0
  5. package/dist/app/api/hazo_auth/library_photo/[category]/[filename]/route.js +82 -0
  6. package/dist/app/api/hazo_auth/library_photos/route.d.ts +9 -0
  7. package/dist/app/api/hazo_auth/library_photos/route.d.ts.map +1 -1
  8. package/dist/app/api/hazo_auth/library_photos/route.js +31 -6
  9. package/dist/cli/generate.d.ts +6 -1
  10. package/dist/cli/generate.d.ts.map +1 -1
  11. package/dist/cli/generate.js +101 -34
  12. package/dist/cli/index.js +64 -11
  13. package/dist/cli/init.d.ts +2 -0
  14. package/dist/cli/init.d.ts.map +1 -0
  15. package/dist/cli/init.js +206 -0
  16. package/dist/client.d.ts +8 -0
  17. package/dist/client.d.ts.map +1 -0
  18. package/dist/client.js +25 -0
  19. package/dist/components/layouts/email_verification/index.d.ts +2 -1
  20. package/dist/components/layouts/email_verification/index.d.ts.map +1 -1
  21. package/dist/components/layouts/email_verification/index.js +3 -2
  22. package/dist/components/layouts/forgot_password/index.d.ts +3 -1
  23. package/dist/components/layouts/forgot_password/index.d.ts.map +1 -1
  24. package/dist/components/layouts/forgot_password/index.js +3 -2
  25. package/dist/components/layouts/my_settings/components/editable_field.js +1 -1
  26. package/dist/components/layouts/my_settings/components/password_change_dialog.js +1 -1
  27. package/dist/components/layouts/my_settings/components/profile_picture_display.js +1 -1
  28. package/dist/components/layouts/my_settings/components/profile_picture_gravatar_tab.js +1 -1
  29. package/dist/components/layouts/my_settings/components/profile_picture_library_tab.js +4 -4
  30. package/dist/components/layouts/my_settings/components/profile_picture_upload_tab.js +4 -4
  31. package/dist/components/layouts/my_settings/index.js +1 -1
  32. package/dist/components/layouts/shared/components/profile_pic_menu.js +2 -2
  33. package/dist/lib/auth_utility_config.server.js +2 -2
  34. package/dist/lib/services/profile_picture_service.d.ts +34 -2
  35. package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
  36. package/dist/lib/services/profile_picture_service.js +157 -15
  37. package/dist/lib/services/user_profiles_cache.d.ts +76 -0
  38. package/dist/lib/services/user_profiles_cache.d.ts.map +1 -0
  39. package/dist/lib/services/user_profiles_cache.js +141 -0
  40. package/dist/lib/services/user_profiles_service.d.ts +17 -0
  41. package/dist/lib/services/user_profiles_service.d.ts.map +1 -1
  42. package/dist/lib/services/user_profiles_service.js +136 -44
  43. package/dist/lib/user_profiles_config.server.d.ts +15 -0
  44. package/dist/lib/user_profiles_config.server.d.ts.map +1 -0
  45. package/dist/lib/user_profiles_config.server.js +23 -0
  46. package/dist/page_components/forgot_password.d.ts +19 -0
  47. package/dist/page_components/forgot_password.d.ts.map +1 -0
  48. package/dist/page_components/forgot_password.js +36 -0
  49. package/dist/page_components/index.d.ts +7 -0
  50. package/dist/page_components/index.d.ts.map +1 -0
  51. package/dist/page_components/index.js +9 -0
  52. package/dist/page_components/login.d.ts +26 -0
  53. package/dist/page_components/login.d.ts.map +1 -0
  54. package/dist/page_components/login.js +40 -0
  55. package/dist/page_components/my_settings.d.ts +64 -0
  56. package/dist/page_components/my_settings.d.ts.map +1 -0
  57. package/dist/page_components/my_settings.js +67 -0
  58. package/dist/page_components/register.d.ts +25 -0
  59. package/dist/page_components/register.d.ts.map +1 -0
  60. package/dist/page_components/register.js +43 -0
  61. package/dist/page_components/reset_password.d.ts +25 -0
  62. package/dist/page_components/reset_password.d.ts.map +1 -0
  63. package/dist/page_components/reset_password.js +43 -0
  64. package/dist/page_components/verify_email.d.ts +21 -0
  65. package/dist/page_components/verify_email.d.ts.map +1 -0
  66. package/dist/page_components/verify_email.js +36 -0
  67. package/dist/server/routes/index.d.ts +1 -0
  68. package/dist/server/routes/index.d.ts.map +1 -1
  69. package/dist/server/routes/index.js +1 -0
  70. package/dist/server/routes/library_photo.d.ts +2 -0
  71. package/dist/server/routes/library_photo.d.ts.map +1 -0
  72. package/dist/server/routes/library_photo.js +3 -0
  73. package/hazo_auth_config.example.ini +25 -5
  74. package/package.json +33 -1
@@ -4,9 +4,18 @@ export declare function GET(request: NextRequest): Promise<NextResponse<{
4
4
  success: boolean;
5
5
  category: string;
6
6
  photos: string[];
7
+ pagination: {
8
+ page: number;
9
+ page_size: number;
10
+ total: number;
11
+ has_more: boolean;
12
+ total_pages: number;
13
+ };
14
+ source: "project" | "node_modules";
7
15
  }> | NextResponse<{
8
16
  success: boolean;
9
17
  categories: string[];
18
+ source: "project" | "node_modules" | null;
10
19
  }> | NextResponse<{
11
20
  error: string;
12
21
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/library_photos/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAMxD,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAGvC,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;IA4D7C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../src/app/api/hazo_auth/library_photos/route.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAUxD,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAOvC,wBAAsB,GAAG,CAAC,OAAO,EAAE,WAAW;;;;;;;;;;;;;;;;;;IAmF7C"}
@@ -1,43 +1,68 @@
1
- // file_description: API route for listing library photo categories and photos in categories
1
+ // file_description: API route for listing library photo categories and photos in categories with pagination support
2
2
  // section: imports
3
3
  import { NextResponse } from "next/server";
4
- import { get_library_categories, get_library_photos } from "../../../../lib/services/profile_picture_service";
4
+ import { get_library_categories, get_library_photos_paginated, get_library_source } from "../../../../lib/services/profile_picture_service";
5
5
  import { create_app_logger } from "../../../../lib/app_logger";
6
6
  import { get_filename, get_line_number } from "../../../../lib/utils/api_route_helpers";
7
7
  // section: route_config
8
8
  export const dynamic = 'force-dynamic';
9
+ // section: constants
10
+ const DEFAULT_PAGE_SIZE = 20;
11
+ const MAX_PAGE_SIZE = 100;
9
12
  // section: api_handler
10
13
  export async function GET(request) {
11
14
  const logger = create_app_logger();
12
15
  try {
13
16
  const { searchParams } = new URL(request.url);
14
17
  const category = searchParams.get("category");
18
+ const page_param = searchParams.get("page");
19
+ const page_size_param = searchParams.get("page_size");
20
+ // Parse pagination parameters
21
+ const page = page_param ? Math.max(1, parseInt(page_param, 10) || 1) : 1;
22
+ const page_size = page_size_param
23
+ ? Math.min(MAX_PAGE_SIZE, Math.max(1, parseInt(page_size_param, 10) || DEFAULT_PAGE_SIZE))
24
+ : DEFAULT_PAGE_SIZE;
15
25
  if (category) {
16
- // Return photos in the specified category
17
- const photos = get_library_photos(category);
26
+ // Return photos in the specified category with pagination
27
+ const result = get_library_photos_paginated(category, page, page_size);
18
28
  logger.info("library_photos_category_requested", {
19
29
  filename: get_filename(),
20
30
  line_number: get_line_number(),
21
31
  category,
22
- photoCount: photos.length,
32
+ page,
33
+ page_size,
34
+ total: result.total,
35
+ returned: result.photos.length,
36
+ source: result.source,
23
37
  });
24
38
  return NextResponse.json({
25
39
  success: true,
26
40
  category,
27
- photos,
41
+ photos: result.photos,
42
+ pagination: {
43
+ page: result.page,
44
+ page_size: result.page_size,
45
+ total: result.total,
46
+ has_more: result.has_more,
47
+ total_pages: Math.ceil(result.total / result.page_size),
48
+ },
49
+ source: result.source,
28
50
  }, { status: 200 });
29
51
  }
30
52
  else {
31
53
  // Return list of categories
32
54
  const categories = get_library_categories();
55
+ const source = get_library_source();
33
56
  logger.info("library_categories_requested", {
34
57
  filename: get_filename(),
35
58
  line_number: get_line_number(),
36
59
  categoryCount: categories.length,
60
+ source,
37
61
  });
38
62
  return NextResponse.json({
39
63
  success: true,
40
64
  categories,
65
+ source,
41
66
  }, { status: 200 });
42
67
  }
43
68
  }
@@ -1,2 +1,7 @@
1
- export declare function generate_routes(custom_app_dir?: string): void;
1
+ export type GenerateOptions = {
2
+ dir?: string;
3
+ pages?: boolean;
4
+ all?: boolean;
5
+ };
6
+ export declare function generate_routes(options?: GenerateOptions): void;
2
7
  //# sourceMappingURL=generate.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AA0EA,wBAAgB,eAAe,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAwE7D"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/cli/generate.ts"],"names":[],"mappings":"AAqBA,MAAM,MAAM,eAAe,GAAG;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,CAAC;AAwJF,wBAAgB,eAAe,CAAC,OAAO,GAAE,eAAoB,GAAG,IAAI,CA8DnE"}
@@ -1,5 +1,5 @@
1
- // file_description: route generation logic for hazo_auth
2
- // This module creates API route files in consuming projects
1
+ // file_description: route and page generation logic for hazo_auth
2
+ // This module creates API route files and page files in consuming projects
3
3
  import * as fs from "fs";
4
4
  import * as path from "path";
5
5
  // section: constants
@@ -17,11 +17,21 @@ const ROUTES = [
17
17
  { name: "upload_profile_picture", path: "api/hazo_auth/upload_profile_picture", method: "POST", export_name: "uploadProfilePicturePOST" },
18
18
  { name: "remove_profile_picture", path: "api/hazo_auth/remove_profile_picture", method: "DELETE", export_name: "removeProfilePictureDELETE" },
19
19
  { name: "library_photos", path: "api/hazo_auth/library_photos", method: "GET", export_name: "libraryPhotosGET" },
20
+ { name: "library_photo", path: "api/hazo_auth/library_photo/[category]/[filename]", method: "GET", export_name: "libraryPhotoGET" },
20
21
  { name: "get_auth", path: "api/hazo_auth/get_auth", method: "POST", export_name: "getAuthPOST" },
21
22
  { name: "validate_reset_token", path: "api/hazo_auth/validate_reset_token", method: "GET", export_name: "validateResetTokenGET" },
22
23
  { name: "profile_picture_filename", path: "api/hazo_auth/profile_picture/[filename]", method: "GET", export_name: "profilePictureFilenameGET" },
23
24
  { name: "invalidate_cache", path: "api/hazo_auth/invalidate_cache", method: "POST", export_name: "invalidateCachePOST" },
24
25
  ];
26
+ const PAGES = [
27
+ { name: "login", path: "hazo_auth/login", component_name: "LoginPage", import_path: "hazo_auth/pages/login" },
28
+ { name: "register", path: "hazo_auth/register", component_name: "RegisterPage", import_path: "hazo_auth/pages/register" },
29
+ { name: "forgot_password", path: "hazo_auth/forgot_password", component_name: "ForgotPasswordPage", import_path: "hazo_auth/pages/forgot_password" },
30
+ { name: "reset_password", path: "hazo_auth/reset_password", component_name: "ResetPasswordPage", import_path: "hazo_auth/pages/reset_password" },
31
+ { name: "verify_email", path: "hazo_auth/verify_email", component_name: "VerifyEmailPage", import_path: "hazo_auth/pages/verify_email" },
32
+ { name: "my_settings", path: "hazo_auth/my_settings", component_name: "MySettingsPage", import_path: "hazo_auth/pages/my_settings" },
33
+ ];
34
+ // Note: The import_path uses "hazo_auth/pages/*" which maps to dist/page_components/* in package.json exports
25
35
  // section: helpers
26
36
  function get_project_root() {
27
37
  return process.cwd();
@@ -43,6 +53,9 @@ function ensure_dir(dir_path) {
43
53
  fs.mkdirSync(dir_path, { recursive: true });
44
54
  }
45
55
  }
56
+ function file_exists(filepath) {
57
+ return fs.existsSync(filepath);
58
+ }
46
59
  function generate_route_content(route) {
47
60
  return `// Generated by hazo_auth - do not edit manually
48
61
  // Route: /${route.path}
@@ -50,32 +63,20 @@ function generate_route_content(route) {
50
63
  export { ${route.export_name} as ${route.method} } from "hazo_auth/server/routes";
51
64
  `;
52
65
  }
53
- function file_exists(filepath) {
54
- return fs.existsSync(filepath);
66
+ function generate_page_content(page) {
67
+ return `// Generated by hazo_auth - do not edit manually
68
+ // Page: /${page.path}
69
+ import { ${page.component_name} } from "${page.import_path}";
70
+
71
+ export default ${page.component_name};
72
+ `;
55
73
  }
56
- // section: main
57
- export function generate_routes(custom_app_dir) {
58
- const project_root = get_project_root();
59
- console.log("\n\x1b[1m🐸 hazo_auth Route Generator\x1b[0m");
60
- console.log("=".repeat(50));
61
- console.log(`Project root: ${project_root}\n`);
62
- let app_dir = custom_app_dir
63
- ? path.join(project_root, custom_app_dir)
64
- : find_app_dir(project_root);
65
- if (!app_dir) {
66
- console.error("\x1b[31mError: Could not find app directory.\x1b[0m");
67
- console.log("Try specifying it with: npx hazo_auth generate-routes --dir=src/app");
68
- process.exit(1);
69
- }
70
- if (!fs.existsSync(app_dir)) {
71
- console.error(`\x1b[31mError: App directory not found: ${app_dir}\x1b[0m`);
72
- process.exit(1);
73
- }
74
- console.log(`App directory: ${app_dir.replace(project_root, ".")}\n`);
74
+ // section: api_route_generation
75
+ function generate_api_routes(app_dir, project_root) {
75
76
  let created = 0;
76
77
  let skipped = 0;
77
78
  let errors = 0;
78
- console.log("\x1b[1mGenerating routes...\x1b[0m\n");
79
+ console.log("\x1b[1m📡 Generating API routes...\x1b[0m\n");
79
80
  for (const route of ROUTES) {
80
81
  const route_dir = path.join(app_dir, route.path);
81
82
  const route_file = path.join(route_dir, "route.ts");
@@ -96,22 +97,88 @@ export function generate_routes(custom_app_dir) {
96
97
  errors++;
97
98
  }
98
99
  }
100
+ return { created, skipped, errors };
101
+ }
102
+ // section: page_generation
103
+ function generate_page_routes(app_dir, project_root) {
104
+ let created = 0;
105
+ let skipped = 0;
106
+ let errors = 0;
107
+ console.log("\n\x1b[1m📄 Generating page routes...\x1b[0m\n");
108
+ for (const page of PAGES) {
109
+ const page_dir = path.join(app_dir, page.path);
110
+ const page_file = path.join(page_dir, "page.tsx");
111
+ if (file_exists(page_file)) {
112
+ console.log(`\x1b[33m[SKIP]\x1b[0m ${page.path}/page.tsx (already exists)`);
113
+ skipped++;
114
+ continue;
115
+ }
116
+ try {
117
+ ensure_dir(page_dir);
118
+ const content = generate_page_content(page);
119
+ fs.writeFileSync(page_file, content, "utf-8");
120
+ console.log(`\x1b[32m[CREATE]\x1b[0m ${page.path}/page.tsx`);
121
+ created++;
122
+ }
123
+ catch (err) {
124
+ console.log(`\x1b[31m[ERROR]\x1b[0m ${page.path}/page.tsx - ${err instanceof Error ? err.message : "Unknown error"}`);
125
+ errors++;
126
+ }
127
+ }
128
+ return { created, skipped, errors };
129
+ }
130
+ // section: main
131
+ export function generate_routes(options = {}) {
132
+ const { dir, pages = false, all = false } = options;
133
+ const project_root = get_project_root();
134
+ const include_pages = pages || all;
135
+ console.log("\n\x1b[1m🐸 hazo_auth Route Generator\x1b[0m");
136
+ console.log("=".repeat(50));
137
+ console.log(`Project root: ${project_root}`);
138
+ console.log(`Mode: ${include_pages ? "API routes + Pages" : "API routes only"}\n`);
139
+ const app_dir = dir
140
+ ? path.join(project_root, dir)
141
+ : find_app_dir(project_root);
142
+ if (!app_dir) {
143
+ console.error("\x1b[31mError: Could not find app directory.\x1b[0m");
144
+ console.log("Try specifying it with: npx hazo_auth generate-routes --dir=src/app");
145
+ process.exit(1);
146
+ }
147
+ if (!fs.existsSync(app_dir)) {
148
+ console.error(`\x1b[31mError: App directory not found: ${app_dir}\x1b[0m`);
149
+ process.exit(1);
150
+ }
151
+ console.log(`App directory: ${app_dir.replace(project_root, ".")}\n`);
152
+ // Generate API routes
153
+ const api_result = generate_api_routes(app_dir, project_root);
154
+ // Generate pages if requested
155
+ let page_result = { created: 0, skipped: 0, errors: 0 };
156
+ if (include_pages) {
157
+ page_result = generate_page_routes(app_dir, project_root);
158
+ }
159
+ // Summary
160
+ const total_created = api_result.created + page_result.created;
161
+ const total_skipped = api_result.skipped + page_result.skipped;
162
+ const total_errors = api_result.errors + page_result.errors;
99
163
  console.log("\n" + "=".repeat(50));
100
164
  console.log("\x1b[1mSummary:\x1b[0m");
101
- console.log(` \x1b[32m✓ Created: ${created}\x1b[0m`);
102
- console.log(` \x1b[33m⊘ Skipped: ${skipped}\x1b[0m`);
103
- if (errors > 0) {
104
- console.log(` \x1b[31m✗ Errors: ${errors}\x1b[0m`);
165
+ console.log(` \x1b[32m✓ Created: ${total_created}\x1b[0m (${api_result.created} routes, ${page_result.created} pages)`);
166
+ console.log(` \x1b[33m⊘ Skipped: ${total_skipped}\x1b[0m`);
167
+ if (total_errors > 0) {
168
+ console.log(` \x1b[31m✗ Errors: ${total_errors}\x1b[0m`);
105
169
  }
106
170
  console.log();
107
- if (created > 0) {
108
- console.log("\x1b[32m🦊 Routes generated successfully!\x1b[0m");
171
+ if (total_created > 0) {
172
+ console.log("\x1b[32m🦊 Generation complete!\x1b[0m");
109
173
  console.log("\nNext steps:");
110
174
  console.log(" 1. Run `npm run dev` to start your development server");
111
- console.log(" 2. Test the routes with `curl http://localhost:3000/api/hazo_auth/me`");
112
- console.log(" 3. Visit http://localhost:3000/api/hazo_auth/health to check setup status\n");
175
+ console.log(" 2. Test API: `curl http://localhost:3000/api/hazo_auth/me`");
176
+ if (include_pages) {
177
+ console.log(" 3. Visit http://localhost:3000/hazo_auth/login to test pages");
178
+ }
179
+ console.log();
113
180
  }
114
- else if (skipped === ROUTES.length) {
115
- console.log("\x1b[33m🦊 All routes already exist. No changes made.\x1b[0m\n");
181
+ else if (total_skipped === ROUTES.length + (include_pages ? PAGES.length : 0)) {
182
+ console.log("\x1b[33m🦊 All files already exist. No changes made.\x1b[0m\n");
116
183
  }
117
184
  }
package/dist/cli/index.js CHANGED
@@ -4,25 +4,29 @@
4
4
  // section: imports
5
5
  import { run_validation } from "./validate.js";
6
6
  import { generate_routes } from "./generate.js";
7
+ import { handle_init } from "./init.js";
7
8
  // section: constants
8
- const VERSION = "1.5.0";
9
+ const VERSION = "1.6.0";
9
10
  const HELP_TEXT = `
10
11
  \x1b[1m🐸 hazo_auth CLI v${VERSION}\x1b[0m
11
12
 
12
13
  Usage: hazo_auth <command> [options]
13
14
 
14
15
  Commands:
16
+ init Initialize hazo_auth in your project (creates directories, copies config)
15
17
  validate Check your hazo_auth setup and configuration
16
- generate-routes Generate API route files in your project
18
+ generate-routes Generate API route files and pages in your project
17
19
 
18
20
  Options:
19
21
  --help, -h Show this help message
20
22
  --version, -v Show version number
21
23
 
22
24
  Examples:
25
+ npx hazo_auth init
23
26
  npx hazo_auth validate
24
27
  npx hazo_auth generate-routes
25
- npx hazo_auth generate-routes --dir=src/app
28
+ npx hazo_auth generate-routes --pages
29
+ npx hazo_auth generate-routes --all --dir=src/app
26
30
 
27
31
  Documentation:
28
32
  https://github.com/your-repo/hazo_auth/blob/main/SETUP_CHECKLIST.md
@@ -61,33 +65,42 @@ async function handle_validate() {
61
65
  process.exit(summary.failed > 0 ? 1 : 0);
62
66
  }
63
67
  function handle_generate_routes(args) {
64
- // Parse --dir argument
65
- let dir;
68
+ const options = {};
66
69
  for (const arg of args) {
67
70
  if (arg.startsWith("--dir=")) {
68
- dir = arg.replace("--dir=", "");
71
+ options.dir = arg.replace("--dir=", "");
72
+ }
73
+ else if (arg === "--pages") {
74
+ options.pages = true;
75
+ }
76
+ else if (arg === "--all") {
77
+ options.all = true;
69
78
  }
70
79
  else if (arg === "--help" || arg === "-h") {
71
80
  console.log(`
72
81
  hazo_auth generate-routes
73
82
 
74
- Generate API route files in your Next.js project.
83
+ Generate API route files and page files in your Next.js project.
75
84
 
76
85
  Usage:
77
86
  hazo_auth generate-routes [options]
78
87
 
79
88
  Options:
80
89
  --dir=<path> Specify the app directory (default: auto-detect)
90
+ --pages Generate page routes in addition to API routes
91
+ --all Generate everything (API routes + pages)
81
92
  --help, -h Show this help message
82
93
 
83
94
  Examples:
84
- hazo_auth generate-routes
85
- hazo_auth generate-routes --dir=src/app
95
+ hazo_auth generate-routes # API routes only
96
+ hazo_auth generate-routes --pages # API routes + pages
97
+ hazo_auth generate-routes --all # Same as --pages
98
+ hazo_auth generate-routes --dir=src/app # Specify app directory
86
99
  `);
87
100
  return;
88
101
  }
89
102
  }
90
- generate_routes(dir);
103
+ generate_routes(options);
91
104
  }
92
105
  // section: main
93
106
  async function main() {
@@ -96,12 +109,52 @@ async function main() {
96
109
  show_version();
97
110
  return;
98
111
  }
99
- if (help || !command) {
112
+ // Show main help only if no command specified
113
+ if (!command) {
100
114
  show_help();
101
115
  return;
102
116
  }
117
+ // If help is requested but command exists, pass help to command handler
118
+ // Commands can show their own help
119
+ if (help) {
120
+ args.push("--help");
121
+ }
103
122
  switch (command) {
123
+ case "init":
124
+ if (help) {
125
+ console.log(`
126
+ hazo_auth init
127
+
128
+ Initialize hazo_auth in your project.
129
+
130
+ Actions:
131
+ - Creates public/profile_pictures/library/ directory
132
+ - Creates public/profile_pictures/uploads/ directory
133
+ - Creates data/ directory (for SQLite)
134
+ - Copies hazo_auth_config.ini and hazo_notify_config.ini
135
+ - Copies profile picture library images
136
+ - Creates .env.local.example template
137
+ `);
138
+ return;
139
+ }
140
+ handle_init();
141
+ break;
104
142
  case "validate":
143
+ if (help) {
144
+ console.log(`
145
+ hazo_auth validate
146
+
147
+ Check your hazo_auth setup and configuration.
148
+
149
+ This command verifies:
150
+ - Config files exist and are readable
151
+ - Required config values are set
152
+ - Environment variables are configured
153
+ - Database connection works
154
+ - Required directories exist
155
+ `);
156
+ return;
157
+ }
105
158
  await handle_validate();
106
159
  break;
107
160
  case "generate-routes":
@@ -0,0 +1,2 @@
1
+ export declare function handle_init(): void;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AA2IA,wBAAgB,WAAW,IAAI,IAAI,CAkHlC"}
@@ -0,0 +1,206 @@
1
+ // file_description: init command for hazo_auth
2
+ // Creates directories and copies config files to consuming projects
3
+ import { fileURLToPath } from "url";
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ // section: esm_shim
7
+ // ESM-compatible __dirname shim
8
+ const __filename = fileURLToPath(import.meta.url);
9
+ const __dirname = path.dirname(__filename);
10
+ // section: constants
11
+ const REQUIRED_DIRECTORIES = [
12
+ "public/profile_pictures/library",
13
+ "public/profile_pictures/uploads",
14
+ "data",
15
+ ];
16
+ const CONFIG_FILES = [
17
+ { source: "hazo_auth_config.example.ini", target: "hazo_auth_config.ini" },
18
+ { source: "hazo_notify_config.example.ini", target: "hazo_notify_config.ini" },
19
+ ];
20
+ // section: helpers
21
+ function get_project_root() {
22
+ return process.cwd();
23
+ }
24
+ function get_package_root() {
25
+ // When running from node_modules, we need to find the hazo_auth package root
26
+ // When running in development, use the current directory
27
+ // Check if we're in node_modules
28
+ const parts = __dirname.split(path.sep);
29
+ const node_modules_index = parts.lastIndexOf("node_modules");
30
+ if (node_modules_index !== -1) {
31
+ // We're in node_modules/hazo_auth/dist/cli
32
+ return parts.slice(0, node_modules_index + 2).join(path.sep);
33
+ }
34
+ // Development mode - go up from src/cli or dist/cli
35
+ return path.resolve(__dirname, "..", "..");
36
+ }
37
+ function ensure_dir(dir_path) {
38
+ if (!fs.existsSync(dir_path)) {
39
+ fs.mkdirSync(dir_path, { recursive: true });
40
+ return true;
41
+ }
42
+ return false;
43
+ }
44
+ function copy_file_if_not_exists(source, target) {
45
+ if (fs.existsSync(target)) {
46
+ return "skipped";
47
+ }
48
+ if (!fs.existsSync(source)) {
49
+ return "error";
50
+ }
51
+ try {
52
+ fs.copyFileSync(source, target);
53
+ return "created";
54
+ }
55
+ catch (_a) {
56
+ return "error";
57
+ }
58
+ }
59
+ function copy_directory(source, target) {
60
+ let copied = 0;
61
+ if (!fs.existsSync(source)) {
62
+ return 0;
63
+ }
64
+ ensure_dir(target);
65
+ const items = fs.readdirSync(source);
66
+ for (const item of items) {
67
+ const source_path = path.join(source, item);
68
+ const target_path = path.join(target, item);
69
+ const stat = fs.statSync(source_path);
70
+ if (stat.isDirectory()) {
71
+ copied += copy_directory(source_path, target_path);
72
+ }
73
+ else if (!fs.existsSync(target_path)) {
74
+ fs.copyFileSync(source_path, target_path);
75
+ copied++;
76
+ }
77
+ }
78
+ return copied;
79
+ }
80
+ function create_gitkeep(dir_path) {
81
+ const gitkeep_path = path.join(dir_path, ".gitkeep");
82
+ if (!fs.existsSync(gitkeep_path)) {
83
+ const files = fs.readdirSync(dir_path);
84
+ if (files.length === 0) {
85
+ fs.writeFileSync(gitkeep_path, "# This file keeps the empty directory in git\n");
86
+ }
87
+ }
88
+ }
89
+ function create_env_template(project_root) {
90
+ const env_example_path = path.join(project_root, ".env.local.example");
91
+ if (fs.existsSync(env_example_path)) {
92
+ return false;
93
+ }
94
+ const content = `# hazo_auth environment variables
95
+ # Copy this file to .env.local and fill in the values
96
+
97
+ # Required for email functionality (email verification, password reset)
98
+ ZEPTOMAIL_API_KEY=your_zeptomail_api_key_here
99
+
100
+ # Optional: Database path (defaults to data/hazo_auth.sqlite)
101
+ # HAZO_AUTH_DB_PATH=./data/hazo_auth.sqlite
102
+ `;
103
+ fs.writeFileSync(env_example_path, content);
104
+ return true;
105
+ }
106
+ // section: main
107
+ export function handle_init() {
108
+ const project_root = get_project_root();
109
+ const package_root = get_package_root();
110
+ console.log("\n\x1b[1m🐸 hazo_auth Initialization\x1b[0m");
111
+ console.log("=".repeat(50));
112
+ console.log(`Project root: ${project_root}`);
113
+ console.log(`Package root: ${package_root}\n`);
114
+ const result = {
115
+ directories_created: [],
116
+ files_copied: [],
117
+ skipped: [],
118
+ errors: [],
119
+ };
120
+ // Step 1: Create directories
121
+ console.log("\x1b[1m📁 Creating directories...\x1b[0m\n");
122
+ for (const dir of REQUIRED_DIRECTORIES) {
123
+ const full_path = path.join(project_root, dir);
124
+ if (ensure_dir(full_path)) {
125
+ console.log(`\x1b[32m[CREATE]\x1b[0m ${dir}/`);
126
+ result.directories_created.push(dir);
127
+ }
128
+ else {
129
+ console.log(`\x1b[33m[EXISTS]\x1b[0m ${dir}/`);
130
+ result.skipped.push(dir);
131
+ }
132
+ }
133
+ // Step 2: Copy config files
134
+ console.log("\n\x1b[1m📄 Copying config files...\x1b[0m\n");
135
+ for (const config of CONFIG_FILES) {
136
+ const source_path = path.join(package_root, config.source);
137
+ const target_path = path.join(project_root, config.target);
138
+ const status = copy_file_if_not_exists(source_path, target_path);
139
+ if (status === "created") {
140
+ console.log(`\x1b[32m[CREATE]\x1b[0m ${config.target}`);
141
+ result.files_copied.push(config.target);
142
+ }
143
+ else if (status === "skipped") {
144
+ console.log(`\x1b[33m[EXISTS]\x1b[0m ${config.target}`);
145
+ result.skipped.push(config.target);
146
+ }
147
+ else {
148
+ console.log(`\x1b[31m[ERROR]\x1b[0m ${config.target} - source not found: ${source_path}`);
149
+ result.errors.push(config.target);
150
+ }
151
+ }
152
+ // Step 3: Copy profile picture library
153
+ console.log("\n\x1b[1m🖼️ Copying profile picture library...\x1b[0m\n");
154
+ const library_source = path.join(package_root, "public", "profile_pictures", "library");
155
+ const library_target = path.join(project_root, "public", "profile_pictures", "library");
156
+ if (fs.existsSync(library_source)) {
157
+ const copied_count = copy_directory(library_source, library_target);
158
+ if (copied_count > 0) {
159
+ console.log(`\x1b[32m[COPY]\x1b[0m ${copied_count} library images`);
160
+ result.files_copied.push(`${copied_count} library images`);
161
+ }
162
+ else {
163
+ console.log(`\x1b[33m[EXISTS]\x1b[0m Library images already present`);
164
+ result.skipped.push("library images");
165
+ }
166
+ }
167
+ else {
168
+ console.log(`\x1b[33m[SKIP]\x1b[0m Library not found at: ${library_source}`);
169
+ result.skipped.push("library images (source not found)");
170
+ }
171
+ // Step 4: Create .gitkeep files for empty directories
172
+ console.log("\n\x1b[1m📌 Creating .gitkeep files...\x1b[0m\n");
173
+ const empty_dirs = ["public/profile_pictures/uploads", "data"];
174
+ for (const dir of empty_dirs) {
175
+ const full_path = path.join(project_root, dir);
176
+ if (fs.existsSync(full_path)) {
177
+ create_gitkeep(full_path);
178
+ console.log(`\x1b[32m[CREATE]\x1b[0m ${dir}/.gitkeep`);
179
+ }
180
+ }
181
+ // Step 5: Create .env.local.example template
182
+ console.log("\n\x1b[1m🔑 Creating environment template...\x1b[0m\n");
183
+ if (create_env_template(project_root)) {
184
+ console.log(`\x1b[32m[CREATE]\x1b[0m .env.local.example`);
185
+ result.files_copied.push(".env.local.example");
186
+ }
187
+ else {
188
+ console.log(`\x1b[33m[EXISTS]\x1b[0m .env.local.example`);
189
+ result.skipped.push(".env.local.example");
190
+ }
191
+ // Summary
192
+ console.log("\n" + "=".repeat(50));
193
+ console.log("\x1b[1mSummary:\x1b[0m");
194
+ console.log(` \x1b[32m✓ Created:\x1b[0m ${result.directories_created.length} directories, ${result.files_copied.length} files`);
195
+ console.log(` \x1b[33m⊘ Skipped:\x1b[0m ${result.skipped.length} items`);
196
+ if (result.errors.length > 0) {
197
+ console.log(` \x1b[31m✗ Errors:\x1b[0m ${result.errors.length}`);
198
+ }
199
+ console.log("\n\x1b[32m🦊 Initialization complete!\x1b[0m");
200
+ console.log("\nNext steps:");
201
+ console.log(" 1. Edit \x1b[36mhazo_auth_config.ini\x1b[0m with your settings");
202
+ console.log(" 2. Copy \x1b[36m.env.local.example\x1b[0m to \x1b[36m.env.local\x1b[0m and add your API keys");
203
+ console.log(" 3. Run \x1b[36mnpx hazo_auth generate-routes --pages\x1b[0m to generate routes and pages");
204
+ console.log(" 4. Run \x1b[36mnpx hazo_auth validate\x1b[0m to check your setup");
205
+ console.log();
206
+ }
@@ -0,0 +1,8 @@
1
+ export * from "./components/index";
2
+ export { cn, merge_class_names } from "./lib/utils";
3
+ export * from "./lib/auth/auth_types";
4
+ export { use_auth_status, trigger_auth_status_refresh } from "./components/layouts/shared/hooks/use_auth_status";
5
+ export { use_hazo_auth, trigger_hazo_auth_refresh } from "./components/layouts/shared/hooks/use_hazo_auth";
6
+ export type { UseHazoAuthOptions, UseHazoAuthResult } from "./components/layouts/shared/hooks/use_hazo_auth";
7
+ export * from "./components/layouts/shared/utils/validation";
8
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAYA,cAAc,oBAAoB,CAAC;AAInC,OAAO,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAIpD,cAAc,uBAAuB,CAAC;AAItC,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,mDAAmD,CAAC;AACjH,OAAO,EAAE,aAAa,EAAE,yBAAyB,EAAE,MAAM,iDAAiD,CAAC;AAC3G,YAAY,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAI7G,cAAc,8CAA8C,CAAC"}