hazo_auth 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +65 -19
  2. package/SETUP_CHECKLIST.md +136 -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 +201 -0
  16. package/dist/lib/services/profile_picture_service.d.ts +34 -2
  17. package/dist/lib/services/profile_picture_service.d.ts.map +1 -1
  18. package/dist/lib/services/profile_picture_service.js +157 -15
  19. package/dist/page_components/forgot_password.d.ts +19 -0
  20. package/dist/page_components/forgot_password.d.ts.map +1 -0
  21. package/dist/page_components/forgot_password.js +36 -0
  22. package/dist/page_components/index.d.ts +7 -0
  23. package/dist/page_components/index.d.ts.map +1 -0
  24. package/dist/page_components/index.js +9 -0
  25. package/dist/page_components/login.d.ts +26 -0
  26. package/dist/page_components/login.d.ts.map +1 -0
  27. package/dist/page_components/login.js +40 -0
  28. package/dist/page_components/my_settings.d.ts +64 -0
  29. package/dist/page_components/my_settings.d.ts.map +1 -0
  30. package/dist/page_components/my_settings.js +67 -0
  31. package/dist/page_components/register.d.ts +25 -0
  32. package/dist/page_components/register.d.ts.map +1 -0
  33. package/dist/page_components/register.js +43 -0
  34. package/dist/page_components/reset_password.d.ts +25 -0
  35. package/dist/page_components/reset_password.d.ts.map +1 -0
  36. package/dist/page_components/reset_password.js +43 -0
  37. package/dist/page_components/verify_email.d.ts +21 -0
  38. package/dist/page_components/verify_email.d.ts.map +1 -0
  39. package/dist/page_components/verify_email.js +36 -0
  40. package/dist/server/routes/index.d.ts +1 -0
  41. package/dist/server/routes/index.d.ts.map +1 -1
  42. package/dist/server/routes/index.js +1 -0
  43. package/dist/server/routes/library_photo.d.ts +2 -0
  44. package/dist/server/routes/library_photo.d.ts.map +1 -0
  45. package/dist/server/routes/library_photo.js +3 -0
  46. package/package.json +29 -1
package/README.md CHANGED
@@ -26,32 +26,61 @@ npm install hazo_auth
26
26
 
27
27
  ## Quick Start
28
28
 
29
- ### 1. Install the package
29
+ The fastest way to get started is using the CLI commands:
30
30
 
31
31
  ```bash
32
+ # 1. Install the package
32
33
  npm install hazo_auth
34
+
35
+ # 2. Initialize your project (creates directories, copies config files)
36
+ npx hazo_auth init
37
+
38
+ # 3. Generate API routes and pages
39
+ npx hazo_auth generate-routes --pages
40
+
41
+ # 4. Set up environment variables
42
+ cp .env.local.example .env.local
43
+ # Edit .env.local and add your ZEPTOMAIL_API_KEY
44
+
45
+ # 5. Start your dev server
46
+ npm run dev
33
47
  ```
34
48
 
35
- ### 2. Copy configuration files
49
+ That's it! Visit `http://localhost:3000/hazo_auth/login` to see the login page.
50
+
51
+ ### CLI Commands
36
52
 
37
53
  ```bash
38
- cp node_modules/hazo_auth/hazo_auth_config.example.ini ./hazo_auth_config.ini
39
- cp node_modules/hazo_auth/hazo_notify_config.example.ini ./hazo_notify_config.ini
54
+ npx hazo_auth init # Initialize project (creates dirs, copies config)
55
+ npx hazo_auth generate-routes # Generate API routes only
56
+ npx hazo_auth generate-routes --pages # Generate API routes + pages
57
+ npx hazo_auth validate # Check your setup and configuration
58
+ npx hazo_auth --help # Show all commands
40
59
  ```
41
60
 
42
- ### 3. Set up environment variables
61
+ ### Using Zero-Config Page Components
43
62
 
44
- Create a `.env.local` file:
63
+ The generated pages import from `hazo_auth/pages/*` which provides zero-config components:
45
64
 
46
- ```env
47
- ZEPTOMAIL_API_KEY=your_api_key_here
65
+ ```typescript
66
+ // Generated app/hazo_auth/login/page.tsx
67
+ import { LoginPage } from "hazo_auth/pages/login";
68
+ export default LoginPage;
48
69
  ```
49
70
 
50
- ### 4. Set up the database
71
+ Available zero-config pages:
72
+ - `LoginPage` - Login form with sensible defaults
73
+ - `RegisterPage` - Registration with password requirements
74
+ - `ForgotPasswordPage` - Password reset request
75
+ - `ResetPasswordPage` - Set new password
76
+ - `VerifyEmailPage` - Email verification
77
+ - `MySettingsPage` - User profile and settings
51
78
 
52
- Run the database setup SQL script (see [Database Setup](#database-setup)).
79
+ All pages work out-of-the-box with no props required!
53
80
 
54
- ### 5. Import and use components
81
+ ### Manual Setup (Advanced)
82
+
83
+ If you prefer manual control, you can use the layout components directly:
55
84
 
56
85
  ```typescript
57
86
  // Import layout components
@@ -415,7 +444,25 @@ The package exports components through these paths:
415
444
  // Main entry point - exports all public APIs
416
445
  import { ... } from "hazo_auth";
417
446
 
418
- // Layout components - one export per auth flow
447
+ // Zero-config page components (recommended for quick setup)
448
+ import { LoginPage } from "hazo_auth/pages/login";
449
+ import { RegisterPage } from "hazo_auth/pages/register";
450
+ import { ForgotPasswordPage } from "hazo_auth/pages/forgot_password";
451
+ import { ResetPasswordPage } from "hazo_auth/pages/reset_password";
452
+ import { VerifyEmailPage } from "hazo_auth/pages/verify_email";
453
+ import { MySettingsPage } from "hazo_auth/pages/my_settings";
454
+
455
+ // Or import all pages at once
456
+ import {
457
+ LoginPage,
458
+ RegisterPage,
459
+ ForgotPasswordPage,
460
+ ResetPasswordPage,
461
+ VerifyEmailPage,
462
+ MySettingsPage
463
+ } from "hazo_auth/pages";
464
+
465
+ // Layout components - for custom implementations
419
466
  import { LoginLayout } from "hazo_auth/components/layouts/login";
420
467
  import { RegisterLayout } from "hazo_auth/components/layouts/register";
421
468
  import { ForgotPasswordLayout } from "hazo_auth/components/layouts/forgot_password";
@@ -903,22 +950,21 @@ This compiles the `src/` directory to `dist/` with:
903
950
 
904
951
  ### Package Exports
905
952
 
906
- The `package.json` exports field defines the public API. The package exposes only the main entry points:
953
+ The `package.json` exports field defines the public API:
907
954
 
908
955
  ```json
909
956
  {
910
957
  "exports": {
911
958
  ".": "./dist/index.js",
959
+ "./pages": "./dist/page_components/index.js",
960
+ "./pages/login": "./dist/page_components/login.js",
961
+ "./pages/register": "./dist/page_components/register.js",
912
962
  "./components/layouts/login": "./dist/components/layouts/login/index.js",
913
963
  "./components/layouts/register": "./dist/components/layouts/register/index.js",
914
- "./components/layouts/forgot_password": "./dist/components/layouts/forgot_password/index.js",
915
- "./components/layouts/reset_password": "./dist/components/layouts/reset_password/index.js",
916
- "./components/layouts/email_verification": "./dist/components/layouts/email_verification/index.js",
917
- "./components/layouts/my_settings": "./dist/components/layouts/my_settings/index.js",
918
- "./components/layouts/user_management": "./dist/components/layouts/user_management/index.js",
919
964
  "./components/layouts/shared": "./dist/components/layouts/shared/index.js",
920
965
  "./lib/auth/hazo_get_auth.server": "./dist/lib/auth/hazo_get_auth.server.js",
921
- "./server": "./dist/server/index.js"
966
+ "./server": "./dist/server/index.js",
967
+ "./server/routes": "./dist/server/routes/index.js"
922
968
  }
923
969
  }
924
970
  ```
@@ -2,6 +2,33 @@
2
2
 
3
3
  This checklist provides step-by-step instructions for setting up the `hazo_auth` package in your Next.js project. AI assistants can follow this guide to ensure complete and correct setup.
4
4
 
5
+ ## Quick Start (Recommended)
6
+
7
+ The fastest way to set up hazo_auth:
8
+
9
+ ```bash
10
+ # 1. Install the package
11
+ npm install hazo_auth
12
+
13
+ # 2. Initialize project (creates directories, copies config files)
14
+ npx hazo_auth init
15
+
16
+ # 3. Generate API routes and pages
17
+ npx hazo_auth generate-routes --pages
18
+
19
+ # 4. Set up environment variables
20
+ cp .env.local.example .env.local
21
+ # Edit .env.local and add ZEPTOMAIL_API_KEY
22
+
23
+ # 5. Start dev server and test
24
+ npm run dev
25
+ # Visit http://localhost:3000/hazo_auth/login
26
+ ```
27
+
28
+ If this works, skip to [Phase 6: Verification Tests](#phase-6-verification-tests).
29
+
30
+ ---
31
+
5
32
  ## Pre-flight Checks
6
33
 
7
34
  Before starting, verify your project meets these requirements:
@@ -33,7 +60,25 @@ ls node_modules/hazo_auth/package.json
33
60
  # Expected: file exists
34
61
  ```
35
62
 
36
- ### Step 1.2: Copy configuration files
63
+ ### Step 1.2: Initialize project (Recommended)
64
+
65
+ Use the CLI to automatically set up directories and copy config files:
66
+
67
+ ```bash
68
+ npx hazo_auth init
69
+ ```
70
+
71
+ This command:
72
+ - Creates `public/profile_pictures/library/` directory
73
+ - Creates `public/profile_pictures/uploads/` directory
74
+ - Creates `data/` directory (for SQLite database)
75
+ - Copies `hazo_auth_config.ini` and `hazo_notify_config.ini`
76
+ - Copies profile picture library images
77
+ - Creates `.env.local.example` template
78
+
79
+ ### Step 1.2b: Manual config setup (Alternative)
80
+
81
+ If you prefer manual setup:
37
82
 
38
83
  ```bash
39
84
  cp node_modules/hazo_auth/hazo_auth_config.example.ini ./hazo_auth_config.ini
@@ -424,86 +469,92 @@ export { GET } from "hazo_auth/server/routes/profile_picture_filename";
424
469
 
425
470
  Create page files for each auth flow.
426
471
 
427
- ### Step 5.1: Create auth pages
472
+ ### Step 5.1: Generate pages automatically (Recommended)
428
473
 
429
- **Login page** - `app/(auth)/login/page.tsx`:
430
- ```typescript
431
- import { LoginLayout } from "hazo_auth/components/layouts/login";
432
-
433
- export default function LoginPage() {
434
- return <LoginLayout />;
435
- }
474
+ ```bash
475
+ npx hazo_auth generate-routes --pages
436
476
  ```
437
477
 
438
- **Register page** - `app/(auth)/register/page.tsx`:
439
- ```typescript
440
- import { RegisterLayout } from "hazo_auth/components/layouts/register";
478
+ This generates both API routes and page routes. The generated pages use zero-config components that work out of the box.
441
479
 
442
- export default function RegisterPage() {
443
- return <RegisterLayout />;
444
- }
480
+ **Generated pages:**
481
+ ```
482
+ app/hazo_auth/
483
+ ├── login/page.tsx
484
+ ├── register/page.tsx
485
+ ├── forgot_password/page.tsx
486
+ ├── reset_password/page.tsx
487
+ ├── verify_email/page.tsx
488
+ └── my_settings/page.tsx
445
489
  ```
446
490
 
447
- **Forgot password page** - `app/(auth)/forgot-password/page.tsx`:
448
- ```typescript
449
- import { ForgotPasswordLayout } from "hazo_auth/components/layouts/forgot_password";
491
+ ### Step 5.2: Manual page creation (Alternative)
450
492
 
451
- export default function ForgotPasswordPage() {
452
- return <ForgotPasswordLayout />;
453
- }
454
- ```
493
+ If you prefer manual setup or need custom paths, create these files:
455
494
 
456
- **Reset password page** - `app/(auth)/reset-password/page.tsx`:
495
+ **Login page** - `app/hazo_auth/login/page.tsx`:
457
496
  ```typescript
458
- import { ResetPasswordLayout } from "hazo_auth/components/layouts/reset_password";
497
+ import { LoginPage } from "hazo_auth/pages/login";
498
+ export default LoginPage;
499
+ ```
459
500
 
460
- export default function ResetPasswordPage() {
461
- return <ResetPasswordLayout />;
462
- }
501
+ **Register page** - `app/hazo_auth/register/page.tsx`:
502
+ ```typescript
503
+ import { RegisterPage } from "hazo_auth/pages/register";
504
+ export default RegisterPage;
463
505
  ```
464
506
 
465
- **Email verification page** - `app/(auth)/verify-email/page.tsx`:
507
+ **Forgot password page** - `app/hazo_auth/forgot_password/page.tsx`:
466
508
  ```typescript
467
- import { EmailVerificationLayout } from "hazo_auth/components/layouts/email_verification";
509
+ import { ForgotPasswordPage } from "hazo_auth/pages/forgot_password";
510
+ export default ForgotPasswordPage;
511
+ ```
468
512
 
469
- export default function VerifyEmailPage() {
470
- return <EmailVerificationLayout />;
471
- }
513
+ **Reset password page** - `app/hazo_auth/reset_password/page.tsx`:
514
+ ```typescript
515
+ import { ResetPasswordPage } from "hazo_auth/pages/reset_password";
516
+ export default ResetPasswordPage;
472
517
  ```
473
518
 
474
- **My settings page** - `app/(auth)/my-settings/page.tsx`:
519
+ **Email verification page** - `app/hazo_auth/verify_email/page.tsx`:
475
520
  ```typescript
476
- import { MySettingsLayout } from "hazo_auth/components/layouts/my_settings";
521
+ import { VerifyEmailPage } from "hazo_auth/pages/verify_email";
522
+ export default VerifyEmailPage;
523
+ ```
477
524
 
478
- export default function MySettingsPage() {
479
- return <MySettingsLayout />;
480
- }
525
+ **My settings page** - `app/hazo_auth/my_settings/page.tsx`:
526
+ ```typescript
527
+ import { MySettingsPage } from "hazo_auth/pages/my_settings";
528
+ export default MySettingsPage;
481
529
  ```
482
530
 
483
- ### Step 5.2: Create layout for auth pages (optional)
531
+ ### Step 5.3: Custom page routes (Advanced)
532
+
533
+ If you need custom paths or want to wrap pages with your own layout:
484
534
 
485
- `app/(auth)/layout.tsx`:
486
535
  ```typescript
487
- export default function AuthLayout({
488
- children,
489
- }: {
490
- children: React.ReactNode;
491
- }) {
536
+ // app/(auth)/login/page.tsx
537
+ import { LoginPage } from "hazo_auth/pages/login";
538
+
539
+ export default function CustomLoginPage() {
492
540
  return (
493
- <div className="min-h-screen flex items-center justify-center bg-background">
494
- {children}
541
+ <div className="min-h-screen flex items-center justify-center">
542
+ <LoginPage
543
+ redirectRoute="/dashboard"
544
+ successMessage="Welcome back!"
545
+ />
495
546
  </div>
496
547
  );
497
548
  }
498
549
  ```
499
550
 
500
551
  **Checklist:**
501
- - [ ] Login page created (`/login`)
502
- - [ ] Register page created (`/register`)
503
- - [ ] Forgot password page created (`/forgot-password`)
504
- - [ ] Reset password page created (`/reset-password`)
505
- - [ ] Email verification page created (`/verify-email`)
506
- - [ ] My settings page created (`/my-settings`)
552
+ - [ ] Login page created (`/hazo_auth/login`)
553
+ - [ ] Register page created (`/hazo_auth/register`)
554
+ - [ ] Forgot password page created (`/hazo_auth/forgot_password`)
555
+ - [ ] Reset password page created (`/hazo_auth/reset_password`)
556
+ - [ ] Email verification page created (`/hazo_auth/verify_email`)
557
+ - [ ] My settings page created (`/hazo_auth/my_settings`)
507
558
 
508
559
  ---
509
560
 
@@ -578,15 +629,22 @@ curl -s http://localhost:3000/api/hazo_auth/library_photos | jq
578
629
  **Expected response:**
579
630
  ```json
580
631
  {
581
- "photos": [
582
- {"url": "/profile_pictures/library/...", "name": "..."},
583
- ...
584
- ]
632
+ "success": true,
633
+ "categories": ["Cars", "Young Cartoons"],
634
+ "source": "project"
585
635
  }
586
636
  ```
587
637
 
588
- **If library photos not showing:**
589
- - Copy profile pictures from `node_modules/hazo_auth/public/profile_pictures/library/` to `public/profile_pictures/library/`
638
+ The `source` field indicates where photos are served from:
639
+ - `"project"` - Photos are in your project's `public/profile_pictures/library/`
640
+ - `"node_modules"` - Photos are served from `node_modules/hazo_auth/public/` via API route
641
+
642
+ **Test paginated photos:**
643
+ ```bash
644
+ curl -s "http://localhost:3000/api/hazo_auth/library_photos?category=Cars&page=1&page_size=5" | jq
645
+ ```
646
+
647
+ **Note:** Library photos work automatically whether they're copied to your project or still in node_modules. The API will serve them from node_modules as a fallback.
590
648
 
591
649
  ### Test 6: Visit Pages in Browser
592
650
 
@@ -596,10 +654,10 @@ npm run dev
596
654
  ```
597
655
 
598
656
  Visit each page and verify it loads:
599
- - [ ] `http://localhost:3000/login` - Login form displays
600
- - [ ] `http://localhost:3000/register` - Registration form displays
601
- - [ ] `http://localhost:3000/forgot-password` - Forgot password form displays
602
- - [ ] `http://localhost:3000/my-settings` - Settings page displays (after login)
657
+ - [ ] `http://localhost:3000/hazo_auth/login` - Login form displays
658
+ - [ ] `http://localhost:3000/hazo_auth/register` - Registration form displays
659
+ - [ ] `http://localhost:3000/hazo_auth/forgot_password` - Forgot password form displays
660
+ - [ ] `http://localhost:3000/hazo_auth/my_settings` - Settings page displays (after login)
603
661
 
604
662
  ---
605
663
 
@@ -620,13 +678,26 @@ Visit each page and verify it loads:
620
678
  **Symptoms:** Avatar shows fallback initials, library photos empty.
621
679
 
622
680
  **Solutions:**
623
- 1. Copy library photos:
681
+ 1. **Run init command** (copies library photos automatically):
682
+ ```bash
683
+ npx hazo_auth init
684
+ ```
685
+
686
+ 2. **Or manually copy library photos:**
624
687
  ```bash
625
688
  mkdir -p public/profile_pictures/library
626
689
  cp -r node_modules/hazo_auth/public/profile_pictures/library/* public/profile_pictures/library/
627
690
  ```
628
- 2. Verify `library_photos` API route exists
629
- 3. Check file permissions on `public/profile_pictures/`
691
+
692
+ 3. **Check API response source:**
693
+ ```bash
694
+ curl -s http://localhost:3000/api/hazo_auth/library_photos | jq '.source'
695
+ ```
696
+ - If `"node_modules"` - Photos are being served from the package (slower but works)
697
+ - If `"project"` - Photos are in your public folder (optimal)
698
+
699
+ 4. Verify `library_photos` and `library_photo` API routes exist
700
+ 5. Check file permissions on `public/profile_pictures/`
630
701
 
631
702
  ### Issue: Database connection failed
632
703
 
@@ -0,0 +1,9 @@
1
+ import { NextRequest, NextResponse } from "next/server";
2
+ export declare const dynamic = "force-dynamic";
3
+ export declare function GET(request: NextRequest, { params }: {
4
+ params: {
5
+ category: string;
6
+ filename: string;
7
+ };
8
+ }): Promise<NextResponse<unknown>>;
9
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../src/app/api/hazo_auth/library_photo/[category]/[filename]/route.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AASxD,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAevC,wBAAsB,GAAG,CACvB,OAAO,EAAE,WAAW,EACpB,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,kCA4E/D"}
@@ -0,0 +1,82 @@
1
+ // file_description: API route to serve library photos from node_modules fallback
2
+ // This route is used when library photos haven't been copied to the project's public folder
3
+ // section: imports
4
+ import { NextResponse } from "next/server";
5
+ import { get_library_photo_path } from "../../../../../../lib/services/profile_picture_service";
6
+ import { create_app_logger } from "../../../../../../lib/app_logger";
7
+ import { get_filename, get_line_number } from "../../../../../../lib/utils/api_route_helpers";
8
+ import fs from "fs";
9
+ import path from "path";
10
+ // section: route_config
11
+ // Cache library photos for 1 hour (they don't change)
12
+ export const dynamic = 'force-dynamic';
13
+ // section: constants
14
+ const MIME_TYPES = {
15
+ ".jpg": "image/jpeg",
16
+ ".jpeg": "image/jpeg",
17
+ ".png": "image/png",
18
+ ".gif": "image/gif",
19
+ ".webp": "image/webp",
20
+ ".svg": "image/svg+xml",
21
+ };
22
+ const CACHE_MAX_AGE = 3600; // 1 hour in seconds
23
+ // section: api_handler
24
+ export async function GET(request, { params }) {
25
+ const logger = create_app_logger();
26
+ const { category, filename } = params;
27
+ try {
28
+ // Validate inputs to prevent path traversal
29
+ if (category.includes("..") ||
30
+ category.includes("/") ||
31
+ category.includes("\\") ||
32
+ filename.includes("..") ||
33
+ filename.includes("/") ||
34
+ filename.includes("\\")) {
35
+ logger.warn("library_photo_invalid_path", {
36
+ filename: get_filename(),
37
+ line_number: get_line_number(),
38
+ category,
39
+ requested_filename: filename,
40
+ });
41
+ return NextResponse.json({ error: "Invalid path" }, { status: 400 });
42
+ }
43
+ // Get the physical file path
44
+ const photo_path = get_library_photo_path(category, filename);
45
+ if (!photo_path) {
46
+ logger.warn("library_photo_not_found", {
47
+ filename: get_filename(),
48
+ line_number: get_line_number(),
49
+ category,
50
+ requested_filename: filename,
51
+ });
52
+ return NextResponse.json({ error: "Photo not found" }, { status: 404 });
53
+ }
54
+ // Read the file
55
+ const file_buffer = fs.readFileSync(photo_path);
56
+ const ext = path.extname(filename).toLowerCase();
57
+ const content_type = MIME_TYPES[ext] || "application/octet-stream";
58
+ // Return the image with caching headers
59
+ return new NextResponse(file_buffer, {
60
+ status: 200,
61
+ headers: {
62
+ "Content-Type": content_type,
63
+ "Content-Length": file_buffer.length.toString(),
64
+ "Cache-Control": `public, max-age=${CACHE_MAX_AGE}, immutable`,
65
+ "X-Library-Source": "node_modules",
66
+ },
67
+ });
68
+ }
69
+ catch (error) {
70
+ const error_message = error instanceof Error ? error.message : "Unknown error";
71
+ const error_stack = error instanceof Error ? error.stack : undefined;
72
+ logger.error("library_photo_error", {
73
+ filename: get_filename(),
74
+ line_number: get_line_number(),
75
+ category,
76
+ requested_filename: filename,
77
+ error_message,
78
+ error_stack,
79
+ });
80
+ return NextResponse.json({ error: "Failed to serve photo" }, { status: 500 });
81
+ }
82
+ }
@@ -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"}